Remove LXC support.

The LXC driver was deprecated in Docker 1.8.
Following the deprecation rules, we can remove a deprecated feature
after two major releases. LXC won't be supported anymore starting on Docker 1.10.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-11-04 14:39:12 -05:00
parent b2f14f9bec
commit 3b5fac462d
62 changed files with 22 additions and 2751 deletions

View File

@ -72,16 +72,6 @@ RUN cd /usr/local/lvm2 \
&& make install_device-mapper && make install_device-mapper
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL # 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 # Install Go
ENV GO_VERSION 1.5.1 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 RUN curl -sSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar -v -C /usr/local -xz

View File

@ -39,16 +39,6 @@ RUN cd /usr/local/lvm2 \
&& make install_device-mapper && make install_device-mapper
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL # 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 ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
# Get the "docker-py" source so we can run their integration tests # Get the "docker-py" source so we can run their integration tests

View File

@ -26,7 +26,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
xz-utils \ xz-utils \
\ \
aufs-tools \ aufs-tools \
lxc \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
ENV AUTO_GOPATH 1 ENV AUTO_GOPATH 1

View File

@ -40,7 +40,6 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
libapparmor-dev \ libapparmor-dev \
libcap-dev \ libcap-dev \
libsqlite3-dev \ libsqlite3-dev \
lxc=1.0* \
mercurial \ mercurial \
pandoc \ pandoc \
parallel \ parallel \

View File

@ -1,6 +1,6 @@
(from "ubuntu:14.04") (from "ubuntu:14.04")
(maintainer "Tianon Gravi <admwiggin@gmail.com> (@tianon)") (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 "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 "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") (run "curl -sSL https://golang.org/dl/go1.3.src.tar.gz | tar -v -C /usr/local -xz")

View File

@ -1379,7 +1379,6 @@ _docker_run() {
--link --link
--log-driver --log-driver
--log-opt --log-opt
--lxc-conf
--mac-address --mac-address
--memory -m --memory -m
--memory-swap --memory-swap

View File

@ -135,7 +135,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' -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 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 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' -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 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)" 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 +323,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' -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 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 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' -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 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)" 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)"

View File

@ -438,7 +438,6 @@ __docker_subcommand() {
"($help)*"{-l=,--label=}"[Set meta data on a container]:label: " "($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-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)*--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)--mac-address=[Container MAC address]:MAC address: "
"($help)--name=[Container name]:name: " "($help)--name=[Container name]:name: "
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)" "($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
@ -541,7 +540,7 @@ __docker_subcommand() {
"($help)*--dns-opt=[DNS options to use]:DNS option: " \ "($help)*--dns-opt=[DNS options to use]:DNS option: " \
"($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \ "($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \
"($help)--disable-legacy-registry[Do not contact legacy registries]" \ "($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 -e --exec-driver)"{-e=,--exec-driver=}"[Exec driver to use]:driver:(native windows)" \
"($help)*--exec-opt=[Set exec driver options]:exec driver options: " \ "($help)*--exec-opt=[Set exec driver options]:exec driver options: " \
"($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \ "($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \
"($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \ "($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \

View File

@ -14,10 +14,6 @@
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0) /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/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/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/.*/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) /var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)

View File

@ -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, file, "docker.pid")
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock") files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client") 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") 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, "config.env")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts") filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
@ -406,11 +405,6 @@ interface(`staff_stub',`
type staff_t; type staff_t;
') ')
') ')
interface(`virt_stub_lxc',`
gen_require(`
type virtd_lxc_t;
')
')
interface(`virt_stub_svirt_sandbox_domain',` interface(`virt_stub_svirt_sandbox_domain',`
gen_require(` gen_require(`
attribute svirt_sandbox_domain; attribute svirt_sandbox_domain;

View File

@ -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_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
manage_files_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_dirs_pattern(docker_t, docker_log_t, docker_log_t)
manage_files_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) 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: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 }; 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_exec_sandbox_files(docker_t)
virt_manage_sandbox_files(docker_t) virt_manage_sandbox_files(docker_t)
virt_relabel_sandbox_filesystem(docker_t) virt_relabel_sandbox_filesystem(docker_t)
# for lxc
virt_transition_svirt_sandbox(docker_t, system_r) virt_transition_svirt_sandbox(docker_t, system_r)
virt_mounton_sandbox_file(docker_t) virt_mounton_sandbox_file(docker_t)
# virt_attach_sandbox_tun_iface(docker_t) # virt_attach_sandbox_tun_iface(docker_t)
@ -387,11 +381,6 @@ optional_policy(`
docker_exec(staff_t) docker_exec(staff_t)
') ')
optional_policy(`
virt_stub_lxc()
docker_exec_lib(virtd_lxc_t)
')
optional_policy(` optional_policy(`
virt_stub_svirt_sandbox_domain() virt_stub_svirt_sandbox_domain()
virt_stub_svirt_sandbox_file() virt_stub_svirt_sandbox_file()

View 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]/ );
}

View File

@ -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

View File

@ -25,7 +25,7 @@ The initial Docker upstart script will not work because it runs on `127.0.0.1`,
``` ```
description "Docker daemon" description "Docker daemon"
start on filesystem and started lxc-net start on filesystem
stop on runlevel [!2345] stop on runlevel [!2345]
respawn respawn

View File

@ -17,8 +17,6 @@ var (
) )
// Config defines the configuration of a docker daemon. // 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 { type Config struct {
CommonConfig CommonConfig

View File

@ -261,7 +261,6 @@ func (container *Container) jsonPath() (string, error) {
return container.getRootResourcePath("config.json") 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 // This directory is only usable when the container is running
func (container *Container) rootfsPath() string { func (container *Container) rootfsPath() string {
return container.basefs return container.basefs

View File

@ -255,12 +255,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices) 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 var rlimits []*ulimit.Rlimit
ulimits := c.hostConfig.Ulimits ulimits := c.hostConfig.Ulimits
@ -345,7 +339,6 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
GIDMapping: gidMap, GIDMapping: gidMap,
GroupAdd: c.hostConfig.GroupAdd, GroupAdd: c.hostConfig.GroupAdd,
Ipc: ipc, Ipc: ipc,
LxcConfig: lxcConfig,
Pid: pid, Pid: pid,
ReadonlyRootfs: c.hostConfig.ReadonlyRootfs, ReadonlyRootfs: c.hostConfig.ReadonlyRootfs,
RemappedRoot: remappedRoot, RemappedRoot: remappedRoot,

View File

@ -451,7 +451,6 @@ func (daemon *Daemon) generateNewName(id string) (string, error) {
func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) { func (daemon *Daemon) generateHostname(id string, config *runconfig.Config) {
// Generate default hostname // Generate default hostname
// FIXME: the lxc template no longer needs to set a default hostname
if config.Hostname == "" { if config.Hostname == "" {
config.Hostname = id[:12] config.Hostname = id[:12]
} }
@ -786,13 +785,6 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
d.containerGraphDB = graph d.containerGraphDB = graph
var sysInitPath string 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) sysInfo := sysinfo.New(false)
// Check if Devices cgroup is mounted, it is hard requirement for container security, // Check if Devices cgroup is mounted, it is hard requirement for container security,

View File

@ -128,10 +128,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
return warnings, err 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 // memory subsystem checks and adjustments
if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 { if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 {
return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB") return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")

View File

@ -148,11 +148,6 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
// ContainerExecCreate sets up an exec in a running container. // ContainerExecCreate sets up an exec in a running container.
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) { 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) container, err := d.getActiveContainer(config.Container)
if err != nil { if err != nil {
return "", err return "", err

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -100,7 +100,6 @@ type Command struct {
GIDMapping []idtools.IDMap `json:"gidmapping"` GIDMapping []idtools.IDMap `json:"gidmapping"`
GroupAdd []string `json:"group_add"` GroupAdd []string `json:"group_add"`
Ipc *Ipc `json:"ipc"` Ipc *Ipc `json:"ipc"`
LxcConfig []string `json:"lxc_config"`
Pid *Pid `json:"pid"` Pid *Pid `json:"pid"`
ReadonlyRootfs bool `json:"readonly_rootfs"` ReadonlyRootfs bool `json:"readonly_rootfs"`
RemappedRoot *User `json:"remap_root"` RemappedRoot *User `json:"remap_root"`

View File

@ -6,24 +6,15 @@ import (
"fmt" "fmt"
"path" "path"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/execdriver/lxc"
"github.com/docker/docker/daemon/execdriver/native" "github.com/docker/docker/daemon/execdriver/native"
"github.com/docker/docker/pkg/sysinfo" "github.com/docker/docker/pkg/sysinfo"
) )
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options. // 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) { func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
switch name { if name != "native" {
case "lxc": return nil, fmt.Errorf("unknown exec driver %s", name)
// 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) return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
} }

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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 // 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 // so we add this badhack to make sure it closes itself
setCloseOnExec("/dev/mapper/control") setCloseOnExec("/dev/mapper/control")

View File

@ -1,9 +0,0 @@
package daemon
import (
"github.com/docker/docker/runconfig"
)
func mergeLxcConfIntoOptions(hostConfig *runconfig.HostConfig) ([]string, error) {
return nil, nil
}

View File

@ -2,14 +2,7 @@
package daemon package daemon
import ( import "github.com/opencontainers/runc/libcontainer/selinux"
"errors"
"fmt"
"strings"
"github.com/docker/docker/runconfig"
"github.com/opencontainers/runc/libcontainer/selinux"
)
func selinuxSetDisabled() { func selinuxSetDisabled() {
selinux.SetDisabled() selinux.SetDisabled()
@ -22,27 +15,3 @@ func selinuxFreeLxcContexts(label string) {
func selinuxEnabled() bool { func selinuxEnabled() bool {
return selinux.SelinuxEnabled() 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
}

View File

@ -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)
}
}

View File

@ -4,7 +4,6 @@ package main
import ( import (
systemdDaemon "github.com/coreos/go-systemd/daemon" 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 // notifySystem sends a message to the host when the server is ready to be used

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
_ "github.com/docker/docker/daemon/execdriver/lxc"
_ "github.com/docker/docker/daemon/execdriver/native" _ "github.com/docker/docker/daemon/execdriver/native"
"github.com/docker/docker/pkg/reexec" "github.com/docker/docker/pkg/reexec"
) )

View File

@ -212,7 +212,6 @@ recommendations.
dpkg-sig \ dpkg-sig \
libcap-dev \ libcap-dev \
libsqlite3-dev \ libsqlite3-dev \
lxc=1.0* \
mercurial \ mercurial \
reprepro \ reprepro \
ruby1.9.1 \ ruby1.9.1 \

View File

@ -29,7 +29,6 @@ in the packages. The core dependencies are:
- bridge-utils - bridge-utils
- device-mapper - device-mapper
- iproute2 - iproute2
- lxc
- sqlite - sqlite
## Installation ## Installation

View File

@ -50,7 +50,6 @@ IRC channel on the Freenode network.
| contrib | Yes |Install additional contributed scripts and components.| | contrib | Yes |Install additional contributed scripts and components.|
| device-mapper | Yes |Enables dependencies for the "devicemapper" graph driver, including necessary kernel flags.| | 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.| | 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.| | vim-syntax | |Pulls in related vim syntax scripts.|
| zsh-completion| |Enable zsh completion support.| | zsh-completion| |Enable zsh completion support.|

View File

@ -174,7 +174,6 @@ Create a container
"HostConfig": { "HostConfig": {
"Binds": ["/tmp:/tmp"], "Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"], "Links": ["redis3:redis"],
"LxcConf": {"lxc.utsname":"docker"},
"Memory": 0, "Memory": 0,
"MemorySwap": 0, "MemorySwap": 0,
"MemoryReservation": 0, "MemoryReservation": 0,
@ -270,8 +269,6 @@ Json Parameters:
+ `volume_name:container_path:ro` to make the bind mount read-only inside the container. + `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 - **Links** - A list of links for the container. Each link entry should be
in the form of `container_name:alias`. 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 - **PortBindings** - A map of exposed container ports and the host port they
should map to. A JSON object in the form should map to. A JSON object in the form
`{ <port>/<protocol>: [{ "HostPort": "<port>" }] }` `{ <port>/<protocol>: [{ "HostPort": "<port>" }] }`

View File

@ -48,7 +48,6 @@ Creates a new container.
--link=[] Add link to another container --link=[] Add link to another container
--log-driver="" Logging driver for container --log-driver="" Logging driver for container
--log-opt=[] Log driver specific options --log-opt=[] Log driver specific options
--lxc-conf=[] Add custom lxc options
-m, --memory="" Memory limit -m, --memory="" Memory limit
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) --mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
--memory-reservation="" Memory soft limit --memory-reservation="" Memory soft limit

View File

@ -439,11 +439,6 @@ Currently supported options of `zfs`:
The Docker daemon uses a specifically built `libcontainer` execution driver as The Docker daemon uses a specifically built `libcontainer` execution driver as
its interface to the Linux kernel `namespaces`, `cgroups`, and `SELinux`. 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 ## Options for the native execdriver
You can configure the `native` (libcontainer) execdriver using options specified You can configure the `native` (libcontainer) execdriver using options specified

View File

@ -47,7 +47,6 @@ parent = "smn_cli"
--link=[] Add link to another container --link=[] Add link to another container
--log-driver="" Logging driver for container --log-driver="" Logging driver for container
--log-opt=[] Log driver specific options --log-opt=[] Log driver specific options
--lxc-conf=[] Add custom lxc options
-m, --memory="" Memory limit -m, --memory="" Memory limit
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) --mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
--memory-reservation="" Memory soft limit --memory-reservation="" Memory soft limit

View File

@ -39,7 +39,6 @@ defaults related to:
* container identification * container identification
* network settings * network settings
* runtime constraints on CPU and memory * runtime constraints on CPU and memory
* privileges and LXC configuration
With the `docker run [OPTIONS]` an operator can add to or override the With the `docker run [OPTIONS]` an operator can add to or override the
image defaults set by a developer. And, additionally, operators can image defaults set by a developer. And, additionally, operators can
@ -75,7 +74,7 @@ following options.
- [Restart policies (--restart)](#restart-policies-restart) - [Restart policies (--restart)](#restart-policies-restart)
- [Clean up (--rm)](#clean-up-rm) - [Clean up (--rm)](#clean-up-rm)
- [Runtime constraints on resources](#runtime-constraints-on-resources) - [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 ## Detached vs foreground
@ -933,21 +932,18 @@ one can use this flag:
$ docker run -ti --rm --group-add audio --group-add dbus --group-add 777 busybox id $ 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 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-add: Add Linux capabilities
--cap-drop: Drop Linux capabilities --cap-drop: Drop Linux capabilities
--privileged=false: Give extended privileges to this container --privileged=false: Give extended privileges to this container
--device=[]: Allows you to run devices inside the container without the --privileged flag. --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 By default, Docker containers are "unprivileged" and cannot, for
example, run a Docker daemon inside a Docker container. This is because 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 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]( "privileged" container is given access to all devices (see
https://github.com/docker/docker/blob/master/daemon/execdriver/lxc/lxc_template.go) the documentation on [cgroups devices](https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
and documentation on [cgroups devices](
https://www.kernel.org/doc/Documentation/cgroups/devices.txt)).
When the operator executes `docker run --privileged`, Docker will enable When the operator executes `docker run --privileged`, Docker will enable
to access to all devices on the host as well as set some configuration to access to all devices on the host as well as set some configuration
@ -1061,22 +1057,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) ## Logging drivers (--log-driver)
The container can have a different logging driver than the Docker daemon. Use The container can have a different logging driver than the Docker daemon. Use
@ -1258,7 +1238,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 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/" declare -x PWD="/"
declare -x SHLVL="1" declare -x SHLVL="1"
declare -x container="lxc"
declare -x deep="purple" declare -x deep="purple"
Similarly the operator can set the **hostname** with `-h`. Similarly the operator can set the **hostname** with `-h`.

View File

@ -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) - 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 - external (volume/graph) drivers which are unaware/incapable of using daemon user mappings
- Using `--privileged` mode containers - 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 - volume use without pre-arranging proper file ownership in mounted volumes
Additionally, while the `root` user inside a user namespaced container Additionally, while the `root` user inside a user namespaced container

View File

@ -31,13 +31,6 @@ if ! mountpoint -q /sys/fs/cgroup; then
# Mount the cgroup hierarchies exactly as they are in the parent system. # Mount the cgroup hierarchies exactly as they are in the parent system.
for HIER in $(cut -d: -f2 /proc/1/cgroup); do 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=*}" SUBSYSTEMS="${HIER%name=*}"
# If cgroup hierarchy is named(mounted with "-o name=foo") we # If cgroup hierarchy is named(mounted with "-o name=foo") we

View File

@ -109,10 +109,6 @@ if [ -z "$DOCKER_CLIENTONLY" ]; then
fi fi
fi fi
if [ "$DOCKER_EXECDRIVER" = 'lxc' ]; then
DOCKER_BUILDTAGS+=' test_no_exec'
fi
# test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately # test whether "btrfs/version.h" exists and apply btrfs_noversion appropriately
if \ if \
command -v gcc &> /dev/null \ command -v gcc &> /dev/null \

View File

@ -58,8 +58,8 @@ func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
"C /dev": true, "C /dev": true,
"A /dev/full": true, // busybox "A /dev/full": true, // busybox
"C /dev/ptmx": true, // libcontainer "C /dev/ptmx": true, // libcontainer
"A /dev/mqueue": true, // lxc "A /dev/mqueue": true,
"A /dev/kmsg": true, // lxc "A /dev/kmsg": true,
"A /dev/fd": true, "A /dev/fd": true,
"A /dev/fuse": true, "A /dev/fuse": true,
"A /dev/ptmx": true, "A /dev/ptmx": true,

View File

@ -66,13 +66,11 @@ func (s *DockerSuite) TestRunLookupGoogleDns(c *check.C) {
} }
// the exit code should be 0 // the exit code should be 0
// some versions of lxc might make this test fail
func (s *DockerSuite) TestRunExitCodeZero(c *check.C) { func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
dockerCmd(c, "run", "busybox", "true") dockerCmd(c, "run", "busybox", "true")
} }
// the exit code should be 1 // the exit code should be 1
// some versions of lxc might make this test fail
func (s *DockerSuite) TestRunExitCodeOne(c *check.C) { func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
_, exitCode, err := dockerCmdWithError("run", "busybox", "false") _, exitCode, err := dockerCmdWithError("run", "busybox", "false")
if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) { 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 // 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) { func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
// TODO Windows: This needs some work to make compatible. // TODO Windows: This needs some work to make compatible.
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)
@ -664,7 +661,7 @@ func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
func (s *DockerSuite) TestRunEnvironment(c *check.C) { func (s *DockerSuite) TestRunEnvironment(c *check.C) {
// TODO Windows: Environment handling is different between Linux and // 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) testRequires(c, DaemonIsLinux)
cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env") cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env")
cmd.Env = append(os.Environ(), cmd.Env = append(os.Environ(),
@ -677,13 +674,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
c.Fatal(err, out) c.Fatal(err, out)
} }
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n") actualEnv := strings.Split(strings.TrimSpace(out), "\n")
actualEnv := []string{}
for i := range actualEnvLxc {
if actualEnvLxc[i] != "container=lxc" {
actualEnv = append(actualEnv, actualEnvLxc[i])
}
}
sort.Strings(actualEnv) sort.Strings(actualEnv)
goodEnv := []string{ goodEnv := []string{
@ -709,7 +700,7 @@ func (s *DockerSuite) TestRunEnvironment(c *check.C) {
func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) { func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
// TODO Windows: Environment handling is different between Linux and // 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) testRequires(c, DaemonIsLinux)
// Test to make sure that when we use -e on env vars that are // 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) c.Fatal(err, out)
} }
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n") actualEnv := strings.Split(strings.TrimSpace(out), "\n")
actualEnv := []string{}
for i := range actualEnvLxc {
if actualEnvLxc[i] != "container=lxc" {
actualEnv = append(actualEnv, actualEnvLxc[i])
}
}
sort.Strings(actualEnv) sort.Strings(actualEnv)
goodEnv := []string{ goodEnv := []string{
@ -750,7 +735,7 @@ func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) { func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
// TODO Windows: Environment handling is different between Linux and // 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) testRequires(c, DaemonIsLinux)
// Test to make sure that when we use -e on env vars that are // 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) c.Fatal(err, out)
} }
actualEnvLxc := strings.Split(strings.TrimSpace(out), "\n") actualEnv := strings.Split(strings.TrimSpace(out), "\n")
actualEnv := []string{}
for i := range actualEnvLxc {
if actualEnvLxc[i] != "container=lxc" {
actualEnv = append(actualEnv, actualEnvLxc[i])
}
}
sort.Strings(actualEnv) sort.Strings(actualEnv)
goodEnv := []string{ goodEnv := []string{

View File

@ -17,7 +17,6 @@ import (
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo" "github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/units"
"github.com/go-check/check" "github.com/go-check/check"
"github.com/kr/pty" "github.com/kr/pty"
) )
@ -437,22 +436,3 @@ func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
expected = "The maximum allowed cpu-shares is" expected = "The maximum allowed cpu-shares is"
c.Assert(out, checker.Contains, expected) 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)
}

View File

@ -37,7 +37,6 @@ docker-create - Create a new container
[**--link**[=*[]*]] [**--link**[=*[]*]]
[**--log-driver**[=*[]*]] [**--log-driver**[=*[]*]]
[**--log-opt**[=*[]*]] [**--log-opt**[=*[]*]]
[**--lxc-conf**[=*[]*]]
[**-m**|**--memory**[=*MEMORY*]] [**-m**|**--memory**[=*MEMORY*]]
[**--mac-address**[=*MAC-ADDRESS*]] [**--mac-address**[=*MAC-ADDRESS*]]
[**--memory-reservation**[=*MEMORY-RESERVATION*]] [**--memory-reservation**[=*MEMORY-RESERVATION*]]
@ -182,9 +181,6 @@ millions of trillions.
**--log-opt**=[] **--log-opt**=[]
Logging driver specific options. Logging driver specific options.
**--lxc-conf**=[]
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
**-m**, **--memory**="" **-m**, **--memory**=""
Memory limit (format: <number>[<unit>], where unit = b, k, m or g) Memory limit (format: <number>[<unit>], where unit = b, k, m or g)

View File

@ -111,7 +111,6 @@ To get information on a container use its ID or instance name:
"HostConfig": { "HostConfig": {
"Binds": null, "Binds": null,
"ContainerIDFile": "", "ContainerIDFile": "",
"LxcConf": [],
"Memory": 0, "Memory": 0,
"MemorySwap": 0, "MemorySwap": 0,
"CpuShares": 0, "CpuShares": 0,

View File

@ -38,7 +38,6 @@ docker-run - Run a command in a new container
[**--link**[=*[]*]] [**--link**[=*[]*]]
[**--log-driver**[=*[]*]] [**--log-driver**[=*[]*]]
[**--log-opt**[=*[]*]] [**--log-opt**[=*[]*]]
[**--lxc-conf**[=*[]*]]
[**-m**|**--memory**[=*MEMORY*]] [**-m**|**--memory**[=*MEMORY*]]
[**--mac-address**[=*MAC-ADDRESS*]] [**--mac-address**[=*MAC-ADDRESS*]]
[**--memory-reservation**[=*MEMORY-RESERVATION*]] [**--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 will set some environment variables in the client container to help indicate
which interface and port to use. 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*" **--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*awslogs*|*splunk*|*none*"
Logging driver for container. Default is defined by daemon `--log-driver` flag. Logging driver for container. Default is defined by daemon `--log-driver` flag.
**Warning**: the `docker logs` command works only for the `json-file` and **Warning**: the `docker logs` command works only for the `json-file` and

View File

@ -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 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: 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 * AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
least the "auplink" utility from aufs-tools) least the "auplink" utility from aufs-tools)
* BTRFS graph driver (requires BTRFS support enabled in the kernel) * BTRFS graph driver (requires BTRFS support enabled in the kernel)

View File

@ -24,7 +24,7 @@ type NetworkMode string
type IsolationLevel string type IsolationLevel string
// IsDefault indicates the default isolation level of a container. On Linux this // 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 { func (i IsolationLevel) IsDefault() bool {
return strings.ToLower(string(i)) == "default" || string(i) == "" return strings.ToLower(string(i)) == "default" || string(i) == ""
} }
@ -164,69 +164,12 @@ type LogConfig struct {
Config map[string]string 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. // HostConfig the non-portable Config structure of a container.
// Here, "non-portable" means "dependent of the host we are running on". // Here, "non-portable" means "dependent of the host we are running on".
// Portable information *should* appear in Config. // Portable information *should* appear in Config.
type HostConfig struct { type HostConfig struct {
Binds []string // List of volume bindings for this container Binds []string // List of volume bindings for this container
ContainerIDFile string // File (path) where the containerId is written ContainerIDFile string // File (path) where the containerId is written
LxcConf *LxcConfig // Additional lxc configuration
Memory int64 // Memory limit (in bytes) Memory int64 // Memory limit (in bytes)
MemoryReservation int64 // Memory soft limit (in bytes) MemoryReservation int64 // Memory soft limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap

View File

@ -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) { func TestMergeConfigs(t *testing.T) {
expectedHostname := "hostname" expectedHostname := "hostname"
expectedContainerIDFile := "containerIdFile" expectedContainerIDFile := "containerIdFile"

View File

@ -62,7 +62,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flDNSOptions = opts.NewListOpts(nil) flDNSOptions = opts.NewListOpts(nil)
flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost) flExtraHosts = opts.NewListOpts(opts.ValidateExtraHost)
flVolumesFrom = opts.NewListOpts(nil) flVolumesFrom = opts.NewListOpts(nil)
flLxcOpts = opts.NewListOpts(nil)
flEnvFile = opts.NewListOpts(nil) flEnvFile = opts.NewListOpts(nil)
flCapAdd = opts.NewListOpts(nil) flCapAdd = opts.NewListOpts(nil)
flCapDrop = 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(&flDNSOptions, []string{"-dns-opt"}, "Set DNS options")
cmd.Var(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)") 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(&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(&flCapAdd, []string{"-cap-add"}, "Add Linux capabilities")
cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities") cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
cmd.Var(&flGroupAdd, []string{"-group-add"}, "Add additional groups to join") 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) entrypoint = stringutils.NewStrSlice(*flEntrypoint)
} }
lc, err := parseKeyValueOpts(flLxcOpts)
if err != nil {
return nil, nil, cmd, err
}
lxcConf := NewLxcConfig(lc)
var ( var (
domainname string domainname string
hostname = *flHostname hostname = *flHostname
@ -340,7 +332,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
hostConfig := &HostConfig{ hostConfig := &HostConfig{
Binds: binds, Binds: binds,
ContainerIDFile: *flContainerIDFile, ContainerIDFile: *flContainerIDFile,
LxcConf: lxcConf,
Memory: flMemory, Memory: flMemory,
MemoryReservation: MemoryReservation, MemoryReservation: MemoryReservation,
MemorySwap: memorySwap, MemorySwap: memorySwap,

View File

@ -12,7 +12,6 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/parsers"
) )
func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) { func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
@ -344,35 +343,6 @@ func setupPlatformVolume(u []string, w []string) ([]string, string) {
return a, s 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 // Simple parse with MacAddress validatation
func TestParseWithMacAddress(t *testing.T) { func TestParseWithMacAddress(t *testing.T) {
invalidMacAddress := "--mac-address=invalidMacAddress" invalidMacAddress := "--mac-address=invalidMacAddress"

View File

@ -61,8 +61,7 @@ func ValidateNetMode(c *Config, hc *HostConfig) error {
} }
// ValidateIsolationLevel performs platform specific validation of the // ValidateIsolationLevel performs platform specific validation of the
// isolation level in the hostconfig structure. Linux only supports "default" // isolation level in the hostconfig structure. Linux only supports "default".
// which is LXC container isolation
func ValidateIsolationLevel(hc *HostConfig) error { func ValidateIsolationLevel(hc *HostConfig) error {
// We may not be passed a host config, such as in the case of docker commit // We may not be passed a host config, such as in the case of docker commit
if hc == nil { if hc == nil {