Skip to main content

alien_core/deployment/
config.rs

1//! Deployment configuration and OTLP observability settings.
2
3use crate::{ExternalBindings, ManagementConfig, StackSettings};
4use bon::Builder;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8use super::{is_false, ComputeBackend, DomainMetadata, EnvironmentVariablesSnapshot};
9
10/// Deployment configuration
11///
12/// Configuration for how to perform the deployment.
13/// Note: Credentials (ClientConfig) are passed separately to step() function.
14#[derive(Debug, Clone, Serialize, Deserialize, Builder)]
15#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
16#[serde(rename_all = "camelCase")]
17pub struct DeploymentConfig {
18    /// User-customizable deployment settings (network, deployment model, approvals).
19    /// Provided by customer via CloudFormation, Terraform, CLI, or Helm.
20    #[serde(default)]
21    pub stack_settings: StackSettings,
22    /// Platform service account/role that will manage the infrastructure remotely.
23    /// Derived from Manager's ServiceAccount, not user-specified.
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub management_config: Option<ManagementConfig>,
26    /// Environment variables snapshot
27    pub environment_variables: EnvironmentVariablesSnapshot,
28    /// Allow frozen resource changes during updates
29    /// When true, skips the frozen resources compatibility check.
30    /// This requires running with elevated cloud credentials.
31    #[serde(default, skip_serializing_if = "is_false")]
32    pub allow_frozen_changes: bool,
33    /// Compute backend for Container and Function resources.
34    /// When None, the platform default is used (Horizon for cloud platforms).
35    /// Contains cluster IDs and management tokens for container orchestration.
36    /// Machine tokens are stored in environment_variables as built-in secret vars.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub compute_backend: Option<ComputeBackend>,
39    /// External bindings for pre-existing services.
40    /// Required for Kubernetes platform (all infrastructure resources).
41    /// Optional for cloud platforms (override specific resources).
42    #[serde(default)]
43    pub external_bindings: ExternalBindings,
44    /// Public URLs for exposed resources (optional override for all platforms).
45    ///
46    /// - **Kubernetes**: Pre-computed by Helm from services config (highly recommended)
47    /// - **Cloud**: Optional override of domain_metadata or load balancer DNS
48    /// - **Local**: Optional override of dynamic localhost URLs
49    ///
50    /// If not set, platforms determine public URLs from other sources:
51    /// - Cloud: domain_metadata FQDN or load balancer DNS
52    /// - Local: http://localhost:{allocated_port}
53    /// - Kubernetes: None (unless provided by Helm)
54    ///
55    /// Key: resource ID, Value: public URL (e.g., "https://api.acme.com")
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub public_urls: Option<HashMap<String, String>>,
58    /// Domain metadata for auto-managed public resources (AWS/GCP/Azure).
59    /// Contains certificate data for cloud provider import and renewal detection.
60    /// Not used by Kubernetes (uses TLS Secrets) or Local (no TLS) platforms.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub domain_metadata: Option<DomainMetadata>,
63    /// OTLP observability configuration for log export (optional).
64    ///
65    /// When set, alien-deployment injects OTEL_EXPORTER_OTLP_* env vars into
66    /// container/function configs, and alien-infra embeds --otlp-logs-* flags
67    /// into horizond VM startup scripts.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub monitoring: Option<OtlpConfig>,
70    /// Manager base URL (e.g., "https://manager.alien.dev").
71    ///
72    /// The manager IS the container registry — its `/v2/` endpoint serves as
73    /// the OCI Distribution API. Controllers derive the proxy host from this
74    /// to configure pull auth (RegistryCredentials, imagePullSecrets).
75    ///
76    /// When None (e.g., `alien dev`), controllers use image URIs as-is.
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub manager_url: Option<String>,
79    /// Deployment token for pull authentication with the manager's registry.
80    ///
81    /// Used by controllers to configure registry credentials so cloud platforms
82    /// and K8s can pull images from the manager's `/v2/` endpoint.
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub deployment_token: Option<String>,
85    /// Native image registry host+prefix for platforms that require it.
86    ///
87    /// Only Lambda (ECR) and Cloud Run (GAR) require native registry URIs.
88    /// All other platforms pull through the manager's proxy.
89    ///
90    /// Derived by the manager from the artifact registry binding:
91    /// - ECR: `{account_id}.dkr.ecr.{region}.amazonaws.com/{repository_prefix}`
92    /// - GAR: `{region}-docker.pkg.dev/{project_id}/{repository_name}`
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub native_image_host: Option<String>,
95}
96
97/// OTLP log export configuration for a deployment.
98///
99/// When set, all compute workloads (containers and horizond VM workers) export
100/// their logs to the given endpoint via OTLP/HTTP.
101///
102/// The `logs_auth_header` is stored as plain text in DeploymentConfig because
103/// alien-runtime reads `OTEL_EXPORTER_OTLP_HEADERS` at tracing-init time,
104/// before vault secrets load. For horizond, the infra controller writes the
105/// same value to the cloud vault (same pattern as the machine token) and the
106/// startup script fetches it at boot via IAM.
107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
108#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
109#[serde(rename_all = "camelCase")]
110pub struct OtlpConfig {
111    /// Full OTLP logs endpoint URL.
112    /// Example: "https://<manager-host>/v1/logs"
113    pub logs_endpoint: String,
114    /// Auth header value in "key=value,..." format used for container OTLP env var injection.
115    ///
116    /// `alien-deployment` injects this as the `OTEL_EXPORTER_OTLP_HEADERS` plain env var
117    /// into all containers. It must be plain (not a vault secret) because alien-runtime
118    /// reads `OTEL_EXPORTER_OTLP_HEADERS` at tracing-init time, before vault secrets load.
119    ///
120    /// horizond VM workers do NOT use this field directly. The ContainerCluster infra
121    /// controller writes the same value to the cloud vault (GCP: Secret Manager,
122    /// AWS: Secrets Manager, Azure: Key Vault) and the startup script fetches it at
123    /// boot via IAM -- the same pattern as the machine token.
124    ///
125    /// Example: "authorization=Bearer <write-token>"
126    pub logs_auth_header: String,
127    /// Full OTLP metrics endpoint URL (optional).
128    /// When set, horizond exports its own VM/container orchestration metrics here.
129    /// Example: "https://api.axiom.co/v1/metrics"
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub metrics_endpoint: Option<String>,
132    /// Auth header value for the metrics endpoint in "key=value,..." format (optional).
133    ///
134    /// When absent, `logs_auth_header` is reused for metrics -- suitable when the same
135    /// credential covers both signals. When present (e.g. Axiom with separate datasets),
136    /// this value is used exclusively for metrics.
137    ///
138    /// Example: "authorization=Bearer <token>,x-axiom-dataset=<metrics-dataset>"
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub metrics_auth_header: Option<String>,
141}