-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcontainer.rs
More file actions
132 lines (113 loc) · 5.09 KB
/
container.rs
File metadata and controls
132 lines (113 loc) · 5.09 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
//! Dependency injection container for testing services
//!
//! This module provides the `Services` struct that acts as a dependency injection container,
//! holding all the service clients and template renderers needed for E2E testing operations.
//! It centralizes service construction and makes them easily accessible throughout tests.
//!
//! ## Services Included
//!
//! - **Command clients**: `OpenTofu`, LXD, Ansible clients for external tool interaction
//! - **Template services**: Template manager and specialized renderers for different tools
//! - **Configuration**: Centralized configuration management
//!
//! ## Usage in Tests
//!
//! This container is primarily used in E2E tests to create all necessary service dependencies
//! in a consistent way. In production, services are created on-demand depending on which
//! command the user is executing.
use std::sync::Arc;
use std::time::Duration;
use crate::adapters::ansible::AnsibleClient;
use crate::adapters::lxd::LxdClient;
use crate::adapters::ssh::SshCredentials;
use crate::adapters::tofu::OpenTofuClient;
use crate::config::Config;
use crate::domain::provider::ProviderConfig;
use crate::domain::template::TemplateManager;
use crate::domain::InstanceName;
use crate::infrastructure::persistence::file_repository_factory::FileRepositoryFactory;
use crate::infrastructure::templating::ansible::AnsibleProjectGenerator;
use crate::infrastructure::templating::ansible::ANSIBLE_SUBFOLDER;
use crate::infrastructure::templating::tofu::TofuProjectGenerator;
use crate::shared::Clock;
use crate::testing::e2e::LXD_OPENTOFU_SUBFOLDER;
use crate::testing::mock_clock::MockClock;
use chrono::DateTime;
/// Default lock timeout for repository operations
///
/// This timeout controls how long repository operations will wait to acquire
/// file locks before giving up. This prevents operations from hanging indefinitely
/// if another process has locked the state file.
///
/// TODO: Make this configurable via Config in the future
const REPOSITORY_LOCK_TIMEOUT_SECS: u64 = 30;
/// Service clients and renderers for performing actions in tests
pub struct Services {
// Command wrappers
pub opentofu_client: Arc<OpenTofuClient>,
pub lxd_client: Arc<LxdClient>,
pub ansible_client: Arc<AnsibleClient>,
// Template related services
pub template_manager: Arc<TemplateManager>,
pub tofu_template_renderer: Arc<TofuProjectGenerator>,
pub ansible_project_generator: Arc<AnsibleProjectGenerator>,
// Infrastructure services
/// Clock service for testable time management
pub clock: Arc<dyn Clock>,
// Persistence layer
/// Factory for creating environment-specific repositories
pub file_repository_factory: Arc<FileRepositoryFactory>,
}
impl Services {
/// Create a new services container using the provided configuration
#[must_use]
pub fn new(
config: &Config,
ssh_credentials: SshCredentials,
instance_name: InstanceName,
provider_config: ProviderConfig,
) -> Self {
// Create template manager
let template_manager = TemplateManager::new(config.templates_dir.clone());
let template_manager = Arc::new(template_manager);
// Create OpenTofu client pointing to build/opentofu_subfolder directory
let opentofu_client = OpenTofuClient::new(config.build_dir.join(LXD_OPENTOFU_SUBFOLDER));
// Create LXD client for instance management
let lxd_client = LxdClient::new();
// Create Ansible client pointing to build/ansible_subfolder directory
let ansible_client = AnsibleClient::new(config.build_dir.join(ANSIBLE_SUBFOLDER));
// Create provision template renderer
let clock = Arc::new(MockClock::new(DateTime::UNIX_EPOCH));
let tofu_template_renderer = TofuProjectGenerator::new(
template_manager.clone(),
config.build_dir.clone(),
ssh_credentials,
22, // Default SSH port for tests
instance_name,
provider_config,
clock,
);
// Create configuration template renderer
let ansible_project_generator =
AnsibleProjectGenerator::new(config.build_dir.clone(), template_manager.clone());
// Create repository factory
let file_repository_factory =
FileRepositoryFactory::new(Duration::from_secs(REPOSITORY_LOCK_TIMEOUT_SECS));
// Create clock service (production implementation uses system time)
let clock: Arc<dyn Clock> = Arc::new(crate::shared::SystemClock);
Self {
// Command wrappers
opentofu_client: Arc::new(opentofu_client),
lxd_client: Arc::new(lxd_client),
ansible_client: Arc::new(ansible_client),
// Template related services
template_manager: template_manager.clone(),
tofu_template_renderer: Arc::new(tofu_template_renderer),
ansible_project_generator: Arc::new(ansible_project_generator),
// Infrastructure services
clock,
// Persistence layer
file_repository_factory: Arc::new(file_repository_factory),
}
}
}