Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions client-sdks/manager/openapi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions client-sdks/manager/rust/openapi-3.0.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 72 additions & 11 deletions crates/alien-deploy-cli/src/commands/up.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -98,6 +98,10 @@ pub struct UpArgs {
#[arg(long)]
pub name: Option<String>,

/// Setup item captured by the deployment-group token.
#[arg(long = "setup-item")]
pub setup_item: Option<String>,

/// Encryption key for operator database (required for pull model)
#[arg(long, env = "OPERATOR_ENCRYPTION_KEY")]
pub encryption_key: Option<String>,
Expand DownExpand Up@@ -927,6 +931,40 @@ machine = "m8i.xlarge"
assert_eq!(error.code, "VALIDATION_ERROR");
}

#[test]
fn deploy_accepts_setup_item_selection() {
let args = UpArgs::parse_from([
"alien-deploy",
"--platform",
"aws",
"--setup-item",
"deployment",
]);

assert_eq!(args.setup_item.as_deref(), Some("deployment"));
}

#[test]
fn deployment_info_url_includes_setup_item_selection() {
let url = deployment_info_url(
"https://api.example.test/",
Platform::Aws,
Some("deployment"),
)
.expect("deployment info URL should be valid");
let query = url.query_pairs().collect::<HashMap<_, _>>();

assert_eq!(url.path(), "/v1/deployment-info");
assert_eq!(
query.get("platform").map(|value| value.as_ref()),
Some("aws")
);
assert_eq!(
query.get("setupItem").map(|value| value.as_ref()),
Some("deployment")
);
}

fn stack_input(id: &str, kind: StackInputKind, required: bool) -> StackInputDefinition {
StackInputDefinition {
id: id.to_string(),
Expand DownExpand Up@@ -1080,7 +1118,14 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>)
let print_progress = should_print_deploy_progress(platform);
let base_platform = parse_base_platform(platform, base_platform_str.as_deref())?;
let public_endpoints = load_public_endpoints(&args, platform, deploy_config.as_ref())?;
let deployer_inputs = match fetch_deployment_info(&resolved.base_url, &token, platform).await {
let deployer_inputs = match fetch_deployment_info(
&resolved.base_url,
&token,
platform,
args.setup_item.as_deref(),
)
.await
{
Ok(info) => {
validate_deployment_readiness(&info, platform)?;
deployer_inputs_from_info(&info, platform)
Expand DownExpand Up@@ -1182,6 +1227,7 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>)
&name,
&stack_settings,
stack_input_values,
args.setup_item.as_deref(),
)
.await?;
let deployment_id = init.deployment_id;
Expand DownExpand Up@@ -2021,6 +2067,7 @@ async fn fetch_deployment_info(
base_url: &str,
token: &str,
platform: Platform,
setup_item: Option<&str>,
) -> Result<DeploymentInfoResponse> {
let http_client = {
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, USER_AGENT};
Expand All@@ -2045,16 +2092,7 @@ async fn fetch_deployment_info(
})?
};

let mut url = reqwest::Url::parse(&format!(
"{}/v1/deployment-info",
base_url.trim_end_matches('/')
))
.into_alien_error()
.context(ErrorData::ConfigurationError {
message: "Invalid platform API base URL".to_string(),
})?;
url.query_pairs_mut()
.append_pair("platform", platform.as_str());
let url = deployment_info_url(base_url, platform, setup_item)?;
let response = http_client
.get(url)
.send()
Expand All@@ -2080,6 +2118,27 @@ async fn fetch_deployment_info(
})
}

fn deployment_info_url(
base_url: &str,
platform: Platform,
setup_item: Option<&str>,
) -> Result<reqwest::Url> {
let mut url = reqwest::Url::parse(&format!(
"{}/v1/deployment-info",
base_url.trim_end_matches('/')
))
.into_alien_error()
.context(ErrorData::ConfigurationError {
message: "Invalid platform API base URL".to_string(),
})?;
url.query_pairs_mut()
.append_pair("platform", platform.as_str());
if let Some(setup_item) = setup_item {
url.query_pairs_mut().append_pair("setupItem", setup_item);
}
Ok(url)
}

fn deployer_inputs_from_info(
info: &DeploymentInfoResponse,
platform: Platform,
Expand DownExpand Up@@ -2605,12 +2664,14 @@ async fn initialize_deployment(
name: &str,
stack_settings: &StackSettings,
input_values: HashMap<String, serde_json::Value>,
setup_item: Option<&str>,
) -> Result<InitResult> {
let body = alien_manager_api::types::InitializeRequest {
name: Some(name.to_string()),
platform: Some(sdk_platform(platform)),
base_platform: base_platform.map(sdk_platform),
initial_desired_release: alien_manager_api::types::InitialDesiredRelease::Active,
setup_item: setup_item.map(ToString::to_string),
stack_settings: Some(sdk_stack_settings(stack_settings)?),
input_values: input_values.into_iter().collect(),
scope: None,
Expand Down
7 changes: 7 additions & 0 deletions crates/alien-manager/openapi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/alien-manager/src/routes/deployments.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -463,6 +463,7 @@ async fn create_deployment(
environment_variables: req.environment_variables,
public_subdomain: None,
input_values: Default::default(),
setup_item: None,
deployment_token: Some(raw_token.clone()),
},
)
Expand Down
8 changes: 7 additions & 1 deletion crates/alien-manager/src/routes/sync.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -190,6 +190,9 @@ pub struct InitializeRequest {
/// creation intent, not a permanent deployment mode: a later update can
/// assign a desired release to a deployment initialized with `none`.
pub initial_desired_release: InitialDesiredRelease,
/// Customer setup item selected from the deployment-group contract.
#[serde(skip_serializing_if = "Option::is_none")]
pub setup_item: Option<String>,
pub stack_settings: Option<alien_core::StackSettings>,
/// Deployer-provided stack inputs. Embedded platform managers resolve
/// these before creating the deployment; standalone managers accept the
Expand DownExpand Up@@ -775,10 +778,12 @@ mod tests {
let request: InitializeRequest = serde_json::from_value(json!({
"platform": "kubernetes",
"permission": "observe",
"initialDesiredRelease": "none"
"initialDesiredRelease": "none",
"setupItem": "deployment"
}))
.expect("explicit no-release initialization should deserialize");
assert_eq!(request.initial_desired_release, InitialDesiredRelease::None);
assert_eq!(request.setup_item.as_deref(), Some("deployment"));

let missing_selection = serde_json::from_value::<InitializeRequest>(json!({
"platform": "kubernetes",
Expand DownExpand Up@@ -1855,6 +1860,7 @@ async fn initialize(
environment_variables: None,
public_subdomain: None,
input_values: req.input_values,
setup_item: req.setup_item,
deployment_token: dep_token,
},
)
Expand Down
2 changes: 2 additions & 0 deletions crates/alien-manager/src/traits/deployment_store.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,6 +148,8 @@ pub struct CreateDeploymentParams {
pub public_subdomain: Option<String>,
/// Stack input values collected before deployment creation.
pub input_values: HashMap<String, serde_json::Value>,
/// Customer setup item selected from the deployment-group contract.
pub setup_item: Option<String>,
/// Raw deployment token for proxy pull auth.
pub deployment_token: Option<String>,
}
Expand Down
1 change: 1 addition & 0 deletions crates/alien-manager/tests/registry_proxy_cloud_test.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -349,6 +349,7 @@ impl CloudProxyTest {
environment_variables: None,
public_subdomain: None,
input_values: Default::default(),
setup_item: None,
deployment_token: Some(deploy_raw.clone()),
},
)
Expand Down
1 change: 1 addition & 0 deletions crates/alien-manager/tests/registry_proxy_test.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -310,6 +310,7 @@ async fn setup() -> TestSetup {
environment_variables: None,
public_subdomain: None,
input_values: Default::default(),
setup_item: None,
deployment_token: Some(deploy_raw.clone()),
},
)
Expand Down
2 changes: 2 additions & 0 deletions crates/alien-manager/tests/sqlite_store_tests.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -96,6 +96,7 @@ async fn create_test_deployment_with_settings(
environment_variables: None,
public_subdomain: None,
input_values: Default::default(),
setup_item: None,
deployment_token: None,
},
)
Expand DownExpand Up@@ -250,6 +251,7 @@ async fn input_values_survive_create_import_and_reimport() {
environment_variables: None,
public_subdomain: None,
input_values: values.clone(),
setup_item: None,
deployment_token: None,
},
)
Expand Down
1 change: 1 addition & 0 deletions crates/alien-manager/tests/stack_import.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1068,6 +1068,7 @@ async fn native_deployment_blocks_imported_name() {
stack_state: None,
environment_variables: None,
input_values: Default::default(),
setup_item: None,
deployment_token: None,
},
)
Expand Down
Loading