use bollard::query_parameters::{
RemoveContainerOptions, RemoveImageOptions, RemoveVolumeOptions, RestartContainerOptions,
StartContainerOptions, StopContainerOptions,
};
use super::{DockerClient, PruneKind, Resource, describe};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Start,
Stop,
Restart,
Pause,
Unpause,
Remove(Resource),
Prune(PruneKind),
Pull,
Run,
Create(Resource),
Connect,
Disconnect,
Rename,
Update,
Recreate,
}
impl Action {
pub fn verb(self) -> &'static str {
match self {
Action::Start => "start",
Action::Stop => "stop",
Action::Restart => "restart",
Action::Pause => "pause",
Action::Unpause => "resume",
Action::Remove(_) => "remove",
Action::Prune(_) => "clean up",
Action::Pull => "pull",
Action::Run => "run",
Action::Create(_) => "create",
Action::Connect => "connect",
Action::Disconnect => "disconnect",
Action::Rename => "rename",
Action::Update => "change",
Action::Recreate => "recreate",
}
}
pub fn past_tense(self) -> &'static str {
match self {
Action::Start => "Started",
Action::Stop => "Stopped",
Action::Restart => "Restarted",
Action::Pause => "Paused",
Action::Unpause => "Resumed",
Action::Remove(_) | Action::Prune(_) => "Removed",
Action::Pull => "Pulled",
Action::Run => "Started",
Action::Create(_) => "Created",
Action::Connect => "Connected",
Action::Disconnect => "Disconnected",
Action::Rename => "Renamed",
Action::Update => "Changed",
Action::Recreate => "Recreated",
}
}
pub fn affects(self) -> Resource {
match self {
Action::Remove(resource) => resource,
Action::Prune(kind) => kind.affects(),
Action::Pull => Resource::Images,
Action::Create(resource) => resource,
Action::Connect | Action::Disconnect => Resource::Networks,
_ => Resource::Containers,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Task {
pub action: Action,
pub id: String,
pub name: String,
}
impl DockerClient {
pub async fn perform(&self, action: Action, id: &str) -> Result<Option<i64>, String> {
if let Action::Prune(kind) = action {
return self.prune(kind).await.map(Some);
}
let docker = &self.docker;
let result = match action {
Action::Start => {
docker
.start_container(id, None::<StartContainerOptions>)
.await
}
Action::Stop => {
docker
.stop_container(id, None::<StopContainerOptions>)
.await
}
Action::Restart => {
docker
.restart_container(id, None::<RestartContainerOptions>)
.await
}
Action::Pause => docker.pause_container(id).await,
Action::Unpause => docker.unpause_container(id).await,
Action::Remove(Resource::Containers) => {
docker
.remove_container(id, None::<RemoveContainerOptions>)
.await
}
Action::Remove(Resource::Images) => {
let opts = RemoveImageOptions {
force: true,
..Default::default()
};
docker.remove_image(id, Some(opts), None).await.map(drop)
}
Action::Remove(Resource::Volumes) => {
self.remove_helpers(Some(id)).await?;
docker.remove_volume(id, None::<RemoveVolumeOptions>).await
}
Action::Remove(Resource::Networks) => docker.remove_network(id).await,
Action::Remove(Resource::Disk)
| Action::Prune(_)
| Action::Pull
| Action::Run
| Action::Create(_)
| Action::Connect
| Action::Disconnect
| Action::Rename
| Action::Update
| Action::Recreate => {
return Err("not something that can be removed".into());
}
};
result.map(|()| None).map_err(describe)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn remove_refreshes_its_own_list() {
assert_eq!(Action::Stop.affects(), Resource::Containers);
assert_eq!(
Action::Remove(Resource::Volumes).affects(),
Resource::Volumes
);
assert_eq!(Action::Remove(Resource::Images).past_tense(), "Removed");
}
}