support_kit/deployments/
deployment_context.rs1use std::path::PathBuf;
2
3use figment::providers::Serialized;
4
5use crate::{shell, Configuration, Registry, ShellCommand, SupportControl};
6
7use super::{HostDeploymentContext, ImageDeploymentContext};
8
9#[derive(Debug, Clone, bon::Builder)]
10pub struct DeploymentContext {
11 #[builder(default)]
12 pub figment: figment::Figment,
13 pub config: Configuration,
14 #[builder(default, into)]
15 pub images: Vec<ImageDeploymentContext>,
16 #[builder(default, into)]
17 pub hosts: Vec<HostDeploymentContext>,
18 pub registry: Registry,
19}
20
21impl DeploymentContext {
22 pub fn from_controller(controller: &SupportControl) -> Self {
23 let figment = controller.figment().unwrap_or_default();
24 let config = controller.config.clone();
25 let host_defs = config
26 .deployment
27 .clone()
28 .map(|deployment| deployment.hosts)
29 .unwrap_or_default();
30
31 let (image_defs, registry) = config
32 .deployment
33 .clone()
34 .and_then(|deployment| deployment.artifacts)
35 .and_then(|artifacts| artifacts.containers)
36 .map(|containers| (containers.images, containers.registry.unwrap_or_default()))
37 .unwrap_or_default();
38
39 let mut images = vec![];
40 let mut hosts = vec![];
41
42 for host in host_defs {
43 hosts.push(
44 HostDeploymentContext::builder()
45 .config(config.clone())
46 .host(host)
47 .registry(registry.clone())
48 .build(),
49 );
50 }
51
52 for image in image_defs {
53 images.push(
54 ImageDeploymentContext::builder()
55 .config(config.clone())
56 .image(image)
57 .registry(registry.clone())
58 .build(),
59 );
60 }
61
62 Self::builder()
63 .figment(figment)
64 .config(config)
65 .images(images)
66 .hosts(hosts)
67 .registry(registry)
68 .build()
69 }
70
71 #[tracing::instrument(skip(self), level = "trace")]
72 pub fn emit_config(&self) -> crate::Result<PathBuf> {
73 let path =
74 std::env::temp_dir().join(format!("{name}.container.json", name = self.config.name()));
75
76 let contents = serde_json::to_value(&self.config)?;
77 let all_configuration = self
78 .figment
79 .clone()
80 .merge(Serialized::from(contents, "default"))
81 .extract::<serde_json::Value>()?;
82
83 let contents = serde_json::to_string(&all_configuration)?;
84
85 tracing::debug!(path = ?path, contents = ?contents, "writing container config file");
86
87 std::fs::write(&path, contents).expect("Unable to write file");
88
89 Ok(path)
90 }
91
92 #[tracing::instrument(skip(self), level = "trace")]
93 pub fn setup_cert_volume(&self) -> crate::Result<ShellCommand> {
94 shell(format!("docker volume create certs"))
95 }
96
97 #[tracing::instrument(skip(self), level = "trace")]
98 pub fn setup_network(&self) -> crate::Result<ShellCommand> {
99 shell(format!(
100 "docker network create {name}-network",
101 name = self.config.name()
102 ))
103 }
104
105 #[tracing::instrument(skip(self), level = "trace")]
109 pub fn get_install_script(&self) -> crate::Result<ShellCommand> {
110 shell(format!(
111 "curl -fsSL https://get.docker.com -o get-docker.sh"
112 ))
113 }
114
115 #[tracing::instrument(skip(self), level = "trace")]
117 pub fn install_docker(&self) -> crate::Result<ShellCommand> {
118 shell(format!("sh get-docker.sh"))
119 }
120
121 #[tracing::instrument(skip(self), level = "trace")]
122 pub fn login(&self) -> crate::Result<ShellCommand> {
123 shell(format!(
124 "docker login {host} -u {account} -p {token}",
125 host = self.registry.host,
126 account = self.registry.account,
127 token = self.registry.token
128 ))
129 }
130
131 #[tracing::instrument(skip(self), level = "trace")]
132 pub fn list_containers(&self) -> crate::Result<ShellCommand> {
133 shell(format!("docker ps"))
134 }
135}
136
137impl From<&SupportControl> for DeploymentContext {
138 fn from(controller: &SupportControl) -> Self {
139 Self::from_controller(controller)
140 }
141}