summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/container.rs184
-rw-r--r--src/docker.rs8
-rw-r--r--src/image.rs76
-rw-r--r--src/lib.rs2
4 files changed, 222 insertions, 48 deletions
diff --git a/src/container.rs b/src/container.rs
index dfd65d2..60f7d61 100644
--- a/src/container.rs
+++ b/src/container.rs
@@ -19,7 +19,7 @@ use crate::{
docker::Docker,
errors::{Error, Result},
exec::{Exec, ExecContainerOptions},
- image::Config,
+ image::ContainerConfig,
network::NetworkSettings,
transport::Payload,
tty::{self, Multiplexer as TtyMultiPlexer},
@@ -365,9 +365,8 @@ impl<'docker> Container<'docker> {
.skip(1)
.collect::<std::path::PathBuf>(),
bytes,
- )
- .unwrap();
- let data = ar.into_inner().unwrap();
+ )?;
+ let data = ar.into_inner()?;
self.copy_to(Path::new("/"), data.into()).await?;
Ok(())
@@ -1195,37 +1194,47 @@ pub struct ContainerInfo {
pub ports: Vec<Port>,
pub state: String,
pub status: String,
- pub size_rw: Option<u64>,
- pub size_root_fs: Option<u64>,
+ pub size_rw: Option<i64>,
+ pub size_root_fs: Option<i64>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ContainerDetails {
- pub app_armor_profile: String,
- pub args: Vec<String>,
- pub config: Config,
+ pub id: String,
#[cfg(feature = "chrono")]
pub created: DateTime<Utc>,
#[cfg(not(feature = "chrono"))]
pub created: String,
- pub driver: String,
- // pub ExecIDs: ??
- pub host_config: HostConfig,
+ pub path: String,
+ pub args: Vec<String>,
+ pub state: State,
+ pub image: String,
+ pub resolv_conf_path: String,
pub hostname_path: String,
pub hosts_path: String,
pub log_path: String,
- pub id: String,
- pub image: String,
- pub mount_label: String,
pub name: String,
- pub network_settings: NetworkSettings,
- pub path: String,
+ pub restart_count: i64,
+ pub driver: String,
+ pub platform: String,
+ pub mount_label: String,
pub process_label: String,
- pub resolv_conf_path: String,
- pub restart_count: u64,
- pub state: State,
+ pub app_armor_profile: String,
+ #[serde(rename = "ExecIDs")]
+ pub exec_ids: Option<Vec<String>>,
+ pub host_config: HostConfig,
+ pub graph_driver: GraphDriverData,
pub mounts: Vec<Mount>,
+ pub config: ContainerConfig,
+ pub network_settings: NetworkSettings,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct GraphDriverData {
+ pub name: String,
+ pub data: HashMap<String, String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -1263,22 +1272,139 @@ pub struct State {
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct HostConfig {
+ pub cpu_shares: Option<i64>,
+ pub memory: Option<i64>,
pub cgroup_parent: Option<String>,
- #[serde(rename = "ContainerIDFile")]
- pub container_id_file: String,
- pub cpu_shares: Option<u64>,
+ pub blkio_weight_device: Option<Vec<ThrottleDevice>>,
+ pub blkio_device_read_bps: Option<Vec<ThrottleDevice>>,
+ pub blkio_device_write_bps: Option<Vec<ThrottleDevice>>,
+ #[serde(rename = "BlkioDeviceReadIOps")]
+ pub blkio_device_read_iops: Option<Vec<ThrottleDevice>>,
+ #[serde(rename = "BlkioDeviceWriteIOps")]
+ pub blkio_device_write_iops: Option<Vec<ThrottleDevice>>,
+ pub cpu_period: Option<i64>,
+ pub cpu_quota: Option<i64>,
+ pub cpu_realtime_period: Option<i64>,
+ pub cpu_realtime_runtime: Option<i64>,
pub cpuset_cpus: Option<String>,
- pub memory: Option<u64>,
+ pub cpuset_mems: Option<String>,
+ pub devices: Option<Vec<DeviceMapping>>,
+ pub device_cgroup_rules: Option<String>,
+ pub device_requests: Option<Vec<DeviceRequest>>,
+ #[serde(rename = "KernelMemoryTCP")]
+ pub kernel_memory_tcp: i64,
+ pub memory_reservation: Option<i64>,
pub memory_swap: Option<i64>,
+ pub memory_swappiness: Option<i64>,
+ #[serde(rename = "NanoCPUs")]
+ pub nano_cpus: Option<i64>,
+ pub oom_kill_disable: bool,
+ pub init: Option<bool>,
+ pub pids_limit: Option<i64>,
+ pub ulimits: Option<Vec<Ulimit>>,
+ pub cpu_count: i64,
+ pub cpu_percent: i64,
+ #[serde(rename = "IOMaximumIOps")]
+ pub io_maximum_iops: u64,
+ #[serde(rename = "IOMaximumBandwith")]
+ pub io_maximum_bandwith: Option<u64>,
+ pub binds: Option<Vec<String>>,
+ #[serde(rename = "ContainerIDFile")]
+ pub container_id_file: String,
+ pub log_config: LogConfig,
pub network_mode: String,
+ pub port_bindings: Option<PortMap>,
+ pub restart_policy: RestartPolicy,
+ pub auto_remove: bool,
+ pub volume_driver: String,
+ pub volumes_from: Option<Vec<String>>,
+ pub mounts: Option<Vec<Mount>>,
+ pub cap_add: Option<Vec<String>>,
+ pub cap_drop: Option<Vec<String>>,
+ pub dns: Option<Vec<String>>,
+ pub dns_options: Option<Vec<String>>,
+ pub dns_search: Option<Vec<String>>,
+ pub extra_hosts: Option<Vec<String>>,
+ pub group_add: Option<Vec<String>>,
+ pub ipc_mode: String,
+ pub cgroup: String,
+ pub links: Option<Vec<String>>,
+ pub oom_score_adj: i64,
pub pid_mode: Option<String>,
- pub port_bindings: Option<HashMap<String, Vec<HashMap<String, String>>>>,
pub privileged: bool,
pub publish_all_ports: bool,
- pub readonly_rootfs: Option<bool>, /* pub RestartPolicy: ???
- * pub SecurityOpt: Option<???>,
- * pub Ulimits: Option<???>
- * pub VolumesFrom: Option<??/> */
+ pub readonly_rootfs: Option<bool>,
+ pub security_opt: Option<Vec<String>>,
+ pub storage_opt: Option<HashMap<String, String>>,
+ pub tmpfs: Option<HashMap<String, String>>,
+ #[serde(rename = "UTSMode")]
+ pub uts_mode: String,
+ pub userns_mode: String,
+ pub shm_size: u64,
+ pub sysctls: Option<HashMap<String, String>>,
+ pub runtime: String,
+ pub console_size: Option<Vec<u64>>,
+ pub isolation: String,
+ pub masked_paths: Option<Vec<String>>,
+ pub readonly_paths: Option<Vec<String>>,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct ThrottleDevice {
+ pub path: String,
+ pub rate: u64,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct RestartPolicy {
+ pub name: String,
+ pub maximum_retry_count: u64,
+}
+
+pub type PortMap = HashMap<String, Option<Vec<PortBinding>>>;
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct PortBinding {
+ pub host_ip: String,
+ pub host_port: String,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct LogConfig {
+ #[serde(rename = "Type")]
+ pub type_: String,
+ #[serde(rename = "Config")]
+ pub config: HashMap<String, String>,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct Ulimit {
+ pub name: String,
+ pub soft: u64,
+ pub hard: u64,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct DeviceMapping {
+ pub path_on_host: Option<String>,
+ pub path_in_container: Option<String>,
+ pub cgroup_permissions: Option<String>,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct DeviceRequest {
+ pub driver: String,
+ pub count: u64,
+ #[serde(rename = "DeviceIDs")]
+ pub device_ids: Vec<String>,
+ pub capabilities: Vec<String>,
+ pub options: Option<serde_json::Value>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
diff --git a/src/docker.rs b/src/docker.rs
index edb97e4..1b7f603 100644
--- a/src/docker.rs
+++ b/src/docker.rs
@@ -7,8 +7,7 @@ use std::{collections::HashMap, env, io, path::Path};
use futures_util::{stream::Stream, TryStreamExt};
use hyper::{client::HttpConnector, Body, Client, Method};
use mime::Mime;
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
+use serde::{de, Deserialize, Serialize};
use url::form_urlencoded;
use crate::{
@@ -355,14 +354,15 @@ impl Docker {
/// Send a streaming post request that returns a stream of JSON values
///
/// Assumes that each received chunk contains one or more JSON values
- pub(crate) fn stream_post_into_values<'a, H>(
+ pub(crate) fn stream_post_into<'a, H, T>(
&'a self,
endpoint: impl AsRef<str> + 'a,
body: Option<(Body, Mime)>,
headers: Option<H>,
- ) -> impl Stream<Item = Result<Value>> + 'a
+ ) -> impl Stream<Item = Result<T>> + 'a
where
H: IntoIterator<Item = (&'static str, String)> + 'a,
+ T: de::DeserializeOwned,
{
self.stream_post(endpoint, body, headers)
.and_then(|chunk| async move {
diff --git a/src/image.rs b/src/image.rs
index addf4ee..6df8cb7 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -7,7 +7,6 @@ use std::{collections::HashMap, io::Read, iter};
use futures_util::{stream::Stream, TryFutureExt, TryStreamExt};
use hyper::Body;
use serde::{Deserialize, Serialize};
-use serde_json::Value;
use url::form_urlencoded;
use crate::{docker::Docker, errors::Result, tarball, transport::tar};
@@ -111,7 +110,7 @@ impl<'docker> Images<'docker> {
pub fn build(
&self,
opts: &BuildOptions,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker {
+ ) -> impl Stream<Item = Result<ImageBuildChunk>> + Unpin + 'docker {
let mut endpoint = vec!["/build".to_owned()];
if let Some(query) = opts.serialize() {
endpoint.push(query)
@@ -131,7 +130,7 @@ impl<'docker> Images<'docker> {
// Bubble up error inside the stream for backwards compatability
tar_result?;
- let value_stream = docker.stream_post_into_values(
+ let value_stream = docker.stream_post_into(
endpoint.join("?"),
Some((Body::from(bytes), tar())),
None::<iter::Empty<_>>,
@@ -191,7 +190,7 @@ impl<'docker> Images<'docker> {
pub fn pull(
&self,
opts: &PullOptions,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker {
+ ) -> impl Stream<Item = Result<ImageBuildChunk>> + Unpin + 'docker {
let mut path = vec!["/images/create".to_owned()];
if let Some(query) = opts.serialize() {
path.push(query);
@@ -200,10 +199,7 @@ impl<'docker> Images<'docker> {
.auth_header()
.map(|a| iter::once(("X-Registry-Auth", a)));
- Box::pin(
- self.docker
- .stream_post_into_values(path.join("?"), None, headers),
- )
+ Box::pin(self.docker.stream_post_into(path.join("?"), None, headers))
}
/// exports a collection of named images,
@@ -230,7 +226,7 @@ impl<'docker> Images<'docker> {
pub fn import<R>(
self,
mut tarball: R,
- ) -> impl Stream<Item = Result<Value>> + Unpin + 'docker
+ ) -> impl Stream<Item = Result<ImageBuildChunk>> + Unpin + 'docker
where
R: Read + Send + 'docker,
{
@@ -240,7 +236,7 @@ impl<'docker> Images<'docker> {
tarball.read_to_end(&mut bytes)?;
- let value_stream = self.docker.stream_post_into_values(
+ let value_stream = self.docker.stream_post_into(
"/images/load",
Some((Body::from(bytes), tar())),
None::<iter::Empty<_>>,
@@ -449,12 +445,20 @@ impl PullOptions {
}
}
-#[derive(Default)]
pub struct PullOptionsBuilder {
auth: Option<RegistryAuth>,
params: HashMap<&'static str, String>,
}
+impl Default for PullOptionsBuilder {
+ fn default() -> Self {
+ let mut params = HashMap::new();
+ params.insert("tag", "latest".to_string());
+
+ PullOptionsBuilder { auth: None, params }
+ }
+}
+
impl PullOptionsBuilder {
/// Name of the image to pull. The name may include a tag or digest.
/// This parameter may only be used when pulling an image.
@@ -485,6 +489,9 @@ impl PullOptionsBuilder {
/// Repository name given to an image when it is imported. The repo may include a tag.
/// This parameter may only be used when importing an image.
+ ///
+ /// By default a `latest` tag is added when calling
+ /// [PullOptionsBuilder::default](PullOptionsBuilder::default].
pub fn repo<R>(
&mut self,
r: R,
@@ -792,7 +799,7 @@ pub struct ImageDetails {
pub architecture: String,
pub author: String,
pub comment: String,
- pub config: Config,
+ pub config: ContainerConfig,
#[cfg(feature = "chrono")]
pub created: DateTime<Utc>,
#[cfg(not(feature = "chrono"))]
@@ -809,7 +816,7 @@ pub struct ImageDetails {
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
-pub struct Config {
+pub struct ContainerConfig {
pub attach_stderr: bool,
pub attach_stdin: bool,
pub attach_stdout: bool,
@@ -831,7 +838,7 @@ pub struct Config {
pub working_dir: String,
}
-impl Config {
+impl ContainerConfig {
pub fn env(&self) -> HashMap<String, String> {
let mut map = HashMap::new();
if let Some(ref vars) = self.env {
@@ -862,6 +869,47 @@ pub enum Status {
Deleted(String),
}
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(untagged)]
+/// Represents a response chunk from Docker api when building, pulling or importing an image.
+pub enum ImageBuildChunk {
+ Update {
+ stream: String,
+ },
+ Error {
+ error: String,
+ #[serde(rename = "errorDetail")]
+ error_detail: ErrorDetail,
+ },
+ Digest {
+ aux: Aux,
+ },
+ PullStatus {
+ status: String,
+ id: Option<String>,
+ progress: Option<String>,
+ #[serde(rename = "progressDetail")]
+ progress_detail: Option<ProgressDetail>,
+ },
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Aux {
+ #[serde(rename = "ID")]
+ id: String,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct ErrorDetail {
+ message: String,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct ProgressDetail {
+ current: Option<u64>,
+ total: Option<u64>,
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/lib.rs b/src/lib.rs
index 4d60523..0d9bac6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -119,7 +119,7 @@ reexport! {
docker::{Version, Info, Event, Actor};
exec::{ExecDetails, ProcessConfig};
image::{
- SearchResult, ImageInfo as Image, ImageDetails, Config, History, Status,
+ SearchResult, ImageInfo as Image, ImageDetails, ContainerConfig, History, Status,
};
network::{
NetworkSettings, NetworkEntry, Ipam, NetworkDetails,