Skip to content

Commit e693b4d

Browse files
committed
feat: add configurable timeout support for provisioned containers
- Add ContainerTimeouts struct with configurable timeouts for different container operations - Support docker_build, container_start, ssh_ready, and ssh_setup timeouts with sensible defaults - Add constructor methods with_timeouts() and with_ssh_ready_timeout() for customization - Update StoppedProvisionedContainer to use configurable docker build timeout - Export ContainerTimeouts in module re-exports for public use - Mark point 6 as completed in provisioned container refactoring plan This improves flexibility for different environments and testing scenarios, addressing point 6 of the provisioned container refactoring plan.
1 parent b502d5a commit e693b4d

File tree

4 files changed

+98
-8
lines changed

4 files changed

+98
-8
lines changed

docs/refactors/provisioned-container-refactoring.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,13 @@ impl ContainerSshManager for DockerContainerSshManager {
355355
- ✅ Configurable timeouts
356356
- ✅ Better failure detection
357357

358-
### 6. Add Timeout Configurations
358+
### ✅ 6. Add Timeout Configurations (Completed)
359+
360+
**Status**: ✅ **COMPLETED**
359361

360362
**Current Issue**: Hardcoded timeouts make the system inflexible.
361363

362-
**Proposed Solution**:
364+
**Implemented Solution**:
363365

364366
```rust
365367
#[derive(Debug, Clone)]

project-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ getent
2121
Gossman
2222
Hostnames
2323
hugepages
24+
impls
2425
journalctl
2526
keygen
2627
keyrings

src/e2e/containers/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ pub mod provisioned;
3838

3939
// Re-export provisioned container types for backward compatibility
4040
pub use provisioned::{
41-
ProvisionedContainerError, Result, RunningProvisionedContainer, StoppedProvisionedContainer,
41+
ContainerTimeouts, ProvisionedContainerError, Result, RunningProvisionedContainer,
42+
StoppedProvisionedContainer,
4243
};
4344

4445
// Re-export docker builder for public use

src/e2e/containers/provisioned.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
//! }
5757
//! ```
5858
59+
use std::time::Duration;
5960
use testcontainers::{
6061
core::{IntoContainerPort, WaitFor},
6162
runners::SyncRunner,
@@ -73,6 +74,33 @@ const DEFAULT_IMAGE_NAME: &str = "torrust-provisioned-instance";
7374
/// Default Docker image tag for provisioned instances
7475
const DEFAULT_IMAGE_TAG: &str = "latest";
7576

77+
/// Container timeout configurations for different operations
78+
///
79+
/// This struct provides configurable timeouts for various container operations
80+
/// to make the system more flexible and adaptable to different environments.
81+
#[derive(Debug, Clone)]
82+
pub struct ContainerTimeouts {
83+
/// Timeout for Docker image build operations
84+
pub docker_build: Duration,
85+
/// Timeout for container startup operations
86+
pub container_start: Duration,
87+
/// Timeout for SSH connectivity to become available
88+
pub ssh_ready: Duration,
89+
/// Timeout for SSH key setup operations
90+
pub ssh_setup: Duration,
91+
}
92+
93+
impl Default for ContainerTimeouts {
94+
fn default() -> Self {
95+
Self {
96+
docker_build: Duration::from_secs(300), // 5 minutes
97+
container_start: Duration::from_secs(60), // 1 minute
98+
ssh_ready: Duration::from_secs(30), // 30 seconds
99+
ssh_setup: Duration::from_secs(15), // 15 seconds
100+
}
101+
}
102+
}
103+
76104
/// Specific error types for provisioned container operations
77105
#[derive(Debug, thiserror::Error)]
78106
pub enum ProvisionedContainerError {
@@ -171,18 +199,76 @@ pub type Result<T> = std::result::Result<T, Box<ProvisionedContainerError>>;
171199
/// Following the pattern from Torrust Tracker `MySQL` driver, where different states
172200
/// have different capabilities enforced at compile time.
173201
/// Initial state - container is stopped/not started yet
174-
#[derive(Debug, Default)]
175-
pub struct StoppedProvisionedContainer {}
202+
#[derive(Debug)]
203+
pub struct StoppedProvisionedContainer {
204+
/// Timeout configurations for container operations
205+
pub timeouts: ContainerTimeouts,
206+
}
207+
208+
#[allow(clippy::derivable_impls)]
209+
impl Default for StoppedProvisionedContainer {
210+
fn default() -> Self {
211+
Self {
212+
timeouts: ContainerTimeouts::default(),
213+
}
214+
}
215+
}
176216

177217
impl StoppedProvisionedContainer {
218+
/// Create a new stopped container with custom timeout configurations
219+
///
220+
/// # Arguments
221+
/// * `timeouts` - Custom timeout configuration for container operations
222+
///
223+
/// # Example
224+
/// ```rust,no_run
225+
/// use torrust_tracker_deploy::e2e::containers::{StoppedProvisionedContainer, ContainerTimeouts};
226+
/// use std::time::Duration;
227+
///
228+
/// let mut timeouts = ContainerTimeouts::default();
229+
/// timeouts.ssh_ready = Duration::from_secs(60);
230+
///
231+
/// let container = StoppedProvisionedContainer::with_timeouts(timeouts);
232+
/// ```
233+
#[must_use]
234+
pub fn with_timeouts(timeouts: ContainerTimeouts) -> Self {
235+
Self { timeouts }
236+
}
237+
238+
/// Create a new stopped container with custom SSH ready timeout
239+
///
240+
/// This is a convenience method for the most commonly customized timeout.
241+
///
242+
/// # Arguments
243+
/// * `ssh_ready_timeout` - How long to wait for SSH to become available
244+
///
245+
/// # Example
246+
/// ```rust,no_run
247+
/// use torrust_tracker_deploy::e2e::containers::StoppedProvisionedContainer;
248+
/// use std::time::Duration;
249+
///
250+
/// let container = StoppedProvisionedContainer::with_ssh_ready_timeout(
251+
/// Duration::from_secs(60)
252+
/// );
253+
/// ```
254+
#[must_use]
255+
pub fn with_ssh_ready_timeout(ssh_ready_timeout: Duration) -> Self {
256+
let timeouts = ContainerTimeouts {
257+
ssh_ready: ssh_ready_timeout,
258+
..ContainerTimeouts::default()
259+
};
260+
Self { timeouts }
261+
}
262+
178263
/// Build the Docker image if needed using the `ContainerImageBuilder`
179-
fn build_image() -> Result<()> {
264+
fn build_image(docker_build_timeout: Duration) -> Result<()> {
180265
let builder = ContainerImageBuilder::new()
181266
.with_name(DEFAULT_IMAGE_NAME)
182267
.with_tag(DEFAULT_IMAGE_TAG)
183268
.with_dockerfile(std::path::PathBuf::from(
184269
"docker/provisioned-instance/Dockerfile",
185-
));
270+
))
271+
.with_build_timeout(docker_build_timeout);
186272
builder.build().map_err(|e| {
187273
Box::new(ProvisionedContainerError::DockerImageBuildFailed { source: *e })
188274
})?;
@@ -199,7 +285,7 @@ impl StoppedProvisionedContainer {
199285
/// - Container networking setup fails
200286
pub fn start(self) -> Result<RunningProvisionedContainer> {
201287
// First build the Docker image if needed
202-
Self::build_image()?;
288+
Self::build_image(self.timeouts.docker_build)?;
203289

204290
info!("Starting provisioned instance container");
205291

0 commit comments

Comments
 (0)