torrust_tracker_deployer_lib/application/command_handlers/show/
handler.rs1use std::sync::Arc;
27
28use tracing::instrument;
29
30use super::errors::ShowCommandHandlerError;
31use super::info::{
32 DockerImagesInfo, EnvironmentInfo, GrafanaInfo, InfrastructureInfo, PrometheusInfo, ServiceInfo,
33};
34use crate::domain::environment::repository::EnvironmentRepository;
35use crate::domain::environment::state::AnyEnvironmentState;
36use crate::domain::grafana::GrafanaConfig;
37use crate::domain::mysql::MysqlServiceConfig;
38use crate::domain::prometheus::PrometheusConfig;
39use crate::domain::tracker::config::TrackerConfig;
40use crate::domain::EnvironmentName;
41
42const DEFAULT_SSH_PORT: u16 = 22;
44
45pub struct ShowCommandHandler {
59 repository: Arc<dyn EnvironmentRepository>,
60}
61
62impl ShowCommandHandler {
63 #[must_use]
65 pub fn new(repository: Arc<dyn EnvironmentRepository>) -> Self {
66 Self { repository }
67 }
68
69 #[instrument(
88 name = "show_command",
89 skip_all,
90 fields(
91 command_type = "show",
92 environment = %env_name
93 )
94 )]
95 pub fn execute(
96 &self,
97 env_name: &EnvironmentName,
98 ) -> Result<EnvironmentInfo, ShowCommandHandlerError> {
99 let any_env = self.load_environment(env_name)?;
100
101 Ok(Self::extract_info(&any_env))
102 }
103
104 fn load_environment(
106 &self,
107 env_name: &EnvironmentName,
108 ) -> Result<AnyEnvironmentState, ShowCommandHandlerError> {
109 if !self.repository.exists(env_name)? {
110 return Err(ShowCommandHandlerError::EnvironmentNotFound {
111 name: env_name.to_string(),
112 });
113 }
114
115 self.repository.load(env_name)?.ok_or_else(|| {
116 ShowCommandHandlerError::EnvironmentNotFound {
117 name: env_name.to_string(),
118 }
119 })
120 }
121
122 fn extract_info(any_env: &AnyEnvironmentState) -> EnvironmentInfo {
124 let name = any_env.name().to_string();
125 let state = any_env.state_display_name().to_string();
126 let provider = any_env.provider_display_name().to_string();
127 let created_at = any_env.created_at();
128 let state_name = any_env.state_name().to_string();
129
130 let tracker_config = any_env.tracker_config();
131 let docker_images = DockerImagesInfo::new(
132 TrackerConfig::docker_image().full_reference(),
133 if tracker_config.uses_mysql() {
134 Some(MysqlServiceConfig::docker_image().full_reference())
135 } else {
136 None
137 },
138 any_env
139 .prometheus_config()
140 .map(|_| PrometheusConfig::docker_image().full_reference()),
141 any_env
142 .grafana_config()
143 .map(|_| GrafanaConfig::docker_image().full_reference()),
144 );
145
146 let mut info =
147 EnvironmentInfo::new(name, state, provider, created_at, docker_images, state_name);
148
149 if let Some(instance_ip) = any_env.instance_ip() {
151 let ssh_creds = any_env.ssh_credentials();
152 let ssh_port = any_env.ssh_port();
153
154 let infra = InfrastructureInfo::new(
155 instance_ip,
156 if ssh_port == 0 {
157 DEFAULT_SSH_PORT
158 } else {
159 ssh_port
160 },
161 ssh_creds.ssh_username.to_string(),
162 ssh_creds.ssh_priv_key_path.to_string_lossy().to_string(),
163 );
164 info = info.with_infrastructure(infra);
165
166 if Self::should_show_services(any_env.state_name()) {
168 let grafana_config = any_env.grafana_config();
171 let services =
172 ServiceInfo::from_tracker_config(tracker_config, instance_ip, grafana_config);
173 info = info.with_services(services);
174
175 if any_env.prometheus_config().is_some() {
177 info = info.with_prometheus(PrometheusInfo::default_internal());
178 }
179
180 if let Some(grafana) = any_env.grafana_config() {
182 info = info.with_grafana(GrafanaInfo::from_config(grafana, instance_ip));
183 }
184 }
185 }
186
187 info
188 }
189
190 fn should_show_services(state_name: &str) -> bool {
195 matches!(
196 state_name,
197 "released" | "running" | "release_failed" | "run_failed"
198 )
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 mod should_show_services {
207 use super::*;
208
209 #[test]
210 fn it_should_show_services_for_released_state() {
211 assert!(ShowCommandHandler::should_show_services("released"));
212 }
213
214 #[test]
215 fn it_should_show_services_for_running_state() {
216 assert!(ShowCommandHandler::should_show_services("running"));
217 }
218
219 #[test]
220 fn it_should_show_services_for_release_failed_state() {
221 assert!(ShowCommandHandler::should_show_services("release_failed"));
222 }
223
224 #[test]
225 fn it_should_show_services_for_run_failed_state() {
226 assert!(ShowCommandHandler::should_show_services("run_failed"));
227 }
228
229 #[test]
230 fn it_should_not_show_services_for_created_state() {
231 assert!(!ShowCommandHandler::should_show_services("created"));
232 }
233
234 #[test]
235 fn it_should_not_show_services_for_provisioned_state() {
236 assert!(!ShowCommandHandler::should_show_services("provisioned"));
237 }
238
239 #[test]
240 fn it_should_not_show_services_for_configured_state() {
241 assert!(!ShowCommandHandler::should_show_services("configured"));
242 }
243 }
244}