Skip to main content

alien_core/import/
request.rs

1use crate::{ManagementConfig, Platform, ResourceType, StackSettings, StackState};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// Oldest setup import payload format this binary can read.
6pub const MIN_SUPPORTED_SETUP_IMPORT_FORMAT_VERSION: u32 = 1;
7
8/// Setup import payload format this binary writes.
9pub const CURRENT_SETUP_IMPORT_FORMAT_VERSION: u32 = 1;
10
11/// Managed Aurora credentials require readers that understand the JSON secret binding.
12pub const MANAGED_POSTGRES_SETUP_IMPORT_FORMAT_VERSION: u32 = 3;
13
14/// Latest setup payload this binary can read. GCP federation packages require v2.
15pub const MAX_SUPPORTED_SETUP_IMPORT_FORMAT_VERSION: u32 =
16    MANAGED_POSTGRES_SETUP_IMPORT_FORMAT_VERSION;
17
18pub fn setup_import_format_version_for_platform(platform: Platform) -> u32 {
19    if platform == Platform::Gcp {
20        2
21    } else {
22        CURRENT_SETUP_IMPORT_FORMAT_VERSION
23    }
24}
25
26/// Package source that produced an import request. Observability label
27/// only — the manager does not branch on this value, and any new deployment
28/// pathway can omit it without affecting import behavior.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
30#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
31#[serde(rename_all = "lowercase")]
32pub enum ImportSourceKind {
33    /// CloudFormation Custom Resource or Stack Outputs.
34    CloudFormation,
35    /// Terraform provider resource.
36    Terraform,
37    /// Helm chart local-import bootstrap path.
38    Helm,
39}
40
41/// Request body for manager-side stack import.
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
44#[serde(rename_all = "camelCase")]
45pub struct StackImportRequest {
46    /// Wire-format version for the setup import payload.
47    pub setup_import_format_version: u32,
48    /// Deployment-group token authorizing the import.
49    pub deployment_group_token: String,
50    /// User-chosen deployment name. Must be unique within the deployment
51    /// group; the manager returns 409 on collision rather than silently
52    /// resolving to an existing deployment. Each setup adapter picks
53    /// the natural source: CloudFormation defaults to the CFN stack name,
54    /// Helm to `{namespace}/{release}`, Terraform requires an explicit
55    /// `name` attribute on the `alien_deployment` resource.
56    pub deployment_name: String,
57    /// Stable physical-name prefix used by the setup package for generated
58    /// resources. Runtime controllers use it when addressing imported
59    /// resources.
60    pub resource_prefix: String,
61    /// Optional source label for observability. Does not affect import
62    /// behavior — the manager dispatches the same `ImporterRegistry`
63    /// regardless of which setup package emitted the payload.
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub source_kind: Option<ImportSourceKind>,
66    /// Setup source metadata needed by the control plane to guide privileged
67    /// teardown. The manager treats this as opaque JSON.
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub setup_metadata: Option<serde_json::Value>,
70    /// Optional release id that produced the setup package. When
71    /// omitted, the manager imports against the latest release.
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub release_id: Option<String>,
74    /// Platform being imported.
75    pub platform: Platform,
76    /// Optional base cloud platform for Kubernetes setup targets such as
77    /// EKS/GKE/AKS. The runtime platform remains Kubernetes.
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub base_platform: Option<Platform>,
80    /// Region or location reported by the setup artifact.
81    pub region: String,
82    /// Setup target this package was generated for.
83    pub setup_target: String,
84    /// Setup compatibility fingerprint embedded in the package.
85    pub setup_fingerprint: String,
86    /// Setup fingerprint algorithm version embedded in the package.
87    pub setup_fingerprint_version: u32,
88    /// Resolved stack settings supplied by the setup artifact.
89    pub stack_settings: StackSettings,
90    /// Platform-derived management configuration, when this setup creates a
91    /// cross-account/cross-tenant management identity.
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub management_config: Option<ManagementConfig>,
94    /// Deployer-provided stack input values collected by generated setup
95    /// surfaces. Platform-backed managers resolve these into runtime
96    /// environment variables before deployment creation; standalone managers
97    /// accept the field for setup package compatibility.
98    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
99    pub input_values: HashMap<String, serde_json::Value>,
100    /// Imported resources with typed per-resource payloads.
101    pub resources: Vec<ImportedResource>,
102}
103
104/// One resolved resource import payload.
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
107#[serde(rename_all = "camelCase")]
108pub struct ImportedResource {
109    /// Resource id from the active stack.
110    pub id: String,
111    /// Resource type from the active stack.
112    #[serde(rename = "type")]
113    pub resource_type: ResourceType,
114    /// Resolved typed payload for this resource.
115    #[cfg_attr(feature = "openapi", schema(value_type = Object))]
116    pub import_data: serde_json::Value,
117}
118
119/// Response body returned after a stack import.
120#[derive(Debug, Clone, Serialize, Deserialize)]
121#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
122#[serde(rename_all = "camelCase")]
123pub struct StackImportResponse {
124    /// Deployment created.
125    pub deployment_id: String,
126    /// Deployment bearer token for the imported deployment, when available.
127    #[serde(default, skip_serializing_if = "Option::is_none")]
128    pub deployment_token: Option<String>,
129    /// Stack settings persisted for the deployment.
130    pub stack_settings: StackSettings,
131    /// Fully populated imported stack state.
132    pub stack_state: StackState,
133}
134
135#[cfg(test)]
136mod tests {
137    use super::ImportSourceKind;
138
139    #[test]
140    fn import_source_kind_serializes_cloudformation_without_separator() {
141        let value = serde_json::to_value(ImportSourceKind::CloudFormation).unwrap();
142        assert_eq!(value, "cloudformation");
143
144        let source: ImportSourceKind = serde_json::from_value(value).unwrap();
145        assert_eq!(source, ImportSourceKind::CloudFormation);
146    }
147}