зеркало из https://github.com/microsoft/docker.git
Коммит
2519f46550
10
Dockerfile
10
Dockerfile
|
@ -72,16 +72,6 @@ RUN cd /usr/local/lvm2 \
|
|||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install lxc
|
||||
ENV LXC_VERSION 1.1.2
|
||||
RUN mkdir -p /usr/src/lxc \
|
||||
&& curl -sSL https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz | tar -v -C /usr/src/lxc/ -xz --strip-components=1
|
||||
RUN cd /usr/src/lxc \
|
||||
&& ./configure \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig
|
||||
|
||||
# Install Go
|
||||
ENV GO_VERSION 1.5.1
|
||||
RUN curl -sSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar -v -C /usr/local -xz
|
||||
|
|
|
@ -39,16 +39,6 @@ RUN cd /usr/local/lvm2 \
|
|||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install lxc
|
||||
ENV LXC_VERSION 1.1.2
|
||||
RUN mkdir -p /usr/src/lxc \
|
||||
&& curl -sSL https://linuxcontainers.org/downloads/lxc/lxc-${LXC_VERSION}.tar.gz | tar -v -C /usr/src/lxc/ -xz --strip-components=1
|
||||
RUN cd /usr/src/lxc \
|
||||
&& ./configure \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig
|
||||
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
|
|
|
@ -26,7 +26,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
xz-utils \
|
||||
\
|
||||
aufs-tools \
|
||||
lxc \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
|
|
|
@ -264,7 +264,6 @@ type ContainerJSONBase struct {
|
|||
Name string
|
||||
RestartCount int
|
||||
Driver string
|
||||
ExecDriver string
|
||||
MountLabel string
|
||||
ProcessLabel string
|
||||
AppArmorProfile string
|
||||
|
|
|
@ -40,7 +40,6 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
|||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
lxc=1.0* \
|
||||
mercurial \
|
||||
pandoc \
|
||||
parallel \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(from "ubuntu:14.04")
|
||||
(maintainer "Tianon Gravi <admwiggin@gmail.com> (@tianon)")
|
||||
(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \tapt-utils \taufs-tools \tautomake \tbtrfs-tools \tbuild-essential \tcurl \tdpkg-sig \tgit \tiptables \tlibapparmor-dev \tlibcap-dev \tlibsqlite3-dev \tlxc=1.0* \tmercurial \tpandoc \tparallel \treprepro \truby1.9.1 \truby1.9.1-dev \ts3cmd=1.1.0* \t--no-install-recommends")
|
||||
(run "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \tapt-utils \taufs-tools \tautomake \tbtrfs-tools \tbuild-essential \tcurl \tdpkg-sig \tgit \tiptables \tlibapparmor-dev \tlibcap-dev \tlibsqlite3-dev \tmercurial \tpandoc \tparallel \treprepro \truby1.9.1 \truby1.9.1-dev \ts3cmd=1.1.0* \t--no-install-recommends")
|
||||
(run "git clone --no-checkout https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2 && cd /usr/local/lvm2 && git checkout -q v2_02_103")
|
||||
(run "cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper && make install_device-mapper")
|
||||
(run "curl -sSL https://golang.org/dl/go1.3.src.tar.gz | tar -v -C /usr/local -xz")
|
||||
|
|
|
@ -659,7 +659,6 @@ _docker_daemon() {
|
|||
--dns
|
||||
--dns-search
|
||||
--dns-opt
|
||||
--exec-driver -e
|
||||
--exec-opt
|
||||
--exec-root
|
||||
--fixed-cidr
|
||||
|
@ -1379,7 +1378,6 @@ _docker_run() {
|
|||
--link
|
||||
--log-driver
|
||||
--log-opt
|
||||
--lxc-conf
|
||||
--mac-address
|
||||
--memory -m
|
||||
--memory-swap
|
||||
|
|
|
@ -51,7 +51,6 @@ 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-opt -d 'Force Docker to use specific DNS options'
|
||||
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 exec-opt -d 'Set exec driver options'
|
||||
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)'
|
||||
|
@ -135,7 +134,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l help -d 'Pri
|
|||
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 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>[<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>[<unit>], where unit = b, k, m or g)"
|
||||
|
@ -324,7 +322,6 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l help -d 'Print
|
|||
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 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>[<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>[<unit>], where unit = b, k, m or g)"
|
||||
|
|
|
@ -438,7 +438,6 @@ __docker_subcommand() {
|
|||
"($help)*"{-l=,--label=}"[Set meta data on a container]:label: "
|
||||
"($help)--log-driver=[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs splunk none)"
|
||||
"($help)*--log-opt=[Log driver specific options]:log driver options: "
|
||||
"($help)*--lxc-conf=[Add custom lxc options]:lxc options: "
|
||||
"($help)--mac-address=[Container MAC address]:MAC address: "
|
||||
"($help)--name=[Container name]:name: "
|
||||
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
|
||||
|
@ -541,7 +540,6 @@ __docker_subcommand() {
|
|||
"($help)*--dns-opt=[DNS options to use]:DNS option: " \
|
||||
"($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \
|
||||
"($help)--disable-legacy-registry[Do not contact legacy registries]" \
|
||||
"($help -e --exec-driver)"{-e=,--exec-driver=}"[Exec driver to use]:driver:(native lxc windows)" \
|
||||
"($help)*--exec-opt=[Set exec driver options]:exec driver options: " \
|
||||
"($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \
|
||||
"($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0)
|
||||
/var/run/docker-client(/.*)? gen_context(system_u:object_r:docker_var_run_t,s0)
|
||||
|
||||
/var/lock/lxc(/.*)? gen_context(system_u:object_r:docker_lock_t,s0)
|
||||
|
||||
/var/log/lxc(/.*)? gen_context(system_u:object_r:docker_log_t,s0)
|
||||
|
||||
/var/lib/docker/init(/.*)? gen_context(system_u:object_r:docker_share_t,s0)
|
||||
/var/lib/docker/containers/.*/hosts gen_context(system_u:object_r:docker_share_t,s0)
|
||||
/var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)
|
||||
|
|
|
@ -292,7 +292,6 @@ interface(`docker_filetrans_named_content',`
|
|||
files_pid_filetrans($1, docker_var_run_t, file, "docker.pid")
|
||||
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
|
||||
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client")
|
||||
logging_log_filetrans($1, docker_log_t, dir, "lxc")
|
||||
files_var_lib_filetrans($1, docker_var_lib_t, dir, "docker")
|
||||
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "config.env")
|
||||
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
|
||||
|
@ -406,11 +405,6 @@ interface(`staff_stub',`
|
|||
type staff_t;
|
||||
')
|
||||
')
|
||||
interface(`virt_stub_lxc',`
|
||||
gen_require(`
|
||||
type virtd_lxc_t;
|
||||
')
|
||||
')
|
||||
interface(`virt_stub_svirt_sandbox_domain',`
|
||||
gen_require(`
|
||||
attribute svirt_sandbox_domain;
|
||||
|
|
|
@ -90,7 +90,6 @@ files_etc_filetrans(docker_t, docker_config_t, dir, "docker")
|
|||
|
||||
manage_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
|
||||
manage_files_pattern(docker_t, docker_lock_t, docker_lock_t)
|
||||
files_lock_filetrans(docker_t, docker_lock_t, { dir file }, "lxc")
|
||||
|
||||
manage_dirs_pattern(docker_t, docker_log_t, docker_log_t)
|
||||
manage_files_pattern(docker_t, docker_log_t, docker_log_t)
|
||||
|
@ -213,10 +212,6 @@ optional_policy(`
|
|||
openvswitch_stream_connect(docker_t)
|
||||
')
|
||||
|
||||
#
|
||||
# lxc rules
|
||||
#
|
||||
|
||||
allow docker_t self:capability { dac_override setgid setpcap setuid sys_admin sys_boot sys_chroot sys_ptrace };
|
||||
|
||||
allow docker_t self:process { getcap setcap setexec setpgid setsched signal_perms };
|
||||
|
@ -317,7 +312,6 @@ optional_policy(`
|
|||
virt_exec_sandbox_files(docker_t)
|
||||
virt_manage_sandbox_files(docker_t)
|
||||
virt_relabel_sandbox_filesystem(docker_t)
|
||||
# for lxc
|
||||
virt_transition_svirt_sandbox(docker_t, system_r)
|
||||
virt_mounton_sandbox_file(docker_t)
|
||||
# virt_attach_sandbox_tun_iface(docker_t)
|
||||
|
@ -387,11 +381,6 @@ optional_policy(`
|
|||
docker_exec(staff_t)
|
||||
')
|
||||
|
||||
optional_policy(`
|
||||
virt_stub_lxc()
|
||||
docker_exec_lib(virtd_lxc_t)
|
||||
')
|
||||
|
||||
optional_policy(`
|
||||
virt_stub_svirt_sandbox_domain()
|
||||
virt_stub_svirt_sandbox_file()
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# A simple helper script to help people build seccomp profiles for
|
||||
# Docker/LXC. The goal is mostly to reduce the attack surface to the
|
||||
# kernel, by restricting access to rarely used, recently added or not used
|
||||
# syscalls.
|
||||
#
|
||||
# This script processes one or more files which contain the list of system
|
||||
# calls to be allowed. See mkseccomp.sample for more information how you
|
||||
# can configure the list of syscalls. When run, this script produces output
|
||||
# which, when stored in a file, can be passed to docker as follows:
|
||||
#
|
||||
# docker run --lxc-conf="lxc.seccomp=$file" <rest of arguments>
|
||||
#
|
||||
# The included sample file shows how to cut about a quarter of all syscalls,
|
||||
# which affecting most applications.
|
||||
#
|
||||
# For specific situations it is possible to reduce the list further. By
|
||||
# reducing the list to just those syscalls required by a certain application
|
||||
# you can make it difficult for unknown/unexpected code to run.
|
||||
#
|
||||
# Run this script as follows:
|
||||
#
|
||||
# ./mkseccomp.pl < mkseccomp.sample >syscalls.list
|
||||
# or
|
||||
# ./mkseccomp.pl mkseccomp.sample >syscalls.list
|
||||
#
|
||||
# Multiple files can be specified, in which case the lists of syscalls are
|
||||
# combined.
|
||||
#
|
||||
# By Martijn van Oosterhout <kleptog@svana.org> Nov 2013
|
||||
|
||||
# How it works:
|
||||
#
|
||||
# This program basically spawns two processes to form a chain like:
|
||||
#
|
||||
# <process data section to prefix __NR_> | cpp | <add header and filter unknown syscalls>
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
if( -t ) {
|
||||
print STDERR "Helper script to make seccomp filters for Docker/LXC.\n";
|
||||
print STDERR "Usage: mkseccomp.pl < [files...]\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $pid = open(my $in, "-|") // die "Couldn't fork1 ($!)\n";
|
||||
|
||||
if($pid == 0) { # Child
|
||||
$pid = open(my $out, "|-") // die "Couldn't fork2 ($!)\n";
|
||||
|
||||
if($pid == 0) { # Child, which execs cpp
|
||||
exec "cpp" or die "Couldn't exec cpp ($!)\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Process the DATA section and output to cpp
|
||||
print $out "#include <sys/syscall.h>\n";
|
||||
while(<>) {
|
||||
if(/^\w/) {
|
||||
print $out "__NR_$_";
|
||||
}
|
||||
}
|
||||
close $out;
|
||||
exit 0;
|
||||
|
||||
}
|
||||
|
||||
# Print header and then process output from cpp.
|
||||
print "1\n";
|
||||
print "whitelist\n";
|
||||
|
||||
while(<$in>) {
|
||||
print if( /^[0-9]/ );
|
||||
}
|
||||
|
|
@ -1,444 +0,0 @@
|
|||
/* This sample file is an example for mkseccomp.pl to produce a seccomp file
|
||||
* which restricts syscalls that are only useful for an admin but allows the
|
||||
* vast majority of normal userspace programs to run normally.
|
||||
*
|
||||
* The format of this file is one line per syscall. This is then processed
|
||||
* and passed to 'cpp' to convert the names to numbers using whatever is
|
||||
* correct for your platform. As such C-style comments are permitted. Note
|
||||
* this also means that C preprocessor macros are also allowed. So it is
|
||||
* possible to create groups surrounded by #ifdef/#endif and control their
|
||||
* inclusion via #define (not #include).
|
||||
*
|
||||
* Syscalls that don't exist on your architecture are silently filtered out.
|
||||
* Syscalls marked with (*) are required for a container to spawn a bash
|
||||
* shell successfully (not necessarily full featured). Listing the same
|
||||
* syscall multiple times is no problem.
|
||||
*
|
||||
* If you want to make a list specifically for one application the easiest
|
||||
* way is to run the application under strace, like so:
|
||||
*
|
||||
* $ strace -f -q -c -o strace.out application args...
|
||||
*
|
||||
* Once you have a reasonable sample of the execution of the program, exit
|
||||
* it. The file strace.out will have a summary of the syscalls used. Copy
|
||||
* that list into this file, comment out everything else except the starred
|
||||
* syscalls (which you need for the container to start) and you're done.
|
||||
*
|
||||
* To get the list of syscalls from the strace output this works well for
|
||||
* me
|
||||
*
|
||||
* $ cut -c52 < strace.out
|
||||
*
|
||||
* This sample list was compiled as a combination of all the syscalls
|
||||
* available on i386 and amd64 on Ubuntu Precise, as such it may not contain
|
||||
* everything and not everything may be relevant for your system. This
|
||||
* shouldn't be a problem.
|
||||
*/
|
||||
|
||||
// Filesystem/File descriptor related
|
||||
access // (*)
|
||||
chdir // (*)
|
||||
chmod
|
||||
chown
|
||||
chown32
|
||||
close // (*)
|
||||
creat
|
||||
dup // (*)
|
||||
dup2 // (*)
|
||||
dup3
|
||||
epoll_create
|
||||
epoll_create1
|
||||
epoll_ctl
|
||||
epoll_ctl_old
|
||||
epoll_pwait
|
||||
epoll_wait
|
||||
epoll_wait_old
|
||||
eventfd
|
||||
eventfd2
|
||||
faccessat // (*)
|
||||
fadvise64
|
||||
fadvise64_64
|
||||
fallocate
|
||||
fanotify_init
|
||||
fanotify_mark
|
||||
ioctl // (*)
|
||||
fchdir
|
||||
fchmod
|
||||
fchmodat
|
||||
fchown
|
||||
fchown32
|
||||
fchownat
|
||||
fcntl // (*)
|
||||
fcntl64
|
||||
fdatasync
|
||||
fgetxattr
|
||||
flistxattr
|
||||
flock
|
||||
fremovexattr
|
||||
fsetxattr
|
||||
fstat // (*)
|
||||
fstat64
|
||||
fstatat64
|
||||
fstatfs
|
||||
fstatfs64
|
||||
fsync
|
||||
ftruncate
|
||||
ftruncate64
|
||||
getcwd // (*)
|
||||
getdents // (*)
|
||||
getdents64
|
||||
getxattr
|
||||
inotify_add_watch
|
||||
inotify_init
|
||||
inotify_init1
|
||||
inotify_rm_watch
|
||||
io_cancel
|
||||
io_destroy
|
||||
io_getevents
|
||||
io_setup
|
||||
io_submit
|
||||
lchown
|
||||
lchown32
|
||||
lgetxattr
|
||||
link
|
||||
linkat
|
||||
listxattr
|
||||
llistxattr
|
||||
llseek
|
||||
_llseek
|
||||
lremovexattr
|
||||
lseek // (*)
|
||||
lsetxattr
|
||||
lstat
|
||||
lstat64
|
||||
mkdir
|
||||
mkdirat
|
||||
mknod
|
||||
mknodat
|
||||
newfstatat
|
||||
_newselect
|
||||
oldfstat
|
||||
oldlstat
|
||||
oldolduname
|
||||
oldstat
|
||||
olduname
|
||||
oldwait4
|
||||
open // (*)
|
||||
openat // (*)
|
||||
pipe // (*)
|
||||
pipe2
|
||||
poll
|
||||
ppoll
|
||||
pread64
|
||||
preadv
|
||||
futimesat
|
||||
pselect6
|
||||
pwrite64
|
||||
pwritev
|
||||
read // (*)
|
||||
readahead
|
||||
readdir
|
||||
readlink
|
||||
readlinkat
|
||||
readv
|
||||
removexattr
|
||||
rename
|
||||
renameat
|
||||
rmdir
|
||||
select
|
||||
sendfile
|
||||
sendfile64
|
||||
setxattr
|
||||
splice
|
||||
stat // (*)
|
||||
stat64
|
||||
statfs // (*)
|
||||
statfs64
|
||||
symlink
|
||||
symlinkat
|
||||
sync
|
||||
sync_file_range
|
||||
sync_file_range2
|
||||
syncfs
|
||||
tee
|
||||
truncate
|
||||
truncate64
|
||||
umask
|
||||
unlink
|
||||
unlinkat
|
||||
ustat
|
||||
utime
|
||||
utimensat
|
||||
utimes
|
||||
write // (*)
|
||||
writev
|
||||
|
||||
// Network related
|
||||
accept
|
||||
accept4
|
||||
bind // (*)
|
||||
connect // (*)
|
||||
getpeername
|
||||
getsockname // (*)
|
||||
getsockopt
|
||||
listen
|
||||
recv
|
||||
recvfrom // (*)
|
||||
recvmmsg
|
||||
recvmsg
|
||||
send
|
||||
sendmmsg
|
||||
sendmsg
|
||||
sendto // (*)
|
||||
setsockopt
|
||||
shutdown
|
||||
socket // (*)
|
||||
socketcall
|
||||
socketpair
|
||||
sethostname // (*)
|
||||
|
||||
// Signal related
|
||||
pause
|
||||
rt_sigaction // (*)
|
||||
rt_sigpending
|
||||
rt_sigprocmask // (*)
|
||||
rt_sigqueueinfo
|
||||
rt_sigreturn // (*)
|
||||
rt_sigsuspend
|
||||
rt_sigtimedwait
|
||||
rt_tgsigqueueinfo
|
||||
sigaction
|
||||
sigaltstack // (*)
|
||||
signal
|
||||
signalfd
|
||||
signalfd4
|
||||
sigpending
|
||||
sigprocmask
|
||||
sigreturn
|
||||
sigsuspend
|
||||
|
||||
// Other needed POSIX
|
||||
alarm
|
||||
brk // (*)
|
||||
clock_adjtime
|
||||
clock_getres
|
||||
clock_gettime
|
||||
clock_nanosleep
|
||||
//clock_settime
|
||||
gettimeofday
|
||||
nanosleep
|
||||
nice
|
||||
sysinfo
|
||||
syslog
|
||||
time
|
||||
timer_create
|
||||
timer_delete
|
||||
timerfd_create
|
||||
timerfd_gettime
|
||||
timerfd_settime
|
||||
timer_getoverrun
|
||||
timer_gettime
|
||||
timer_settime
|
||||
times
|
||||
uname // (*)
|
||||
|
||||
// Memory control
|
||||
madvise
|
||||
mbind
|
||||
mincore
|
||||
mlock
|
||||
mlockall
|
||||
mmap // (*)
|
||||
mmap2
|
||||
mprotect // (*)
|
||||
mremap
|
||||
msync
|
||||
munlock
|
||||
munlockall
|
||||
munmap // (*)
|
||||
remap_file_pages
|
||||
set_mempolicy
|
||||
vmsplice
|
||||
|
||||
// Process control
|
||||
capget
|
||||
capset // (*)
|
||||
clone // (*)
|
||||
execve // (*)
|
||||
exit // (*)
|
||||
exit_group // (*)
|
||||
fork
|
||||
getcpu
|
||||
getpgid
|
||||
getpgrp // (*)
|
||||
getpid // (*)
|
||||
getppid // (*)
|
||||
getpriority
|
||||
getresgid
|
||||
getresgid32
|
||||
getresuid
|
||||
getresuid32
|
||||
getrlimit // (*)
|
||||
getrusage
|
||||
getsid
|
||||
getuid // (*)
|
||||
getuid32
|
||||
getegid // (*)
|
||||
getegid32
|
||||
geteuid // (*)
|
||||
geteuid32
|
||||
getgid // (*)
|
||||
getgid32
|
||||
getgroups
|
||||
getgroups32
|
||||
getitimer
|
||||
get_mempolicy
|
||||
kill
|
||||
//personality
|
||||
prctl
|
||||
prlimit64
|
||||
sched_getaffinity
|
||||
sched_getparam
|
||||
sched_get_priority_max
|
||||
sched_get_priority_min
|
||||
sched_getscheduler
|
||||
sched_rr_get_interval
|
||||
//sched_setaffinity
|
||||
//sched_setparam
|
||||
//sched_setscheduler
|
||||
sched_yield
|
||||
setfsgid
|
||||
setfsgid32
|
||||
setfsuid
|
||||
setfsuid32
|
||||
setgid
|
||||
setgid32
|
||||
setgroups
|
||||
setgroups32
|
||||
setitimer
|
||||
setpgid // (*)
|
||||
setpriority
|
||||
setregid
|
||||
setregid32
|
||||
setresgid
|
||||
setresgid32
|
||||
setresuid
|
||||
setresuid32
|
||||
setreuid
|
||||
setreuid32
|
||||
setrlimit
|
||||
setsid
|
||||
setuid
|
||||
setuid32
|
||||
ugetrlimit
|
||||
vfork
|
||||
wait4 // (*)
|
||||
waitid
|
||||
waitpid
|
||||
|
||||
// IPC
|
||||
ipc
|
||||
mq_getsetattr
|
||||
mq_notify
|
||||
mq_open
|
||||
mq_timedreceive
|
||||
mq_timedsend
|
||||
mq_unlink
|
||||
msgctl
|
||||
msgget
|
||||
msgrcv
|
||||
msgsnd
|
||||
semctl
|
||||
semget
|
||||
semop
|
||||
semtimedop
|
||||
shmat
|
||||
shmctl
|
||||
shmdt
|
||||
shmget
|
||||
|
||||
// Linux specific, mostly needed for thread-related stuff
|
||||
arch_prctl // (*)
|
||||
get_robust_list
|
||||
get_thread_area
|
||||
gettid
|
||||
futex // (*)
|
||||
restart_syscall // (*)
|
||||
set_robust_list // (*)
|
||||
set_thread_area
|
||||
set_tid_address // (*)
|
||||
tgkill
|
||||
tkill
|
||||
|
||||
// Admin syscalls, these are blocked
|
||||
//acct
|
||||
//adjtimex
|
||||
//bdflush
|
||||
//chroot
|
||||
//create_module
|
||||
//delete_module
|
||||
//get_kernel_syms // Obsolete
|
||||
//idle // Obsolete
|
||||
//init_module
|
||||
//ioperm
|
||||
//iopl
|
||||
//ioprio_get
|
||||
//ioprio_set
|
||||
//kexec_load
|
||||
//lookup_dcookie // oprofile only?
|
||||
//migrate_pages // NUMA
|
||||
//modify_ldt
|
||||
//mount
|
||||
//move_pages // NUMA
|
||||
//name_to_handle_at // NFS server
|
||||
//nfsservctl // NFS server
|
||||
//open_by_handle_at // NFS server
|
||||
//perf_event_open
|
||||
//pivot_root
|
||||
//process_vm_readv // For debugger
|
||||
//process_vm_writev // For debugger
|
||||
//ptrace // For debugger
|
||||
//query_module
|
||||
//quotactl
|
||||
//reboot
|
||||
//setdomainname
|
||||
//setns
|
||||
//settimeofday
|
||||
//sgetmask // Obsolete
|
||||
//ssetmask // Obsolete
|
||||
//stime
|
||||
//swapoff
|
||||
//swapon
|
||||
//_sysctl
|
||||
//sysfs
|
||||
//sys_setaltroot
|
||||
//umount
|
||||
//umount2
|
||||
//unshare
|
||||
//uselib
|
||||
//vhangup
|
||||
//vm86
|
||||
//vm86old
|
||||
|
||||
// Kernel key management
|
||||
//add_key
|
||||
//keyctl
|
||||
//request_key
|
||||
|
||||
// Unimplemented
|
||||
//afs_syscall
|
||||
//break
|
||||
//ftime
|
||||
//getpmsg
|
||||
//gtty
|
||||
//lock
|
||||
//madvise1
|
||||
//mpx
|
||||
//prof
|
||||
//profil
|
||||
//putpmsg
|
||||
//security
|
||||
//stty
|
||||
//tuxcall
|
||||
//ulimit
|
||||
//vserver
|
|
@ -25,7 +25,7 @@ The initial Docker upstart script will not work because it runs on `127.0.0.1`,
|
|||
```
|
||||
description "Docker daemon"
|
||||
|
||||
start on filesystem and started lxc-net
|
||||
start on filesystem
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
|
|
@ -21,7 +21,6 @@ type CommonConfig struct {
|
|||
DNS []string
|
||||
DNSOptions []string
|
||||
DNSSearch []string
|
||||
ExecDriver string
|
||||
ExecOptions []string
|
||||
ExecRoot string
|
||||
GraphDriver string
|
||||
|
@ -62,7 +61,6 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
|
|||
cmd.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", usageFn("Root of the Docker execdriver"))
|
||||
cmd.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, usageFn("--restart on the daemon has been deprecated in favor of --restart policies on docker run"))
|
||||
cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
|
||||
cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
|
||||
cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
|
||||
// FIXME: why the inconsistency between "hosts" and "sockets"?
|
||||
cmd.Var(opts.NewListOptsRef(&config.DNS, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
|
||||
|
|
|
@ -17,8 +17,6 @@ var (
|
|||
)
|
||||
|
||||
// Config defines the configuration of a docker daemon.
|
||||
// These are the configuration settings that you pass
|
||||
// to the docker daemon when you launch it with say: `docker daemon -e lxc`
|
||||
type Config struct {
|
||||
CommonConfig
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ type CommonContainer struct {
|
|||
LogPath string
|
||||
Name string
|
||||
Driver string
|
||||
ExecDriver string
|
||||
// MountLabel contains the options for the 'mount' command
|
||||
MountLabel string
|
||||
ProcessLabel string
|
||||
|
@ -258,7 +257,6 @@ func (container *Container) jsonPath() (string, error) {
|
|||
return container.getRootResourcePath("config.json")
|
||||
}
|
||||
|
||||
// This method must be exported to be used from the lxc template
|
||||
// This directory is only usable when the container is running
|
||||
func (container *Container) rootfsPath() string {
|
||||
return container.basefs
|
||||
|
|
|
@ -255,12 +255,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
|
|||
|
||||
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
|
||||
|
||||
// TODO: this can be removed after lxc-conf is fully deprecated
|
||||
lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rlimits []*ulimit.Rlimit
|
||||
ulimits := c.hostConfig.Ulimits
|
||||
|
||||
|
@ -345,7 +339,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
|
|||
GIDMapping: gidMap,
|
||||
GroupAdd: c.hostConfig.GroupAdd,
|
||||
Ipc: ipc,
|
||||
LxcConfig: lxcConfig,
|
||||
Pid: pid,
|
||||
ReadonlyRootfs: c.hostConfig.ReadonlyRootfs,
|
||||
RemappedRoot: remappedRoot,
|
||||
|
|
|
@ -451,7 +451,6 @@ func (daemon *Daemon) generateNewName(id string) (string, error) {
|
|||
|
||||
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
|
||||
// Generate default hostname
|
||||
// FIXME: the lxc template no longer needs to set a default hostname
|
||||
if config.Hostname == "" {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
|
@ -490,7 +489,6 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
|
|||
base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
|
||||
base.Name = name
|
||||
base.Driver = daemon.driver.String()
|
||||
base.ExecDriver = daemon.execDriver.Name()
|
||||
|
||||
return base, err
|
||||
}
|
||||
|
@ -786,13 +784,6 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
d.containerGraphDB = graph
|
||||
|
||||
var sysInitPath string
|
||||
if config.ExecDriver == "lxc" {
|
||||
initPath, err := configureSysInit(config, rootUID, rootGID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sysInitPath = initPath
|
||||
}
|
||||
|
||||
sysInfo := sysinfo.New(false)
|
||||
// Check if Devices cgroup is mounted, it is hard requirement for container security,
|
||||
|
@ -801,7 +792,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
return nil, fmt.Errorf("Devices cgroup isn't mounted")
|
||||
}
|
||||
|
||||
ed, err := execdrivers.NewDriver(config.ExecDriver, config.ExecOptions, config.ExecRoot, config.Root, sysInitPath, sysInfo)
|
||||
ed, err := execdrivers.NewDriver(config.ExecOptions, config.ExecRoot, config.Root, sysInitPath, sysInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -15,11 +15,8 @@ import (
|
|||
)
|
||||
|
||||
func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
|
||||
if config.ExecDriver != "native" && config.RemappedRoot != "" {
|
||||
return nil, nil, fmt.Errorf("User namespace remapping is only supported with the native execdriver")
|
||||
}
|
||||
if runtime.GOOS == "windows" && config.RemappedRoot != "" {
|
||||
return nil, nil, fmt.Errorf("User namespaces are not supported on Windows")
|
||||
if runtime.GOOS != "linux" && config.RemappedRoot != "" {
|
||||
return nil, nil, fmt.Errorf("User namespaces are not supported on Linux")
|
||||
}
|
||||
|
||||
// if the daemon was started with remapped root option, parse
|
||||
|
|
|
@ -166,7 +166,7 @@ func TestLoadWithVolume(t *testing.T) {
|
|||
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||
|
||||
cfg := fmt.Sprintf(config, vfsPath)
|
||||
|
@ -255,7 +255,7 @@ func TestLoadWithBindMount(t *testing.T) {
|
|||
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"UpdateDns":false,"Volumes":{"/vol1": "/vol1"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||
|
||||
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
|
||||
|
@ -346,7 +346,7 @@ func TestLoadWithVolume17RC(t *testing.T) {
|
|||
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"UpdateDns":false,"MountPoints":{"/vol1":{"Name":"6a3c03fc4a4e588561a543cc3bdd50089e27bd11bbb0e551e19bf735e2514101","Destination":"/vol1","Driver":"local","RW":true,"Source":"","Relabel":""}},"AppliedVolumesFrom":null}`
|
||||
|
||||
if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(config), 0644); err != nil {
|
||||
|
@ -450,7 +450,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
|
|||
"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
|
||||
"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
|
||||
"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
|
||||
"Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
|
||||
"UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}`
|
||||
|
||||
cfg := fmt.Sprintf(config, vfsPath)
|
||||
|
|
|
@ -128,10 +128,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
|
|||
return warnings, err
|
||||
}
|
||||
|
||||
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
||||
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
||||
}
|
||||
|
||||
// memory subsystem checks and adjustments
|
||||
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
|
||||
return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
|
||||
|
|
|
@ -148,11 +148,6 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
|||
|
||||
// ContainerExecCreate sets up an exec in a running container.
|
||||
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
||||
// Not all drivers support Exec (LXC for example)
|
||||
if err := checkExecSupport(d.execDriver.Name()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
container, err := d.getActiveContainer(config.Container)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
// +build freebsd
|
||||
|
||||
package daemon
|
||||
|
||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
||||
// or nil if it is supported.
|
||||
func checkExecSupport(drivername string) error {
|
||||
return nil
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||
)
|
||||
|
||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
||||
// or nil if it is supported.
|
||||
func checkExecSupport(drivername string) error {
|
||||
if strings.HasPrefix(drivername, lxc.DriverName) {
|
||||
return lxc.ErrExec
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package daemon
|
||||
|
||||
// checkExecSupport returns an error if the exec driver does not support exec,
|
||||
// or nil if it is supported.
|
||||
func checkExecSupport(DriverName string) error {
|
||||
return nil
|
||||
}
|
|
@ -100,7 +100,6 @@ type Command struct {
|
|||
GIDMapping []idtools.IDMap `json:"gidmapping"`
|
||||
GroupAdd []string `json:"group_add"`
|
||||
Ipc *Ipc `json:"ipc"`
|
||||
LxcConfig []string `json:"lxc_config"`
|
||||
Pid *Pid `json:"pid"`
|
||||
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
||||
RemappedRoot *User `json:"remap_root"`
|
||||
|
|
|
@ -10,10 +10,6 @@ import (
|
|||
)
|
||||
|
||||
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
|
||||
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
switch name {
|
||||
case "jail":
|
||||
return nil, fmt.Errorf("jail driver not yet supported on FreeBSD")
|
||||
}
|
||||
return nil, fmt.Errorf("unknown exec driver %s", name)
|
||||
func NewDriver(options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
return nil, fmt.Errorf("jail driver not yet supported on FreeBSD")
|
||||
}
|
||||
|
|
|
@ -3,27 +3,14 @@
|
|||
package execdrivers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||
"github.com/docker/docker/daemon/execdriver/native"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
|
||||
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
switch name {
|
||||
case "lxc":
|
||||
// we want to give the lxc driver the full docker root because it needs
|
||||
// to access and write config and template files in /var/lib/docker/containers/*
|
||||
// to be backwards compatible
|
||||
logrus.Warn("LXC built-in support is deprecated.")
|
||||
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
|
||||
case "native":
|
||||
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown exec driver %s", name)
|
||||
func NewDriver(options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
|
||||
}
|
||||
|
|
|
@ -3,18 +3,12 @@
|
|||
package execdrivers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/execdriver/windows"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
|
||||
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
switch name {
|
||||
case "windows":
|
||||
return windows.NewDriver(root, initPath, options)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown exec driver %s", name)
|
||||
func NewDriver(options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
return windows.NewDriver(root, initPath, options)
|
||||
}
|
||||
|
|
|
@ -1,906 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
sysinfo "github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/docker/pkg/version"
|
||||
"github.com/kr/pty"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
// DriverName for lxc driver
|
||||
const DriverName = "lxc"
|
||||
|
||||
// ErrExec defines unsupported error message
|
||||
var ErrExec = errors.New("Unsupported: Exec is not supported by the lxc driver")
|
||||
|
||||
// Driver contains all information for lxc driver,
|
||||
// it implements execdriver.Driver
|
||||
type Driver struct {
|
||||
root string // root path for the driver to use
|
||||
libPath string
|
||||
initPath string
|
||||
apparmor bool
|
||||
sharedRoot bool
|
||||
activeContainers map[string]*activeContainer
|
||||
machineMemory int64
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type activeContainer struct {
|
||||
container *configs.Config
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
// NewDriver returns a new lxc driver, called from NewDriver of execdriver
|
||||
func NewDriver(root, libPath, initPath string, apparmor bool) (*Driver, error) {
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// setup unconfined symlink
|
||||
if err := linkLxcStart(root); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meminfo, err := sysinfo.ReadMemInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Driver{
|
||||
apparmor: apparmor,
|
||||
root: root,
|
||||
libPath: libPath,
|
||||
initPath: initPath,
|
||||
sharedRoot: rootIsShared(),
|
||||
activeContainers: make(map[string]*activeContainer),
|
||||
machineMemory: meminfo.MemTotal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Name implements the exec driver Driver interface.
|
||||
func (d *Driver) Name() string {
|
||||
version := d.version()
|
||||
return fmt.Sprintf("%s-%s", DriverName, version)
|
||||
}
|
||||
|
||||
func setupNetNs(nsPath string) (*os.Process, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
origns, err := netns.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer origns.Close()
|
||||
|
||||
f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
nsFD := f.Fd()
|
||||
if err := netns.Set(netns.NsHandle(nsFD)); err != nil {
|
||||
return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err)
|
||||
}
|
||||
defer netns.Set(origns)
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done")
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("failed to start netns process: %v", err)
|
||||
}
|
||||
|
||||
return cmd.Process, nil
|
||||
}
|
||||
|
||||
func killNetNsProc(proc *os.Process) {
|
||||
proc.Kill()
|
||||
proc.Wait()
|
||||
}
|
||||
|
||||
// Run implements the exec driver Driver interface,
|
||||
// it calls 'exec.Cmd' to launch lxc commands to run a container.
|
||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
var (
|
||||
term execdriver.Terminal
|
||||
err error
|
||||
dataPath = d.containerDir(c.ID)
|
||||
)
|
||||
|
||||
if c.Network == nil || (c.Network.NamespacePath == "" && c.Network.ContainerID == "") {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
|
||||
}
|
||||
|
||||
container, err := d.createContainer(c)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
if c.ProcessConfig.Tty {
|
||||
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
|
||||
} else {
|
||||
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
||||
}
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
c.ProcessConfig.Terminal = term
|
||||
|
||||
d.Lock()
|
||||
d.activeContainers[c.ID] = &activeContainer{
|
||||
container: container,
|
||||
cmd: &c.ProcessConfig.Cmd,
|
||||
}
|
||||
d.Unlock()
|
||||
|
||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
||||
Source: d.initPath,
|
||||
Destination: c.InitPath,
|
||||
Writable: false,
|
||||
Private: true,
|
||||
})
|
||||
|
||||
if err := d.generateEnvConfig(c); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
configPath, err := d.generateLXCConfig(c)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
params := []string{
|
||||
"lxc-start",
|
||||
"-n", c.ID,
|
||||
"-f", configPath,
|
||||
"-q",
|
||||
}
|
||||
|
||||
// From lxc>=1.1 the default behavior is to daemonize containers after start
|
||||
lxcVersion := version.Version(d.version())
|
||||
if lxcVersion.GreaterThanOrEqualTo(version.Version("1.1")) {
|
||||
params = append(params, "-F")
|
||||
}
|
||||
|
||||
proc := &os.Process{}
|
||||
if c.Network.ContainerID != "" {
|
||||
params = append(params,
|
||||
"--share-net", c.Network.ContainerID,
|
||||
)
|
||||
} else {
|
||||
proc, err = setupNetNs(c.Network.NamespacePath)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
pidStr := fmt.Sprintf("%d", proc.Pid)
|
||||
params = append(params,
|
||||
"--share-net", pidStr)
|
||||
}
|
||||
if c.Ipc != nil {
|
||||
if c.Ipc.ContainerID != "" {
|
||||
params = append(params,
|
||||
"--share-ipc", c.Ipc.ContainerID,
|
||||
)
|
||||
} else if c.Ipc.HostIpc {
|
||||
params = append(params,
|
||||
"--share-ipc", "1",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
params = append(params,
|
||||
"--",
|
||||
c.InitPath,
|
||||
)
|
||||
|
||||
if c.ProcessConfig.User != "" {
|
||||
params = append(params, "-u", c.ProcessConfig.User)
|
||||
}
|
||||
|
||||
if c.ProcessConfig.Privileged {
|
||||
if d.apparmor {
|
||||
params[0] = path.Join(d.root, "lxc-start-unconfined")
|
||||
|
||||
}
|
||||
params = append(params, "-privileged")
|
||||
}
|
||||
|
||||
if c.WorkingDir != "" {
|
||||
params = append(params, "-w", c.WorkingDir)
|
||||
}
|
||||
|
||||
params = append(params, "--", c.ProcessConfig.Entrypoint)
|
||||
params = append(params, c.ProcessConfig.Arguments...)
|
||||
|
||||
if d.sharedRoot {
|
||||
// lxc-start really needs / to be non-shared, or all kinds of stuff break
|
||||
// when lxc-start unmount things and those unmounts propagate to the main
|
||||
// mount namespace.
|
||||
// What we really want is to clone into a new namespace and then
|
||||
// mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
|
||||
// without exec in go we have to do this horrible shell hack...
|
||||
shellString :=
|
||||
"mount --make-rslave /; exec " +
|
||||
stringutils.ShellQuoteArguments(params)
|
||||
|
||||
params = []string{
|
||||
"unshare", "-m", "--", "/bin/sh", "-c", shellString,
|
||||
}
|
||||
}
|
||||
logrus.Debugf("lxc params %s", params)
|
||||
var (
|
||||
name = params[0]
|
||||
arg = params[1:]
|
||||
)
|
||||
aname, err := exec.LookPath(name)
|
||||
if err != nil {
|
||||
aname = name
|
||||
}
|
||||
c.ProcessConfig.Path = aname
|
||||
c.ProcessConfig.Args = append([]string{name}, arg...)
|
||||
|
||||
if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
|
||||
killNetNsProc(proc)
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
if err := c.ProcessConfig.Start(); err != nil {
|
||||
killNetNsProc(proc)
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
var (
|
||||
waitErr error
|
||||
waitLock = make(chan struct{})
|
||||
)
|
||||
|
||||
go func() {
|
||||
if err := c.ProcessConfig.Wait(); err != nil {
|
||||
if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
|
||||
waitErr = err
|
||||
}
|
||||
}
|
||||
close(waitLock)
|
||||
}()
|
||||
|
||||
terminate := func(terr error) (execdriver.ExitStatus, error) {
|
||||
if c.ProcessConfig.Process != nil {
|
||||
c.ProcessConfig.Process.Kill()
|
||||
c.ProcessConfig.Wait()
|
||||
}
|
||||
return execdriver.ExitStatus{ExitCode: -1}, terr
|
||||
}
|
||||
// Poll lxc for RUNNING status
|
||||
pid, err := d.waitForStart(c, waitLock)
|
||||
if err != nil {
|
||||
killNetNsProc(proc)
|
||||
return terminate(err)
|
||||
}
|
||||
killNetNsProc(proc)
|
||||
|
||||
cgroupPaths, err := cgroupPaths(c.ID)
|
||||
if err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
state := &libcontainer.State{
|
||||
InitProcessPid: pid,
|
||||
CgroupPaths: cgroupPaths,
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(dataPath, "state.json"))
|
||||
if err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := json.NewEncoder(f).Encode(state); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
c.ContainerPid = pid
|
||||
|
||||
if hooks.Start != nil {
|
||||
logrus.Debugf("Invoking startCallback")
|
||||
chOOM := make(chan struct{})
|
||||
close(chOOM)
|
||||
hooks.Start(&c.ProcessConfig, pid, chOOM)
|
||||
}
|
||||
|
||||
oomKillNotification := notifyChannelOOM(cgroupPaths)
|
||||
|
||||
<-waitLock
|
||||
exitCode := getExitCode(c)
|
||||
|
||||
_, oomKill := <-oomKillNotification
|
||||
logrus.Debugf("oomKill error: %v, waitErr: %v", oomKill, waitErr)
|
||||
|
||||
// check oom error
|
||||
if oomKill {
|
||||
exitCode = 137
|
||||
}
|
||||
|
||||
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: oomKill}, waitErr
|
||||
}
|
||||
|
||||
func notifyChannelOOM(paths map[string]string) <-chan struct{} {
|
||||
oom, err := notifyOnOOM(paths)
|
||||
if err != nil {
|
||||
logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
|
||||
c := make(chan struct{})
|
||||
close(c)
|
||||
return c
|
||||
}
|
||||
return oom
|
||||
}
|
||||
|
||||
// copy from libcontainer
|
||||
func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
|
||||
dir := paths["memory"]
|
||||
if dir == "" {
|
||||
return nil, fmt.Errorf("There is no path for %q in state", "memory")
|
||||
}
|
||||
oomControl, err := os.Open(filepath.Join(dir, "memory.oom_control"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
|
||||
if syserr != 0 {
|
||||
oomControl.Close()
|
||||
return nil, syserr
|
||||
}
|
||||
|
||||
eventfd := os.NewFile(fd, "eventfd")
|
||||
|
||||
eventControlPath := filepath.Join(dir, "cgroup.event_control")
|
||||
data := fmt.Sprintf("%d %d", eventfd.Fd(), oomControl.Fd())
|
||||
if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil {
|
||||
eventfd.Close()
|
||||
oomControl.Close()
|
||||
return nil, err
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
defer func() {
|
||||
close(ch)
|
||||
eventfd.Close()
|
||||
oomControl.Close()
|
||||
}()
|
||||
buf := make([]byte, 8)
|
||||
for {
|
||||
if _, err := eventfd.Read(buf); err != nil {
|
||||
logrus.Warn(err)
|
||||
return
|
||||
}
|
||||
// When a cgroup is destroyed, an event is sent to eventfd.
|
||||
// So if the control path is gone, return instead of notifying.
|
||||
if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
|
||||
logrus.Warn(err)
|
||||
return
|
||||
}
|
||||
ch <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// createContainer populates and configures the container type with the
|
||||
// data provided by the execdriver.Command
|
||||
func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
|
||||
container := execdriver.InitContainer(c)
|
||||
if err := execdriver.SetupCgroups(container, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return container, nil
|
||||
}
|
||||
|
||||
// Return an map of susbystem -> absolute container cgroup path
|
||||
func cgroupPaths(containerID string) (map[string]string, error) {
|
||||
subsystems, err := cgroups.GetAllSubsystems()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("subsystems: %s", subsystems)
|
||||
paths := make(map[string]string)
|
||||
for _, subsystem := range subsystems {
|
||||
cgroupRoot, cgroupDir, err := findCgroupRootAndDir(subsystem)
|
||||
logrus.Debugf("cgroup path %s %s", cgroupRoot, cgroupDir)
|
||||
if err != nil {
|
||||
//unsupported subystem
|
||||
continue
|
||||
}
|
||||
// if we are running dind
|
||||
dockerPathIdx := strings.LastIndex(cgroupDir, "docker")
|
||||
if dockerPathIdx != -1 {
|
||||
cgroupDir = cgroupDir[:dockerPathIdx-1]
|
||||
}
|
||||
path := filepath.Join(cgroupRoot, cgroupDir, "lxc", containerID)
|
||||
paths[subsystem] = path
|
||||
}
|
||||
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
// this is copy from old libcontainer nodes.go
|
||||
func createDeviceNodes(rootfs string, nodesToCreate []*configs.Device) error {
|
||||
oldMask := syscall.Umask(0000)
|
||||
defer syscall.Umask(oldMask)
|
||||
|
||||
for _, node := range nodesToCreate {
|
||||
if err := createDeviceNode(rootfs, node); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates the device node in the rootfs of the container.
|
||||
func createDeviceNode(rootfs string, node *configs.Device) error {
|
||||
var (
|
||||
dest = filepath.Join(rootfs, node.Path)
|
||||
parent = filepath.Dir(dest)
|
||||
)
|
||||
|
||||
if err := os.MkdirAll(parent, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileMode := node.FileMode
|
||||
switch node.Type {
|
||||
case 'c':
|
||||
fileMode |= syscall.S_IFCHR
|
||||
case 'b':
|
||||
fileMode |= syscall.S_IFBLK
|
||||
default:
|
||||
return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path)
|
||||
}
|
||||
|
||||
if err := syscall.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("mknod %s %s", node.Path, err)
|
||||
}
|
||||
|
||||
if err := syscall.Chown(dest, int(node.Uid), int(node.Gid)); err != nil {
|
||||
return fmt.Errorf("chown %s to %d:%d", node.Path, node.Uid, node.Gid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupUser changes the groups, gid, and uid for the user inside the container
|
||||
// copy from libcontainer, cause not it's private
|
||||
func setupUser(userSpec string) error {
|
||||
// Set up defaults.
|
||||
defaultExecUser := user.ExecUser{
|
||||
Uid: syscall.Getuid(),
|
||||
Gid: syscall.Getgid(),
|
||||
Home: "/",
|
||||
}
|
||||
passwdPath, err := user.GetPasswdPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupPath, err := user.GetGroupPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
execUser, err := user.GetExecUserPath(userSpec, &defaultExecUser, passwdPath, groupPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.Setgroups(execUser.Sgids); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Setgid(execUser.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Setuid(execUser.Uid); err != nil {
|
||||
return err
|
||||
}
|
||||
// if we didn't get HOME already, set it based on the user's HOME
|
||||
if envHome := os.Getenv("HOME"); envHome == "" {
|
||||
if err := os.Setenv("HOME", execUser.Home); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getExitCode returns the exit code of the process.
|
||||
// If the process has not exited -1 will be returned.
|
||||
func getExitCode(c *execdriver.Command) int {
|
||||
if c.ProcessConfig.ProcessState == nil {
|
||||
return -1
|
||||
}
|
||||
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||
}
|
||||
|
||||
// Kill implements the exec driver Driver interface.
|
||||
func (d *Driver) Kill(c *execdriver.Command, sig int) error {
|
||||
if sig == 9 || c.ProcessConfig.Process == nil {
|
||||
return killLxc(c.ID, sig)
|
||||
}
|
||||
|
||||
return c.ProcessConfig.Process.Signal(syscall.Signal(sig))
|
||||
}
|
||||
|
||||
// Pause implements the exec driver Driver interface,
|
||||
// it executes lxc-freeze to pause a container.
|
||||
func (d *Driver) Pause(c *execdriver.Command) error {
|
||||
_, err := exec.LookPath("lxc-freeze")
|
||||
if err == nil {
|
||||
output, errExec := exec.Command("lxc-freeze", "-n", c.ID).CombinedOutput()
|
||||
if errExec != nil {
|
||||
return fmt.Errorf("Err: %s Output: %s", errExec, output)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Unpause implements the exec driver Driver interface,
|
||||
// it executes lxc-unfreeze to unpause a container.
|
||||
func (d *Driver) Unpause(c *execdriver.Command) error {
|
||||
_, err := exec.LookPath("lxc-unfreeze")
|
||||
if err == nil {
|
||||
output, errExec := exec.Command("lxc-unfreeze", "-n", c.ID).CombinedOutput()
|
||||
if errExec != nil {
|
||||
return fmt.Errorf("Err: %s Output: %s", errExec, output)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Terminate implements the exec driver Driver interface.
|
||||
func (d *Driver) Terminate(c *execdriver.Command) error {
|
||||
return killLxc(c.ID, 9)
|
||||
}
|
||||
|
||||
func (d *Driver) version() string {
|
||||
var (
|
||||
version string
|
||||
output []byte
|
||||
err error
|
||||
)
|
||||
if _, errPath := exec.LookPath("lxc-version"); errPath == nil {
|
||||
output, err = exec.Command("lxc-version").CombinedOutput()
|
||||
} else {
|
||||
output, err = exec.Command("lxc-start", "--version").CombinedOutput()
|
||||
}
|
||||
if err == nil {
|
||||
version = strings.TrimSpace(string(output))
|
||||
if parts := strings.SplitN(version, ":", 2); len(parts) == 2 {
|
||||
version = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func killLxc(id string, sig int) error {
|
||||
var (
|
||||
err error
|
||||
output []byte
|
||||
)
|
||||
_, err = exec.LookPath("lxc-kill")
|
||||
if err == nil {
|
||||
output, err = exec.Command("lxc-kill", "-n", id, strconv.Itoa(sig)).CombinedOutput()
|
||||
} else {
|
||||
// lxc-stop does not take arbitrary signals like lxc-kill does
|
||||
output, err = exec.Command("lxc-stop", "-k", "-n", id).CombinedOutput()
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Err: %s Output: %s", err, output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// wait for the process to start and return the pid for the process
|
||||
func (d *Driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) {
|
||||
var (
|
||||
err error
|
||||
output []byte
|
||||
)
|
||||
// We wait for the container to be fully running.
|
||||
// Timeout after 5 seconds. In case of broken pipe, just retry.
|
||||
// Note: The container can run and finish correctly before
|
||||
// the end of this loop
|
||||
for now := time.Now(); time.Since(now) < 5*time.Second; {
|
||||
select {
|
||||
case <-waitLock:
|
||||
// If the process dies while waiting for it, just return
|
||||
return -1, nil
|
||||
default:
|
||||
}
|
||||
|
||||
output, err = d.getInfo(c.ID)
|
||||
if err == nil {
|
||||
info, err := parseLxcInfo(string(output))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if info.Running {
|
||||
return info.Pid, nil
|
||||
}
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
return -1, execdriver.ErrNotRunning
|
||||
}
|
||||
|
||||
func (d *Driver) getInfo(id string) ([]byte, error) {
|
||||
return exec.Command("lxc-info", "-n", id).CombinedOutput()
|
||||
}
|
||||
|
||||
type info struct {
|
||||
ID string
|
||||
driver *Driver
|
||||
}
|
||||
|
||||
func (i *info) IsRunning() bool {
|
||||
var running bool
|
||||
|
||||
output, err := i.driver.getInfo(i.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting info for lxc container %s: %s (%s)", i.ID, err, output)
|
||||
return false
|
||||
}
|
||||
if strings.Contains(string(output), "RUNNING") {
|
||||
running = true
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
// Info implements the exec driver Driver interface.
|
||||
func (d *Driver) Info(id string) execdriver.Info {
|
||||
return &info{
|
||||
ID: id,
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func findCgroupRootAndDir(subsystem string) (string, string, error) {
|
||||
cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return cgroupRoot, cgroupDir, nil
|
||||
}
|
||||
|
||||
// GetPidsForContainer implements the exec driver Driver interface.
|
||||
func (d *Driver) GetPidsForContainer(id string) ([]int, error) {
|
||||
pids := []int{}
|
||||
|
||||
// cpu is chosen because it is the only non optional subsystem in cgroups
|
||||
subsystem := "cpu"
|
||||
cgroupRoot, cgroupDir, err := findCgroupRootAndDir(subsystem)
|
||||
if err != nil {
|
||||
return pids, err
|
||||
}
|
||||
|
||||
filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
// With more recent lxc versions use, cgroup will be in lxc/
|
||||
filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks")
|
||||
}
|
||||
|
||||
output, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return pids, err
|
||||
}
|
||||
for _, p := range strings.Split(string(output), "\n") {
|
||||
if len(p) == 0 {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(p)
|
||||
if err != nil {
|
||||
return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
|
||||
}
|
||||
pids = append(pids, pid)
|
||||
}
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
func linkLxcStart(root string) error {
|
||||
sourcePath, err := exec.LookPath("lxc-start")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
targetPath := path.Join(root, "lxc-start-unconfined")
|
||||
|
||||
if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
} else if err == nil {
|
||||
if err := os.Remove(targetPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return os.Symlink(sourcePath, targetPath)
|
||||
}
|
||||
|
||||
// TODO: This can be moved to the mountinfo reader in the mount pkg
|
||||
func rootIsShared() bool {
|
||||
if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
cols := strings.Split(line, " ")
|
||||
if len(cols) >= 6 && cols[4] == "/" {
|
||||
return strings.HasPrefix(cols[6], "shared")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No idea, probably safe to assume so
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *Driver) containerDir(containerID string) string {
|
||||
return path.Join(d.libPath, "containers", containerID)
|
||||
}
|
||||
|
||||
func (d *Driver) generateLXCConfig(c *execdriver.Command) (string, error) {
|
||||
root := path.Join(d.containerDir(c.ID), "config.lxc")
|
||||
|
||||
fo, err := os.Create(root)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer fo.Close()
|
||||
|
||||
if err := lxcTemplateCompiled.Execute(fo, struct {
|
||||
*execdriver.Command
|
||||
AppArmor bool
|
||||
}{
|
||||
Command: c,
|
||||
AppArmor: d.apparmor,
|
||||
}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (d *Driver) generateEnvConfig(c *execdriver.Command) error {
|
||||
data, err := json.Marshal(c.ProcessConfig.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p := path.Join(d.libPath, "containers", c.ID, "config.env")
|
||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
||||
Source: p,
|
||||
Destination: "/.dockerenv",
|
||||
Writable: false,
|
||||
Private: true,
|
||||
})
|
||||
|
||||
return ioutil.WriteFile(p, data, 0600)
|
||||
}
|
||||
|
||||
// Clean implements the exec driver Driver interface,
|
||||
// it's not implemented by lxc.
|
||||
func (d *Driver) Clean(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TtyConsole implements the exec driver Terminal interface,
|
||||
// it stores the master and slave ends of the container's pty.
|
||||
type TtyConsole struct {
|
||||
MasterPty *os.File
|
||||
SlavePty *os.File
|
||||
}
|
||||
|
||||
// NewTtyConsole returns a new TtyConsole struct.
|
||||
// Wired up to the provided process config and stdin/stdout/stderr pipes.
|
||||
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
// lxc is special in that we cannot create the master outside of the container without
|
||||
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
|
||||
// the crazy setup on command right now instead of passing the console path to lxc and telling it
|
||||
// to open up that console. we save a couple of openfiles in the native driver because we can do
|
||||
// this.
|
||||
ptyMaster, ptySlave, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tty := &TtyConsole{
|
||||
MasterPty: ptyMaster,
|
||||
SlavePty: ptySlave,
|
||||
}
|
||||
|
||||
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
||||
tty.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processConfig.Console = tty.SlavePty.Name()
|
||||
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
// Resize implements Resize method of Terminal interface
|
||||
func (t *TtyConsole) Resize(h, w int) error {
|
||||
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
}
|
||||
|
||||
// AttachPipes attaches given pipes to exec.Cmd
|
||||
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
|
||||
command.Stdout = t.SlavePty
|
||||
command.Stderr = t.SlavePty
|
||||
|
||||
go func() {
|
||||
if wb, ok := pipes.Stdout.(interface {
|
||||
CloseWriters() error
|
||||
}); ok {
|
||||
defer wb.CloseWriters()
|
||||
}
|
||||
|
||||
io.Copy(pipes.Stdout, t.MasterPty)
|
||||
}()
|
||||
|
||||
if pipes.Stdin != nil {
|
||||
command.Stdin = t.SlavePty
|
||||
command.SysProcAttr.Setctty = true
|
||||
|
||||
go func() {
|
||||
io.Copy(t.MasterPty, pipes.Stdin)
|
||||
|
||||
pipes.Stdin.Close()
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements Close method of Terminal interface
|
||||
func (t *TtyConsole) Close() error {
|
||||
t.SlavePty.Close()
|
||||
return t.MasterPty.Close()
|
||||
}
|
||||
|
||||
// Exec implements the exec driver Driver interface,
|
||||
// it is not implemented by lxc.
|
||||
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
return -1, ErrExec
|
||||
}
|
||||
|
||||
// Stats implements the exec driver Driver interface.
|
||||
// Lxc doesn't implement it's own Stats, it does some trick by implementing
|
||||
// execdriver.Stats to get stats info by libcontainer APIs.
|
||||
func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) {
|
||||
if _, ok := d.activeContainers[id]; !ok {
|
||||
return nil, fmt.Errorf("%s is not a key in active containers", id)
|
||||
}
|
||||
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
|
||||
}
|
||||
|
||||
// SupportsHooks implements the execdriver Driver interface.
|
||||
// The LXC execdriver does not support the hook mechanism, which is currently unique to runC/libcontainer.
|
||||
func (d *Driver) SupportsHooks() bool {
|
||||
return false
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Define error messages
|
||||
var (
|
||||
ErrCannotParse = errors.New("cannot parse raw input")
|
||||
)
|
||||
|
||||
type lxcInfo struct {
|
||||
Running bool
|
||||
Pid int
|
||||
}
|
||||
|
||||
func parseLxcInfo(raw string) (*lxcInfo, error) {
|
||||
if raw == "" {
|
||||
return nil, ErrCannotParse
|
||||
}
|
||||
var (
|
||||
err error
|
||||
s = bufio.NewScanner(strings.NewReader(raw))
|
||||
info = &lxcInfo{}
|
||||
)
|
||||
for s.Scan() {
|
||||
text := s.Text()
|
||||
|
||||
if s.Err() != nil {
|
||||
return nil, s.Err()
|
||||
}
|
||||
|
||||
parts := strings.Split(text, ":")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(parts[0])) {
|
||||
case "state":
|
||||
info.Running = strings.TrimSpace(parts[1]) == "RUNNING"
|
||||
case "pid":
|
||||
info.Pid, err = strconv.Atoi(strings.TrimSpace(parts[1]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseRunningInfo(t *testing.T) {
|
||||
raw := `
|
||||
state: RUNNING
|
||||
pid: 50`
|
||||
|
||||
info, err := parseLxcInfo(raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !info.Running {
|
||||
t.Fatal("info should return a running state")
|
||||
}
|
||||
if info.Pid != 50 {
|
||||
t.Fatalf("info should have pid 50 got %d", info.Pid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyInfo(t *testing.T) {
|
||||
_, err := parseLxcInfo("")
|
||||
if err == nil {
|
||||
t.Fatal("error should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadInfo(t *testing.T) {
|
||||
_, err := parseLxcInfo("state")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
||||
// InitArgs contains args provided to the init function for a driver
|
||||
type InitArgs struct {
|
||||
User string
|
||||
Gateway string
|
||||
IP string
|
||||
WorkDir string
|
||||
Privileged bool
|
||||
Env []string
|
||||
Args []string
|
||||
Mtu int
|
||||
Console string
|
||||
Pipe int
|
||||
Root string
|
||||
CapAdd string
|
||||
CapDrop string
|
||||
}
|
||||
|
||||
func init() {
|
||||
// like always lxc requires a hack to get this to work
|
||||
reexec.Register("/.dockerinit", dockerInititalizer)
|
||||
}
|
||||
|
||||
func dockerInititalizer() {
|
||||
initializer()
|
||||
}
|
||||
|
||||
// initializer is the lxc driver's init function that is run inside the namespace to setup
|
||||
// additional configurations
|
||||
func initializer() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
args := getArgs()
|
||||
|
||||
if err := setupNamespace(args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func setupNamespace(args *InitArgs) error {
|
||||
if err := setupEnv(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := finalizeNamespace(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path, err := exec.LookPath(args.Args[0])
|
||||
if err != nil {
|
||||
logrus.Infof("Unable to locate %v", args.Args[0])
|
||||
os.Exit(127)
|
||||
}
|
||||
|
||||
if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
|
||||
return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getArgs() *InitArgs {
|
||||
var (
|
||||
// Get cmdline arguments
|
||||
user = flag.String("u", "", "username or uid")
|
||||
gateway = flag.String("g", "", "gateway address")
|
||||
ip = flag.String("i", "", "ip address")
|
||||
workDir = flag.String("w", "", "workdir")
|
||||
privileged = flag.Bool("privileged", false, "privileged mode")
|
||||
mtu = flag.Int("mtu", 1500, "interface mtu")
|
||||
capAdd = flag.String("cap-add", "", "capabilities to add")
|
||||
capDrop = flag.String("cap-drop", "", "capabilities to drop")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
return &InitArgs{
|
||||
User: *user,
|
||||
Gateway: *gateway,
|
||||
IP: *ip,
|
||||
WorkDir: *workDir,
|
||||
Privileged: *privileged,
|
||||
Args: flag.Args(),
|
||||
Mtu: *mtu,
|
||||
CapAdd: *capAdd,
|
||||
CapDrop: *capDrop,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear environment pollution introduced by lxc-start
|
||||
func setupEnv(args *InitArgs) error {
|
||||
// Get env
|
||||
var env []string
|
||||
dockerenv, err := os.Open(".dockerenv")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to load environment variables: %v", err)
|
||||
}
|
||||
defer dockerenv.Close()
|
||||
if err := json.NewDecoder(dockerenv).Decode(&env); err != nil {
|
||||
return fmt.Errorf("Unable to decode environment variables: %v", err)
|
||||
}
|
||||
// Propagate the plugin-specific container env variable
|
||||
env = append(env, "container="+os.Getenv("container"))
|
||||
|
||||
args.Env = env
|
||||
|
||||
os.Clearenv()
|
||||
for _, kv := range args.Env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
os.Setenv(parts[0], parts[1])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup working directory
|
||||
func setupWorkingDirectory(args *InitArgs) error {
|
||||
if args.WorkDir == "" {
|
||||
return nil
|
||||
}
|
||||
if err := syscall.Chdir(args.WorkDir); err != nil {
|
||||
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
func finalizeNamespace(args *InitArgs) error {
|
||||
if err := utils.CloseExecFrom(3); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupUser(args.User); err != nil {
|
||||
return fmt.Errorf("setup user %s", err)
|
||||
}
|
||||
if err := setupWorkingDirectory(args); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// +build !linux
|
||||
|
||||
package lxc
|
||||
|
||||
// InitArgs contains args provided to the init function for a driver
|
||||
type InitArgs struct {
|
||||
}
|
||||
|
||||
func finalizeNamespace(args *InitArgs) error {
|
||||
panic("Not supported on this platform")
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
"github.com/opencontainers/runc/libcontainer/label"
|
||||
)
|
||||
|
||||
// LxcTemplate is the template for lxc driver, it's used
|
||||
// to configure LXC.
|
||||
const LxcTemplate = `
|
||||
lxc.network.type = none
|
||||
# root filesystem
|
||||
{{$ROOTFS := .Rootfs}}
|
||||
lxc.rootfs = {{$ROOTFS}}
|
||||
|
||||
# use a dedicated pts for the container (and limit the number of pseudo terminal
|
||||
# available)
|
||||
lxc.pts = 1024
|
||||
|
||||
# disable the main console
|
||||
lxc.console = none
|
||||
|
||||
# no controlling tty at all
|
||||
lxc.tty = 1
|
||||
|
||||
{{if .ProcessConfig.Privileged}}
|
||||
lxc.cgroup.devices.allow = a
|
||||
{{else}}
|
||||
# no implicit access to devices
|
||||
lxc.cgroup.devices.deny = a
|
||||
#Allow the devices passed to us in the AllowedDevices list.
|
||||
{{range $allowedDevice := .AllowedDevices}}
|
||||
lxc.cgroup.devices.allow = {{$allowedDevice.CgroupString}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
# standard mount point
|
||||
# Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
|
||||
lxc.pivotdir = lxc_putold
|
||||
|
||||
# lxc.autodev is not compatible with lxc --device switch
|
||||
lxc.autodev = 0
|
||||
|
||||
# NOTICE: These mounts must be applied within the namespace
|
||||
{{if .ProcessConfig.Privileged}}
|
||||
# WARNING: mounting procfs and/or sysfs read-write is a known attack vector.
|
||||
# See e.g. http://blog.zx2c4.com/749 and https://bit.ly/T9CkqJ
|
||||
# We mount them read-write here, but later, dockerinit will call the Restrict() function to remount them read-only.
|
||||
# We cannot mount them directly read-only, because that would prevent loading AppArmor profiles.
|
||||
lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
||||
lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
||||
{{if .AppArmor}}
|
||||
lxc.aa_profile = unconfined
|
||||
{{end}}
|
||||
{{else}}
|
||||
# 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 .AppArmorProfile}}
|
||||
lxc.aa_profile = {{.AppArmorProfile}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .ProcessConfig.Tty}}
|
||||
lxc.mount.entry = {{.ProcessConfig.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw,create=file 0 0
|
||||
{{end}}
|
||||
|
||||
lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMountLabel "newinstance,ptmxmode=0666,nosuid,noexec,create=dir" ""}} 0 0
|
||||
lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec,create=dir" ""}} 0 0
|
||||
|
||||
{{range $value := .Mounts}}
|
||||
{{$createVal := isDirectory $value.Source}}
|
||||
{{if $value.Writable}}
|
||||
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
|
||||
{{else}}
|
||||
lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
# limits
|
||||
{{if .Resources}}
|
||||
{{if .Resources.Memory}}
|
||||
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
|
||||
{{end}}
|
||||
{{if gt .Resources.MemorySwap 0}}
|
||||
lxc.cgroup.memory.memsw.limit_in_bytes = {{.Resources.MemorySwap}}
|
||||
{{end}}
|
||||
{{if gt .Resources.MemoryReservation 0}}
|
||||
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.MemoryReservation}}
|
||||
{{end}}
|
||||
{{if gt .Resources.KernelMemory 0}}
|
||||
lxc.cgroup.memory.kmem.limit_in_bytes = {{.Resources.KernelMemory}}
|
||||
{{end}}
|
||||
{{if .Resources.CPUShares}}
|
||||
lxc.cgroup.cpu.shares = {{.Resources.CPUShares}}
|
||||
{{end}}
|
||||
{{if .Resources.CPUPeriod}}
|
||||
lxc.cgroup.cpu.cfs_period_us = {{.Resources.CPUPeriod}}
|
||||
{{end}}
|
||||
{{if .Resources.CpusetCpus}}
|
||||
lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
|
||||
{{end}}
|
||||
{{if .Resources.CpusetMems}}
|
||||
lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}}
|
||||
{{end}}
|
||||
{{if .Resources.CPUQuota}}
|
||||
lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CPUQuota}}
|
||||
{{end}}
|
||||
{{if .Resources.BlkioWeight}}
|
||||
lxc.cgroup.blkio.weight = {{.Resources.BlkioWeight}}
|
||||
{{end}}
|
||||
{{if .Resources.OomKillDisable}}
|
||||
lxc.cgroup.memory.oom_control = {{.Resources.OomKillDisable}}
|
||||
{{end}}
|
||||
{{if gt .Resources.MemorySwappiness 0}}
|
||||
lxc.cgroup.memory.swappiness = {{.Resources.MemorySwappiness}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .LxcConfig}}
|
||||
{{range $value := .LxcConfig}}
|
||||
lxc.{{$value}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .ProcessConfig.Env}}
|
||||
lxc.utsname = {{getHostname .ProcessConfig.Env}}
|
||||
{{end}}
|
||||
|
||||
{{if .ProcessConfig.Privileged}}
|
||||
# No cap values are needed, as lxc is starting in privileged mode
|
||||
{{else}}
|
||||
{{ with keepCapabilities .CapAdd .CapDrop }}
|
||||
{{range .}}
|
||||
lxc.cap.keep = {{.}}
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{ with dropList .CapDrop }}
|
||||
{{range .}}
|
||||
lxc.cap.drop = {{.}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
`
|
||||
|
||||
var lxcTemplateCompiled *template.Template
|
||||
|
||||
// Escape spaces in strings according to the fstab documentation, which is the
|
||||
// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
|
||||
func escapeFstabSpaces(field string) string {
|
||||
return strings.Replace(field, " ", "\\040", -1)
|
||||
}
|
||||
|
||||
func keepCapabilities(adds []string, drops []string) ([]string, error) {
|
||||
container := nativeTemplate.New()
|
||||
logrus.Debugf("adds %s drops %s\n", adds, drops)
|
||||
caps, err := execdriver.TweakCapabilities(container.Capabilities, adds, drops)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var newCaps []string
|
||||
for _, cap := range caps {
|
||||
logrus.Debugf("cap %s\n", cap)
|
||||
realCap := execdriver.GetCapability(cap)
|
||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
||||
newCaps = append(newCaps, numCap)
|
||||
}
|
||||
|
||||
return newCaps, nil
|
||||
}
|
||||
|
||||
func dropList(drops []string) ([]string, error) {
|
||||
if stringutils.InSlice(drops, "all") {
|
||||
var newCaps []string
|
||||
for _, capName := range execdriver.GetAllCapabilities() {
|
||||
cap := execdriver.GetCapability(capName)
|
||||
logrus.Debugf("drop cap %s\n", cap.Key)
|
||||
numCap := fmt.Sprintf("%d", cap.Value)
|
||||
newCaps = append(newCaps, numCap)
|
||||
}
|
||||
return newCaps, nil
|
||||
}
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func isDirectory(source string) string {
|
||||
f, err := os.Stat(source)
|
||||
logrus.Debugf("dir: %s\n", source)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "dir"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
if f.IsDir() {
|
||||
return "dir"
|
||||
}
|
||||
return "file"
|
||||
}
|
||||
|
||||
func getLabel(c map[string][]string, name string) string {
|
||||
label := c["label"]
|
||||
for _, l := range label {
|
||||
parts := strings.SplitN(l, "=", 2)
|
||||
if strings.TrimSpace(parts[0]) == name {
|
||||
return strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getHostname(env []string) string {
|
||||
for _, kv := range env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if parts[0] == "HOSTNAME" && len(parts) == 2 {
|
||||
return parts[1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
funcMap := template.FuncMap{
|
||||
"escapeFstabSpaces": escapeFstabSpaces,
|
||||
"formatMountLabel": label.FormatMountLabel,
|
||||
"isDirectory": isDirectory,
|
||||
"keepCapabilities": keepCapabilities,
|
||||
"dropList": dropList,
|
||||
"getHostname": getHostname,
|
||||
}
|
||||
lxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package lxc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
func TestLXCConfig(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "TestLXCConfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
|
||||
// Memory is allocated randomly for testing
|
||||
r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
|
||||
var (
|
||||
memMin = 33554432
|
||||
memMax = 536870912
|
||||
mem = memMin + r.Intn(memMax-memMin)
|
||||
swap = memMax
|
||||
cpuMin = 100
|
||||
cpuMax = 10000
|
||||
cpu = cpuMin + r.Intn(cpuMax-cpuMin)
|
||||
)
|
||||
|
||||
driver, err := NewDriver(root, root, "", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := &execdriver.Command{
|
||||
CommonCommand: execdriver.CommonCommand{
|
||||
ID: "1",
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: execdriver.ProcessConfig{},
|
||||
Resources: &execdriver.Resources{
|
||||
MemorySwap: int64(swap),
|
||||
CommonResources: execdriver.CommonResources{
|
||||
Memory: int64(mem),
|
||||
CPUShares: int64(cpu),
|
||||
},
|
||||
},
|
||||
},
|
||||
AllowedDevices: make([]*configs.Device, 0),
|
||||
}
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
grepFile(t, p,
|
||||
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
|
||||
|
||||
grepFile(t, p,
|
||||
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", swap))
|
||||
}
|
||||
|
||||
func TestCustomLxcConfig(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
|
||||
driver, err := NewDriver(root, root, "", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
processConfig := execdriver.ProcessConfig{
|
||||
Privileged: false,
|
||||
}
|
||||
command := &execdriver.Command{
|
||||
CommonCommand: execdriver.CommonCommand{
|
||||
ID: "1",
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
},
|
||||
LxcConfig: []string{
|
||||
"lxc.utsname = docker",
|
||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
grepFile(t, p, "lxc.utsname = docker")
|
||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
||||
}
|
||||
|
||||
func grepFile(t *testing.T, path string, pattern string) {
|
||||
grepFileWithReverse(t, path, pattern, false)
|
||||
}
|
||||
|
||||
func grepFileWithReverse(t *testing.T, path string, pattern string, inverseGrep bool) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := bufio.NewReader(f)
|
||||
var (
|
||||
line string
|
||||
)
|
||||
err = nil
|
||||
for err == nil {
|
||||
line, err = r.ReadString('\n')
|
||||
if strings.Contains(line, pattern) == true {
|
||||
if inverseGrep {
|
||||
t.Fatalf("grepFile: pattern \"%s\" found in \"%s\"", pattern, path)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if inverseGrep {
|
||||
return
|
||||
}
|
||||
t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
|
||||
}
|
||||
|
||||
func TestEscapeFstabSpaces(t *testing.T) {
|
||||
var testInputs = map[string]string{
|
||||
" ": "\\040",
|
||||
"": "",
|
||||
"/double space": "/double\\040\\040space",
|
||||
"/some long test string": "/some\\040long\\040test\\040string",
|
||||
"/var/lib/docker": "/var/lib/docker",
|
||||
" leading": "\\040leading",
|
||||
"trailing ": "trailing\\040",
|
||||
}
|
||||
for in, exp := range testInputs {
|
||||
if out := escapeFstabSpaces(in); exp != out {
|
||||
t.Logf("Expected %s got %s", exp, out)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDirectory(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "TestIsDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if isDirectory(tempDir) != "dir" {
|
||||
t.Logf("Could not identify %s as a directory", tempDir)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if isDirectory(tempFile.Name()) != "file" {
|
||||
t.Logf("Could not identify %s as a file", tempFile.Name())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomLxcConfigMounts(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
tempDir, err := ioutil.TempDir("", "TestIsDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
|
||||
driver, err := NewDriver(root, root, "", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
processConfig := execdriver.ProcessConfig{
|
||||
Privileged: false,
|
||||
}
|
||||
mounts := []execdriver.Mount{
|
||||
{
|
||||
Source: tempDir,
|
||||
Destination: tempDir,
|
||||
Writable: false,
|
||||
Private: true,
|
||||
},
|
||||
{
|
||||
Source: tempFile.Name(),
|
||||
Destination: tempFile.Name(),
|
||||
Writable: true,
|
||||
Private: true,
|
||||
},
|
||||
}
|
||||
command := &execdriver.Command{
|
||||
CommonCommand: execdriver.CommonCommand{
|
||||
ID: "1",
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
},
|
||||
Mounts: mounts,
|
||||
ProcessConfig: processConfig,
|
||||
},
|
||||
LxcConfig: []string{
|
||||
"lxc.utsname = docker",
|
||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
grepFile(t, p, "lxc.utsname = docker")
|
||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
||||
|
||||
grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir"))
|
||||
grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file"))
|
||||
}
|
||||
|
||||
func TestCustomLxcConfigMisc(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
driver, err := NewDriver(root, root, "", true)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
processConfig := execdriver.ProcessConfig{
|
||||
Privileged: false,
|
||||
}
|
||||
|
||||
processConfig.Env = []string{"HOSTNAME=testhost"}
|
||||
command := &execdriver.Command{
|
||||
CommonCommand: execdriver.CommonCommand{
|
||||
ID: "1",
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
},
|
||||
LxcConfig: []string{
|
||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
},
|
||||
CapAdd: []string{"net_admin", "syslog"},
|
||||
CapDrop: []string{"kill", "mknod"},
|
||||
AppArmorProfile: "lxc-container-default-with-nesting",
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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")
|
||||
container := nativeTemplate.New()
|
||||
for _, cap := range container.Capabilities {
|
||||
realCap := execdriver.GetCapability(cap)
|
||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
||||
if cap != "MKNOD" && cap != "KILL" {
|
||||
grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
|
||||
}
|
||||
}
|
||||
|
||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
|
||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
|
||||
}
|
||||
|
||||
func TestCustomLxcConfigMiscOverride(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "TestCustomLxcConfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
os.MkdirAll(path.Join(root, "containers", "1"), 0777)
|
||||
driver, err := NewDriver(root, root, "", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
processConfig := execdriver.ProcessConfig{
|
||||
Privileged: false,
|
||||
}
|
||||
|
||||
processConfig.Env = []string{"HOSTNAME=testhost"}
|
||||
command := &execdriver.Command{
|
||||
CommonCommand: execdriver.CommonCommand{
|
||||
ID: "1",
|
||||
Network: &execdriver.Network{
|
||||
Mtu: 1500,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
},
|
||||
LxcConfig: []string{
|
||||
"lxc.cgroup.cpuset.cpus = 0,1",
|
||||
"lxc.network.ipv4 = 172.0.0.1",
|
||||
},
|
||||
CapAdd: []string{"NET_ADMIN", "SYSLOG"},
|
||||
CapDrop: []string{"KILL", "MKNOD"},
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// hostname
|
||||
grepFile(t, p, "lxc.utsname = testhost")
|
||||
grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
|
||||
container := nativeTemplate.New()
|
||||
for _, cap := range container.Capabilities {
|
||||
realCap := execdriver.GetCapability(cap)
|
||||
numCap := fmt.Sprintf("%d", realCap.Value)
|
||||
if cap != "MKNOD" && cap != "KILL" {
|
||||
grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
|
||||
}
|
||||
}
|
||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
|
||||
grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
|
||||
}
|
|
@ -1504,7 +1504,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
|
|||
}
|
||||
|
||||
// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
|
||||
// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
|
||||
// that are not Close-on-exec,
|
||||
// so we add this badhack to make sure it closes itself
|
||||
setCloseOnExec("/dev/mapper/control")
|
||||
|
||||
|
|
|
@ -128,7 +128,6 @@ func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.Co
|
|||
Name: container.Name,
|
||||
RestartCount: container.RestartCount,
|
||||
Driver: container.Driver,
|
||||
ExecDriver: container.ExecDriver,
|
||||
MountLabel: container.MountLabel,
|
||||
ProcessLabel: container.ProcessLabel,
|
||||
ExecIDs: container.getExecIDs(),
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
|
@ -2,14 +2,7 @@
|
|||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/opencontainers/runc/libcontainer/selinux"
|
||||
)
|
||||
import "github.com/opencontainers/runc/libcontainer/selinux"
|
||||
|
||||
func selinuxSetDisabled() {
|
||||
selinux.SetDisabled()
|
||||
|
@ -22,27 +15,3 @@ func selinuxFreeLxcContexts(label string) {
|
|||
func selinuxEnabled() bool {
|
||||
return selinux.SelinuxEnabled()
|
||||
}
|
||||
|
||||
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error) {
|
||||
if hostConfig == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := []string{}
|
||||
|
||||
// merge in the lxc conf options into the generic config map
|
||||
if lxcConf := hostConfig.LxcConf; lxcConf != nil {
|
||||
lxSlice := lxcConf.Slice()
|
||||
for _, pair := range lxSlice {
|
||||
// because lxc conf gets the driver name lxc.XXXX we need to trim it off
|
||||
// and let the lxc driver add it back later if needed
|
||||
if !strings.Contains(pair.Key, ".") {
|
||||
return nil, errors.New("Illegal Key passed into LXC Configurations")
|
||||
}
|
||||
parts := strings.SplitN(pair.Key, ".", 2)
|
||||
out = append(out, fmt.Sprintf("%s=%s", parts[1], pair.Value))
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// +build linux
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
func TestMergeLxcConfig(t *testing.T) {
|
||||
kv := []runconfig.KeyValuePair{
|
||||
{"lxc.cgroups.cpuset", "1,2"},
|
||||
}
|
||||
hostConfig := &runconfig.HostConfig{
|
||||
LxcConf: runconfig.NewLxcConfig(kv),
|
||||
}
|
||||
|
||||
out, err := mergeLxcConfIntoOptions(hostConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to merge Lxc Config: %s", err)
|
||||
}
|
||||
|
||||
cpuset := out[0]
|
||||
if expected := "cgroups.cpuset=1,2"; cpuset != expected {
|
||||
t.Fatalf("expected %s got %s", expected, cpuset)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ package main
|
|||
|
||||
import (
|
||||
systemdDaemon "github.com/coreos/go-systemd/daemon"
|
||||
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
||||
)
|
||||
|
||||
// notifySystem sends a message to the host when the server is ready to be used
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/docker/docker/daemon/execdriver/lxc"
|
||||
_ "github.com/docker/docker/daemon/execdriver/native"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
|
|
@ -212,7 +212,6 @@ recommendations.
|
|||
dpkg-sig \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
lxc=1.0* \
|
||||
mercurial \
|
||||
reprepro \
|
||||
ruby1.9.1 \
|
||||
|
|
|
@ -29,7 +29,6 @@ in the packages. The core dependencies are:
|
|||
- bridge-utils
|
||||
- device-mapper
|
||||
- iproute2
|
||||
- lxc
|
||||
- sqlite
|
||||
|
||||
## Installation
|
||||
|
|
|
@ -50,7 +50,6 @@ IRC channel on the Freenode network.
|
|||
| contrib | Yes |Install additional contributed scripts and components.|
|
||||
| device-mapper | Yes |Enables dependencies for the "devicemapper" graph driver, including necessary kernel flags.|
|
||||
| doc | |Add extra documentation (API, Javadoc, etc). It is recommended to enable per package instead of globally.|
|
||||
| lxc | |Enables dependencies for the "lxc" execution driver.|
|
||||
| vim-syntax | |Pulls in related vim syntax scripts.|
|
||||
| zsh-completion| |Enable zsh completion support.|
|
||||
|
||||
|
|
|
@ -175,7 +175,6 @@ Create a container
|
|||
"HostConfig": {
|
||||
"Binds": ["/tmp:/tmp"],
|
||||
"Links": ["redis3:redis"],
|
||||
"LxcConf": {"lxc.utsname":"docker"},
|
||||
"Memory": 0,
|
||||
"MemorySwap": 0,
|
||||
"MemoryReservation": 0,
|
||||
|
@ -271,8 +270,6 @@ Json Parameters:
|
|||
+ `volume_name:container_path:ro` to make the bind mount read-only inside the container.
|
||||
- **Links** - A list of links for the container. Each link entry should be
|
||||
in the form of `container_name:alias`.
|
||||
- **LxcConf** - LXC specific configurations. These configurations only
|
||||
work when using the `lxc` execution driver.
|
||||
- **PortBindings** - A map of exposed container ports and the host port they
|
||||
should map to. A JSON object in the form
|
||||
`{ <port>/<protocol>: [{ "HostPort": "<port>" }] }`
|
||||
|
@ -676,8 +673,6 @@ Status Codes:
|
|||
|
||||
This endpoint returns a live stream of a container's resource usage statistics.
|
||||
|
||||
> **Note**: this functionality currently only works when using the *libcontainer* exec-driver.
|
||||
|
||||
**Example request**:
|
||||
|
||||
GET /containers/redis1/stats HTTP/1.1
|
||||
|
|
|
@ -48,7 +48,6 @@ Creates a new container.
|
|||
--link=[] Add link to another container
|
||||
--log-driver="" Logging driver for container
|
||||
--log-opt=[] Log driver specific options
|
||||
--lxc-conf=[] Add custom lxc options
|
||||
-m, --memory="" Memory limit
|
||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||
--memory-reservation="" Memory soft limit
|
||||
|
|
|
@ -29,7 +29,6 @@ weight = -1
|
|||
--dns-opt=[] DNS options to use
|
||||
--dns-search=[] DNS search domains to use
|
||||
--default-ulimit=[] Set default ulimit settings for containers
|
||||
-e, --exec-driver="native" Exec driver to use
|
||||
--exec-opt=[] Set exec driver options
|
||||
--exec-root="/var/run/docker" Root of the Docker execdriver
|
||||
--fixed-cidr="" IPv4 subnet for fixed IPs
|
||||
|
@ -439,11 +438,6 @@ Currently supported options of `zfs`:
|
|||
The Docker daemon uses a specifically built `libcontainer` execution driver as
|
||||
its interface to the Linux kernel `namespaces`, `cgroups`, and `SELinux`.
|
||||
|
||||
There is still legacy support for the original [LXC userspace tools](
|
||||
https://linuxcontainers.org/) via the `lxc` execution driver, however, this is
|
||||
not where the primary development of new functionality is taking place.
|
||||
Add `-e lxc` to the daemon flags to use the `lxc` execution driver.
|
||||
|
||||
## Options for the native execdriver
|
||||
|
||||
You can configure the `native` (libcontainer) execdriver using options specified
|
||||
|
|
|
@ -47,7 +47,6 @@ parent = "smn_cli"
|
|||
--link=[] Add link to another container
|
||||
--log-driver="" Logging driver for container
|
||||
--log-opt=[] Log driver specific options
|
||||
--lxc-conf=[] Add custom lxc options
|
||||
-m, --memory="" Memory limit
|
||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||
--memory-reservation="" Memory soft limit
|
||||
|
|
|
@ -39,7 +39,6 @@ defaults related to:
|
|||
* container identification
|
||||
* network settings
|
||||
* runtime constraints on CPU and memory
|
||||
* privileges and LXC configuration
|
||||
|
||||
With the `docker run [OPTIONS]` an operator can add to or override the
|
||||
image defaults set by a developer. And, additionally, operators can
|
||||
|
@ -75,7 +74,7 @@ following options.
|
|||
- [Restart policies (--restart)](#restart-policies-restart)
|
||||
- [Clean up (--rm)](#clean-up-rm)
|
||||
- [Runtime constraints on resources](#runtime-constraints-on-resources)
|
||||
- [Runtime privilege, Linux capabilities, and LXC configuration](#runtime-privilege-linux-capabilities-and-lxc-configuration)
|
||||
- [Runtime privilege and Linux capabilities](#runtime-privilege-and-linux-capabilities)
|
||||
|
||||
## Detached vs foreground
|
||||
|
||||
|
@ -965,21 +964,18 @@ one can use this flag:
|
|||
$ docker run -ti --rm --group-add audio --group-add dbus --group-add 777 busybox id
|
||||
uid=0(root) gid=0(root) groups=10(wheel),29(audio),81(dbus),777
|
||||
|
||||
## Runtime privilege, Linux capabilities, and LXC configuration
|
||||
## Runtime privilege and Linux capabilities
|
||||
|
||||
--cap-add: Add Linux capabilities
|
||||
--cap-drop: Drop Linux capabilities
|
||||
--privileged=false: Give extended privileges to this container
|
||||
--device=[]: Allows you to run devices inside the container without the --privileged flag.
|
||||
--lxc-conf=[]: Add custom lxc options
|
||||
|
||||
By default, Docker containers are "unprivileged" and cannot, for
|
||||
example, run a Docker daemon inside a Docker container. This is because
|
||||
by default a container is not allowed to access any devices, but a
|
||||
"privileged" container is given access to all devices (see [lxc-template.go](
|
||||
https://github.com/docker/docker/blob/master/daemon/execdriver/lxc/lxc_template.go)
|
||||
and documentation on [cgroups devices](
|
||||
https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
|
||||
"privileged" container is given access to all devices (see
|
||||
the documentation on [cgroups devices](https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
|
||||
|
||||
When the operator executes `docker run --privileged`, Docker will enable
|
||||
to access to all devices on the host as well as set some configuration
|
||||
|
@ -1093,22 +1089,6 @@ To mount a FUSE based filesystem, you need to combine both `--cap-add` and
|
|||
....
|
||||
|
||||
|
||||
If the Docker daemon was started using the `lxc` exec-driver
|
||||
(`docker daemon --exec-driver=lxc`) then the operator can also specify LXC options
|
||||
using one or more `--lxc-conf` parameters. These can be new parameters or
|
||||
override existing parameters from the [lxc-template.go](
|
||||
https://github.com/docker/docker/blob/master/daemon/execdriver/lxc/lxc_template.go).
|
||||
Note that in the future, a given host's docker daemon may not use LXC, so this
|
||||
is an implementation-specific configuration meant for operators already
|
||||
familiar with using LXC directly.
|
||||
|
||||
> **Note:**
|
||||
> If you use `--lxc-conf` to modify a container's configuration which is also
|
||||
> managed by the Docker daemon, then the Docker daemon will not know about this
|
||||
> modification, and you will need to manage any conflicts yourself. For example,
|
||||
> you can use `--lxc-conf` to set a container's IP address, but this will not be
|
||||
> reflected in the `/etc/hosts` file.
|
||||
|
||||
## Logging drivers (--log-driver)
|
||||
|
||||
The container can have a different logging driver than the Docker daemon. Use
|
||||
|
@ -1290,7 +1270,6 @@ above, or already defined by the developer with a Dockerfile `ENV`:
|
|||
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
declare -x PWD="/"
|
||||
declare -x SHLVL="1"
|
||||
declare -x container="lxc"
|
||||
declare -x deep="purple"
|
||||
|
||||
Similarly the operator can set the **hostname** with `-h`.
|
||||
|
|
|
@ -109,7 +109,6 @@ running a Docker daemon with experimental user namespaces enabled:
|
|||
- A `--readonly` container filesystem (a Linux kernel restriction on remount with new flags of a currently mounted filesystem when inside a user namespace)
|
||||
- external (volume/graph) drivers which are unaware/incapable of using daemon user mappings
|
||||
- Using `--privileged` mode containers
|
||||
- Using the lxc execdriver (only the `native` execdriver is enabled to use user namespaces)
|
||||
- volume use without pre-arranging proper file ownership in mounted volumes
|
||||
|
||||
Additionally, while the `root` user inside a user namespaced container
|
||||
|
|
|
@ -31,13 +31,6 @@ if ! mountpoint -q /sys/fs/cgroup; then
|
|||
# Mount the cgroup hierarchies exactly as they are in the parent system.
|
||||
for HIER in $(cut -d: -f2 /proc/1/cgroup); do
|
||||
|
||||
# The following sections address a bug which manifests itself
|
||||
# by a cryptic "lxc-start: no ns_cgroup option specified" when
|
||||
# trying to start containers within a container.
|
||||
# The bug seems to appear when the cgroup hierarchies are not
|
||||
# mounted on the exact same directories in the host, and in the
|
||||
# container.
|
||||
|
||||
SUBSYSTEMS="${HIER%name=*}"
|
||||
|
||||
# If cgroup hierarchy is named(mounted with "-o name=foo") we
|
||||
|
|
|
@ -109,10 +109,6 @@ if [ -z "$DOCKER_CLIENTONLY" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ "$DOCKER_EXECDRIVER" = 'lxc' ]; then
|
||||
DOCKER_BUILDTAGS+=' test_no_exec'
|
||||
fi
|
||||
|
||||
# test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately
|
||||
if \
|
||||
command -v gcc &> /dev/null \
|
||||
|
|
|
@ -13,7 +13,6 @@ fi
|
|||
exec 41>&1 42>&2
|
||||
|
||||
export DOCKER_GRAPHDRIVER=${DOCKER_GRAPHDRIVER:-vfs}
|
||||
export DOCKER_EXECDRIVER=${DOCKER_EXECDRIVER:-native}
|
||||
export DOCKER_USERLANDPROXY=${DOCKER_USERLANDPROXY:-true}
|
||||
|
||||
# example usage: DOCKER_STORAGE_OPTS="dm.basesize=20G,dm.loopdatasize=200G"
|
||||
|
@ -49,7 +48,6 @@ if [ -z "$DOCKER_TEST_HOST" ]; then
|
|||
docker daemon --debug \
|
||||
--host "$DOCKER_HOST" \
|
||||
--storage-driver "$DOCKER_GRAPHDRIVER" \
|
||||
--exec-driver "$DOCKER_EXECDRIVER" \
|
||||
--pidfile "$DEST/docker.pid" \
|
||||
--userland-proxy="$DOCKER_USERLANDPROXY" \
|
||||
$storage_params \
|
||||
|
|
|
@ -27,7 +27,6 @@ func (s *DockerSuite) TestExecResizeApiHeightWidthNoInt(c *check.C) {
|
|||
// Part of #14845
|
||||
func (s *DockerSuite) TestExecResizeImmediatelyAfterExecStart(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
|
||||
name := "exec_resize_test"
|
||||
dockerCmd(c, "run", "-d", "-i", "-t", "--name", name, "--restart", "always", "busybox", "/bin/sh")
|
||||
|
|
|
@ -18,7 +18,7 @@ func (s *DockerSuite) TestInspectApiContainerResponse(c *check.C) {
|
|||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
keysBase := []string{"Id", "State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings",
|
||||
"ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "ExecDriver", "MountLabel", "ProcessLabel", "GraphDriver"}
|
||||
"ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "MountLabel", "ProcessLabel", "GraphDriver"}
|
||||
|
||||
cases := []struct {
|
||||
version string
|
||||
|
|
|
@ -5459,7 +5459,6 @@ func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) {
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, SameHostDaemon)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
|
|
|
@ -870,7 +870,7 @@ func (s *DockerDaemonSuite) TestDaemonDefaultGatewayIPv4ExplicitOutsideContainer
|
|||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestDaemonDefaultNetworkInvalidClusterConfig(c *check.C) {
|
||||
testRequires(c, SameHostDaemon)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
// Start daemon without docker0 bridge
|
||||
defaultNetworkBridge := "docker0"
|
||||
|
@ -1032,7 +1032,7 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *che
|
|||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) {
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
if err := s.d.StartWithBusybox("--default-ulimit", "nofile=42:42", "--default-ulimit", "nproc=1024:1024"); err != nil {
|
||||
c.Fatal(err)
|
||||
|
@ -1527,7 +1527,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterCrash(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestRunContainerWithBridgeNone(c *check.C) {
|
||||
testRequires(c, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
c.Assert(s.d.StartWithBusybox("-b", "none"), check.IsNil)
|
||||
|
||||
out, err := s.d.Cmd("run", "--rm", "busybox", "ip", "l")
|
||||
|
|
|
@ -58,8 +58,8 @@ func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
|
|||
"C /dev": true,
|
||||
"A /dev/full": true, // busybox
|
||||
"C /dev/ptmx": true, // libcontainer
|
||||
"A /dev/mqueue": true, // lxc
|
||||
"A /dev/kmsg": true, // lxc
|
||||
"A /dev/mqueue": true,
|
||||
"A /dev/kmsg": true,
|
||||
"A /dev/fd": true,
|
||||
"A /dev/fuse": true,
|
||||
"A /dev/ptmx": true,
|
||||
|
|
|
@ -47,7 +47,6 @@ func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, oomControl)
|
||||
testRequires(c, NotGCCGO)
|
||||
|
||||
|
@ -84,7 +83,6 @@ func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestEventsOOMDisableTrue(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, oomControl)
|
||||
testRequires(c, NotGCCGO)
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ func (s *DockerSuite) TestExperimentalVersion(c *check.C) {
|
|||
// 1. validate uid/gid maps are set properly
|
||||
// 2. verify that files created are owned by remapped root
|
||||
func (s *DockerDaemonSuite) TestDaemonUserNamespaceRootSetting(c *check.C) {
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, SameHostDaemon)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
|
||||
c.Assert(s.d.StartWithBusybox("--userns-remap", "default"), checker.IsNil)
|
||||
|
||||
|
|
|
@ -50,8 +50,7 @@ func getContainerStatus(c *check.C, containerID string) string {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestNetworkNat(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
msg := "it works"
|
||||
startServerContainer(c, msg, 8080)
|
||||
endpoint := getExternalAddress(c)
|
||||
|
@ -67,8 +66,7 @@ func (s *DockerSuite) TestNetworkNat(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestNetworkLocalhostTCPNat(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon)
|
||||
var (
|
||||
msg = "hi yall"
|
||||
)
|
||||
|
@ -85,8 +83,7 @@ func (s *DockerSuite) TestNetworkLocalhostTCPNat(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestNetworkLoopbackNat(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
|
||||
msg := "it works"
|
||||
startServerContainer(c, msg, 8080)
|
||||
endpoint := getExternalAddress(c)
|
||||
|
|
|
@ -66,13 +66,11 @@ func (s *DockerSuite) TestRunLookupGoogleDns(c *check.C) {
|
|||
}
|
||||
|
||||
// the exit code should be 0
|
||||
// some versions of lxc might make this test fail
|
||||
func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
|
||||
dockerCmd(c, "run", "busybox", "true")
|
||||
}
|
||||
|
||||
// the exit code should be 1
|
||||
// some versions of lxc might make this test fail
|
||||
func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
|
||||
_, exitCode, err := dockerCmdWithError("run", "busybox", "false")
|
||||
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
|
||||
|
@ -84,7 +82,6 @@ func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
|
|||
}
|
||||
|
||||
// it should be possible to pipe in data via stdin to a process running in a container
|
||||
// some versions of lxc might make this test fail
|
||||
func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
|
||||
// TODO Windows: This needs some work to make compatible.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
@ -262,7 +259,7 @@ func (s *DockerSuite) TestRunCreateVolumesInSymlinkDir(c *check.C) {
|
|||
if daemonPlatform == "windows" {
|
||||
testRequires(c, SameHostDaemon, WindowsDaemonSupportsVolumes)
|
||||
} else {
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver)
|
||||
testRequires(c, SameHostDaemon)
|
||||
}
|
||||
|
||||
name := "test-volume-symlink"
|
||||
|
@ -664,7 +661,7 @@ func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
||||
// TODO Windows: Environment handling is different between Linux and
|
||||
// Windows and this test relies currently on lxc and unix functionality.
|
||||
// Windows and this test relies currently on unix functionality.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env")
|
||||
cmd.Env = append(os.Environ(),
|
||||
|
@ -677,13 +674,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
|||
c.Fatal(err, out)
|
||||
}
|
||||
|
||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
||||
actualEnv := []string{}
|
||||
for i := range actualEnvLxc {
|
||||
if actualEnvLxc[i] != "container=lxc" {
|
||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
||||
}
|
||||
}
|
||||
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||
sort.Strings(actualEnv)
|
||||
|
||||
goodEnv := []string{
|
||||
|
@ -709,7 +700,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
||||
// TODO Windows: Environment handling is different between Linux and
|
||||
// Windows and this test relies currently on lxc and unix functionality.
|
||||
// Windows and this test relies currently on unix functionality.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Test to make sure that when we use -e on env vars that are
|
||||
|
@ -724,13 +715,7 @@ func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
|||
c.Fatal(err, out)
|
||||
}
|
||||
|
||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
||||
actualEnv := []string{}
|
||||
for i := range actualEnvLxc {
|
||||
if actualEnvLxc[i] != "container=lxc" {
|
||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
||||
}
|
||||
}
|
||||
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||
sort.Strings(actualEnv)
|
||||
|
||||
goodEnv := []string{
|
||||
|
@ -750,7 +735,7 @@ func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
|
||||
// TODO Windows: Environment handling is different between Linux and
|
||||
// Windows and this test relies currently on lxc and unix functionality.
|
||||
// Windows and this test relies currently on unix functionality.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Test to make sure that when we use -e on env vars that are
|
||||
|
@ -764,13 +749,7 @@ func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
|
|||
c.Fatal(err, out)
|
||||
}
|
||||
|
||||
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n")
|
||||
actualEnv := []string{}
|
||||
for i := range actualEnvLxc {
|
||||
if actualEnvLxc[i] != "container=lxc" {
|
||||
actualEnv = append(actualEnv, actualEnvLxc[i])
|
||||
}
|
||||
}
|
||||
actualEnv := strings.Split(strings.TrimSpace(out), "\n")
|
||||
sort.Strings(actualEnv)
|
||||
|
||||
goodEnv := []string{
|
||||
|
@ -944,7 +923,7 @@ func (s *DockerSuite) TestRunCapAddALLDropNetAdminCanDownInterface(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunGroupAdd(c *check.C) {
|
||||
// Not applicable for Windows as there is no concept of --group-add
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, _ := dockerCmd(c, "run", "--group-add=audio", "--group-add=staff", "--group-add=777", "busybox", "sh", "-c", "id")
|
||||
|
||||
groupsList := "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777"
|
||||
|
@ -1301,7 +1280,7 @@ func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) {
|
|||
// uses the host's /etc/resolv.conf and does not have any dns options provided.
|
||||
func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
|
||||
// Not applicable on Windows as testing unix specific functionality
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
|
||||
tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
|
||||
|
@ -2261,9 +2240,6 @@ func (s *DockerSuite) TestRunExposePort(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestRunUnknownCommand(c *check.C) {
|
||||
if daemonPlatform != "windows" {
|
||||
testRequires(c, NativeExecDriver)
|
||||
}
|
||||
out, _, _ := dockerCmdWithStdoutStderr(c, "create", "busybox", "/bin/nada")
|
||||
|
||||
cID := strings.TrimSpace(out)
|
||||
|
@ -2405,7 +2381,7 @@ func (s *DockerSuite) TestContainerNetworkMode(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunModePidHost(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix-specific capabilities
|
||||
testRequires(c, NativeExecDriver, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
hostPid, err := os.Readlink("/proc/1/ns/pid")
|
||||
if err != nil {
|
||||
|
@ -2427,7 +2403,7 @@ func (s *DockerSuite) TestRunModePidHost(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunModeUTSHost(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix-specific capabilities
|
||||
testRequires(c, NativeExecDriver, SameHostDaemon, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
hostUTS, err := os.Readlink("/proc/1/ns/uts")
|
||||
if err != nil {
|
||||
|
@ -2657,7 +2633,7 @@ func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) {
|
||||
// Not applicable on Windows which does not support --read-only
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
for _, f := range []string{"/file", "/etc/hosts", "/etc/resolv.conf", "/etc/hostname", "/sys/kernel", "/dev/.dont.touch.me"} {
|
||||
testReadOnlyFile(f, c)
|
||||
|
@ -2668,7 +2644,7 @@ func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
|
|||
// Not applicable on Windows due to use of Unix specific functionality, plus
|
||||
// the use of --read-only which is not supported.
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
// Ensure we have not broken writing /dev/pts
|
||||
out, status := dockerCmd(c, "run", "--read-only", "--rm", "busybox", "mount")
|
||||
|
@ -2683,7 +2659,7 @@ func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
|
|||
|
||||
func testReadOnlyFile(filename string, c *check.C) {
|
||||
// Not applicable on Windows which does not support --read-only
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _, err := dockerCmdWithError("run", "--read-only", "--rm", "busybox", "touch", filename)
|
||||
if err == nil {
|
||||
|
@ -2707,7 +2683,7 @@ func testReadOnlyFile(filename string, c *check.C) {
|
|||
func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *check.C) {
|
||||
// Not applicable on Windows which does not support --link
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
dockerCmd(c, "run", "-d", "--name", "test-etc-hosts-ro-linked", "busybox", "top")
|
||||
|
||||
|
@ -2720,7 +2696,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *
|
|||
func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDnsFlag(c *check.C) {
|
||||
// Not applicable on Windows which does not support either --read-only or --dns.
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--read-only", "--dns", "1.1.1.1", "busybox", "/bin/cat", "/etc/resolv.conf")
|
||||
if !strings.Contains(string(out), "1.1.1.1") {
|
||||
|
@ -2731,7 +2707,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDnsFlag(c *check.C)
|
|||
func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithAddHostFlag(c *check.C) {
|
||||
// Not applicable on Windows which does not support --read-only
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--read-only", "--add-host", "testreadonly:127.0.0.1", "busybox", "/bin/cat", "/etc/hosts")
|
||||
if !strings.Contains(string(out), "testreadonly") {
|
||||
|
@ -2836,7 +2812,7 @@ func (s *DockerSuite) TestRunWriteToProcAsound(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunReadProcTimer(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
out, code, err := dockerCmdWithError("run", "busybox", "cat", "/proc/timer_stats")
|
||||
if code != 0 {
|
||||
return
|
||||
|
@ -2851,7 +2827,7 @@ func (s *DockerSuite) TestRunReadProcTimer(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunReadProcLatency(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, NativeExecDriver, DaemonIsLinux)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
// some kernels don't have this configured so skip the test if this file is not found
|
||||
// on the host running the tests.
|
||||
if _, err := os.Stat("/proc/latency_stats"); err != nil {
|
||||
|
@ -2896,7 +2872,6 @@ func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) {
|
|||
func (s *DockerSuite) TestMountIntoProc(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
_, code, err := dockerCmdWithError("run", "-v", "/proc//sys", "busybox", "true")
|
||||
if err == nil || code == 0 {
|
||||
c.Fatal("container should not be able to mount into /proc")
|
||||
|
@ -2906,7 +2881,7 @@ func (s *DockerSuite) TestMountIntoProc(c *check.C) {
|
|||
func (s *DockerSuite) TestMountIntoSys(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, NotUserNamespace)
|
||||
dockerCmd(c, "run", "-v", "/sys/fs/cgroup", "busybox", "true")
|
||||
}
|
||||
|
||||
|
@ -2914,7 +2889,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
|
|||
c.Skip("unstable test: is apparmor in a container reliable?")
|
||||
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, Apparmor, NativeExecDriver, DaemonIsLinux)
|
||||
testRequires(c, Apparmor, DaemonIsLinux)
|
||||
|
||||
name := "acidburn"
|
||||
if out, _, err := dockerCmdWithError("run", "--name", name, "jess/unshare", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount"); err == nil || !strings.Contains(out, "Permission denied") {
|
||||
|
@ -2948,7 +2923,6 @@ func (s *DockerSuite) TestRunPublishPort(c *check.C) {
|
|||
func (s *DockerSuite) TestDevicePermissions(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
const permissions = "crw-rw-rw-"
|
||||
out, status := dockerCmd(c, "run", "--device", "/dev/fuse:/dev/fuse:mrw", "busybox:latest", "ls", "-l", "/dev/fuse")
|
||||
if status != 0 {
|
||||
|
@ -2962,7 +2936,6 @@ func (s *DockerSuite) TestDevicePermissions(c *check.C) {
|
|||
func (s *DockerSuite) TestRunCapAddCHOWN(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, NativeExecDriver)
|
||||
out, _ := dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=CHOWN", "busybox", "sh", "-c", "adduser -D -H newuser && chown newuser /home && echo ok")
|
||||
|
||||
if actual := strings.Trim(out, "\r\n"); actual != "ok" {
|
||||
|
@ -3005,7 +2978,7 @@ func (s *DockerSuite) TestVolumeFromMixedRWOptions(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, Apparmor, NativeExecDriver, DaemonIsLinux, NotUserNamespace)
|
||||
testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
testWritePaths := []string{
|
||||
/* modprobe and core_pattern should both be denied by generic
|
||||
|
@ -3274,7 +3247,7 @@ func (s *DockerSuite) TestPtraceContainerProcsFromHost(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestAppArmorDeniesPtrace(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver, Apparmor, DaemonIsLinux, NotGCCGO)
|
||||
testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux, NotGCCGO)
|
||||
|
||||
// Run through 'sh' so we are NOT pid 1. Pid 1 may be able to trace
|
||||
// itself, but pid>1 should not be able to trace pid1.
|
||||
|
@ -3298,7 +3271,7 @@ func (s *DockerSuite) TestAppArmorDeniesChmodProc(c *check.C) {
|
|||
c.Skip("Test is failing, and what it tests is unclear")
|
||||
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, SameHostDaemon, NativeExecDriver, Apparmor, DaemonIsLinux)
|
||||
testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux)
|
||||
_, exitCode, _ := dockerCmdWithError("run", "busybox", "chmod", "744", "/proc/cpuinfo")
|
||||
if exitCode == 0 {
|
||||
// If our test failed, attempt to repair the host system...
|
||||
|
@ -3311,7 +3284,7 @@ func (s *DockerSuite) TestAppArmorDeniesChmodProc(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunCapAddSYSTIME(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=SYS_TIME", "busybox", "sh", "-c", "grep ^CapEff /proc/self/status | sed 's/^CapEff:\t//' | grep ^0000000002000000$")
|
||||
}
|
||||
|
@ -3348,7 +3321,7 @@ func (s *DockerSuite) TestRunNamedVolume(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunWithUlimits(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n")
|
||||
ul := strings.TrimSpace(out)
|
||||
|
@ -3359,7 +3332,7 @@ func (s *DockerSuite) TestRunWithUlimits(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
cgroupParent := "test"
|
||||
name := "cgroup-test"
|
||||
|
@ -3389,7 +3362,7 @@ func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) {
|
|||
|
||||
func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
cgroupParent := "/cgroup-parent/test"
|
||||
name := "cgroup-test"
|
||||
|
@ -3419,7 +3392,7 @@ func (s *DockerSuite) TestRunContainerWithCgroupParentAbsPath(c *check.C) {
|
|||
func (s *DockerSuite) TestRunContainerWithCgroupMountRO(c *check.C) {
|
||||
// Not applicable on Windows as uses Unix specific functionality
|
||||
// --read-only + userns has remount issues
|
||||
testRequires(c, DaemonIsLinux, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
|
||||
filename := "/sys/fs/cgroup/devices/test123"
|
||||
out, _, err := dockerCmdWithError("run", "busybox", "touch", filename)
|
||||
|
@ -3574,7 +3547,7 @@ func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
// Create 2 networks using bridge driver
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
|
||||
|
@ -3593,7 +3566,7 @@ func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
// Create 2 networks using bridge driver
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
|
||||
|
@ -3638,7 +3611,7 @@ func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
// Create 2 networks using bridge driver
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
|
||||
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/pkg/units"
|
||||
"github.com/go-check/check"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
@ -93,7 +92,7 @@ func (s *DockerSuite) TestRunWithVolumesIsRecursive(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestRunDeviceDirectory(c *check.C) {
|
||||
testRequires(c, NativeExecDriver, NotUserNamespace)
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
if _, err := os.Stat("/dev/snd"); err != nil {
|
||||
c.Skip("Host does not have /dev/snd")
|
||||
}
|
||||
|
@ -315,7 +314,7 @@ func (s *DockerSuite) TestRunEchoStdoutWithMemoryLimit(c *check.C) {
|
|||
// 16M memory and as much swap memory as they need (if the host
|
||||
// supports swap memory).
|
||||
func (s *DockerSuite) TestRunWithoutMemoryswapLimit(c *check.C) {
|
||||
testRequires(c, NativeExecDriver)
|
||||
testRequires(c, DaemonIsLinux)
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, swapMemorySupport)
|
||||
dockerCmd(c, "run", "-m", "16m", "--memory-swap", "-1", "busybox", "true")
|
||||
|
@ -425,7 +424,7 @@ func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
|
||||
testRequires(c, cpuShare, NativeExecDriver)
|
||||
testRequires(c, cpuShare, DaemonIsLinux)
|
||||
out, _, err := dockerCmdWithError("run", "--cpu-shares", "1", "busybox", "echo", "test")
|
||||
c.Assert(err, check.NotNil, check.Commentf(out))
|
||||
expected := "The minimum allowed cpu-shares is 2"
|
||||
|
@ -441,22 +440,3 @@ func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
|
|||
expected = "The maximum allowed cpu-shares is"
|
||||
c.Assert(out, checker.Contains, expected)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunWithCorrectMemorySwapOnLXC(c *check.C) {
|
||||
testRequires(c, memoryLimitSupport)
|
||||
testRequires(c, swapMemorySupport)
|
||||
testRequires(c, SameHostDaemon)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-d", "-m", "32m", "--memory-swap", "64m", "busybox", "top")
|
||||
if _, err := os.Stat("/sys/fs/cgroup/memory/lxc"); err != nil {
|
||||
c.Skip("Excecution driver must be LXC for this test")
|
||||
}
|
||||
id := strings.TrimSpace(out)
|
||||
memorySwap, err := ioutil.ReadFile(fmt.Sprintf("/sys/fs/cgroup/memory/lxc/%s/memory.memsw.limit_in_bytes", id))
|
||||
c.Assert(err, check.IsNil)
|
||||
cgSwap, err := strconv.ParseInt(strings.TrimSpace(string(memorySwap)), 10, 64)
|
||||
c.Assert(err, check.IsNil)
|
||||
swap, err := units.RAMInBytes("64m")
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(cgSwap, check.Equals, swap)
|
||||
}
|
||||
|
|
|
@ -229,9 +229,6 @@ func (d *Daemon) Start(arg ...string) error {
|
|||
if d.storageDriver != "" {
|
||||
args = append(args, "--storage-driver", d.storageDriver)
|
||||
}
|
||||
if d.execDriver != "" {
|
||||
args = append(args, "--exec-driver", d.execDriver)
|
||||
}
|
||||
|
||||
args = append(args, arg...)
|
||||
d.cmd = exec.Command(dockerBinary, args...)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -23,8 +21,6 @@ type testRequirement struct {
|
|||
|
||||
// List test requirements
|
||||
var (
|
||||
daemonExecDriver string
|
||||
|
||||
DaemonIsWindows = testRequirement{
|
||||
func() bool { return daemonPlatform == "windows" },
|
||||
"Test requires a Windows daemon",
|
||||
|
@ -105,30 +101,6 @@ var (
|
|||
},
|
||||
fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryBinary),
|
||||
}
|
||||
NativeExecDriver = testRequirement{
|
||||
func() bool {
|
||||
if daemonExecDriver == "" {
|
||||
// get daemon info
|
||||
status, body, err := sockRequest("GET", "/info", nil)
|
||||
if err != nil || status != http.StatusOK {
|
||||
log.Fatalf("sockRequest failed for /info: %v", err)
|
||||
}
|
||||
|
||||
type infoJSON struct {
|
||||
ExecutionDriver string
|
||||
}
|
||||
var info infoJSON
|
||||
if err = json.Unmarshal(body, &info); err != nil {
|
||||
log.Fatalf("unable to unmarshal body: %v", err)
|
||||
}
|
||||
|
||||
daemonExecDriver = info.ExecutionDriver
|
||||
}
|
||||
|
||||
return strings.HasPrefix(daemonExecDriver, "native")
|
||||
},
|
||||
"Test requires the native (libcontainer) exec driver.",
|
||||
}
|
||||
NotOverlay = testRequirement{
|
||||
func() bool {
|
||||
cmd := exec.Command("grep", "^overlay / overlay", "/proc/mounts")
|
||||
|
|
|
@ -37,7 +37,6 @@ docker-create - Create a new container
|
|||
[**--link**[=*[]*]]
|
||||
[**--log-driver**[=*[]*]]
|
||||
[**--log-opt**[=*[]*]]
|
||||
[**--lxc-conf**[=*[]*]]
|
||||
[**-m**|**--memory**[=*MEMORY*]]
|
||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||
|
@ -182,9 +181,6 @@ millions of trillions.
|
|||
**--log-opt**=[]
|
||||
Logging driver specific options.
|
||||
|
||||
**--lxc-conf**=[]
|
||||
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||
|
||||
**-m**, **--memory**=""
|
||||
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ docker-daemon - Enable daemon mode
|
|||
[**--dns**[=*[]*]]
|
||||
[**--dns-opt**[=*[]*]]
|
||||
[**--dns-search**[=*[]*]]
|
||||
[**-e**|**--exec-driver**[=*native*]]
|
||||
[**--exec-opt**[=*[]*]]
|
||||
[**--exec-root**[=*/var/run/docker*]]
|
||||
[**--fixed-cidr**[=*FIXED-CIDR*]]
|
||||
|
@ -112,9 +111,6 @@ format.
|
|||
**--dns-search**=[]
|
||||
DNS search domains to use.
|
||||
|
||||
**-e**, **--exec-driver**=""
|
||||
Force Docker to use specific exec driver. Default is `native`.
|
||||
|
||||
**--exec-opt**=[]
|
||||
Set exec driver options. See EXEC DRIVER OPTIONS.
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ To get information on a container use its ID or instance name:
|
|||
"HostConfig": {
|
||||
"Binds": null,
|
||||
"ContainerIDFile": "",
|
||||
"LxcConf": [],
|
||||
"Memory": 0,
|
||||
"MemorySwap": 0,
|
||||
"CpuShares": 0,
|
||||
|
|
|
@ -38,7 +38,6 @@ docker-run - Run a command in a new container
|
|||
[**--link**[=*[]*]]
|
||||
[**--log-driver**[=*[]*]]
|
||||
[**--log-opt**[=*[]*]]
|
||||
[**--lxc-conf**[=*[]*]]
|
||||
[**-m**|**--memory**[=*MEMORY*]]
|
||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||
|
@ -274,9 +273,6 @@ container can access the exposed port via a private networking interface. Docker
|
|||
will set some environment variables in the client container to help indicate
|
||||
which interface and port to use.
|
||||
|
||||
**--lxc-conf**=[]
|
||||
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
|
||||
|
||||
**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*none*"
|
||||
Logging driver for container. Default is defined by daemon `--log-driver` flag.
|
||||
**Warning**: the `docker logs` command works only for the `json-file` and
|
||||
|
|
|
@ -225,8 +225,8 @@ inside it)
|
|||
|
||||
# EXEC DRIVER OPTIONS
|
||||
|
||||
Use the **--exec-opt** flags to specify options to the exec-driver. The only
|
||||
driver that accepts this flag is the *native* (libcontainer) driver. As a
|
||||
Use the **--exec-opt** flags to specify options to the execution driver. The only
|
||||
runtime that accepts any options is Linux. As a
|
||||
result, you must also specify **-s=**native for this option to have effect. The
|
||||
following is the only *native* option:
|
||||
|
||||
|
|
|
@ -298,7 +298,6 @@ the client will even run on alternative platforms such as Mac OS X / Darwin.
|
|||
Some of Docker's features are activated by using optional command-line flags or
|
||||
by having support for them in the kernel or userspace. A few examples include:
|
||||
|
||||
* LXC execution driver (requires version 1.0.7 or later of lxc and the lxc-libs)
|
||||
* AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
|
||||
least the "auplink" utility from aufs-tools)
|
||||
* BTRFS graph driver (requires BTRFS support enabled in the kernel)
|
||||
|
|
|
@ -24,7 +24,7 @@ type NetworkMode string
|
|||
type IsolationLevel string
|
||||
|
||||
// IsDefault indicates the default isolation level of a container. On Linux this
|
||||
// is LXC. On Windows, this is a Windows Server Container.
|
||||
// is the native driver. On Windows, this is a Windows Server Container.
|
||||
func (i IsolationLevel) IsDefault() bool {
|
||||
return strings.ToLower(string(i)) == "default" || string(i) == ""
|
||||
}
|
||||
|
@ -164,69 +164,12 @@ type LogConfig struct {
|
|||
Config map[string]string
|
||||
}
|
||||
|
||||
// LxcConfig represents the specific LXC configuration of the container.
|
||||
type LxcConfig struct {
|
||||
values []KeyValuePair
|
||||
}
|
||||
|
||||
// MarshalJSON marshals (or serializes) the LxcConfig into JSON.
|
||||
func (c *LxcConfig) MarshalJSON() ([]byte, error) {
|
||||
if c == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return json.Marshal(c.Slice())
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals (or deserializes) the specified byte slices from JSON to
|
||||
// a LxcConfig.
|
||||
func (c *LxcConfig) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var kv []KeyValuePair
|
||||
if err := json.Unmarshal(b, &kv); err != nil {
|
||||
var h map[string]string
|
||||
if err := json.Unmarshal(b, &h); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range h {
|
||||
kv = append(kv, KeyValuePair{k, v})
|
||||
}
|
||||
}
|
||||
c.values = kv
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Len returns the number of specific lxc configuration.
|
||||
func (c *LxcConfig) Len() int {
|
||||
if c == nil {
|
||||
return 0
|
||||
}
|
||||
return len(c.values)
|
||||
}
|
||||
|
||||
// Slice returns the specific lxc configuration into a slice of KeyValuePair.
|
||||
func (c *LxcConfig) Slice() []KeyValuePair {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.values
|
||||
}
|
||||
|
||||
// NewLxcConfig creates a LxcConfig from the specified slice of KeyValuePair.
|
||||
func NewLxcConfig(values []KeyValuePair) *LxcConfig {
|
||||
return &LxcConfig{values}
|
||||
}
|
||||
|
||||
// HostConfig the non-portable Config structure of a container.
|
||||
// Here, "non-portable" means "dependent of the host we are running on".
|
||||
// Portable information *should* appear in Config.
|
||||
type HostConfig struct {
|
||||
Binds []string // List of volume bindings for this container
|
||||
ContainerIDFile string // File (path) where the containerId is written
|
||||
LxcConf *LxcConfig // Additional lxc configuration
|
||||
Memory int64 // Memory limit (in bytes)
|
||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
||||
|
|
|
@ -162,53 +162,6 @@ func TestRestartPolicy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLxcConfigMarshalJSON(t *testing.T) {
|
||||
lxcConfigs := map[*LxcConfig]string{
|
||||
nil: "",
|
||||
&LxcConfig{}: "null",
|
||||
&LxcConfig{
|
||||
[]KeyValuePair{{"key1", "value1"}},
|
||||
}: `[{"Key":"key1","Value":"value1"}]`,
|
||||
}
|
||||
|
||||
for lxcconfig, expected := range lxcConfigs {
|
||||
data, err := lxcconfig.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(data) != expected {
|
||||
t.Fatalf("Expected %v, got %v", expected, string(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLxcConfigUnmarshalJSON(t *testing.T) {
|
||||
keyvaluePairs := map[string][]KeyValuePair{
|
||||
"": {{"key1", "value1"}},
|
||||
"[]": {},
|
||||
`[{"Key":"key2","Value":"value2"}]`: {{"key2", "value2"}},
|
||||
}
|
||||
for json, expectedParts := range keyvaluePairs {
|
||||
lxcConfig := &LxcConfig{
|
||||
[]KeyValuePair{{"key1", "value1"}},
|
||||
}
|
||||
if err := lxcConfig.UnmarshalJSON([]byte(json)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actualParts := lxcConfig.Slice()
|
||||
if len(actualParts) != len(expectedParts) {
|
||||
t.Fatalf("Expected %v keyvaluePairs, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
||||
}
|
||||
for index, part := range actualParts {
|
||||
if part != expectedParts[index] {
|
||||
t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeConfigs(t *testing.T) {
|
||||
expectedHostname := "hostname"
|
||||
expectedContainerIDFile := "containerIdFile"
|
||||
|
|
|
@ -62,7 +62,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
flDNSOptions = opts.NewListOpts(nil)
|
||||
flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost)
|
||||
flVolumesFrom = opts.NewListOpts(nil)
|
||||
flLxcOpts = opts.NewListOpts(nil)
|
||||
flEnvFile = opts.NewListOpts(nil)
|
||||
flCapAdd = opts.NewListOpts(nil)
|
||||
flCapDrop = opts.NewListOpts(nil)
|
||||
|
@ -121,7 +120,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
cmd.Var(&flDNSOptions, []string{"-dns-opt"}, "Set DNS options")
|
||||
cmd.Var(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)")
|
||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||
cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options")
|
||||
cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
|
||||
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
|
||||
cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join")
|
||||
|
@ -223,12 +221,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
entrypoint = stringutils.NewStrSlice(*flEntrypoint)
|
||||
}
|
||||
|
||||
lc, err := parseKeyValueOpts(flLxcOpts)
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
lxcConf := NewLxcConfig(lc)
|
||||
|
||||
var (
|
||||
domainname string
|
||||
hostname = *flHostname
|
||||
|
@ -340,7 +332,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
hostConfig := &HostConfig{
|
||||
Binds: binds,
|
||||
ContainerIDFile: *flContainerIDFile,
|
||||
LxcConf: lxcConf,
|
||||
Memory: flMemory,
|
||||
MemoryReservation: MemoryReservation,
|
||||
MemorySwap: memorySwap,
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/nat"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
)
|
||||
|
||||
func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
|
||||
|
@ -344,35 +343,6 @@ func setupPlatformVolume(u []string, w []string) ([]string, string) {
|
|||
return a, s
|
||||
}
|
||||
|
||||
func TestParseLxcConfOpt(t *testing.T) {
|
||||
opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
|
||||
|
||||
for _, o := range opts {
|
||||
k, v, err := parsers.ParseKeyValueOpt(o)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
if k != "lxc.utsname" {
|
||||
t.Fail()
|
||||
}
|
||||
if v != "docker" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// With parseRun too
|
||||
_, hostconfig, _, err := parseRun([]string{"lxc.utsname=docker", "lxc.utsname = docker ", "img", "cmd"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, lxcConf := range hostconfig.LxcConf.Slice() {
|
||||
if lxcConf.Key != "lxc.utsname" || lxcConf.Value != "docker" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Simple parse with MacAddress validatation
|
||||
func TestParseWithMacAddress(t *testing.T) {
|
||||
invalidMacAddress := "--mac-address=invalidMacAddress"
|
||||
|
|
|
@ -61,8 +61,7 @@ func ValidateNetMode(c *Config, hc *HostConfig) error {
|
|||
}
|
||||
|
||||
// ValidateIsolationLevel performs platform specific validation of the
|
||||
// isolation level in the hostconfig structure. Linux only supports "default"
|
||||
// which is LXC container isolation
|
||||
// isolation level in the hostconfig structure. Linux only supports "default".
|
||||
func ValidateIsolationLevel(hc *HostConfig) error {
|
||||
// We may not be passed a host config, such as in the case of docker commit
|
||||
if hc == nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче