systemprompt_cloud/deploy/provider/
mod.rs1mod gitops;
17mod health;
18mod systemprompt;
19mod values_file;
20
21use std::collections::HashMap;
22use std::future::Future;
23
24use systemprompt_manifest::HostingProvider;
25
26use crate::error::{CloudError, CloudResult};
27
28pub use gitops::{GitOpsDeploy, GitOpsDeployParams};
29pub use health::{TenantHealth, probe_tenant, tenant_base_url, wait_until_ready};
30pub use systemprompt::SystempromptCloud;
31pub use values_file::{ValuesFileError, set_yaml_scalar};
32
33pub trait DeployProvider: Send + Sync {
36 fn provider(&self) -> HostingProvider;
37
38 fn secrets_transport(&self) -> SecretsTransport;
39
40 fn registry_credentials(&self) -> impl Future<Output = CloudResult<RegistryTarget>> + Send;
41
42 fn push_secrets(
43 &self,
44 batch: SecretBatch,
45 ) -> impl Future<Output = CloudResult<SecretsOutcome>> + Send;
46
47 fn rollout(
48 &self,
49 image: &BuiltImage,
50 ) -> impl Future<Output = CloudResult<RolloutReport>> + Send;
51
52 fn status(&self) -> impl Future<Output = CloudResult<TenantHealth>> + Send;
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum DeployProviderKind {
57 SystempromptCloud,
58 GitOps,
59}
60
61impl DeployProviderKind {
62 pub const fn for_provider(provider: HostingProvider) -> CloudResult<Self> {
63 match provider {
64 HostingProvider::Systemprompt => Ok(Self::SystempromptCloud),
65 HostingProvider::Kubernetes | HostingProvider::Gke => Ok(Self::GitOps),
66 HostingProvider::DockerLocal => Err(CloudError::ProviderNotDeployable { provider }),
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum SecretsTransport {
73 Push,
74 External,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct RegistryTarget {
79 pub image: String,
80 pub login: Option<RegistryLogin>,
81}
82
83#[derive(Clone, PartialEq, Eq)]
84pub struct RegistryLogin {
85 pub registry: String,
86 pub username: String,
87 pub token: String,
88}
89
90impl std::fmt::Debug for RegistryLogin {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 f.debug_struct("RegistryLogin")
93 .field("registry", &self.registry)
94 .field("username", &self.username)
95 .finish_non_exhaustive()
96 }
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum SecretPurpose {
101 Profile,
102 VaultBootstrap,
103 PlatformCredentials,
104 ProfilePath,
105}
106
107#[derive(Clone, PartialEq, Eq)]
108pub enum SecretBatch {
109 Values {
110 purpose: SecretPurpose,
111 entries: HashMap<String, String>,
112 },
113 Declared {
114 purpose: SecretPurpose,
115 keys: Vec<String>,
116 },
117}
118
119impl SecretBatch {
120 #[must_use]
121 pub const fn purpose(&self) -> SecretPurpose {
122 match self {
123 Self::Values { purpose, .. } | Self::Declared { purpose, .. } => *purpose,
124 }
125 }
126
127 #[must_use]
128 pub fn keys(&self) -> Vec<String> {
129 let mut keys: Vec<String> = match self {
130 Self::Values { entries, .. } => entries.keys().cloned().collect(),
131 Self::Declared { keys, .. } => keys.clone(),
132 };
133 keys.sort();
134 keys.dedup();
135 keys
136 }
137}
138
139impl std::fmt::Debug for SecretBatch {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 f.debug_struct("SecretBatch")
142 .field("purpose", &self.purpose())
143 .field("keys", &self.keys())
144 .finish()
145 }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq)]
149pub enum SecretsOutcome {
150 Pushed { keys: Vec<String> },
151 External { required: Vec<String> },
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
155pub struct BuiltImage {
156 pub reference: String,
157 pub pushed: bool,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct RolloutReport {
162 pub image: String,
163 pub status: String,
164 pub app_url: Option<String>,
165 pub commit: Option<String>,
166}