support_kit/deployments/
deployment_command.rs1use clap::Parser;
2
3use crate::SupportControl;
4
5use super::DeploymentContext;
6
7#[derive(Clone, Copy, Parser, Debug, PartialEq)]
8#[clap(rename_all = "kebab-case")]
9pub enum DeploymentCommand {
10 Install,
11 Setup,
12 Build,
13 Start,
14 List,
15 Login,
16 Pull,
17 Push,
18 Restart,
19}
20
21impl DeploymentCommand {
22 #[tracing::instrument(skip(self, controller), level = "trace")]
23 pub async fn exec_remote(&self, controller: &SupportControl) -> crate::Result<()> {
24 Ok(exec_remote_container_op(&controller, *self).await?)
25 }
26
27 #[tracing::instrument(skip(self, controller), level = "trace")]
28 pub async fn exec_local(&self, controller: &SupportControl) -> crate::Result<()> {
29 Ok(exec_local_container_op(&controller, self).await?)
30 }
31}
32
33#[tracing::instrument(skip(controller, command), level = "trace")]
34pub async fn exec_local_container_op(
35 controller: &SupportControl,
36 command: &DeploymentCommand,
37) -> crate::Result<()> {
38 let deployment_context = DeploymentContext::from(controller);
39 tracing::trace!(command = ?command, "executing local container operation");
40 match command {
41 DeploymentCommand::Build => {
42 for image in deployment_context.images {
43 image.build()?.run()?;
44 }
45 }
46 DeploymentCommand::Install => {
47 deployment_context.get_install_script()?.run()?;
48 deployment_context.install_docker()?.run()?;
49 }
50 DeploymentCommand::List => deployment_context.list_containers()?.run()?,
51 DeploymentCommand::Login => deployment_context.login()?.run()?,
52 DeploymentCommand::Pull => {
53 for image in deployment_context.images {
54 image.pull()?.run()?;
55 }
56 }
57 DeploymentCommand::Push => {
58 for image in deployment_context.images {
59 image.push()?.run()?;
60 }
61 }
62 DeploymentCommand::Restart => {
63 let path = deployment_context.emit_config()?;
64 let path = if path.is_absolute() {
65 path
66 } else {
67 std::env::current_dir()
68 .expect("unable to get current directory")
69 .join(path)
70 };
71
72 for image in deployment_context.images {
73 image.pull()?.run()?;
74 image.kill_all()?.run()?;
75 image.start(path.clone())?.run()?;
76 }
77 }
78 DeploymentCommand::Setup => {
79 deployment_context.setup_cert_volume()?.run()?;
80
81 for image in deployment_context.images {
82 image.setup_log_volume()?.run()?;
83 image.setup_data_volume()?.run()?;
84 image.setup_config_volume()?.run()?;
85 }
86 }
87 DeploymentCommand::Start => {
88 let path = deployment_context.emit_config()?;
89 let path = if path.is_absolute() {
90 path
91 } else {
92 std::env::current_dir()
93 .expect("unable to get current directory")
94 .join(path)
95 };
96
97 for image in deployment_context.images {
98 image.start(path.clone())?.run()?;
99 }
100 }
101 }
102
103 Ok(())
104}
105
106#[tracing::instrument(skip(controller, command), level = "trace")]
107pub async fn exec_remote_container_op(
108 controller: &SupportControl,
109 command: DeploymentCommand,
110) -> crate::Result<()> {
111 let deployment_context = DeploymentContext::from(controller);
112 tracing::trace!(command = ?command, "executing remote container operation");
113 match command {
114 DeploymentCommand::Build => {
115 for image in deployment_context.images {
116 controller
117 .on_remotes()
118 .commands(image.build()?)
119 .call()
120 .await?;
121 }
122 }
123 DeploymentCommand::Install => {
124 controller
125 .on_remotes()
126 .commands(bon::vec![
127 deployment_context.get_install_script()?,
128 deployment_context.install_docker()?
129 ])
130 .call()
131 .await?;
132 }
133 DeploymentCommand::List => {
134 controller
135 .on_remotes()
136 .commands(deployment_context.list_containers()?)
137 .call()
138 .await?;
139 }
140 DeploymentCommand::Login => {
141 controller
142 .on_remotes()
143 .commands(deployment_context.login()?)
144 .call()
145 .await?;
146 }
147 DeploymentCommand::Pull => {
148 for image in deployment_context.images {
149 controller
150 .on_remotes()
151 .commands(image.pull()?)
152 .call()
153 .await?;
154 }
155 }
156 DeploymentCommand::Push => {}
157 DeploymentCommand::Restart => {
158 let path = deployment_context.emit_config()?;
159 let from_path = path.to_string_lossy();
160 let to_path = format!("./{name}.json", name = controller.config.name());
161
162 for host in deployment_context.hosts {
163 host.send_file(&from_path, &to_path)?.run()?;
164 }
165
166 for image in deployment_context.images {
167 controller
168 .on_remotes()
169 .commands(bon::vec![
170 image.pull()?,
171 image.kill_all()?,
172 image.start(to_path.clone())?
173 ])
174 .call()
175 .await?;
176 }
177 }
178 DeploymentCommand::Setup => {
179 let certs_volume = deployment_context.setup_cert_volume()?;
180
181 for image in deployment_context.images {
182 controller
183 .on_remotes()
184 .commands(bon::vec![
185 certs_volume.clone(),
186 image.setup_log_volume()?,
187 image.setup_data_volume()?,
188 image.setup_config_volume()?
189 ])
190 .call()
191 .await?;
192 }
193 }
194 DeploymentCommand::Start => {
195 let path = deployment_context.emit_config()?;
196
197 let from_path = path.to_string_lossy();
198 let to_path = format!("{name}.container.json", name = controller.config.name());
199
200 for host in deployment_context.hosts {
201 host.send_file(&from_path, &to_path)?.run()?;
202 }
203
204 for image_controller in deployment_context.images {
205 controller
206 .on_remotes()
207 .commands(image_controller.start(to_path.clone())?)
208 .call()
209 .await?;
210 }
211 }
212 }
213
214 Ok(())
215}