mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-19 12:16:30 +00:00
Compare commits
46 Commits
v1.8.0-rc3
...
v1.5.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| a3934504f9 | |||
| 3c090db4e9 | |||
| b7c3fdfd0d | |||
| aa682a845b | |||
| 218d0dcc9d | |||
| 510d8f8634 | |||
| b65600f6b6 | |||
| 79dcea718c | |||
| 072b09c45d | |||
| c2d9837745 | |||
| fa5dfbb18b | |||
| 6532a075f3 | |||
| 3b4a4bf809 | |||
| 4602909566 | |||
| 588f350b61 | |||
| 6e5ff509b2 | |||
| 61d341c2ca | |||
| b996d379a1 | |||
| b0935ea730 | |||
| 96fe13b49b | |||
| 12ccde442a | |||
| 4262cfe41f | |||
| ddc2e25546 | |||
| 6646cff646 | |||
| ac8fd856c0 | |||
| 48754d673c | |||
| 723684525a | |||
| 32aceadbe6 | |||
| c67d3e159c | |||
| a080e2add7 | |||
| 24d81b0ddb | |||
| 08f2fad40b | |||
| f91fbe39ce | |||
| 018ab080bb | |||
| fe94ecb2c1 | |||
| 7b2e67036f | |||
| e130faea1b | |||
| 38f09de334 | |||
| f9ba68ddfb | |||
| 16913455bd | |||
| 32f189cd08 | |||
| 526ca42282 | |||
| b98b42d843 | |||
| 7bf03dd132 | |||
| 034aa3b2c4 | |||
| 6da1e01e6c |
@@ -1,5 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
## 1.5.0 (2015-02-05)
|
||||
|
||||
#### Builder
|
||||
+ Dockerfile to use for a given `docker build` can be specified with the `-f` flag
|
||||
* Dockerfile and .dockerignore files can be themselves excluded as part of the .dockerignore file, thus preventing modifications to these files invalidating ADD or COPY instructions cache
|
||||
* ADD and COPY instructions accept relative paths
|
||||
* Dockerfile `FROM scratch` instruction is now interpreted as a no-base specifier
|
||||
* Improve performance when exposing a large number of ports
|
||||
|
||||
#### Hack
|
||||
+ Allow client-side only integration tests for Windows
|
||||
* Include docker-py integration tests against Docker daemon as part of our test suites
|
||||
|
||||
#### Packaging
|
||||
+ Support for the new version of the registry HTTP API
|
||||
* Speed up `docker push` for images with a majority of already existing layers
|
||||
- Fixed contacting a private registry through a proxy
|
||||
|
||||
#### Remote API
|
||||
+ A new endpoint will stream live container resource metrics and can be accessed with the `docker stats` command
|
||||
+ Containers can be renamed using the new `rename` endpoint and the associated `docker rename` command
|
||||
* Container `inspect` endpoint show the ID of `exec` commands running in this container
|
||||
* Container `inspect` endpoint show the number of times Docker auto-restarted the container
|
||||
* New types of event can be streamed by the `events` endpoint: ‘OOM’ (container died with out of memory), ‘exec_create’, and ‘exec_start'
|
||||
- Fixed returned string fields which hold numeric characters incorrectly omitting surrounding double quotes
|
||||
|
||||
#### Runtime
|
||||
+ Docker daemon has full IPv6 support
|
||||
+ The `docker run` command can take the `--pid=host` flag to use the host PID namespace, which makes it possible for example to debug host processes using containerized debugging tools
|
||||
+ The `docker run` command can take the `--read-only` flag to make the container’s root filesystem mounted as readonly, which can be used in combination with volumes to force a container’s processes to only write to locations that will be persisted
|
||||
+ Container total memory usage can be limited for `docker run` using the `—memory-swap` flag
|
||||
* Major stability improvements for devicemapper storage driver
|
||||
* Better integration with host system: containers will reflect changes to the host's `/etc/resolv.conf` file when restarted
|
||||
* Better integration with host system: per-container iptable rules are moved to the DOCKER chain
|
||||
- Fixed container exiting on out of memory to return an invalid exit code
|
||||
|
||||
#### Other
|
||||
* The HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables are properly taken into account by the client when connecting to the Docker daemon
|
||||
|
||||
## 1.4.1 (2014-12-15)
|
||||
|
||||
#### Runtime
|
||||
|
||||
+4
-2
@@ -84,8 +84,10 @@ RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1
|
||||
ENV DOCKER_CROSSPLATFORMS \
|
||||
linux/386 linux/arm \
|
||||
darwin/amd64 darwin/386 \
|
||||
freebsd/amd64 freebsd/386 freebsd/arm \
|
||||
windows/amd64 windows/386
|
||||
freebsd/amd64 freebsd/386 freebsd/arm
|
||||
|
||||
# TODO when https://jenkins.dockerproject.com/job/Windows/ is green, add windows back to the list above
|
||||
# windows/amd64 windows/386
|
||||
|
||||
# (set an explicit GOARM of 5 for maximum compatibility)
|
||||
ENV GOARM 5
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
@@ -55,7 +55,7 @@ func MatchesContentType(contentType, expectedType string) bool {
|
||||
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
||||
// otherwise generates a new one
|
||||
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||
err := os.MkdirAll(path.Dir(trustKeyPath), 0700)
|
||||
err := os.MkdirAll(filepath.Dir(trustKeyPath), 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||
return nil, fmt.Errorf("Error saving key file: %s", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("Error loading key file: %s", err)
|
||||
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
|
||||
}
|
||||
return trustKey, nil
|
||||
}
|
||||
|
||||
+21
-21
@@ -6,21 +6,21 @@ import "time"
|
||||
|
||||
type ThrottlingData struct {
|
||||
// Number of periods with throttling active
|
||||
Periods uint64 `json:"periods,omitempty"`
|
||||
Periods uint64 `json:"periods"`
|
||||
// Number of periods when the container hit its throttling limit.
|
||||
ThrottledPeriods uint64 `json:"throttled_periods,omitempty"`
|
||||
ThrottledPeriods uint64 `json:"throttled_periods"`
|
||||
// Aggregate time the container was throttled for in nanoseconds.
|
||||
ThrottledTime uint64 `json:"throttled_time,omitempty"`
|
||||
ThrottledTime uint64 `json:"throttled_time"`
|
||||
}
|
||||
|
||||
// All CPU stats are aggregated since container inception.
|
||||
type CpuUsage struct {
|
||||
// Total CPU time consumed.
|
||||
// Units: nanoseconds.
|
||||
TotalUsage uint64 `json:"total_usage,omitempty"`
|
||||
TotalUsage uint64 `json:"total_usage"`
|
||||
// Total CPU time consumed per core.
|
||||
// Units: nanoseconds.
|
||||
PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
|
||||
PercpuUsage []uint64 `json:"percpu_usage"`
|
||||
// Time spent by tasks of the cgroup in kernel mode.
|
||||
// Units: nanoseconds.
|
||||
UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
|
||||
@@ -30,41 +30,41 @@ type CpuUsage struct {
|
||||
}
|
||||
|
||||
type CpuStats struct {
|
||||
CpuUsage CpuUsage `json:"cpu_usage,omitempty"`
|
||||
CpuUsage CpuUsage `json:"cpu_usage"`
|
||||
SystemUsage uint64 `json:"system_cpu_usage"`
|
||||
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
|
||||
}
|
||||
|
||||
type MemoryStats struct {
|
||||
// current res_counter usage for memory
|
||||
Usage uint64 `json:"usage,omitempty"`
|
||||
Usage uint64 `json:"usage"`
|
||||
// maximum usage ever recorded.
|
||||
MaxUsage uint64 `json:"max_usage,omitempty"`
|
||||
MaxUsage uint64 `json:"max_usage"`
|
||||
// TODO(vishh): Export these as stronger types.
|
||||
// all the stats exported via memory.stat.
|
||||
Stats map[string]uint64 `json:"stats,omitempty"`
|
||||
Stats map[string]uint64 `json:"stats"`
|
||||
// number of times memory usage hits limits.
|
||||
Failcnt uint64 `json:"failcnt"`
|
||||
Limit uint64 `json:"limit"`
|
||||
}
|
||||
|
||||
type BlkioStatEntry struct {
|
||||
Major uint64 `json:"major,omitempty"`
|
||||
Minor uint64 `json:"minor,omitempty"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Value uint64 `json:"value,omitempty"`
|
||||
Major uint64 `json:"major"`
|
||||
Minor uint64 `json:"minor"`
|
||||
Op string `json:"op"`
|
||||
Value uint64 `json:"value"`
|
||||
}
|
||||
|
||||
type BlkioStats struct {
|
||||
// number of bytes tranferred to and from the block device
|
||||
IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive,omitempty"`
|
||||
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive,omitempty"`
|
||||
IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive,omitempty"`
|
||||
IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive,omitempty"`
|
||||
IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive,omitempty"`
|
||||
IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive,omitempty"`
|
||||
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"`
|
||||
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"`
|
||||
IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"`
|
||||
IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"`
|
||||
IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"`
|
||||
IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"`
|
||||
IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"`
|
||||
IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"`
|
||||
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"`
|
||||
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"`
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
imagepkg "github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
@@ -433,7 +434,7 @@ func (b *Builder) pullImage(name string) (*imagepkg.Image, error) {
|
||||
job.SetenvBool("json", b.StreamFormatter.Json())
|
||||
job.SetenvBool("parallel", true)
|
||||
job.SetenvJson("authConfig", pullRegistryAuth)
|
||||
job.Stdout.Add(b.OutOld)
|
||||
job.Stdout.Add(ioutils.NopWriteCloser(b.OutOld))
|
||||
if err := job.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -104,6 +104,22 @@ __docker_pos_first_nonflag() {
|
||||
echo $counter
|
||||
}
|
||||
|
||||
# Transforms a multiline list of strings into a single line string
|
||||
# with the words separated by "|".
|
||||
# This is used to prepare arguments to __docker_pos_first_nonflag().
|
||||
__docker_to_alternatives() {
|
||||
local parts=( $1 )
|
||||
local IFS='|'
|
||||
echo "${parts[*]}"
|
||||
}
|
||||
|
||||
# Transforms a multiline list of options into an extglob pattern
|
||||
# suitable for use in case statements.
|
||||
__docker_to_extglob() {
|
||||
local extglob=$( __docker_to_alternatives "$1" )
|
||||
echo "@($extglob)"
|
||||
}
|
||||
|
||||
__docker_resolve_hostname() {
|
||||
command -v host >/dev/null 2>&1 || return
|
||||
COMPREPLY=( $(host 2>/dev/null "${cur%:}" | awk '/has address/ {print $4}') )
|
||||
@@ -154,15 +170,47 @@ __docker_capabilities() {
|
||||
}
|
||||
|
||||
_docker_docker() {
|
||||
local boolean_options="
|
||||
--api-enable-cors
|
||||
--daemon -d
|
||||
--debug -D
|
||||
--help -h
|
||||
--icc
|
||||
--ip-forward
|
||||
--ip-masq
|
||||
--iptables
|
||||
--ipv6
|
||||
--selinux-enabled
|
||||
--tls
|
||||
--tlsverify
|
||||
--version -v
|
||||
"
|
||||
|
||||
case "$prev" in
|
||||
-H)
|
||||
--graph|-g)
|
||||
_filedir -d
|
||||
return
|
||||
;;
|
||||
--log-level|-l)
|
||||
COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) )
|
||||
return
|
||||
;;
|
||||
--pidfile|-p|--tlscacert|--tlscert|--tlskey)
|
||||
_filedir
|
||||
return
|
||||
;;
|
||||
--storage-driver|-s)
|
||||
COMPREPLY=( $( compgen -W "aufs devicemapper btrfs overlay" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
|
||||
return
|
||||
;;
|
||||
$main_options_with_args_glob )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "-H" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "$boolean_options $main_options_with_args" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) )
|
||||
@@ -561,6 +609,8 @@ _docker_run() {
|
||||
--sig-proxy
|
||||
"
|
||||
|
||||
local options_with_args_glob=$(__docker_to_extglob "$options_with_args")
|
||||
|
||||
case "$prev" in
|
||||
--add-host)
|
||||
case "$cur" in
|
||||
@@ -677,7 +727,7 @@ _docker_run() {
|
||||
__docker_containers_all
|
||||
return
|
||||
;;
|
||||
--cpuset|--cpu-shares|-c|--dns|--dns-search|--entrypoint|--expose|--hostname|-h|--lxc-conf|--mac-address|--memory|-m|--name|-n|--publish|-p|--user|-u|--workdir|-w)
|
||||
$options_with_args_glob )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@@ -687,7 +737,7 @@ _docker_run() {
|
||||
COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
local counter=$( __docker_pos_first_nonflag $( echo $options_with_args | tr -d "\n" | tr " " "|" ) )
|
||||
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
|
||||
|
||||
if [ $cword -eq $counter ]; then
|
||||
__docker_image_repos_and_tags_and_ids
|
||||
@@ -739,6 +789,10 @@ _docker_start() {
|
||||
esac
|
||||
}
|
||||
|
||||
_docker_stats() {
|
||||
__docker_containers_running
|
||||
}
|
||||
|
||||
_docker_stop() {
|
||||
case "$prev" in
|
||||
--time|-t)
|
||||
@@ -801,6 +855,9 @@ _docker_wait() {
|
||||
}
|
||||
|
||||
_docker() {
|
||||
local previous_extglob_setting=$(shopt -p extglob)
|
||||
shopt -s extglob
|
||||
|
||||
local commands=(
|
||||
attach
|
||||
build
|
||||
@@ -833,6 +890,7 @@ _docker() {
|
||||
save
|
||||
search
|
||||
start
|
||||
stats
|
||||
stop
|
||||
tag
|
||||
top
|
||||
@@ -841,6 +899,33 @@ _docker() {
|
||||
wait
|
||||
)
|
||||
|
||||
local main_options_with_args="
|
||||
--bip
|
||||
--bridge -b
|
||||
--dns
|
||||
--dns-search
|
||||
--exec-driver -e
|
||||
--fixed-cidr
|
||||
--fixed-cidr-v6
|
||||
--graph -g
|
||||
--group -G
|
||||
--host -H
|
||||
--insecure-registry
|
||||
--ip
|
||||
--label
|
||||
--log-level -l
|
||||
--mtu
|
||||
--pidfile -p
|
||||
--registry-mirror
|
||||
--storage-driver -s
|
||||
--storage-opt
|
||||
--tlscacert
|
||||
--tlscert
|
||||
--tlskey
|
||||
"
|
||||
|
||||
local main_options_with_args_glob=$(__docker_to_extglob "$main_options_with_args")
|
||||
|
||||
COMPREPLY=()
|
||||
local cur prev words cword
|
||||
_get_comp_words_by_ref -n : cur prev words cword
|
||||
@@ -849,7 +934,7 @@ _docker() {
|
||||
local counter=1
|
||||
while [ $counter -lt $cword ]; do
|
||||
case "${words[$counter]}" in
|
||||
-H)
|
||||
$main_options_with_args_glob )
|
||||
(( counter++ ))
|
||||
;;
|
||||
-*)
|
||||
@@ -867,6 +952,7 @@ _docker() {
|
||||
local completions_func=_docker_${command}
|
||||
declare -F $completions_func >/dev/null && $completions_func
|
||||
|
||||
eval "$previous_extglob_setting"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -51,23 +51,28 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -s d -l daemon -d 'Enable
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l dns -d 'Force Docker to use specific DNS servers'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l dns-search -d 'Force Docker to use specific DNS search domains'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s e -l exec-driver -d 'Force the Docker runtime to use a specific exec driver'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l fixed-cidr -d 'IPv4 subnet for fixed IPs (ex: 10.20.0.0/16)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l fixed-cidr -d 'IPv4 subnet for fixed IPs (e.g. 10.20.0.0/16)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l fixed-cidr-v6 -d 'IPv6 subnet for fixed IPs (e.g.: 2001:a02b/48)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s G -l group -d 'Group to assign the unix socket specified by -H when running in daemon mode'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s g -l graph -d 'Path to use as the root of the Docker runtime'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s H -l host -d 'The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l icc -d 'Enable inter-container communication'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s h -l help -d 'Print usage'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l icc -d 'Allow unrestricted inter-container and Docker daemon host communication'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l insecure-registry -d 'Enable insecure communication with specified registries (no certificate verification for HTTPS and enable HTTP fallback) (e.g., localhost:5000 or 10.20.0.0/16)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l ip -d 'Default IP address to use when binding container ports'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-forward -d 'Enable net.ipv4.ip_forward'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-forward -d 'Enable net.ipv4.ip_forward and IPv6 forwarding if --fixed-cidr-v6 is defined. IPv6 forwarding may interfere with your existing IPv6 configuration when using Router Advertisement.'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l ip-masq -d "Enable IP masquerading for bridge's IP range"
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l iptables -d "Enable Docker's addition of iptables rules"
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l ipv6 -d 'Enable IPv6 networking'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s l -l log-level -d 'Set the logging level (debug, info, warn, error, fatal)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l label -d 'Set key=value labels to the daemon (displayed in `docker info`)'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l mtu -d 'Set the containers network MTU'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s p -l pidfile -d 'Path to use for daemon PID file'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l registry-mirror -d 'Specify a preferred Docker registry mirror'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -s s -l storage-driver -d 'Force the Docker runtime to use a specific storage driver'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l selinux-enabled -d 'Enable selinux support. SELinux does not presently support the BTRFS storage driver'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l storage-opt -d 'Set storage driver options'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l tls -d 'Use TLS; implied by tls-verify flags'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l tls -d 'Use TLS; implied by --tlsverify flag'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l tlscacert -d 'Trust only remotes providing a certificate signed by the CA given here'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l tlscert -d 'Path to TLS certificate file'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -l tlskey -d 'Path to TLS key file'
|
||||
@@ -77,14 +82,18 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -s v -l version -d 'Print
|
||||
# subcommands
|
||||
# attach
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a attach -d 'Attach to a running container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l no-stdin -d 'Do not attach STDIN'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l sig-proxy -d 'Proxy all received signals to the process (even in non-TTY mode). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -l sig-proxy -d 'Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from attach' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# build
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a build -d 'Build an image from a Dockerfile'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s f -l file -d "Name of the Dockerfile(Default is 'Dockerfile' at context root)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l force-rm -d 'Always remove intermediate containers, even after unsuccessful builds'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l no-cache -d 'Do not use cache when building the image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l pull -d 'Always attempt to pull a newer version of the image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s q -l quiet -d 'Suppress the verbose output generated by the containers'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -l rm -d 'Remove intermediate containers after a successful build'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d 'Repository name (and optionally a tag) to be applied to the resulting image in case of success'
|
||||
@@ -92,12 +101,14 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d '
|
||||
# commit
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a commit -d "Create a new image from a container's changes"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s m -l message -d 'Commit message'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s p -l pause -d 'Pause container during commit'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container"
|
||||
|
||||
# cp
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d "Copy files/folders from a container's filesystem to the host path"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from cp' -l help -d 'Print usage'
|
||||
|
||||
# create
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a create -d 'Create a new container'
|
||||
@@ -108,23 +119,29 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-add -d '
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-drop -d 'Drop Linux capabilities'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cidfile -d 'Write the container ID to the file'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cpuset -d 'CPUs in which to allow execution (0-3, 0,1)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns -d 'Set custom DNS servers'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns-search -d 'Set custom DNS search domains'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s e -l env -d 'Set environment variables'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l env-file -d 'Read in a line delimited file of environment variables'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l expose -d 'Expose a port from the container without publishing it to your host'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l expose -d 'Expose a port or a range of ports (e.g. --expose=3300-3310) from the container without publishing it to your host'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s h -l hostname -d 'Container host name'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of name:alias'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s p -l publish -d "Publish a container's port to the host"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l pid -d 'Default is to create a private PID namespace for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l privileged -d 'Give extended privileges to this container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l read-only -d "Mount the container's root filesystem as read only"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l restart -d 'Restart policy to apply when a container exits (no, on-failure[:max-retry], always)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l security-opt -d 'Security Options'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s t -l tty -d 'Allocate a pseudo-TTY'
|
||||
@@ -136,26 +153,32 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -a '(__fish_pri
|
||||
|
||||
# diff
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a diff -d "Inspect changes on a container's filesystem"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from diff' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from diff' -a '(__fish_print_docker_containers all)' -d "Container"
|
||||
|
||||
# events
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a events -d 'Get real time events from the server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from events' -s f -l filter -d "Provide filter values (i.e., 'event=stop')"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l since -d 'Show all events created since timestamp'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from events' -l until -d 'Stream events until this timestamp'
|
||||
|
||||
# exec
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a exec -d 'Run a command in an existing container'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a exec -d 'Run a command in a running container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s d -l detach -d 'Detached mode: run command in the background'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -s t -l tty -d 'Allocate a pseudo-TTY'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from exec' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# export
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a export -d 'Stream the contents of a container as a tar archive'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from export' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from export' -a '(__fish_print_docker_containers all)' -d "Container"
|
||||
|
||||
# history
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a history -d 'Show the history of an image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from history' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from history' -l no-trunc -d "Don't truncate output"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from history' -s q -l quiet -d 'Only show numeric IDs'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from history' -a '(__fish_print_docker_images)' -d "Image"
|
||||
@@ -164,34 +187,40 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from history' -a '(__fish_pr
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a images -d 'List images'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s a -l all -d 'Show all images (by default filter out the intermediate image layers)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s f -l filter -d "Provide filter values (i.e., 'dangling=true')"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -l no-trunc -d "Don't truncate output"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -s q -l quiet -d 'Only show numeric IDs'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from images' -a '(__fish_print_docker_repositories)' -d "Repository"
|
||||
|
||||
# import
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a import -d 'Create a new filesystem image from the contents of a tarball'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from import' -l help -d 'Print usage'
|
||||
|
||||
# info
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a info -d 'Display system-wide information'
|
||||
|
||||
# inspect
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container or image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -s f -l format -d 'Format the output using the given go template.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -a '(__fish_print_docker_images)' -d "Image"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -a '(__fish_print_docker_containers all)' -d "Container"
|
||||
|
||||
# kill
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a kill -d 'Kill a running container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -s s -l signal -d 'Signal to send to the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from kill' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# load
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a load -d 'Load an image from a tar archive'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from load' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from load' -s i -l input -d 'Read from a tar archive file, instead of STDIN'
|
||||
|
||||
# login
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a login -d 'Register or log in to a Docker registry server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s e -l email -d 'Email'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s p -l password -d 'Password'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s u -l username -d 'Username'
|
||||
|
||||
@@ -201,12 +230,14 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -a logout -d 'Log out fro
|
||||
# logs
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a logs -d 'Fetch the logs of a container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -s f -l follow -d 'Follow log output'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -s t -l timestamps -d 'Show timestamps'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -l tail -d 'Output the specified number of lines at the end of logs (defaults to all logs)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from logs' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# port
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a port -d 'Lookup the public-facing port that is NAT-ed to PRIVATE_PORT'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from port' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from port' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# pause
|
||||
@@ -218,32 +249,40 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -a ps -d 'List containers
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s a -l all -d 'Show all containers. Only running containers are shown by default.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l before -d 'Show only container created before Id or Name, include non-running ones.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s f -l filter -d 'Provide filter values. Valid filters:'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s l -l latest -d 'Show only the latest created container, include non-running ones.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s n -d 'Show n last created containers, include non-running ones.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l no-trunc -d "Don't truncate output"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s q -l quiet -d 'Only display numeric IDs'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s s -l size -d 'Display sizes'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -s s -l size -d 'Display total file sizes'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from ps' -l since -d 'Show only containers created since Id or Name, include non-running ones.'
|
||||
|
||||
# pull
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a pull -d 'Pull an image or a repository from a Docker registry server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -s a -l all-tags -d 'Download all tagged images in the repository'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -a '(__fish_print_docker_images)' -d "Image"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from pull' -a '(__fish_print_docker_repositories)' -d "Repository"
|
||||
|
||||
# push
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a push -d 'Push an image or a repository to a Docker registry server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from push' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from push' -a '(__fish_print_docker_images)' -d "Image"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from push' -a '(__fish_print_docker_repositories)' -d "Repository"
|
||||
|
||||
# rename
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a rename -d 'Rename an existing container'
|
||||
|
||||
# restart
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a restart -d 'Restart a running container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -s t -l time -d 'Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from restart' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# rm
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a rm -d 'Remove one or more containers'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s f -l force -d 'Force the removal of a running container (uses SIGKILL)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s l -l link -d 'Remove the specified link and not the underlying container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -s v -l volumes -d 'Remove the volumes associated with the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -a '(__fish_print_docker_containers stopped)' -d "Container"
|
||||
@@ -251,6 +290,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from rm' -a '(__fish_print_d
|
||||
# rmi
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a rmi -d 'Remove one or more images'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -s f -l force -d 'Force removal of the image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -l no-prune -d 'Do not delete untagged parents'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from rmi' -a '(__fish_print_docker_images)' -d "Image"
|
||||
|
||||
@@ -264,27 +304,33 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cap-drop -d 'Dr
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cidfile -d 'Write the container ID to the file'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cpuset -d 'CPUs in which to allow execution (0-3, 0,1)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s d -l detach -d 'Detached mode: run the container in the background and print the new container ID'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns -d 'Set custom DNS servers'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns-search -d 'Set custom DNS search domains'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s e -l env -d 'Set environment variables'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l env-file -d 'Read in a line delimited file of environment variables'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l expose -d 'Expose a port from the container without publishing it to your host'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l expose -d 'Expose a port or a range of ports (e.g. --expose=3300-3310) from the container without publishing it to your host'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s h -l hostname -d 'Container host name'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactive -d 'Keep STDIN open even if not attached'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of name:alias'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of <name|id>:alias'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s p -l publish -d "Publish a container's port to the host"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l pid -d 'Default is to create a private PID namespace for the container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l privileged -d 'Give extended privileges to this container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l read-only -d "Mount the container's root filesystem as read only"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l restart -d 'Restart policy to apply when a container exits (no, on-failure[:max-retry], always)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (even in non-TTY mode). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)'
|
||||
@@ -294,32 +340,43 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -a '(__fish_print_
|
||||
|
||||
# save
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a save -d 'Save an image to a tar archive'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from save' -s o -l output -d 'Write to a file, instead of STDOUT'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from save' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from save' -s o -l output -d 'Write to an file, instead of STDOUT'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from save' -a '(__fish_print_docker_images)' -d "Image"
|
||||
|
||||
# search
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a search -d 'Search for an image on the Docker Hub'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l automated -d 'Only show automated builds'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from search' -l no-trunc -d "Don't truncate output"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from search' -s s -l stars -d 'Only displays with at least x stars'
|
||||
|
||||
# start
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a start -d 'Start a stopped container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s a -l attach -d "Attach container's STDOUT and STDERR and forward all signals to the process"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from start' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from start' -s i -l interactive -d "Attach container's STDIN"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from start' -a '(__fish_print_docker_containers stopped)' -d "Container"
|
||||
|
||||
# stats
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a stats -d "Display a live stream of one or more containers' resource usage statistics"
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from stats' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from stats' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# stop
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a stop -d 'Stop a running container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -s t -l time -d 'Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from stop' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# tag
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a tag -d 'Tag an image into a repository'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from tag' -s f -l force -d 'Force'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from tag' -l help -d 'Print usage'
|
||||
|
||||
# top
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a top -d 'Lookup the running processes of a container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from top' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from top' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
# unpause
|
||||
@@ -331,6 +388,7 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -a version -d 'Show the D
|
||||
|
||||
# wait
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a wait -d 'Block until a container stops, then print its exit code'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ lxc.aa_profile = unconfined
|
||||
# In non-privileged mode, lxc will automatically mount /proc and /sys in readonly mode
|
||||
# for security. See: http://man7.org/linux/man-pages/man5/lxc.container.conf.5.html
|
||||
lxc.mount.auto = proc sys
|
||||
{{if .AppArmor}}
|
||||
lxc.aa_profile = .AppArmorProfile
|
||||
{{if .AppArmorProfile}}
|
||||
lxc.aa_profile = {{.AppArmorProfile}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
|
||||
@@ -248,7 +248,8 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
driver, err := NewDriver(root, "", false)
|
||||
driver, err := NewDriver(root, "", true)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -271,9 +272,10 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
||||
Bridge: "docker0",
|
||||
},
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
CapAdd: []string{"net_admin", "syslog"},
|
||||
CapDrop: []string{"kill", "mknod"},
|
||||
ProcessConfig: processConfig,
|
||||
CapAdd: []string{"net_admin", "syslog"},
|
||||
CapDrop: []string{"kill", "mknod"},
|
||||
AppArmorProfile: "lxc-container-default-with-nesting",
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
@@ -287,7 +289,7 @@ func TestCustomLxcConfigMisc(t *testing.T) {
|
||||
grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24")
|
||||
grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
|
||||
grepFile(t, p, "lxc.network.flags = up")
|
||||
|
||||
grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
|
||||
// hostname
|
||||
grepFile(t, p, "lxc.utsname = testhost")
|
||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
||||
|
||||
@@ -150,6 +150,21 @@ func InitDriver(job *engine.Job) engine.Status {
|
||||
}
|
||||
}
|
||||
|
||||
// a bridge might exist but not have any IPv6 addr associated with it yet
|
||||
// (for example, an existing Docker installation that has only been used
|
||||
// with IPv4 and docker0 already is set up) In that case, we can perform
|
||||
// the bridge init for IPv6 here, else we will error out below if --ipv6=true
|
||||
if len(addrsv6) == 0 && enableIPv6 {
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
// recheck addresses now that IPv6 is setup on the bridge
|
||||
addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check if route to fixedCIDRv6 is set
|
||||
}
|
||||
|
||||
@@ -396,26 +411,14 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error
|
||||
return err
|
||||
}
|
||||
|
||||
if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
||||
return fmt.Errorf("Unable to add private network: %s", err)
|
||||
}
|
||||
|
||||
if enableIPv6 {
|
||||
// Enable IPv6 on the bridge
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("unable to enable IPv6 addresses on bridge: %s\n", err)
|
||||
}
|
||||
|
||||
ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
log.Errorf("BridgeIPv6 parsing failed")
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
|
||||
return fmt.Errorf("Unable to add private IPv6 network: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
@@ -424,6 +427,30 @@ func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupIPv6Bridge(bridgeIPv6 string) error {
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Enable IPv6 on the bridge
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
}
|
||||
|
||||
ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err)
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
|
||||
return fmt.Errorf("Unable to add private IPv6 network: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createBridgeIface(name string) error {
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
// only set the bridge's mac address if the kernel version is > 3.3
|
||||
|
||||
@@ -74,7 +74,7 @@ func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
||||
return netIP.Mask(network.Mask), net.IP(lastIP)
|
||||
}
|
||||
|
||||
// Return the IPv4 address of a network interface
|
||||
// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface
|
||||
func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ func init() {
|
||||
{"images", "List images"},
|
||||
{"import", "Create a new filesystem image from the contents of a tarball"},
|
||||
{"info", "Display system-wide information"},
|
||||
{"inspect", "Return low-level information on a container"},
|
||||
{"inspect", "Return low-level information on a container or image"},
|
||||
{"kill", "Kill a running container"},
|
||||
{"load", "Load an image from a tar archive"},
|
||||
{"login", "Register or log in to a Docker registry server"},
|
||||
|
||||
@@ -59,7 +59,7 @@ as context.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
## Building an image using a Dockefile located inside the current directory
|
||||
## Building an image using a Dockerfile located inside the current directory
|
||||
|
||||
Docker images can be built using the build command and a Dockerfile:
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ unix://[/path/to/socket] to use.
|
||||
Display system-wide information
|
||||
|
||||
**docker-inspect(1)**
|
||||
Return low-level information on a container
|
||||
Return low-level information on a container or image
|
||||
|
||||
**docker-kill(1)**
|
||||
Kill a running container (which includes the wrapper process and everything
|
||||
|
||||
@@ -86,6 +86,7 @@ pages:
|
||||
- ['articles/networking.md', 'Articles', 'Advanced networking']
|
||||
- ['articles/security.md', 'Articles', 'Security']
|
||||
- ['articles/https.md', 'Articles', 'Running Docker with HTTPS']
|
||||
- ['articles/registry_mirror.md', 'Articles', 'Run a local registry mirror']
|
||||
- ['articles/host_integration.md', 'Articles', 'Automatically starting containers']
|
||||
- ['articles/baseimages.md', 'Articles', 'Creating a base image']
|
||||
- ['articles/dockerfile_best-practices.md', 'Articles', 'Best practices for writing Dockerfiles']
|
||||
|
||||
+6
-2
@@ -72,6 +72,9 @@ setup_s3() {
|
||||
|
||||
build_current_documentation() {
|
||||
mkdocs build
|
||||
cd site/
|
||||
gzip -9k -f search_content.json
|
||||
cd ..
|
||||
}
|
||||
|
||||
upload_current_documentation() {
|
||||
@@ -87,8 +90,6 @@ upload_current_documentation() {
|
||||
echo "Uploading $src"
|
||||
echo " to $dst"
|
||||
echo
|
||||
#s3cmd --recursive --follow-symlinks --preserve --acl-public sync "$src" "$dst"
|
||||
#aws s3 cp --profile $BUCKET --cache-control "max-age=3600" --acl public-read "site/search_content.json" "$dst"
|
||||
|
||||
# a really complicated way to send only the files we want
|
||||
# if there are too many in any one set, aws s3 sync seems to fall over with 2 files to go
|
||||
@@ -100,6 +101,9 @@ upload_current_documentation() {
|
||||
echo "$run"
|
||||
echo "======================="
|
||||
$run
|
||||
|
||||
# Make sure the search_content.json.gz file has the right content-encoding
|
||||
aws s3 cp --profile $BUCKET --cache-control $cache --content-encoding="gzip" --acl public-read "site/search_content.json.gz" "$dst"
|
||||
}
|
||||
|
||||
invalidate_cache() {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Articles
|
||||
|
||||
- [Docker Basics](basics/)
|
||||
- [Docker Security](security/)
|
||||
- [Running the Docker daemon with HTTPS](https/)
|
||||
- [Configure Networking](networking/)
|
||||
- [Using Supervisor with Docker](using_supervisord/)
|
||||
- [Process Management with CFEngine](cfengine_process_management/)
|
||||
- [Using Puppet](puppet/)
|
||||
- [Create a Base Image](baseimages/)
|
||||
- [Runtime Metrics](runmetrics/)
|
||||
- [Automatically Start Containers](host_integration/)
|
||||
- [Link via an Ambassador Container](ambassador_pattern_linking/)
|
||||
- [Increase a Boot2Docker Volume](b2d_volume_resize/)
|
||||
- [Run a Local Registry Mirror](registry_mirror/)
|
||||
@@ -26,7 +26,7 @@ it will only connect to servers with a certificate signed by that CA.
|
||||
|
||||
## Create a CA, server and client keys with OpenSSL
|
||||
|
||||
> **Note:** replace all instances of `$HOST` in the following example with the
|
||||
> **Note**: replace all instances of `$HOST` in the following example with the
|
||||
> DNS name of your Docker daemon's host.
|
||||
|
||||
First generate CA private and public keys:
|
||||
@@ -40,26 +40,26 @@ First generate CA private and public keys:
|
||||
Verifying - Enter pass phrase for ca-key.pem:
|
||||
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
|
||||
Enter pass phrase for ca-key.pem:
|
||||
You are about to be asked to enter information that will be incorporated
|
||||
into your certificate request.
|
||||
What you are about to enter is what is called a Distinguished Name or a DN.
|
||||
There are quite a few fields but you can leave some blank
|
||||
For some fields there will be a default value,
|
||||
If you enter '.', the field will be left blank.
|
||||
-----
|
||||
Country Name (2 letter code) [AU]:
|
||||
State or Province Name (full name) [Some-State]:Queensland
|
||||
Locality Name (eg, city) []:Brisbane
|
||||
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc
|
||||
Organizational Unit Name (eg, section) []:Boot2Docker
|
||||
Common Name (e.g. server FQDN or YOUR name) []:$HOST
|
||||
Email Address []:Sven@home.org.au
|
||||
You are about to be asked to enter information that will be incorporated
|
||||
into your certificate request.
|
||||
What you are about to enter is what is called a Distinguished Name or a DN.
|
||||
There are quite a few fields but you can leave some blank
|
||||
For some fields there will be a default value,
|
||||
If you enter '.', the field will be left blank.
|
||||
-----
|
||||
Country Name (2 letter code) [AU]:
|
||||
State or Province Name (full name) [Some-State]:Queensland
|
||||
Locality Name (eg, city) []:Brisbane
|
||||
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc
|
||||
Organizational Unit Name (eg, section) []:Boot2Docker
|
||||
Common Name (e.g. server FQDN or YOUR name) []:$HOST
|
||||
Email Address []:Sven@home.org.au
|
||||
|
||||
Now that we have a CA, you can create a server key and certificate
|
||||
signing request (CSR). Make sure that "Common Name" (i.e., server FQDN or YOUR
|
||||
name) matches the hostname you will use to connect to Docker:
|
||||
|
||||
> **Note:** replace all instances of `$HOST` in the following example with the
|
||||
> **Note**: replace all instances of `$HOST` in the following example with the
|
||||
> DNS name of your Docker daemon's host.
|
||||
|
||||
$ openssl genrsa -out server-key.pem 2048
|
||||
@@ -69,7 +69,7 @@ name) matches the hostname you will use to connect to Docker:
|
||||
e is 65537 (0x10001)
|
||||
$ openssl req -subj "/CN=$HOST" -new -key server-key.pem -out server.csr
|
||||
|
||||
Next, we're going to sign the key with our CA:
|
||||
Next, we're going to sign the public key with our CA:
|
||||
|
||||
$ openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \
|
||||
-CAcreateserial -out server-cert.pem
|
||||
@@ -93,7 +93,7 @@ config file:
|
||||
|
||||
$ echo extendedKeyUsage = clientAuth > extfile.cnf
|
||||
|
||||
Now sign the key:
|
||||
Now sign the public key:
|
||||
|
||||
$ openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \
|
||||
-CAcreateserial -out cert.pem -extfile extfile.cnf
|
||||
@@ -102,6 +102,24 @@ Now sign the key:
|
||||
Getting CA Private Key
|
||||
Enter pass phrase for ca-key.pem:
|
||||
|
||||
After generating `cert.pem` and `server-cert.pem` you can safely remove the
|
||||
two certificate signing requests:
|
||||
|
||||
$ rm -v client.csr server.csr
|
||||
|
||||
With a default `umask` of 022, your secret keys will be *world-readable* and
|
||||
writable for you and your group.
|
||||
|
||||
In order to protect your keys from accidental damage, you will want to remove their
|
||||
write permissions. To make them only readable by you, change file modes as follows:
|
||||
|
||||
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
|
||||
|
||||
Certificates can be world-readable, but you might want to remove write access to
|
||||
prevent accidental damage:
|
||||
|
||||
$ chmod -v 0444 ca.pem server-cert.pem cert.pem
|
||||
|
||||
Now you can make the Docker daemon only accept connections from clients
|
||||
providing a certificate trusted by our CA:
|
||||
|
||||
@@ -111,7 +129,7 @@ providing a certificate trusted by our CA:
|
||||
To be able to connect to Docker and validate its certificate, you now
|
||||
need to provide your client keys, certificates and trusted CA:
|
||||
|
||||
> **Note:** replace all instances of `$HOST` in the following example with the
|
||||
> **Note**: replace all instances of `$HOST` in the following example with the
|
||||
> DNS name of your Docker daemon's host.
|
||||
|
||||
$ docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem \
|
||||
@@ -130,16 +148,13 @@ need to provide your client keys, certificates and trusted CA:
|
||||
## Secure by default
|
||||
|
||||
If you want to secure your Docker client connections by default, you can move
|
||||
the files to the `.docker` directory in your home directory - and set the
|
||||
the files to the `.docker` directory in your home directory -- and set the
|
||||
`DOCKER_HOST` and `DOCKER_TLS_VERIFY` variables as well (instead of passing
|
||||
`-H=tcp://:2376` and `--tlsverify` on every call).
|
||||
|
||||
$ mkdir -p ~/.docker
|
||||
$ cp ca.pem ~/.docker/ca.pem
|
||||
$ cp cert.pem ~/.docker/cert.pem
|
||||
$ cp key.pem ~/.docker/key.pem
|
||||
$ export DOCKER_HOST=tcp://:2376
|
||||
$ export DOCKER_TLS_VERIFY=1
|
||||
$ mkdir -pv ~/.docker
|
||||
$ cp -v {ca,cert,key}.pem ~/.docker
|
||||
$ export DOCKER_HOST=tcp://:2376 DOCKER_TLS_VERIFY=1
|
||||
|
||||
Docker will now connect securely by default:
|
||||
|
||||
@@ -165,11 +180,11 @@ Docker in various other modes by mixing the flags.
|
||||
certificate and authenticate server based on given CA
|
||||
|
||||
If found, the client will send its client certificate, so you just need
|
||||
to drop your keys into `~/.docker/<ca, cert or key>.pem`. Alternatively,
|
||||
to drop your keys into `~/.docker/{ca,cert,key}.pem`. Alternatively,
|
||||
if you want to store your keys in another location, you can specify that
|
||||
location using the environment variable `DOCKER_CERT_PATH`.
|
||||
|
||||
$ export DOCKER_CERT_PATH=${HOME}/.docker/zone1/
|
||||
$ export DOCKER_CERT_PATH=~/.docker/zone1/
|
||||
$ docker --tlsverify ps
|
||||
|
||||
### Connecting to the Secure Docker port using `curl`
|
||||
|
||||
@@ -687,6 +687,7 @@ stopping the service and removing the interface:
|
||||
$ sudo service docker stop
|
||||
$ sudo ip link set dev docker0 down
|
||||
$ sudo brctl delbr docker0
|
||||
$ sudo iptables -t nat -F POSTROUTING
|
||||
|
||||
Then, before starting the Docker service, create your own bridge and
|
||||
give it whatever configuration you want. Here we will create a simple
|
||||
@@ -713,6 +714,15 @@ illustrate the technique.
|
||||
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
|
||||
$ sudo service docker start
|
||||
|
||||
# Confirming new outgoing NAT masquerade is set up
|
||||
|
||||
$ sudo iptables -t nat -L -n
|
||||
...
|
||||
Chain POSTROUTING (policy ACCEPT)
|
||||
target prot opt source destination
|
||||
MASQUERADE all -- 192.168.5.0/24 0.0.0.0/0
|
||||
|
||||
|
||||
The result should be that the Docker server starts successfully and is
|
||||
now prepared to bind containers to the new bridge. After pausing to
|
||||
verify the bridge's configuration, try creating a container — you will
|
||||
|
||||
@@ -39,7 +39,7 @@ our container.
|
||||
|
||||
Here we're installing the `openssh-server`,
|
||||
`apache2` and `supervisor`
|
||||
(which provides the Supervisor daemon) packages. We're also creating two
|
||||
(which provides the Supervisor daemon) packages. We're also creating four
|
||||
new directories that are needed to run our SSH daemon and Supervisor.
|
||||
|
||||
## Adding Supervisor's configuration file
|
||||
|
||||
@@ -278,6 +278,10 @@ Webhooks are available under the Settings menu of each Repository.
|
||||
> **Note:** If you want to test your webhook out we recommend using
|
||||
> a tool like [requestb.in](http://requestb.in/).
|
||||
|
||||
> **Note**: The Docker Hub servers are currently in the IP range
|
||||
> `162.242.195.64 - 162.242.195.127`, so you can restrict your webhooks to
|
||||
> accept webhook requests from that set of IP addresses.
|
||||
|
||||
### Webhook chains
|
||||
|
||||
Webhook chains allow you to chain calls to multiple services. For example,
|
||||
|
||||
@@ -105,9 +105,6 @@ Settings page. A webhook is called only after a successful `push` is
|
||||
made. The webhook calls are HTTP POST requests with a JSON payload
|
||||
similar to the example shown below.
|
||||
|
||||
> **Note:** For testing, you can try an HTTP request tool like
|
||||
> [requestb.in](http://requestb.in/).
|
||||
|
||||
*Example webhook JSON payload:*
|
||||
|
||||
```
|
||||
@@ -141,6 +138,13 @@ new updates to your images and repositories. To get started adding webhooks,
|
||||
go to the desired repo in the Hub, and click "Webhooks" under the "Settings"
|
||||
box.
|
||||
|
||||
> **Note:** For testing, you can try an HTTP request tool like
|
||||
> [requestb.in](http://requestb.in/).
|
||||
|
||||
> **Note**: The Docker Hub servers are currently in the IP range
|
||||
> `162.242.195.64 - 162.242.195.127`, so you can restrict your webhooks to
|
||||
> accept webhook requests from that set of IP addresses.
|
||||
|
||||
### Webhook chains
|
||||
|
||||
Webhook chains allow you to chain calls to multiple services. For example,
|
||||
|
||||
@@ -385,6 +385,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -385,6 +385,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -539,6 +539,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -574,6 +574,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -622,6 +622,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -615,6 +615,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -625,6 +625,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -148,6 +148,7 @@ Create a container
|
||||
"Privileged": false,
|
||||
"Dns": ["8.8.8.8"],
|
||||
"DnsSearch": [""],
|
||||
"ExtraHosts": null,
|
||||
"VolumesFrom": ["parent", "other:ro"],
|
||||
"CapAdd": ["NET_ADMIN"],
|
||||
"CapDrop": ["MKNOD"],
|
||||
@@ -220,6 +221,8 @@ Json Parameters:
|
||||
a boolean value.
|
||||
- **Dns** - A list of dns servers for the container to use.
|
||||
- **DnsSearch** - A list of DNS search domains
|
||||
- **ExtraHosts** - A list of hostnames/IP mappings to be added to the
|
||||
container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`.
|
||||
- **VolumesFrom** - A list of volumes to inherit from another container.
|
||||
Specified in the form `<container name>[:<ro|rw>]`
|
||||
- **CapAdd** - A list of kernel capabilties to add to the container.
|
||||
@@ -767,6 +770,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -148,6 +148,7 @@ Create a container
|
||||
"Privileged": false,
|
||||
"Dns": ["8.8.8.8"],
|
||||
"DnsSearch": [""],
|
||||
"ExtraHosts": null,
|
||||
"VolumesFrom": ["parent", "other:ro"],
|
||||
"CapAdd": ["NET_ADMIN"],
|
||||
"CapDrop": ["MKNOD"],
|
||||
@@ -220,6 +221,8 @@ Json Parameters:
|
||||
a boolean value.
|
||||
- **Dns** - A list of dns servers for the container to use.
|
||||
- **DnsSearch** - A list of DNS search domains
|
||||
- **ExtraHosts** - A list of hostnames/IP mappings to be added to the
|
||||
container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`.
|
||||
- **VolumesFrom** - A list of volumes to inherit from another container.
|
||||
Specified in the form `<container name>[:<ro|rw>]`
|
||||
- **CapAdd** - A list of kernel capabilties to add to the container.
|
||||
@@ -713,6 +716,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -149,6 +149,7 @@ Create a container
|
||||
"ReadonlyRootfs": false,
|
||||
"Dns": ["8.8.8.8"],
|
||||
"DnsSearch": [""],
|
||||
"ExtraHosts": null,
|
||||
"VolumesFrom": ["parent", "other:ro"],
|
||||
"CapAdd": ["NET_ADMIN"],
|
||||
"CapDrop": ["MKNOD"],
|
||||
@@ -223,6 +224,8 @@ Json Parameters:
|
||||
Specified as a boolean value.
|
||||
- **Dns** - A list of dns servers for the container to use.
|
||||
- **DnsSearch** - A list of DNS search domains
|
||||
- **ExtraHosts** - A list of hostnames/IP mappings to be added to the
|
||||
container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`.
|
||||
- **VolumesFrom** - A list of volumes to inherit from another container.
|
||||
Specified in the form `<container name>[:<ro|rw>]`
|
||||
- **CapAdd** - A list of kernel capabilties to add to the container.
|
||||
@@ -870,6 +873,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -397,6 +397,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -445,6 +445,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -460,6 +460,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -458,6 +458,41 @@ Status Codes:
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -564,6 +564,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -509,6 +509,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -557,6 +557,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
@@ -561,6 +561,41 @@ Status Codes:
|
||||
4. Read the extracted size and output it on the correct output
|
||||
5. Goto 1)
|
||||
|
||||
### Attach to a container (websocket)
|
||||
|
||||
`GET /containers/(id)/attach/ws`
|
||||
|
||||
Attach to the container `id` via websocket
|
||||
|
||||
Implements websocket protocol handshake according to [RFC 6455](http://tools.ietf.org/html/rfc6455)
|
||||
|
||||
**Example request**
|
||||
|
||||
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
|
||||
|
||||
**Example response**
|
||||
|
||||
{{ STREAM }}
|
||||
|
||||
Query Parameters:
|
||||
|
||||
- **logs** – 1/True/true or 0/False/false, return logs. Default false
|
||||
- **stream** – 1/True/true or 0/False/false, return stream.
|
||||
Default false
|
||||
- **stdin** – 1/True/true or 0/False/false, if stream=true, attach
|
||||
to stdin. Default false
|
||||
- **stdout** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stdout log, if stream=true, attach to stdout. Default false
|
||||
- **stderr** – 1/True/true or 0/False/false, if logs=true, return
|
||||
stderr log, if stream=true, attach to stderr. Default false
|
||||
|
||||
Status Codes:
|
||||
|
||||
- **200** – no error
|
||||
- **400** – bad parameter
|
||||
- **404** – no such container
|
||||
- **500** – server error
|
||||
|
||||
### Wait a container
|
||||
|
||||
`POST /containers/(id)/wait`
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 2.7 KiB |
Vendored
+13
-7
@@ -1,12 +1,6 @@
|
||||
$(document).ready(function ()
|
||||
{
|
||||
|
||||
// Tipue Search activation
|
||||
$('#tipue_search_input').tipuesearch({
|
||||
'mode': 'json',
|
||||
'contentLocation': '/search_content.json'
|
||||
});
|
||||
|
||||
prettyPrint();
|
||||
|
||||
// Resizing
|
||||
@@ -51,6 +45,18 @@ $(document).ready(function ()
|
||||
},
|
||||
});
|
||||
|
||||
function getURLP(name)
|
||||
{
|
||||
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20')) || null;
|
||||
}
|
||||
if (getURLP("q")) {
|
||||
// Tipue Search activation
|
||||
$('#tipue_search_input').tipuesearch({
|
||||
'mode': 'json',
|
||||
'contentLocation': '/search_content.json.gz'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function resizeMenuDropdown ()
|
||||
@@ -92,4 +98,4 @@ function getCookie(cname) {
|
||||
if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
@@ -150,3 +152,85 @@ func TestCatchallEmptyName(t *testing.T) {
|
||||
t.Fatalf("Engine.Job(\"\").Run() should return an error")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a job within a job both using the same underlying standard
|
||||
// output writer does not close the output of the outer job when the inner
|
||||
// job's stdout is wrapped with a NopCloser. When not wrapped, it should
|
||||
// close the outer job's output.
|
||||
func TestNestedJobSharedOutput(t *testing.T) {
|
||||
var (
|
||||
outerHandler Handler
|
||||
innerHandler Handler
|
||||
wrapOutput bool
|
||||
)
|
||||
|
||||
outerHandler = func(job *Job) Status {
|
||||
job.Stdout.Write([]byte("outer1"))
|
||||
|
||||
innerJob := job.Eng.Job("innerJob")
|
||||
|
||||
if wrapOutput {
|
||||
innerJob.Stdout.Add(ioutils.NopWriteCloser(job.Stdout))
|
||||
} else {
|
||||
innerJob.Stdout.Add(job.Stdout)
|
||||
}
|
||||
|
||||
if err := innerJob.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// If wrapOutput was *false* this write will do nothing.
|
||||
// FIXME (jlhawn): It should cause an error to write to
|
||||
// closed output.
|
||||
job.Stdout.Write([]byte(" outer2"))
|
||||
|
||||
return StatusOK
|
||||
}
|
||||
|
||||
innerHandler = func(job *Job) Status {
|
||||
job.Stdout.Write([]byte(" inner"))
|
||||
|
||||
return StatusOK
|
||||
}
|
||||
|
||||
eng := New()
|
||||
eng.Register("outerJob", outerHandler)
|
||||
eng.Register("innerJob", innerHandler)
|
||||
|
||||
// wrapOutput starts *false* so the expected
|
||||
// output of running the outer job will be:
|
||||
//
|
||||
// "outer1 inner"
|
||||
//
|
||||
outBuf := new(bytes.Buffer)
|
||||
outerJob := eng.Job("outerJob")
|
||||
outerJob.Stdout.Add(outBuf)
|
||||
|
||||
if err := outerJob.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedOutput := "outer1 inner"
|
||||
if outBuf.String() != expectedOutput {
|
||||
t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
|
||||
}
|
||||
|
||||
// Set wrapOutput to true so that the expected
|
||||
// output of running the outer job will be:
|
||||
//
|
||||
// "outer1 inner outer2"
|
||||
//
|
||||
wrapOutput = true
|
||||
outBuf.Reset()
|
||||
outerJob = eng.Job("outerJob")
|
||||
outerJob.Stdout.Add(outBuf)
|
||||
|
||||
if err := outerJob.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedOutput = "outer1 inner outer2"
|
||||
if outBuf.String() != expectedOutput {
|
||||
t.Fatalf("expected job output to be %q, got %q", expectedOutput, outBuf.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,28 @@ func (graph *Graph) Mktemp(id string) (string, error) {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func (graph *Graph) newTempFile() (*os.File, error) {
|
||||
tmp, err := graph.Mktemp("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.TempFile(tmp, "")
|
||||
}
|
||||
|
||||
func bufferToFile(f *os.File, src io.Reader) (int64, error) {
|
||||
n, err := io.Copy(f, src)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err = f.Sync(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// setupInitLayer populates a directory with mountpoints suitable
|
||||
// for bind-mounting dockerinit into the container. The mountpoint is simply an
|
||||
// empty file at /.dockerinit
|
||||
|
||||
+25
-23
@@ -3,11 +3,9 @@ package graph
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/engine"
|
||||
@@ -71,14 +69,13 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if layer.Config == nil {
|
||||
return nil, errors.New("Missing layer configuration")
|
||||
}
|
||||
manifest.Architecture = layer.Architecture
|
||||
manifest.FSLayers = make([]*registry.FSLayer, 0, 4)
|
||||
manifest.History = make([]*registry.ManifestHistory, 0, 4)
|
||||
var metadata runconfig.Config
|
||||
metadata = *layer.Config
|
||||
if layer.Config != nil {
|
||||
metadata = *layer.Config
|
||||
}
|
||||
|
||||
for ; layer != nil; layer, err = layer.GetParent() {
|
||||
if err != nil {
|
||||
@@ -95,28 +92,33 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error
|
||||
}
|
||||
}
|
||||
|
||||
archive, err := layer.TarLayer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
checksum := layer.Checksum
|
||||
if tarsum.VersionLabelForChecksum(checksum) != tarsum.Version1.String() {
|
||||
archive, err := layer.TarLayer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
checksum = tarSum.Sum(nil)
|
||||
}
|
||||
|
||||
tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tarId := tarSum.Sum(nil)
|
||||
|
||||
manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: tarId})
|
||||
|
||||
layersSeen[layer.ID] = true
|
||||
jsonData, err := ioutil.ReadFile(path.Join(s.graph.Root, layer.ID, "json"))
|
||||
jsonData, err := layer.RawJson()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot retrieve the path for {%s}: %s", layer.ID, err)
|
||||
}
|
||||
|
||||
manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: checksum})
|
||||
|
||||
layersSeen[layer.ID] = true
|
||||
|
||||
manifest.History = append(manifest.History, ®istry.ManifestHistory{V1Compatibility: string(jsonData)})
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,6 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *
|
||||
for _, image := range repoData.ImgList {
|
||||
downloadImage := func(img *registry.ImgData) {
|
||||
if askedTag != "" && img.Tag != askedTag {
|
||||
log.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
|
||||
if parallel {
|
||||
errors <- nil
|
||||
}
|
||||
|
||||
+40
-22
@@ -236,10 +236,7 @@ func (s *TagStore) pushImage(r *registry.Session, out io.Writer, imgID, ep strin
|
||||
// Send the layer
|
||||
log.Debugf("rendered layer for %s of [%d] size", imgData.ID, layerData.Size)
|
||||
|
||||
prgRd := utils.ProgressReader(layerData, int(layerData.Size), out, sf, false, utils.TruncateID(imgData.ID), "Pushing")
|
||||
defer prgRd.Close()
|
||||
|
||||
checksum, checksumPayload, err := r.PushImageLayerRegistry(imgData.ID, prgRd, ep, token, jsonRaw)
|
||||
checksum, checksumPayload, err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf, false, utils.TruncateID(imgData.ID), "Pushing"), ep, token, jsonRaw)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -325,16 +322,6 @@ func (s *TagStore) pushV2Repository(r *registry.Session, eng *engine.Engine, out
|
||||
return fmt.Errorf("Failed to parse json: %s", err)
|
||||
}
|
||||
|
||||
img, err = s.graph.Get(img.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
arch, err := img.TarLayer()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not get tar layer: %s", err)
|
||||
}
|
||||
|
||||
// Call mount blob
|
||||
exists, err := r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, sumParts[0], manifestSum, auth)
|
||||
if err != nil {
|
||||
@@ -343,15 +330,9 @@ func (s *TagStore) pushV2Repository(r *registry.Session, eng *engine.Engine, out
|
||||
}
|
||||
|
||||
if !exists {
|
||||
prgRd := utils.ProgressReader(arch, int(img.Size), out, sf, false, utils.TruncateID(img.ID), "Pushing")
|
||||
defer prgRd.Close()
|
||||
|
||||
err = r.PutV2ImageBlob(endpoint, repoInfo.RemoteName, sumParts[0], manifestSum, prgRd, auth)
|
||||
if err != nil {
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Image push failed", nil))
|
||||
if err := s.PushV2Image(r, img, endpoint, repoInfo.RemoteName, sumParts[0], manifestSum, sf, out, auth); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Image successfully pushed", nil))
|
||||
} else {
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Image already exists", nil))
|
||||
}
|
||||
@@ -361,6 +342,43 @@ func (s *TagStore) pushV2Repository(r *registry.Session, eng *engine.Engine, out
|
||||
return r.PutV2ImageManifest(endpoint, repoInfo.RemoteName, tag, bytes.NewReader([]byte(manifestBytes)), auth)
|
||||
}
|
||||
|
||||
// PushV2Image pushes the image content to the v2 registry, first buffering the contents to disk
|
||||
func (s *TagStore) PushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName, sumType, sumStr string, sf *utils.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) error {
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Buffering to Disk", nil))
|
||||
|
||||
image, err := s.graph.Get(img.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
arch, err := image.TarLayer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tf, err := s.graph.newTempFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
tf.Close()
|
||||
os.Remove(tf.Name())
|
||||
}()
|
||||
|
||||
size, err := bufferToFile(tf, arch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send the layer
|
||||
log.Debugf("rendered layer for %s of [%d] size", img.ID, size)
|
||||
|
||||
if err := r.PutV2ImageBlob(endpoint, imageName, sumType, sumStr, utils.ProgressReader(tf, int(size), out, sf, false, utils.TruncateID(img.ID), "Pushing"), auth); err != nil {
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Image push failed", nil))
|
||||
return err
|
||||
}
|
||||
out.Write(sf.FormatProgress(utils.TruncateID(img.ID), "Image successfully pushed", nil))
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: Allow to interrupt current push when new push of same image is done.
|
||||
func (s *TagStore) CmdPush(job *engine.Job) engine.Status {
|
||||
if n := len(job.Args); n != 1 {
|
||||
@@ -411,7 +429,7 @@ func (s *TagStore) CmdPush(job *engine.Job) engine.Status {
|
||||
}
|
||||
|
||||
// error out, no fallback to V1
|
||||
return job.Error(err)
|
||||
return job.Errorf("Error pushing to registry: %s", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
+8
-7
@@ -9,7 +9,6 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/tarsum"
|
||||
"github.com/docker/docker/runconfig"
|
||||
@@ -81,8 +80,8 @@ func LoadImage(root string) (*Image, error) {
|
||||
|
||||
// StoreImage stores file system layer data for the given image to the
|
||||
// image's registered storage driver. Image metadata is stored in a file
|
||||
// at the specified root directory. This function also computes the TarSum
|
||||
// of `layerData` (currently using tarsum.dev).
|
||||
// at the specified root directory. This function also computes a checksum
|
||||
// of `layerData` if the image does not have one already.
|
||||
func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
|
||||
// Store the layer
|
||||
var (
|
||||
@@ -96,15 +95,18 @@ func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error
|
||||
if layerData != nil {
|
||||
// If the image doesn't have a checksum, we should add it. The layer
|
||||
// checksums are verified when they are pulled from a remote, but when
|
||||
// a container is committed it should be added here.
|
||||
if img.Checksum == "" {
|
||||
// a container is committed it should be added here. Also ensure that
|
||||
// the stored checksum has the latest version of tarsum (assuming we
|
||||
// are using tarsum).
|
||||
if tarsum.VersionLabelForChecksum(img.Checksum) != tarsum.Version1.String() {
|
||||
// Either there was no checksum or it's not a tarsum.v1
|
||||
layerDataDecompressed, err := archive.DecompressStream(layerData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer layerDataDecompressed.Close()
|
||||
|
||||
if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
|
||||
if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.Version1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -274,7 +276,6 @@ func (img *Image) CheckDepth() error {
|
||||
func NewImgJSON(src []byte) (*Image, error) {
|
||||
ret := &Image{}
|
||||
|
||||
log.Debugf("Json string: {%s}", src)
|
||||
// FIXME: Is there a cleaner way to "purify" the input json?
|
||||
if err := json.Unmarshal(src, ret); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -81,6 +81,9 @@ func TestAttachAfterDetach(t *testing.T) {
|
||||
}()
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
if err := waitRun(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cpty.Write([]byte{16})
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
cpty.Write([]byte{17})
|
||||
|
||||
@@ -403,3 +403,77 @@ func TestDaemonKeyMigration(t *testing.T) {
|
||||
|
||||
logDone("daemon - key migration")
|
||||
}
|
||||
|
||||
// Simulate an older daemon (pre 1.3) coming up with volumes specified in containers
|
||||
// without corrosponding volume json
|
||||
func TestDaemonUpgradeWithVolumes(t *testing.T) {
|
||||
d := NewDaemon(t)
|
||||
|
||||
graphDir := filepath.Join(os.TempDir(), "docker-test")
|
||||
defer os.RemoveAll(graphDir)
|
||||
if err := d.StartWithBusybox("-g", graphDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpDir := filepath.Join(os.TempDir(), "test")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if out, err := d.Cmd("create", "-v", tmpDir+":/foo", "--name=test", "busybox"); err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
if err := d.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Remove this since we're expecting the daemon to re-create it too
|
||||
if err := os.RemoveAll(tmpDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
configDir := filepath.Join(graphDir, "volumes")
|
||||
|
||||
if err := os.RemoveAll(configDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := d.Start("-g", graphDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
|
||||
t.Fatalf("expected volume path %s to exist but it does not", tmpDir)
|
||||
}
|
||||
|
||||
dir, err := ioutil.ReadDir(configDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(dir) == 0 {
|
||||
t.Fatalf("expected volumes config dir to contain data for new volume")
|
||||
}
|
||||
|
||||
// Now with just removing the volume config and not the volume data
|
||||
if err := d.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(configDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := d.Start("-g", graphDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dir, err = ioutil.ReadDir(configDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(dir) == 0 {
|
||||
t.Fatalf("expected volumes config dir to contain data for new volume")
|
||||
}
|
||||
|
||||
logDone("daemon - volumes from old(pre 1.3) daemon work")
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||
)
|
||||
|
||||
// pulling an image from the central registry should work
|
||||
@@ -80,3 +84,35 @@ func TestPushInterrupt(t *testing.T) {
|
||||
|
||||
logDone("push - interrupted")
|
||||
}
|
||||
|
||||
func TestPushEmptyLayer(t *testing.T) {
|
||||
defer setupRegistry(t)()
|
||||
repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
|
||||
emptyTarball, err := ioutil.TempFile("", "empty_tarball")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create test file: %v", err)
|
||||
}
|
||||
tw := tar.NewWriter(emptyTarball)
|
||||
err = tw.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating empty tarball: %v", err)
|
||||
}
|
||||
freader, err := os.Open(emptyTarball.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("Could not open test tarball: %v", err)
|
||||
}
|
||||
|
||||
importCmd := exec.Command(dockerBinary, "import", "-", repoName)
|
||||
importCmd.Stdin = freader
|
||||
out, _, err := runCommandWithOutput(importCmd)
|
||||
if err != nil {
|
||||
t.Errorf("import failed with errors: %v, output: %q", err, out)
|
||||
}
|
||||
|
||||
// Now verify we can push it
|
||||
pushCmd := exec.Command(dockerBinary, "push", repoName)
|
||||
if out, _, err := runCommandWithOutput(pushCmd); err != nil {
|
||||
t.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
|
||||
}
|
||||
logDone("push - empty layer config to private registry")
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("[tar autodetect] n: %v", bs)
|
||||
|
||||
compression := DetectCompression(bs)
|
||||
switch compression {
|
||||
|
||||
@@ -122,6 +122,7 @@ type tHashConfig struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// NOTE: DO NOT include MD5 or SHA1, which are considered insecure.
|
||||
standardHashConfigs = map[string]tHashConfig{
|
||||
"sha256": {name: "sha256", hash: crypto.SHA256},
|
||||
"sha512": {name: "sha512", hash: crypto.SHA512},
|
||||
|
||||
@@ -22,6 +22,18 @@ const (
|
||||
VersionDev
|
||||
)
|
||||
|
||||
// VersionLabelForChecksum returns the label for the given tarsum
|
||||
// checksum, i.e., everything before the first `+` character in
|
||||
// the string or an empty string if no label separator is found.
|
||||
func VersionLabelForChecksum(checksum string) string {
|
||||
// Checksums are in the form: {versionLabel}+{hashID}:{hex}
|
||||
sepIndex := strings.Index(checksum, "+")
|
||||
if sepIndex < 0 {
|
||||
return ""
|
||||
}
|
||||
return checksum[:sepIndex]
|
||||
}
|
||||
|
||||
// Get a list of all known tarsum Version
|
||||
func GetVersions() []Version {
|
||||
v := []Version{}
|
||||
|
||||
+20
-5
@@ -2,11 +2,26 @@
|
||||
|
||||
DEST=$1
|
||||
|
||||
PKGVERSION="$VERSION"
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
PKGVERSION="$PKGVERSION-$(date +%Y%m%d%H%M%S)-$GITCOMMIT"
|
||||
PKGVERSION="${VERSION//-/'~'}"
|
||||
# if we have a "-dev" suffix or have change in Git, let's make this package version more complex so it works better
|
||||
if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
|
||||
GIT_UNIX="$(git log -1 --pretty='%at')"
|
||||
GIT_DATE="$(date --date "@$GIT_UNIX" +'%Y%m%d.%H%M%S')"
|
||||
GIT_COMMIT="$(git log -1 --pretty='%h')"
|
||||
GIT_VERSION="git${GIT_DATE}.0.${GIT_COMMIT}"
|
||||
# GIT_VERSION is now something like 'git20150128.112847.0.17e840a'
|
||||
PKGVERSION="$PKGVERSION~$GIT_VERSION"
|
||||
fi
|
||||
|
||||
# $ dpkg --compare-versions 1.5.0 gt 1.5.0~rc1 && echo true || echo false
|
||||
# true
|
||||
# $ dpkg --compare-versions 1.5.0~rc1 gt 1.5.0~git20150128.112847.17e840a && echo true || echo false
|
||||
# true
|
||||
# $ dpkg --compare-versions 1.5.0~git20150128.112847.17e840a gt 1.5.0~dev~git20150128.112847.17e840a && echo true || echo false
|
||||
# true
|
||||
|
||||
# ie, 1.5.0 > 1.5.0~rc1 > 1.5.0~git20150128.112847.17e840a > 1.5.0~dev~git20150128.112847.17e840a
|
||||
|
||||
PACKAGE_ARCHITECTURE="$(dpkg-architecture -qDEB_HOST_ARCH)"
|
||||
PACKAGE_URL="http://www.docker.com/"
|
||||
PACKAGE_MAINTAINER="support@docker.com"
|
||||
@@ -124,7 +139,7 @@ EOF
|
||||
|
||||
# create lxc-docker-VERSION package
|
||||
fpm -s dir -C $DIR \
|
||||
--name lxc-docker-$VERSION --version $PKGVERSION \
|
||||
--name lxc-docker-$VERSION --version "$PKGVERSION" \
|
||||
--after-install $DEST/postinst \
|
||||
--before-remove $DEST/prerm \
|
||||
--after-remove $DEST/postrm \
|
||||
@@ -157,7 +172,7 @@ EOF
|
||||
|
||||
# create empty lxc-docker wrapper package
|
||||
fpm -s empty \
|
||||
--name lxc-docker --version $PKGVERSION \
|
||||
--name lxc-docker --version "$PKGVERSION" \
|
||||
--architecture "$PACKAGE_ARCHITECTURE" \
|
||||
--depends lxc-docker-$VERSION \
|
||||
--description "$PACKAGE_DESCRIPTION" \
|
||||
|
||||
@@ -231,10 +231,13 @@ func (e *Endpoint) pingV2() (RegistryInfo, error) {
|
||||
// Ensure it supports the v2 Registry API.
|
||||
var supportsV2 bool
|
||||
|
||||
for _, versionName := range resp.Header[http.CanonicalHeaderKey("Docker-Distribution-API-Version")] {
|
||||
if versionName == "registry/2.0" {
|
||||
supportsV2 = true
|
||||
break
|
||||
HeaderLoop:
|
||||
for _, supportedVersions := range resp.Header[http.CanonicalHeaderKey("Docker-Distribution-API-Version")] {
|
||||
for _, versionName := range strings.Fields(supportedVersions) {
|
||||
if versionName == "registry/2.0" {
|
||||
supportsV2 = true
|
||||
break HeaderLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ func TestValidateEndpointAmbiguousAPIVersion(t *testing.T) {
|
||||
})
|
||||
|
||||
requireBasicAuthHandlerV2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0")
|
||||
// This mock server supports v2.0, v2.1, v42.0, and v100.0
|
||||
w.Header().Add("Docker-Distribution-API-Version", "registry/100.0 registry/42.0")
|
||||
w.Header().Add("Docker-Distribution-API-Version", "registry/2.0 registry/2.1")
|
||||
requireBasicAuthHandler.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
|
||||
+21
-10
@@ -124,15 +124,16 @@ func (r *Session) HeadV2ImageBlob(ep *Endpoint, imageName, sumType, sum string,
|
||||
return false, err
|
||||
}
|
||||
res.Body.Close() // close early, since we're not needing a body on this call .. yet?
|
||||
switch res.StatusCode {
|
||||
case 200:
|
||||
switch {
|
||||
case res.StatusCode >= 200 && res.StatusCode < 400:
|
||||
// return something indicating no push needed
|
||||
return true, nil
|
||||
case 404:
|
||||
case res.StatusCode == 404:
|
||||
// return something indicating blob push needed
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("Failed to mount %q - %s:%s : %d", imageName, sumType, sum, res.StatusCode)
|
||||
|
||||
return false, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying head request for %s - %s:%s", res.StatusCode, imageName, sumType, sum), res)
|
||||
}
|
||||
|
||||
func (r *Session) GetV2ImageBlob(ep *Endpoint, imageName, sumType, sum string, blobWrtr io.Writer, auth *RequestAuthorization) error {
|
||||
@@ -189,7 +190,7 @@ func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum str
|
||||
if res.StatusCode == 401 {
|
||||
return nil, 0, errLoginRequired
|
||||
}
|
||||
return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob", res.StatusCode, imageName), res)
|
||||
return nil, 0, utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to pull %s blob - %s:%s", res.StatusCode, imageName, sumType, sum), res)
|
||||
}
|
||||
lenStr := res.Header.Get("Content-Length")
|
||||
l, err := strconv.ParseInt(lenStr, 10, 64)
|
||||
@@ -246,7 +247,12 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string
|
||||
if res.StatusCode == 401 {
|
||||
return errLoginRequired
|
||||
}
|
||||
return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob", res.StatusCode, imageName), res)
|
||||
errBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
|
||||
return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s blob - %s:%s", res.StatusCode, imageName, sumType, sumStr), res)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -272,13 +278,18 @@ func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, ma
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, _ := ioutil.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if res.StatusCode != 200 {
|
||||
defer res.Body.Close()
|
||||
|
||||
// All 2xx and 3xx responses can be accepted for a put.
|
||||
if res.StatusCode >= 400 {
|
||||
if res.StatusCode == 401 {
|
||||
return errLoginRequired
|
||||
}
|
||||
log.Debugf("Unexpected response from server: %q %#v", b, res.Header)
|
||||
errBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
|
||||
return utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res)
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -57,9 +57,10 @@ func (r *Repository) newVolume(path string, writable bool) (*Volume, error) {
|
||||
}
|
||||
path = filepath.Clean(path)
|
||||
|
||||
path, err = filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Ignore the error here since the path may not exist
|
||||
// Really just want to make sure the path we are using is real(or non-existant)
|
||||
if cleanPath, err := filepath.EvalSymlinks(path); err == nil {
|
||||
path = cleanPath
|
||||
}
|
||||
|
||||
v := &Volume{
|
||||
@@ -169,13 +170,11 @@ func (r *Repository) Delete(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if volume.IsBindMount {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := r.driver.Remove(volume.ID); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
if !volume.IsBindMount {
|
||||
if err := r.driver.Remove(volume.ID); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user