use async_trait::async_trait;
use bollard::Docker;
use bollard::query_parameters::{RestartContainerOptions, StopContainerOptions};
use ironflow_core::error::OperationError;
use ironflow_core::operation::{Operation, OperationContext, TypedOperation};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::containers::DockerRef;
use crate::helpers::{docker_error, to_value};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerStartOutput {
pub container: String,
}
pub struct ContainerStart {
docker: Docker,
container: String,
}
impl ContainerStart {
pub fn new(client: impl Into<DockerRef>, container: impl Into<String>) -> Self {
Self {
docker: client.into().0,
container: container.into(),
}
}
pub async fn run(
&self,
_ctx: &OperationContext,
) -> Result<ContainerStartOutput, OperationError> {
self.docker
.start_container(
&self.container,
None::<bollard::query_parameters::StartContainerOptions>,
)
.await
.map_err(docker_error)?;
Ok(ContainerStartOutput {
container: self.container.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerStart {
fn kind(&self) -> &str {
"docker"
}
async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
to_value(&self.run(ctx).await?)
}
fn input(&self) -> Option<Value> {
Some(serde_json::json!({
"operation": "container_start",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerStart {
type Output = ContainerStartOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerStopOutput {
pub container: String,
}
pub struct ContainerStop {
docker: Docker,
container: String,
timeout: Option<i64>,
}
impl ContainerStop {
pub fn new(client: impl Into<DockerRef>, container: impl Into<String>) -> Self {
Self {
docker: client.into().0,
container: container.into(),
timeout: None,
}
}
pub fn timeout(mut self, secs: i64) -> Self {
self.timeout = Some(secs);
self
}
pub async fn run(
&self,
_ctx: &OperationContext,
) -> Result<ContainerStopOutput, OperationError> {
let options = StopContainerOptions {
t: Some(self.timeout.unwrap_or(10) as i32),
signal: None,
};
self.docker
.stop_container(&self.container, Some(options))
.await
.map_err(docker_error)?;
Ok(ContainerStopOutput {
container: self.container.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerStop {
fn kind(&self) -> &str {
"docker"
}
async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
to_value(&self.run(ctx).await?)
}
fn input(&self) -> Option<Value> {
Some(serde_json::json!({
"operation": "container_stop",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerStop {
type Output = ContainerStopOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerRestartOutput {
pub container: String,
}
pub struct ContainerRestart {
docker: Docker,
container: String,
timeout: Option<i64>,
}
impl ContainerRestart {
pub fn new(client: impl Into<DockerRef>, container: impl Into<String>) -> Self {
Self {
docker: client.into().0,
container: container.into(),
timeout: None,
}
}
pub fn timeout(mut self, secs: i64) -> Self {
self.timeout = Some(secs);
self
}
pub async fn run(
&self,
_ctx: &OperationContext,
) -> Result<ContainerRestartOutput, OperationError> {
let options = RestartContainerOptions {
t: Some(self.timeout.unwrap_or(10) as i32),
signal: None,
};
self.docker
.restart_container(&self.container, Some(options))
.await
.map_err(docker_error)?;
Ok(ContainerRestartOutput {
container: self.container.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerRestart {
fn kind(&self) -> &str {
"docker"
}
async fn execute(&self, ctx: &OperationContext) -> Result<Value, OperationError> {
to_value(&self.run(ctx).await?)
}
fn input(&self) -> Option<Value> {
Some(serde_json::json!({
"operation": "container_restart",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerRestart {
type Output = ContainerRestartOutput;
}