-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcompose.rs
More file actions
151 lines (133 loc) · 4.8 KB
/
Copy pathcompose.rs
File metadata and controls
151 lines (133 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Docker Compose release steps
//!
//! This module contains all steps required to deploy Docker Compose:
//! - Template rendering
//! - Compose files deployment to remote
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tracing::info;
use crate::adapters::ansible::AnsibleClient;
use crate::application::command_handlers::common::StepResult;
use crate::application::command_handlers::release::errors::ReleaseCommandHandlerError;
use crate::application::steps::{DeployComposeFilesStep, RenderDockerComposeTemplatesStep};
use crate::application::traits::CommandProgressListener;
use crate::domain::environment::state::ReleaseStep;
use crate::domain::environment::{Environment, Releasing};
use crate::shared::clock::SystemClock;
/// Release Docker Compose configuration
///
/// Executes all steps required to deploy Docker Compose:
/// 1. Render Docker Compose templates
/// 2. Deploy compose files to remote
///
/// # Arguments
///
/// * `environment` - The environment in Releasing state
/// * `listener` - Optional progress listener for detail and debug reporting
///
/// # Errors
///
/// Returns a tuple of (error, step) if any Docker Compose step fails
pub async fn release(
environment: &Environment<Releasing>,
listener: Option<&dyn CommandProgressListener>,
) -> StepResult<(), ReleaseCommandHandlerError, ReleaseStep> {
let compose_build_dir = render_templates(environment, listener).await?;
deploy_files_to_remote(environment, &compose_build_dir, listener)?;
Ok(())
}
/// Render Docker Compose templates to the build directory
///
/// # Arguments
///
/// * `environment` - The environment in Releasing state
/// * `listener` - Optional progress listener for detail and debug reporting
///
/// # Errors
///
/// Returns a tuple of (error, `ReleaseStep::RenderDockerComposeTemplates`) if rendering fails
async fn render_templates(
environment: &Environment<Releasing>,
listener: Option<&dyn CommandProgressListener>,
) -> StepResult<PathBuf, ReleaseCommandHandlerError, ReleaseStep> {
let current_step = ReleaseStep::RenderDockerComposeTemplates;
if let Some(l) = listener {
l.on_debug(&format!(
"Template source: {}/docker-compose/",
environment.templates_dir().display()
));
}
let clock = Arc::new(SystemClock);
let step = RenderDockerComposeTemplatesStep::new(
Arc::new(environment.clone()),
environment.templates_dir(),
environment.build_dir().clone(),
clock,
);
let compose_build_dir = step.execute().await.map_err(|e| {
(
ReleaseCommandHandlerError::TemplateRendering {
message: e.to_string(),
source: Box::new(e),
},
current_step,
)
})?;
if let Some(l) = listener {
l.on_detail("Rendering docker-compose.yml and .env from templates");
l.on_debug(&format!("Template output: {}", compose_build_dir.display()));
}
info!(
command = "release",
compose_build_dir = %compose_build_dir.display(),
"Docker Compose templates rendered successfully"
);
Ok(compose_build_dir)
}
/// Deploy compose files to the remote host via Ansible
///
/// # Arguments
///
/// * `environment` - The environment in Releasing state
/// * `compose_build_dir` - Path to the rendered compose files
/// * `listener` - Optional progress listener for detail and debug reporting
///
/// # Errors
///
/// Returns a tuple of (error, `ReleaseStep::DeployComposeFilesToRemote`) if deployment fails
#[allow(clippy::result_large_err)]
fn deploy_files_to_remote(
environment: &Environment<Releasing>,
compose_build_dir: &Path,
listener: Option<&dyn CommandProgressListener>,
) -> StepResult<(), ReleaseCommandHandlerError, ReleaseStep> {
let current_step = ReleaseStep::DeployComposeFilesToRemote;
if let Some(l) = listener {
l.on_debug(&format!(
"Ansible working directory: {}",
environment.ansible_build_dir().display()
));
l.on_debug("Executing playbook: ansible-playbook deploy-compose-files.yml");
}
let ansible_client = Arc::new(AnsibleClient::new(environment.ansible_build_dir()));
let step = DeployComposeFilesStep::new(ansible_client, compose_build_dir.to_path_buf());
step.execute().map_err(|e| {
(
ReleaseCommandHandlerError::ComposeFilesDeployment {
message: e.to_string(),
source: Box::new(e),
},
current_step,
)
})?;
if let Some(l) = listener {
l.on_detail("Deploying docker-compose.yml and .env to /opt/torrust");
}
info!(
command = "release",
compose_build_dir = %compose_build_dir.display(),
instance_ip = ?environment.instance_ip(),
"Compose files deployed to remote host successfully"
);
Ok(())
}