summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
authorEli W. Hunter <elihunter173@gmail.com>2021-02-07 19:17:32 -0500
committerEli W. Hunter <elihunter173@gmail.com>2021-03-08 18:48:30 -0500
commit349d8f2f7343506f986a5773e72f260c78fe9289 (patch)
tree7569c25d73c516b762df3ffcabfbc56feb6a316f /src/lib.rs
parent007b05eaf5127bbaea27cfc816f307946bd7aa5f (diff)
Split up lib.rs
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs1523
1 files changed, 18 insertions, 1505 deletions
diff --git a/src/lib.rs b/src/lib.rs
index a011396..8113191 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,8 +23,18 @@ pub mod rep;
pub mod transport;
pub mod tty;
+pub mod container;
+pub mod docker;
+pub mod exec;
+pub mod image;
+pub mod network;
+pub mod service;
+pub mod volume;
+
mod tarball;
+pub use hyper::Uri;
+
pub use crate::{
builder::{
BuildOptions, ContainerConnectionOptions, ContainerFilter, ContainerListOptions,
@@ -33,1509 +43,12 @@ pub use crate::{
RegistryAuth, RmContainerOptions, ServiceFilter, ServiceListOptions, ServiceOptions,
TagOptions, VolumeCreateOptions,
},
- errors::Error,
-};
-use crate::{
- rep::{
- Change, Container as ContainerRep, ContainerCreateInfo, ContainerDetails, Event,
- ExecDetails, Exit, History, Image as ImageRep, ImageDetails, Info, NetworkCreateInfo,
- NetworkDetails as NetworkInfo, SearchResult, ServiceCreateInfo, ServiceDetails,
- Services as ServicesRep, Stats, Status, Top, Version, Volume as VolumeRep,
- VolumeCreateInfo, Volumes as VolumesRep,
- },
- transport::{tar, Headers, Payload, Transport},
- tty::Multiplexer as TtyMultiPlexer,
-};
-use futures_util::{
- io::{AsyncRead, AsyncWrite},
- stream::Stream,
- TryFutureExt, TryStreamExt,
+ container::{Container, Containers},
+ docker::Docker,
+ errors::{Error, Result},
+ exec::Exec,
+ image::{Image, Images},
+ network::{Network, Networks},
+ service::{Service, Services},
+ volume::{Volume, Volumes},
};
-// use futures::{future::Either, Future, IntoFuture, Stream};
-pub use hyper::Uri;
-use hyper::{client::HttpConnector, Body, Client, Method};
-#[cfg(feature = "tls")]
-use hyper_openssl::HttpsConnector;
-#[cfg(feature = "unix-socket")]
-use hyperlocal::UnixConnector;
-use mime::Mime;
-#[cfg(feature = "tls")]
-use openssl::ssl::{SslConnector, SslFiletype, SslMethod};
-use serde_json::Value;
-use std::{env, io, io::Read, iter, path::Path, time::Duration};
-use url::form_urlencoded;
-
-/// Represents the result of all docker operations
-pub type Result<T> = std::result::Result<T, Error>;
-
-/// Entrypoint interface for communicating with docker daemon
-#[derive(Clone)]
-pub struct Docker {
- transport: Transport,
-}
-
-/// Interface for accessing and manipulating a named docker image
-pub struct Image<'docker> {
- docker: &'docker Docker,
- name: String,
-}
-
-impl<'docker> Image<'docker> {
- /// Exports an interface for operations that may be performed against a named image
- pub fn new<S>(
- docker: &'docker Docker,
- name: S,
- ) -> Self
- where
- S: Into<String>,
- {
- Image {
- docker,
- name: name.into(),
- }
- }
-
- /// Inspects a named image's details
- pub async fn inspect(&self) -> Result<ImageDetails> {
- self.docker
- .get_json(&format!("/images/{}/json", self.name)[..])
- .await
- }
-
- /// Lists the history of the images set of changes
- pub async fn history(&self) -> Result<Vec<History>> {
- self.docker
- .get_json(&format!("/images/{}/history", self.name)[..])
- .await
- }
-
- /// Deletes an image
- pub async fn delete(&self) -> Result<Vec<Status>> {
- self.docker
- .delete_json::<Vec<Status>>(&format!("/images/{}", self.name)[..])
- .await
- }
-
- /// Export this image to a tarball
- pub fn export(&self) -> impl Stream<Item = Result<Vec<u8>>> + Unpin + 'docker {
- Box::pin(
- self.docker
- .stream_get(format!("/images/{}/get", self.name))
- .map_ok(|c| c.to_vec()),
- )
- }
-
- /// Adds a tag to an image
- pub async fn tag(
- &self,
- opts: &TagOptions,
- ) -> Result<()> {
- let mut path = vec![format!("/images/{}/tag", self.name)];
- if let Some(query) = opts.serialize() {
- path.push(query)
- }
- let _ = self.docker.post(&path.join("?"), None).await?;
- Ok(())
- }
-}
-
-/// Interface for docker images
-pub struct Images<'docker> {
- docker: &'docker Docker,
-}
-
-impl<'docker> Images<'docker> {
- /// Exports an interface for interacting with docker images
- pub fn new(docker: &'docker Docker) -> Self {
- Images { docker }
- }
-
- /// Builds a new image build by reading a Dockerfile in a target directory
- pub fn build(
- &self,
- opts: &BuildOptions,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker {
- let mut endpoint = vec!["/build".to_owned()];
- if let Some(query) = opts.serialize() {
- endpoint.push(query)
- }
-
- // To not tie the lifetime of `opts` to the 'stream, we do the tarring work outside of the
- // stream. But for backwards compatability, we have to return the error inside of the
- // stream.
- let mut bytes = Vec::default();
- let tar_result = tarball::dir(&mut bytes, opts.path.as_str());
-
- // We must take ownership of the Docker reference. If we don't then the lifetime of 'stream
- // is incorrectly tied to `self`.
- let docker = self.docker;
- Box::pin(
- async move {
- // Bubble up error inside the stream for backwards compatability
- tar_result?;
-
- let value_stream = docker.stream_post_into_values(
- endpoint.join("?"),
- Some((Body::from(bytes), tar())),
- None::<iter::Empty<_>>,
- );
-
- Ok(value_stream)
- }
- .try_flatten_stream(),
- )
- }
-
- /// Lists the docker images on the current docker host
- pub async fn list(
- &self,
- opts: &ImageListOptions,
- ) -> Result<Vec<ImageRep>> {
- let mut path = vec!["/images/json".to_owned()];
- if let Some(query) = opts.serialize() {
- path.push(query);
- }
- self.docker.get_json::<Vec<ImageRep>>(&path.join("?")).await
- }
-
- /// Returns a reference to a set of operations available for a named image
- pub fn get<S>(
- &self,
- name: S,
- ) -> Image<'docker>
- where
- S: Into<String>,
- {
- Image::new(self.docker, name)
- }
-
- /// Search for docker images by term
- pub async fn search(
- &self,
- term: &str,
- ) -> Result<Vec<SearchResult>> {
- let query = form_urlencoded::Serializer::new(String::new())
- .append_pair("term", term)
- .finish();
- self.docker
- .get_json::<Vec<SearchResult>>(&format!("/images/search?{}", query)[..])
- .await
- }
-
- /// Pull and create a new docker images from an existing image
- pub fn pull(
- &self,
- opts: &PullOptions,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker {
- let mut path = vec!["/images/create".to_owned()];
- if let Some(query) = opts.serialize() {
- path.push(query);
- }
- let headers = opts
- .auth_header()
- .map(|a| iter::once(("X-Registry-Auth", a)));
-
- Box::pin(
- self.docker
- .stream_post_into_values(path.join("?"), None, headers),
- )
- }
-
- /// exports a collection of named images,
- /// either by name, name:tag, or image id, into a tarball
- pub fn export(
- &self,
- names: Vec<&str>,
- ) -> impl Stream<Item = Result<Vec<u8>>> + 'docker {
- let params = names.iter().map(|n| ("names", *n));
- let query = form_urlencoded::Serializer::new(String::new())
- .extend_pairs(params)
- .finish();
- self.docker
- .stream_get(format!("/images/get?{}", query))
- .map_ok(|c| c.to_vec())
- }
-
- /// imports an image or set of images from a given tarball source
- /// source can be uncompressed on compressed via gzip, bzip2 or xz
- pub fn import<R>(
- self,
- mut tarball: R,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker
- where
- R: Read + Send + 'docker,
- {
- Box::pin(
- async move {
- let mut bytes = Vec::default();
-
- tarball.read_to_end(&mut bytes)?;
-
- let value_stream = self.docker.stream_post_into_values(
- "/images/load",
- Some((Body::from(bytes), tar())),
- None::<iter::Empty<_>>,
- );
- Ok(value_stream)
- }
- .try_flatten_stream(),
- )
- }
-}
-
-/// Interface for accessing and manipulating a docker container
-pub struct Container<'docker> {
- docker: &'docker Docker,
- id: String,
-}
-
-impl<'docker> Container<'docker> {
- /// Exports an interface exposing operations against a container instance
- pub fn new<S>(
- docker: &'docker Docker,
- id: S,
- ) -> Self
- where
- S: Into<String>,
- {
- Container {
- docker,
- id: id.into(),
- }
- }
-
- /// a getter for the container id
- pub fn id(&self) -> &str {
- &self.id
- }
-
- /// Inspects the current docker container instance's details
- pub async fn inspect(&self) -> Result<ContainerDetails> {
- self.docker
- .get_json::<ContainerDetails>(&format!("/containers/{}/json", self.id)[..])
- .await
- }
-
- /// Returns a `top` view of information about the container process
- pub async fn top(
- &self,
- psargs: Option<&str>,
- ) -> Result<Top> {
- let mut path = vec![format!("/containers/{}/top", self.id)];
- if let Some(ref args) = psargs {
- let encoded = form_urlencoded::Serializer::new(String::new())
- .append_pair("ps_args", args)
- .finish();
- path.push(encoded)
- }
- self.docker.get_json(&path.join("?")).await
- }
-
- /// Returns a stream of logs emitted but the container instance
- pub fn logs(
- &self,
- opts: &LogsOptions,
- ) -> impl Stream<Item = Result<tty::TtyChunk>> + Unpin + 'docker {
- let mut path = vec![format!("/containers/{}/logs", self.id)];
- if let Some(query) = opts.serialize() {
- path.push(query)
- }
-
- let stream = Box::pin(self.docker.stream_get(path.join("?")));
-
- Box::pin(tty::decode(stream))
- }
-
- /// Attaches a multiplexed TCP stream to the container that can be used to read Stdout, Stderr and write Stdin.
- async fn attach_raw(&self) -> Result<impl AsyncRead + AsyncWrite + Send + 'docker> {
- self.docker
- .stream_post_upgrade(
- format!(
- "/containers/{}/attach?stream=1&stdout=1&stderr=1&stdin=1",
- self.id
- ),
- None,
- )
- .await
- }
-
- /// Attaches a `[TtyMultiplexer]` to the container.
- ///
- /// The `[TtyMultiplexer]` implements Stream for returning Stdout and Stderr chunks. It also implements `[AsyncWrite]` for writing to Stdin.
- ///
- /// The multiplexer can be split into its read and write halves with the `[split](TtyMultiplexer::split)` method
- pub async fn attach(&self) -> Result<TtyMultiPlexer<'docker>> {
- let tcp_stream = self.attach_raw().await?;
-
- Ok(TtyMultiPlexer::new(tcp_stream))
- }
-
- /// Returns a set of changes made to the container instance
- pub async fn changes(&self) -> Result<Vec<Change>> {
- self.docker
- .get_json::<Vec<Change>>(&format!("/containers/{}/changes", self.id)[..])
- .await
- }
-
- /// Exports the current docker container into a tarball
- pub fn export(&self) -> impl Stream<Item = Result<Vec<u8>>> + 'docker {
- self.docker
- .stream_get(format!("/containers/{}/export", self.id))
- .map_ok(|c| c.to_vec())
- }
-
- /// Returns a stream of stats specific to this container instance
- pub fn stats(&self) -> impl Stream<Item = Result<Stats>> + Unpin + 'docker {
- let codec = futures_codec::LinesCodec {};
-
- let reader = Box::pin(
- self.docker
- .stream_get(format!("/containers/{}/stats", self.id))
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
- )
- .into_async_read();
-
- Box::pin(
- futures_codec::FramedRead::new(reader, codec)
- .map_err(Error::IO)
- .and_then(|s: String| async move {
- serde_json::from_str(&s).map_err(Error::SerdeJsonError)
- }),
- )
- }
-
- /// Start the container instance
- pub async fn start(&self) -> Result<()> {
- self.docker
- .post(&format!("/containers/{}/start", self.id)[..], None)
- .await?;
- Ok(())
- }
-
- /// Stop the container instance
- pub async fn stop(
- &self,
- wait: Option<Duration>,
- ) -> Result<()> {
- let mut path = vec![format!("/containers/{}/stop", self.id)];
- if let Some(w) = wait {
- let encoded = form_urlencoded::Serializer::new(String::new())
- .append_pair("t", &w.as_secs().to_string())
- .finish();
-
- path.push(encoded)
- }
- self.docker.post(&path.join("?"), None).await?;
- Ok(())
- }
-
- /// Restart the container instance
- pub async fn restart(
- &self,
- wait: Option<Duration>,
- ) -> Result<()> {
- let mut path = vec![format!("/containers/{}/restart", self.id)];
- if let Some(w) = wait {
- let encoded = form_urlencoded::Serializer::new(String::new())
- .append_pair("t", &w.as_secs().to_string())
- .finish();
- path.push(encoded)
- }
- self.docker.post(&path.join("?"), None).await?;
- Ok(())
- }
-
- /// Kill the container instance
- pub async fn kill(
- &self,
- signal: Option<&str>,
- ) -> Result<()> {
- let mut path = vec![format!("/containers/{}/kill", self.id)];
- if let Some(sig) = signal {
- let encoded = form_urlencoded::Serializer::new(String::new())
- .append_pair("signal", &sig.to_owned())
- .finish();
- path.push(encoded)
- }
- self.docker.post(&path.join("?"), None).await?;
- Ok(())
- }
-
- /// Rename the container instance
- pub async fn rename(
- &self,
- name: &str,
- ) -> Result<()> {
- let query = form_urlencoded::Serializer::new(String::new())
- .append_pair("name", name)
- .finish();
- self.docker
- .post(
- &format!("/containers/{}/rename?{}", self.id, query)[..],
- None,
- )
- .await?;
- Ok(())
- }
-
- /// Pause the container instance
- pub async fn pause(&self) -> Result<()> {
- self.docker
- .post(&format!("/containers/{}/pause", self.id)[..], None)
- .await?;
- Ok(())
- }
-
- /// Unpause the container instance
- pub async fn unpause(&self) -> Result<()> {
- self.docker
- .post(&format!("/containers/{}/unpause", self.id)[..], None)
- .await?;
- Ok(())
- }
-
- /// Wait until the container stops
- pub async fn wait(&self) -> Result<Exit> {
- self.docker
- .post_json(
- format!("/containers/{}/wait", self.id),
- Option::<(Body, Mime)>::None,
- )
- .await
- }
-
- /// Delete the container instance
- ///
- /// Use remove instead to use the force/v options.
- pub async fn delete(&self) -> Result<()> {
- self.docker
- .delete(&format!("/containers/{}", self.id)[..])
- .await?;
- Ok(())
- }
-
- /// Delete the container instance (todo: force/v)
- pub async fn remove(
- &self,
- opts: RmContainerOptions,
- ) -> Result<()> {
- let mut path = vec![format!("/containers/{}", self.id)];
- if let Some(query) = opts.serialize() {
- path.push(query)
- }
- self.docker.delete(&path.join("?")).await?;
- Ok(())
- }
-
- /// Execute a command in this container
- pub fn exec(
- &self,
- opts: &ExecContainerOptions,
- ) -> impl Stream<Item = Result<tty::TtyChunk>> + Unpin + 'docker {
- Exec::create_and_start(self.docker, &self.id, opts)
- }
-
- /// Copy a file/folder from the container. The resulting stream is a tarball of the extracted
- /// files.
- ///
- /// If `path` is not an absolute path, it is relative to the container’s root directory. The
- /// resource specified by `path` must exist. To assert that the resource is expected to be a
- /// directory, `path` should end in `/` or `/.` (assuming a path separator of `/`). If `path`
- /// ends in `/.` then this indicates that only the contents of the path directory should be
- /// copied. A symlink is always resolved to its target.
- pub fn copy_from(
- &self,
- path: &Path,
- ) -> impl Stream<Item = Result<Vec<u8>>> + 'docker {
- let path_arg = form_urlencoded::Serializer::new(String::new())
- .append_pair("path", &path.to_string_lossy())
- .finish();
-
- let endpoint = format!("/containers/{}/archive?{}", self.id, path_arg);
- self.docker.stream_get(endpoint).map_ok(|c| c.to_vec())
- }
-
- /// Copy a byte slice as file into (see `bytes`) the container.
- ///
- /// The file will be copied at the given location (see `path`) and will be owned by root
- /// with access mask 644.
- pub async fn copy_file_into<P: AsRef<Path>>(
- &self,
- path: P,
- bytes: &[u8],
- ) -> Result<()> {
- let path = path.as_ref();
-
- let mut ar = tar::Builder::new(Vec::new());
- let mut header = tar::Header::new_gnu();
- header.set_size(bytes.len() as u64);
- header.set_mode(0o0644);
- ar.append_data(
- &mut header,
- path.to_path_buf()
- .iter()
- .skip(1)
- .collect::<std::path::PathBuf>(),
- bytes,
- )
- .unwrap();
- let data = ar.into_inner().unwrap();
-
- self.copy_to(Path::new("/"), data.into()).await?;
- Ok(())
- }
-
- /// Copy a tarball (see `body`) to the container.
- ///
- /// The tarball will be copied to the container and extracted at the given location (see `path`).
- pub async fn copy_to(
- &self,
- path: &Path,
- body: Body,
- ) -> Result<()> {
- let path_arg = form_urlencoded::Serializer::new(String::new())
- .append_pair("path", &path.to_string_lossy())
- .finish();
-
- let mime = "application/x-tar".parse::<Mime>().unwrap();
-
- self.docker
- .put(
- &format!("/containers/{}/archive?{}", self.id, path_arg),
- Some((body, mime)),
- )
- .await?;
- Ok(())
- }
-}
-
-/// Interface for docker containers
-pub struct Containers<'docker> {
- docker: &'docker Docker,
-}
-
-impl<'docker> Containers<'docker> {
- /// Exports an interface for interacting with docker containers
- pub fn new(docker: &'docker Docker) -> Self {
- Containers { docker }
- }
-
- /// Lists the container instances on the docker host
- pub async fn list(
- &self,
- opts: &ContainerListOptions,
- ) -> Result<Vec<ContainerRep>> {
- let mut path = vec!["/containers/json".to_owned()];
- if let Some(query) = opts.serialize() {
- path.push(query)
- }
- self.docker
- .get_json::<Vec<ContainerRep>>(&path.join("?"))
- .await
- }
-
- /// Returns a reference to a set of operations available to a specific container instance
- ///
- /// # Warning
- ///
- /// This function does not check whether the container with `name` actually exists and returns
- /// a potentially invalid handle.
- pub fn get<S>(
- &self,
- name: S,
- ) -> Container<'docker>
- where
- S: Into<String>,
- {
- Container::new(self.docker, name)
- }
-
- /// Same as `Container::get()`, but checks whether the container exists and returns None if it
- /// doesn't
- pub async fn get_checked<S>(
- &self,
- name: S,
- ) -> Result<Option<Container<'docker>>>
- where
- S: AsRef<str>,
- {
- let listopts = ContainerListOptions::builder().all().build();
- self.list(&listopts)
- .await?
- .into_iter()
- .find(|rep| rep.id == name.as_ref())
- .map(|rep| Container::new(self.docker, rep.id))
- .map(Ok)
- .transpose()
- }
-
- /// Returns a builder interface for creating a new container instance
- pub async fn create(
- &self,
- opts: &ContainerOptions,
- ) -> Result<ContainerCreateInfo> {
- let body: Body = opts.serialize()?.into();
- let mut path = vec!["/containers/create".to_owned()];
-
- if let Some(ref name) = opts.name {
- path.push(
- form_urlencoded::Serializer::new(String::new())
- .append_pair("name", name)
- .finish(),
- );
- }
-
- self.docker
- .post_json(&path.join("?"), Some((body, mime::APPLICATION_JSON)))
- .await
- }
-}
-/// Interface for docker exec instance
-pub struct Exec<'docker> {
- docker: &'docker Docker,
- id: String,
-}
-
-impl<'docker> Exec<'docker> {
- fn new<S>(
- docker: &'docker Docker,
- id: S,
- ) -> Self
- where
- S: Into<String>,
- {
- Exec {
- docker,
- id: id.into(),
- }
- }
-
- /// Creates a new exec instance that will be executed in a container with id == container_id
- pub async fn create(
- docker: &'docker Docker,
- container_id: &str,
- opts: &ExecContainerOptions,
- ) -> Result<Exec<'docker>> {
- #[derive(serde::Deserialize)]
- #[serde(rename_all = "PascalCase")]
- struct Response {
- id: String,
- }
-
- let body: Body = opts.serialize()?.into();
-
- let id = docker
- .post_json(
- &format!("/containers/{}/exec", container_id),
- Some((body, mime::APPLICATION_JSON)),
- )
- .await
- .map(|resp: Response| resp.id)?;
-
- Ok(Exec::new(docker, id))
- }
-
- // This exists for Container::exec()
- //
- // We need to combine `Exec::create` and `Exec::start` into one method because otherwise you
- // needlessly tie the Stream to the lifetime of `container_id` and `opts`. This is because
- // `Exec::create` is async so it must occur inside of the `async move` block. However, this
- // means that `container_id` and `opts` are both expected to be alive in the returned stream
- // because we can't do the work of creating an endpoint from `container_id` or serializing
- // `opts`. By doing this work outside of the stream, we get owned values that we can then move
- // into the stream and have the lifetimes work out as you would expect.
- //
- // Yes, it is sad that we can't do the easy method and thus have some duplicated code.
- pub(crate) fn create_and_start(
- docker: &'docker Docker,
- container_id: &str,
- opts: &ExecContainerOptions,
- ) -> impl Stream<Item = Result<tty::TtyChunk>> + Unpin + 'docker {
- #[derive(serde::Deserialize)]
- #[serde(rename_all = "PascalCase")]
- struct Response {
- id: String,
- }
-
- // To not tie the lifetime of `opts` to the stream, we do the serializing work outside of
- // the stream. But for backwards compatability, we have to return the error inside of the
- // stream.
- let body_result = opts.serialize();
-
- // To not tie the lifetime of `container_id` to the stream, we convert it to an (owned)
- // endpoint outside of the stream.
- let container_endpoint = format!("/containers/{}/exec", container_id);
-
- Box::pin(
- async move {
- // Bubble up the error inside the stream for backwards compatability
- let body: Body = body_result?.into();
-
- let exec_id = docker
- .post_json(&container_endpoint, Some((body, mime::APPLICATION_JSON)))
- .await
- .map(|resp: Response| resp.id)?;
-
- let stream = Box::pin(docker.stream_post(
- format!("/exec/{}/start", exec_id),
- Some(("{}".into(), mime::APPLICATION_JSON)),
- None::<iter::Empty<_>>,
- ));
-
- Ok(tty::decode(stream))
- }
- .try_flatten_stream(),
- )
- }
-
- /// Get a reference to a set of operations available to an already created exec instance.
- ///
- /// It's in callers responsibility to ensure that exec instance with specified id actually
- /// exists. Use [Exec::create](Exec::create) to ensure that the exec instance is created
- /// beforehand.
- pub async fn get<S>(
- docker: &'docker Docker,
- id: S,
- ) -> Exec<'docker>
- where
- S: Into<String>,
- {
- Exec::new(docker, id)
- }
-
- /// Starts this exec instance returning a multiplexed tty stream
- pub fn start(&self) -> impl Stream<Item = Result<tty::TtyChunk>> + 'docker {
- // We must take ownership of the docker reference to not needlessly tie the stream to the
- // lifetime of `self`.
- let docker = self.docker;
- // We convert `self.id` into the (owned) endpoint outside of the stream to not needlessly
- // tie the stream to the lifetime of `self`.
- let endpoint = format!("/exec/{}/start", &self.id);
- Box::pin(
- async move {
- let stream = Box::pin(docker.stream_post(
- endpoint,
- Some(("{}".into(), mime::APPLICATION_JSON)),
- None::<iter::Empty<_>>,
- ));
-
- Ok(tty::decode(stream))
- }
- .try_flatten_stream(),
- )
- }
-
- /// Inspect this exec instance to aquire detailed information
- pub async fn inspect(&self) -> Result<ExecDetails> {
- self.docker
- .get_json(&format!("/exec/{}/json", &self.id)[..])
- .await
- }
-
- pub async fn resize(
- &self,
- opts: &ExecResizeOptions,
- ) -> Result<()> {
- let body: Body = opts.serialize()?.into();
-
- self.docker
- .post_json(
- &format!("/exec/{}/resize", &self.id)[..],
- Some((body, mime::APPLICATION_JSON)),
- )
- .await
- }
-}
-
-/// Interface for docker network
-pub struct Networks<'docker> {
- docker: &'docker Docker,
-}
-
-impl<'docker> Networks<'docker> {
- /// Exports an interface for interacting with docker Networks
- pub fn new(docker: &'docker Docker) -> Self {
- Networks { docker }
- }
-
- /// List the docker networks on the current docker host
- pub async fn list(
- &self,
- opts: &NetworkListOptions,
- ) -> Result<Vec<NetworkInfo>> {
- let mut path = vec!["/networks".to_owned()];
- if let Some(query) = opts.serialize() {
- path.push(query);
- }
- self.docker.get_json(&path.join("?")).await
- }
-
- /// Returns a reference to a set of operations available to a specific network instance
- pub fn get<S>(
- &self,
- id: S,
- ) -> Network<'docker>
- where
- S: Into<String>,
- {
- Network::new(self.docker, id)
- }
-
- /// Create a new Network instance
- pub async fn create(
- &self,
- opts: &NetworkCreateOptions,
- ) -> Result<NetworkCreateInfo> {
- let body: Body = opts.serialize()?.into();
- let path = vec!["/networks/create".to_owned()];
-
- self.docker
- .post_json(&path.join("?"), Some((body, mime::APPLICATION_JSON)))
- .await
- }
-}
-
-/// Interface for accessing and manipulating a docker network
-pub struct Network<'docker> {
- docker: &'docker Docker,
- id: String,
-}
-
-impl<'docker> Network<'docker> {
- /// Exports an interface exposing operations against a network instance
- pub fn new<S>(
- docker: &'docker Docker,
- id: S,
- ) -> Self
- where
- S: Into<String>,
- {
- Network {
- docker,
- id: id.into(),
- }
- }
-
- /// a getter for the Network id
- pub fn id(&self) -> &str {
- &self.id
- }
-
- /// Inspects the current docker network instance's details
- pub async fn inspect(&self) -> Result<NetworkInfo> {
- self.docker
- .get_json(&format!("/networks/{}", self.id)[..])
- .await
- }
-
- /// Delete the network instance
- pub async fn delete(&self) -> Result<()> {
- self.docker
- .delete(&format!("/networks/{}", self.id)[..])
- .await?;
- Ok(())
- }
-
- /// Connect container to network
- pub async fn connect(
- &self,
- opts: &ContainerConnectionOptions,
- ) -> Result<()> {
- self.do_connection("connect", opts).await
- }
-
- /// Disconnect container to network
- pub async fn disconnect(
- &self,
- opts: &ContainerConnectionOptions,
- ) -> Result<()> {
- self.do_connection("disconnect", opts).await
- }
-
- async fn do_connection(
- &self,
- segment: &str,
- opts: &ContainerConnectionOptions,
- ) -> Result<()> {
- let body: Body = opts.serialize()?.into();
-
- self.docker
- .post(
- &format!("/networks/{}/{}", self.id, segment)[..],
- Some((body, mime::APPLICATION_JSON)),
- )
- .await?;
- Ok(())
- }
-}
-
-/// Interface for docker volumes
-pub struct Volumes<'docker> {
- docker: &'docker Docker,
-}
-
-impl<'docker> Volumes<'docker> {
- /// Exports an interface for interacting with docker volumes
- pub fn new(docker: &'docker Docker) -> Self {
- Volumes { docker }
- }
-
- pub async fn create(
- &self,
- opts: &VolumeCreateOptions,
- ) -> Result<VolumeCreateInfo> {
- let body: Body = opts.serialize()?.into();
- let path = vec!["/volumes/create".to_owned()];
-
- self.docker
- .post_json(&path.join("?"), Some((body, mime::APPLICATION_JSON)))
- .await
- }
-
- /// Lists the docker volumes on the current docker host
- pub async fn list(&self) -> Result<Vec<VolumeRep>> {
- let path = vec!["/volumes".to_owned()];
-
- let volumes_rep = self.docker.get_json::<VolumesRep>(&path.join("?")).await?;
- Ok(match volumes_rep.volumes {
- Some(volumes) => volumes,
- None => vec![],
- })
- }
-
- /// Returns a reference to a set of operations available for a named volume
- pub fn get(
- &self,
- name: &str,
- ) -> Volume<'docker> {
- Volume::new(self.docker, name)
- }
-}
-
-/// Interface for accessing and manipulating a named docker volume
-pub struct Volume<'docker> {
- docker: &'docker Docker,
- name: String,
-}
-
-impl<'docker> Volume<'docker> {
- /// Exports an interface for operations that may be performed against a named volume
- pub fn new<S>(
- docker: &'docker Docker,
- name: S,
- ) -> Self
- where
- S: Into<String>,
- {
- Volume {
- docker,
- name: name.into(),
- }
- }
-
- /// Deletes a volume
- pub async fn delete(&self) -> Result<()> {
- self.docker
- .delete(&format!("/volumes/{}", self.name)[..])
- .await?;
- Ok(())
- }
-}
-
-/// Interface for docker services
-pub struct Services<'docker> {
- docker: &'docker Docker,
-}
-
-impl<'docker> Services<'docker> {
- /// Exports an interface for interacting with docker services
- pub fn new(docker: &'docker Docker) -> Self {
- Services { docker }
- }
-
- /// Lists the docker services on the current docker host
- pub async fn list(
- &self,
- opts: &ServiceListOptions,
- ) -> Result<ServicesRep> {
- let mut path = vec!["/services".to_owned()];
- if let Some(query) = opts.serialize() {
- path.push(query);
- }
-
- self.docker.get_json::<ServicesRep>(&path.join("?")).await
- }
-
- /// Returns a reference to a set of operations available for a named service
- pub fn get(
- &self,
- name: &str,
- ) -> Service<'docker> {
- Service::new(self.docker, name)
- }
-}
-