use async_trait::async_trait;
use bollard::Docker;
use bollard::query_parameters::{RenameContainerOptions, TopOptions};
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 ContainerPauseOutput {
pub container: String,
}
pub struct ContainerPause {
docker: Docker,
container: String,
}
impl ContainerPause {
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<ContainerPauseOutput, OperationError> {
self.docker
.pause_container(&self.container)
.await
.map_err(docker_error)?;
Ok(ContainerPauseOutput {
container: self.container.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerPause {
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_pause",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerPause {
type Output = ContainerPauseOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerUnpauseOutput {
pub container: String,
}
pub struct ContainerUnpause {
docker: Docker,
container: String,
}
impl ContainerUnpause {
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<ContainerUnpauseOutput, OperationError> {
self.docker
.unpause_container(&self.container)
.await
.map_err(docker_error)?;
Ok(ContainerUnpauseOutput {
container: self.container.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerUnpause {
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_unpause",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerUnpause {
type Output = ContainerUnpauseOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerRenameOutput {
pub old_name: String,
pub new_name: String,
}
pub struct ContainerRename {
docker: Docker,
container: String,
new_name: String,
}
impl ContainerRename {
pub fn new(
client: impl Into<DockerRef>,
container: impl Into<String>,
new_name: impl Into<String>,
) -> Self {
Self {
docker: client.into().0,
container: container.into(),
new_name: new_name.into(),
}
}
pub async fn run(
&self,
_ctx: &OperationContext,
) -> Result<ContainerRenameOutput, OperationError> {
let options = RenameContainerOptions {
name: self.new_name.clone(),
};
self.docker
.rename_container(&self.container, options)
.await
.map_err(docker_error)?;
Ok(ContainerRenameOutput {
old_name: self.container.clone(),
new_name: self.new_name.clone(),
})
}
}
#[async_trait]
impl Operation for ContainerRename {
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_rename",
"container": self.container,
"new_name": self.new_name,
}))
}
}
impl TypedOperation for ContainerRename {
type Output = ContainerRenameOutput;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContainerTopOutput {
pub titles: Vec<String>,
pub processes: Vec<Vec<String>>,
}
pub struct ContainerTop {
docker: Docker,
container: String,
ps_args: Option<String>,
}
impl ContainerTop {
pub fn new(client: impl Into<DockerRef>, container: impl Into<String>) -> Self {
Self {
docker: client.into().0,
container: container.into(),
ps_args: None,
}
}
pub fn ps_args(mut self, args: impl Into<String>) -> Self {
self.ps_args = Some(args.into());
self
}
pub async fn run(&self, _ctx: &OperationContext) -> Result<ContainerTopOutput, OperationError> {
let options = self.ps_args.as_ref().map(|args| TopOptions {
ps_args: args.to_string(),
});
let response = self
.docker
.top_processes(&self.container, options)
.await
.map_err(docker_error)?;
Ok(ContainerTopOutput {
titles: response.titles.unwrap_or_default(),
processes: response.processes.unwrap_or_default(),
})
}
}
#[async_trait]
impl Operation for ContainerTop {
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_top",
"container": self.container,
}))
}
}
impl TypedOperation for ContainerTop {
type Output = ContainerTopOutput;
}