torrust_tracker_deployer_lib/domain/environment/state/
provisioned.rs1use serde::{Deserialize, Serialize};
12
13use crate::domain::environment::state::{AnyEnvironmentState, Configuring, StateTypeError};
14use crate::domain::environment::Environment;
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct Provisioned;
25
26impl Environment<Provisioned> {
28 #[must_use]
32 pub fn start_configuring(self) -> Environment<Configuring> {
33 self.with_state(Configuring)
34 }
35}
36
37impl Environment<Provisioned> {
39 #[must_use]
41 pub fn into_any(self) -> AnyEnvironmentState {
42 AnyEnvironmentState::Provisioned(self)
43 }
44}
45
46impl AnyEnvironmentState {
48 pub fn try_into_provisioned(self) -> Result<Environment<Provisioned>, StateTypeError> {
54 match self {
55 Self::Provisioned(env) => Ok(env),
56 other => Err(StateTypeError::UnexpectedState {
57 expected: "provisioned",
58 actual: other.state_name().to_string(),
59 }),
60 }
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn it_should_create_provisioned_state() {
70 let state = Provisioned;
71 assert_eq!(state, Provisioned);
72 }
73
74 mod conversion_tests {
75 use super::*;
76 use crate::adapters::ssh::SshCredentials;
77 use crate::domain::environment::name::EnvironmentName;
78 use crate::domain::environment::runtime_outputs::ProvisionMethod;
79 use crate::domain::environment::state::ProvisionFailureContext;
80 use crate::domain::provider::{LxdConfig, ProviderConfig};
81 use crate::domain::ProfileName;
82 use crate::shared::Username;
83 use std::net::{IpAddr, Ipv4Addr};
84 use std::path::PathBuf;
85
86 fn default_lxd_provider_config(env_name: &EnvironmentName) -> ProviderConfig {
87 ProviderConfig::Lxd(LxdConfig {
88 profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
89 })
90 }
91
92 fn create_test_ssh_credentials() -> SshCredentials {
93 let username = Username::new("test-user".to_string()).unwrap();
94 SshCredentials::new(
95 PathBuf::from("/tmp/test_key"),
96 PathBuf::from("/tmp/test_key.pub"),
97 username,
98 )
99 }
100
101 fn create_test_environment_provisioned() -> Environment<Provisioned> {
102 let name = EnvironmentName::new("test-env".to_string()).unwrap();
103 let ssh_creds = create_test_ssh_credentials();
104 Environment::new(
105 name.clone(),
106 default_lxd_provider_config(&name),
107 ssh_creds,
108 22,
109 chrono::Utc::now(),
110 )
111 .start_provisioning()
112 .provisioned(
113 IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)),
114 ProvisionMethod::Provisioned,
115 )
116 }
117
118 fn create_test_provision_context() -> ProvisionFailureContext {
119 use crate::domain::environment::state::{BaseFailureContext, ProvisionStep};
120 use crate::domain::environment::TraceId;
121 use crate::shared::ErrorKind;
122 use chrono::Utc;
123 use std::time::Duration;
124
125 ProvisionFailureContext {
126 failed_step: ProvisionStep::CloudInitWait,
127 error_kind: ErrorKind::Timeout,
128 base: BaseFailureContext {
129 error_summary: "error".to_string(),
130 failed_at: Utc::now(),
131 execution_started_at: Utc::now(),
132 execution_duration: Duration::from_secs(0),
133 trace_id: TraceId::default(),
134 trace_file_path: None,
135 },
136 }
137 }
138
139 #[test]
140 fn it_should_convert_provisioned_environment_into_any() {
141 let env = create_test_environment_provisioned();
142 let any_env = env.into_any();
143 assert!(matches!(any_env, AnyEnvironmentState::Provisioned(_)));
144 }
145
146 #[test]
147 fn it_should_convert_any_to_provisioned_successfully() {
148 let env = create_test_environment_provisioned();
149 let any_env = env.into_any();
150 let result = any_env.try_into_provisioned();
151 assert!(result.is_ok());
152 }
153
154 #[test]
155 fn it_should_fail_converting_provision_failed_to_provisioned() {
156 let name = EnvironmentName::new("test-env".to_string()).unwrap();
157 let ssh_creds = create_test_ssh_credentials();
158 let env = Environment::new(
159 name.clone(),
160 default_lxd_provider_config(&name),
161 ssh_creds,
162 22,
163 chrono::Utc::now(),
164 )
165 .start_provisioning()
166 .provision_failed(create_test_provision_context());
167 let any_env = env.into_any();
168 let result = any_env.try_into_provisioned();
169 assert!(result.is_err());
170 let err = result.unwrap_err();
171 assert!(err.to_string().contains("provisioned"));
172 assert!(err.to_string().contains("provision_failed"));
173 }
174 }
175
176 mod transition_tests {
177 use super::*;
178 use crate::adapters::ssh::SshCredentials;
179 use crate::domain::environment::name::EnvironmentName;
180 use crate::domain::environment::runtime_outputs::ProvisionMethod;
181 use crate::domain::environment::state::{Configuring, Destroyed};
182 use crate::domain::provider::{LxdConfig, ProviderConfig};
183 use crate::domain::ProfileName;
184 use crate::shared::Username;
185 use std::net::{IpAddr, Ipv4Addr};
186 use std::path::PathBuf;
187
188 fn default_lxd_provider_config(env_name: &EnvironmentName) -> ProviderConfig {
189 ProviderConfig::Lxd(LxdConfig {
190 profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
191 })
192 }
193
194 fn create_test_environment() -> Environment<Provisioned> {
195 let env_name = EnvironmentName::new("test-state".to_string()).unwrap();
196 let ssh_username = Username::new("torrust".to_string()).unwrap();
197 let ssh_credentials = SshCredentials::new(
198 PathBuf::from("test_key"),
199 PathBuf::from("test_key.pub"),
200 ssh_username,
201 );
202 Environment::new(
203 env_name.clone(),
204 default_lxd_provider_config(&env_name),
205 ssh_credentials,
206 22,
207 chrono::Utc::now(),
208 )
209 .start_provisioning()
210 .provisioned(
211 IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)),
212 ProvisionMethod::Provisioned,
213 )
214 }
215
216 #[test]
217 fn it_should_transition_from_provisioned_to_configuring() {
218 let env = create_test_environment();
219 let env = env.start_configuring();
220
221 assert_eq!(*env.state(), Configuring);
222 assert_eq!(env.name().as_str(), "test-state");
223 }
224
225 #[test]
226 fn it_should_transition_to_destroyed_from_provisioned() {
227 let env = create_test_environment();
228 let env = env.destroy();
229
230 assert_eq!(*env.state(), Destroyed);
231 assert_eq!(env.name().as_str(), "test-state");
232 }
233 }
234}