mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-19 12:16:30 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20d4e6f29e |
@@ -7,7 +7,6 @@
|
||||
+ build containers with resource constraints, ie `docker build --cpu-shares=100 --memory=1024m...`
|
||||
+ `commit --change` to apply specified Dockerfile instructions while committing the image
|
||||
+ `import --change` to apply specified Dockerfile instructions while importing the image
|
||||
+ basic build cancellation
|
||||
|
||||
#### Client
|
||||
+ Windows Support
|
||||
|
||||
+3
-3
@@ -281,16 +281,16 @@ func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
go func() {
|
||||
prevH, prevW := cli.getTtySize()
|
||||
prevW, prevH := cli.getTtySize()
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
h, w := cli.getTtySize()
|
||||
w, h := cli.getTtySize()
|
||||
|
||||
if prevW != w || prevH != h {
|
||||
cli.resizeTty(id, isExec)
|
||||
}
|
||||
prevH = h
|
||||
prevW = w
|
||||
prevH = h
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
|
||||
@@ -49,7 +49,7 @@ post-start script
|
||||
fi
|
||||
if ! printf "%s" "$DOCKER_OPTS" | grep -qE -e '-H|--host'; then
|
||||
while ! [ -e /var/run/docker.sock ]; do
|
||||
initctl status $UPSTART_JOB | grep -qE "(stop|respawn)/" && exit 1
|
||||
initctl status $UPSTART_JOB | grep -q "stop/" && exit 1
|
||||
echo "Waiting for /var/run/docker.sock"
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
@@ -156,7 +156,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
startCallback(&c.ProcessConfig, pid)
|
||||
}
|
||||
|
||||
oom := notifyOnOOM(cont)
|
||||
oomKillNotification, err := cont.NotifyOOM()
|
||||
if err != nil {
|
||||
oomKillNotification = nil
|
||||
log.Warnf("Your kernel does not support OOM notifications: %s", err)
|
||||
}
|
||||
waitF := p.Wait
|
||||
if nss := cont.Config().Namespaces; !nss.Contains(configs.NEWPID) {
|
||||
// we need such hack for tracking processes with inerited fds,
|
||||
@@ -172,52 +176,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
ps = execErr.ProcessState
|
||||
}
|
||||
cont.Destroy()
|
||||
_, oomKill := <-oom
|
||||
|
||||
_, oomKill := <-oomKillNotification
|
||||
|
||||
return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
|
||||
}
|
||||
|
||||
// notifyOnOOM returns a channel that signals if the container received an OOM notification
|
||||
// for any process. If it is unable to subscribe to OOM notifications then a closed
|
||||
// channel is returned as it will be non-blocking and return the correct result when read.
|
||||
func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
|
||||
oom, err := container.NotifyOOM()
|
||||
if err != nil {
|
||||
log.Warnf("Your kernel does not support OOM notifications: %s", err)
|
||||
c := make(chan struct{})
|
||||
close(c)
|
||||
return c
|
||||
}
|
||||
return oom
|
||||
}
|
||||
|
||||
func killCgroupProcs(c libcontainer.Container) {
|
||||
var procs []*os.Process
|
||||
if err := c.Pause(); err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
pids, err := c.Processes()
|
||||
if err != nil {
|
||||
// don't care about childs if we can't get them, this is mostly because cgroup already deleted
|
||||
log.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
|
||||
}
|
||||
for _, pid := range pids {
|
||||
if p, err := os.FindProcess(pid); err == nil {
|
||||
procs = append(procs, p)
|
||||
if err := p.Kill(); err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := c.Resume(); err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
for _, p := range procs {
|
||||
if _, err := p.Wait(); err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
|
||||
return func() (*os.ProcessState, error) {
|
||||
pid, err := p.Pid()
|
||||
@@ -225,6 +189,8 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processes, err := c.Processes()
|
||||
|
||||
process, err := os.FindProcess(pid)
|
||||
s, err := process.Wait()
|
||||
if err != nil {
|
||||
@@ -234,7 +200,19 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
|
||||
}
|
||||
s = execErr.ProcessState
|
||||
}
|
||||
killCgroupProcs(c)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
for _, pid := range processes {
|
||||
process, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to kill process: %d", pid)
|
||||
continue
|
||||
}
|
||||
process.Kill()
|
||||
}
|
||||
|
||||
p.Wait()
|
||||
return s, err
|
||||
}
|
||||
|
||||
@@ -17,20 +17,29 @@ type Syslog struct {
|
||||
}
|
||||
|
||||
func New(tag string) (logger.Logger, error) {
|
||||
log, err := syslog.New(syslog.LOG_USER, fmt.Sprintf("%s: <%s> ", path.Base(os.Args[0]), tag))
|
||||
log, err := syslog.New(syslog.LOG_USER, path.Base(os.Args[0]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Syslog{
|
||||
writer: log,
|
||||
tag: tag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Syslog) Log(msg *logger.Message) error {
|
||||
logMessage := fmt.Sprintf("%s: %s", s.tag, string(msg.Line))
|
||||
if msg.Source == "stderr" {
|
||||
return s.writer.Err(string(msg.Line))
|
||||
if err := s.writer.Err(logMessage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
if err := s.writer.Info(logMessage); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return s.writer.Info(string(msg.Line))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Syslog) Close() error {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -107,13 +106,6 @@ func InitDriver(job *engine.Job) engine.Status {
|
||||
fixedCIDR = job.Getenv("FixedCIDR")
|
||||
fixedCIDRv6 = job.Getenv("FixedCIDRv6")
|
||||
)
|
||||
|
||||
// try to modprobe bridge first
|
||||
// see gh#12177
|
||||
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat").Output(); err != nil {
|
||||
log.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
|
||||
}
|
||||
|
||||
initPortMapper()
|
||||
|
||||
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
||||
|
||||
+4
-11
@@ -22,17 +22,10 @@ EOF
|
||||
}
|
||||
|
||||
create_robots_txt() {
|
||||
if [ "$AWS_S3_BUCKET" == "docs.docker.com" ]; then
|
||||
cat > ./sources/robots.txt <<-'EOF'
|
||||
User-agent: *
|
||||
Allow: /
|
||||
EOF
|
||||
else
|
||||
cat > ./sources/robots.txt <<-'EOF'
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
EOF
|
||||
fi
|
||||
cat > ./sources/robots.txt <<'EOF'
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
EOF
|
||||
}
|
||||
|
||||
setup_s3() {
|
||||
|
||||
@@ -22,7 +22,7 @@ is developed, you can launch only Linux containers from your Windows machine.
|
||||
|
||||
## Demonstration
|
||||
|
||||
<iframe width="640" height="480" src="//www.youtube.com/embed/TjMU3bDX4vo?rel=0" frameborder="0" allowfullscreen></iframe>
|
||||
<iframe width="640" height="480" src="//www.youtube.com/embed/oSHN8_uiZd4?rel=0" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -147,10 +147,3 @@ You can do this with
|
||||
`%USERPROFILE%\.ssh\id_boot2docker`
|
||||
- then click: "Save Private Key".
|
||||
- Then use the saved file to login with PuTTY using `docker@127.0.0.1:2022`.
|
||||
|
||||
## References
|
||||
|
||||
If you have Docker hosts running and if you don't wish to do a
|
||||
Boot2Docker installation, you can install the docker.exe using
|
||||
unofficial Windows package manager Chocolately. For information
|
||||
on how to do this, see [Docker package on Chocolatey](http://chocolatey.org/packages/docker).
|
||||
|
||||
+181
-198
@@ -20,230 +20,213 @@ command_exists() {
|
||||
command -v "$@" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
echo_docker_as_nonroot() {
|
||||
your_user=your-user
|
||||
[ "$user" != 'root' ] && your_user="$user"
|
||||
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output
|
||||
cat <<-EOF
|
||||
case "$(uname -m)" in
|
||||
*64)
|
||||
;;
|
||||
*)
|
||||
echo >&2 'Error: you are not using a 64bit platform.'
|
||||
echo >&2 'Docker currently only supports 64bit platforms.'
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
If you would like to use Docker as a non-root user, you should now consider
|
||||
adding your user to the "docker" group with something like:
|
||||
if command_exists docker || command_exists lxc-docker; then
|
||||
echo >&2 'Warning: "docker" or "lxc-docker" command appears to already exist.'
|
||||
echo >&2 'Please ensure that you do not already have docker installed.'
|
||||
echo >&2 'You may press Ctrl+C now to abort this process and rectify this situation.'
|
||||
( set -x; sleep 20 )
|
||||
fi
|
||||
|
||||
sudo usermod -aG docker $your_user
|
||||
user="$(id -un 2>/dev/null || true)"
|
||||
|
||||
Remember that you will have to log out and back in for this to take effect!
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
do_install() {
|
||||
case "$(uname -m)" in
|
||||
*64)
|
||||
;;
|
||||
*)
|
||||
cat >&2 <<-'EOF'
|
||||
Error: you are not using a 64bit platform.
|
||||
Docker currently only supports 64bit platforms.
|
||||
EOF
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if command_exists docker || command_exists lxc-docker; then
|
||||
cat >&2 <<-'EOF'
|
||||
Warning: "docker" or "lxc-docker" command appears to already exist.
|
||||
Please ensure that you do not already have docker installed.
|
||||
You may press Ctrl+C now to abort this process and rectify this situation.
|
||||
EOF
|
||||
( set -x; sleep 20 )
|
||||
sh_c='sh -c'
|
||||
if [ "$user" != 'root' ]; then
|
||||
if command_exists sudo; then
|
||||
sh_c='sudo -E sh -c'
|
||||
elif command_exists su; then
|
||||
sh_c='su -c'
|
||||
else
|
||||
echo >&2 'Error: this installer needs the ability to run commands as root.'
|
||||
echo >&2 'We are unable to find either "sudo" or "su" available to make this happen.'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
user="$(id -un 2>/dev/null || true)"
|
||||
curl=''
|
||||
if command_exists curl; then
|
||||
curl='curl -sSL'
|
||||
elif command_exists wget; then
|
||||
curl='wget -qO-'
|
||||
elif command_exists busybox && busybox --list-modules | grep -q wget; then
|
||||
curl='busybox wget -qO-'
|
||||
fi
|
||||
|
||||
sh_c='sh -c'
|
||||
if [ "$user" != 'root' ]; then
|
||||
if command_exists sudo; then
|
||||
sh_c='sudo -E sh -c'
|
||||
elif command_exists su; then
|
||||
sh_c='su -c'
|
||||
# perform some very rudimentary platform detection
|
||||
lsb_dist=''
|
||||
if command_exists lsb_release; then
|
||||
lsb_dist="$(lsb_release -si)"
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
|
||||
lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
|
||||
lsb_dist='debian'
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
|
||||
lsb_dist='fedora'
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
|
||||
lsb_dist="$(. /etc/os-release && echo "$ID")"
|
||||
fi
|
||||
|
||||
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$lsb_dist" in
|
||||
amzn|fedora)
|
||||
if [ "$lsb_dist" = 'amzn' ]; then
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; yum -y -q install docker'
|
||||
)
|
||||
else
|
||||
cat >&2 <<-'EOF'
|
||||
Error: this installer needs the ability to run commands as root.
|
||||
We are unable to find either "sudo" or "su" available to make this happen.
|
||||
EOF
|
||||
exit 1
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; yum -y -q install docker-io'
|
||||
)
|
||||
fi
|
||||
fi
|
||||
if command_exists docker && [ -e /var/run/docker.sock ]; then
|
||||
(
|
||||
set -x
|
||||
$sh_c 'docker version'
|
||||
) || true
|
||||
fi
|
||||
your_user=your-user
|
||||
[ "$user" != 'root' ] && your_user="$user"
|
||||
echo
|
||||
echo 'If you would like to use Docker as a non-root user, you should now consider'
|
||||
echo 'adding your user to the "docker" group with something like:'
|
||||
echo
|
||||
echo ' sudo usermod -aG docker' $your_user
|
||||
echo
|
||||
echo 'Remember that you will have to log out and back in for this to take effect!'
|
||||
echo
|
||||
exit 0
|
||||
;;
|
||||
|
||||
curl=''
|
||||
if command_exists curl; then
|
||||
curl='curl -sSL'
|
||||
elif command_exists wget; then
|
||||
curl='wget -qO-'
|
||||
elif command_exists busybox && busybox --list-modules | grep -q wget; then
|
||||
curl='busybox wget -qO-'
|
||||
fi
|
||||
ubuntu|debian|linuxmint)
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# perform some very rudimentary platform detection
|
||||
lsb_dist=''
|
||||
if command_exists lsb_release; then
|
||||
lsb_dist="$(lsb_release -si)"
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
|
||||
lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
|
||||
lsb_dist='debian'
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
|
||||
lsb_dist='fedora'
|
||||
fi
|
||||
if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
|
||||
lsb_dist="$(. /etc/os-release && echo "$ID")"
|
||||
fi
|
||||
|
||||
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$lsb_dist" in
|
||||
amzn|fedora|centos)
|
||||
if [ "$lsb_dist" = 'amzn' ]; then
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; yum -y -q install docker'
|
||||
)
|
||||
else
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; yum -y -q install docker-io'
|
||||
)
|
||||
did_apt_get_update=
|
||||
apt_get_update() {
|
||||
if [ -z "$did_apt_get_update" ]; then
|
||||
( set -x; $sh_c 'sleep 3; apt-get update' )
|
||||
did_apt_get_update=1
|
||||
fi
|
||||
if command_exists docker && [ -e /var/run/docker.sock ]; then
|
||||
(
|
||||
set -x
|
||||
$sh_c 'docker version'
|
||||
) || true
|
||||
fi
|
||||
echo_docker_as_nonroot
|
||||
exit 0
|
||||
;;
|
||||
}
|
||||
|
||||
ubuntu|debian|linuxmint)
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
# aufs is preferred over devicemapper; try to ensure the driver is available.
|
||||
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
|
||||
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
|
||||
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
|
||||
|
||||
did_apt_get_update=
|
||||
apt_get_update() {
|
||||
if [ -z "$did_apt_get_update" ]; then
|
||||
( set -x; $sh_c 'sleep 3; apt-get update' )
|
||||
did_apt_get_update=1
|
||||
fi
|
||||
}
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
|
||||
|
||||
# aufs is preferred over devicemapper; try to ensure the driver is available.
|
||||
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
|
||||
if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
|
||||
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
|
||||
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true
|
||||
|
||||
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
|
||||
echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
|
||||
echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
|
||||
( set -x; sleep 10 )
|
||||
fi
|
||||
else
|
||||
echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
|
||||
echo >&2 ' package. We have no AUFS support. Consider installing the packages'
|
||||
echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
|
||||
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
|
||||
echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)'
|
||||
echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!'
|
||||
( set -x; sleep 10 )
|
||||
fi
|
||||
else
|
||||
echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual'
|
||||
echo >&2 ' package. We have no AUFS support. Consider installing the packages'
|
||||
echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.'
|
||||
( set -x; sleep 10 )
|
||||
fi
|
||||
fi
|
||||
|
||||
# install apparmor utils if they're missing and apparmor is enabled in the kernel
|
||||
# otherwise Docker will fail to start
|
||||
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
|
||||
if command -v apparmor_parser &> /dev/null; then
|
||||
echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
|
||||
else
|
||||
echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
|
||||
fi
|
||||
# install apparmor utils if they're missing and apparmor is enabled in the kernel
|
||||
# otherwise Docker will fail to start
|
||||
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
|
||||
if command -v apparmor_parser &> /dev/null; then
|
||||
echo 'apparmor is enabled in the kernel and apparmor utils were already installed'
|
||||
else
|
||||
echo 'apparmor is enabled in the kernel, but apparmor_parser missing'
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' )
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -e /usr/lib/apt/methods/https ]; then
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
|
||||
fi
|
||||
if [ -z "$curl" ]; then
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
|
||||
curl='curl -sSL'
|
||||
if [ ! -e /usr/lib/apt/methods/https ]; then
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' )
|
||||
fi
|
||||
if [ -z "$curl" ]; then
|
||||
apt_get_update
|
||||
( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' )
|
||||
curl='curl -sSL'
|
||||
fi
|
||||
(
|
||||
set -x
|
||||
if [ "https://get.docker.com/" = "$url" ]; then
|
||||
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
|
||||
elif [ "https://test.docker.com/" = "$url" ]; then
|
||||
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
|
||||
else
|
||||
$sh_c "$curl ${url}gpg | apt-key add -"
|
||||
fi
|
||||
$sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
|
||||
$sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
|
||||
)
|
||||
if command_exists docker && [ -e /var/run/docker.sock ]; then
|
||||
(
|
||||
set -x
|
||||
if [ "https://get.docker.com/" = "$url" ]; then
|
||||
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9"
|
||||
elif [ "https://test.docker.com/" = "$url" ]; then
|
||||
$sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6"
|
||||
else
|
||||
$sh_c "$curl ${url}gpg | apt-key add -"
|
||||
fi
|
||||
$sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list"
|
||||
$sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker'
|
||||
)
|
||||
if command_exists docker && [ -e /var/run/docker.sock ]; then
|
||||
(
|
||||
set -x
|
||||
$sh_c 'docker version'
|
||||
) || true
|
||||
fi
|
||||
echo_docker_as_nonroot
|
||||
exit 0
|
||||
;;
|
||||
$sh_c 'docker version'
|
||||
) || true
|
||||
fi
|
||||
your_user=your-user
|
||||
[ "$user" != 'root' ] && your_user="$user"
|
||||
echo
|
||||
echo 'If you would like to use Docker as a non-root user, you should now consider'
|
||||
echo 'adding your user to the "docker" group with something like:'
|
||||
echo
|
||||
echo ' sudo usermod -aG docker' $your_user
|
||||
echo
|
||||
echo 'Remember that you will have to log out and back in for this to take effect!'
|
||||
echo
|
||||
exit 0
|
||||
;;
|
||||
|
||||
gentoo)
|
||||
if [ "$url" = "https://test.docker.com/" ]; then
|
||||
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
|
||||
cat >&2 <<-'EOF'
|
||||
gentoo)
|
||||
if [ "$url" = "https://test.docker.com/" ]; then
|
||||
echo >&2
|
||||
echo >&2 ' You appear to be trying to install the latest nightly build in Gentoo.'
|
||||
echo >&2 ' The portage tree should contain the latest stable release of Docker, but'
|
||||
echo >&2 ' if you want something more recent, you can always use the live ebuild'
|
||||
echo >&2 ' provided in the "docker" overlay available via layman. For more'
|
||||
echo >&2 ' instructions, please see the following URL:'
|
||||
echo >&2 ' https://github.com/tianon/docker-overlay#using-this-overlay'
|
||||
echo >&2 ' After adding the "docker" overlay, you should be able to:'
|
||||
echo >&2 ' emerge -av =app-emulation/docker-9999'
|
||||
echo >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
You appear to be trying to install the latest nightly build in Gentoo.'
|
||||
The portage tree should contain the latest stable release of Docker, but'
|
||||
if you want something more recent, you can always use the live ebuild'
|
||||
provided in the "docker" overlay available via layman. For more'
|
||||
instructions, please see the following URL:'
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; emerge app-emulation/docker'
|
||||
)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
https://github.com/tianon/docker-overlay#using-this-overlay'
|
||||
cat >&2 <<'EOF'
|
||||
|
||||
After adding the "docker" overlay, you should be able to:'
|
||||
Either your platform is not easily detectable, is not supported by this
|
||||
installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
|
||||
a package for Docker. Please visit the following URL for more detailed
|
||||
installation instructions:
|
||||
|
||||
emerge -av =app-emulation/docker-9999'
|
||||
https://docs.docker.com/en/latest/installation/
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(
|
||||
set -x
|
||||
$sh_c 'sleep 3; emerge app-emulation/docker'
|
||||
)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
|
||||
cat >&2 <<-'EOF'
|
||||
|
||||
Either your platform is not easily detectable, is not supported by this
|
||||
installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have
|
||||
a package for Docker. Please visit the following URL for more detailed
|
||||
installation instructions:
|
||||
|
||||
https://docs.docker.com/en/latest/installation/
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# wrapped up in a function so that we have some protection against only getting
|
||||
# half the file during "curl | sh"
|
||||
do_install
|
||||
EOF
|
||||
exit 1
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ rm -rf src/github.com/docker/distribution
|
||||
mkdir -p src/github.com/docker/distribution
|
||||
mv tmp-digest src/github.com/docker/distribution/digest
|
||||
|
||||
clone git github.com/docker/libcontainer bd8ec36106086f72b66e1be85a81202b93503e44
|
||||
clone git github.com/docker/libcontainer c8512754166539461fd860451ff1a0af7491c197
|
||||
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
|
||||
rm -rf src/github.com/docker/libcontainer/vendor
|
||||
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli' | grep -v 'github.com/Sirupsen/logrus')"
|
||||
|
||||
@@ -3237,35 +3237,6 @@ func TestRunNetHost(t *testing.T) {
|
||||
logDone("run - net host mode")
|
||||
}
|
||||
|
||||
func TestRunNetContainerWhichHost(t *testing.T) {
|
||||
testRequires(t, SameHostDaemon)
|
||||
defer deleteAllContainers()
|
||||
|
||||
hostNet, err := os.Readlink("/proc/1/ns/net")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(dockerBinary, "run", "-d", "--net=host", "--name=test", "busybox", "top")
|
||||
out, _, err := runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
cmd = exec.Command(dockerBinary, "run", "--net=container:test", "busybox", "readlink", "/proc/self/ns/net")
|
||||
out, _, err = runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
out = strings.Trim(out, "\n")
|
||||
if hostNet != out {
|
||||
t.Fatalf("Container should have host network namespace")
|
||||
}
|
||||
|
||||
logDone("run - net container mode, where container in host mode")
|
||||
}
|
||||
|
||||
func TestRunAllowPortRangeThroughPublish(t *testing.T) {
|
||||
defer deleteAllContainers()
|
||||
|
||||
@@ -3411,28 +3382,3 @@ func TestRunVolumesFromRestartAfterRemoved(t *testing.T) {
|
||||
|
||||
logDone("run - can restart a volumes-from container after producer is removed")
|
||||
}
|
||||
|
||||
func TestRunPidHostWithChildIsKillable(t *testing.T) {
|
||||
defer deleteAllContainers()
|
||||
name := "ibuildthecloud"
|
||||
if out, err := exec.Command(dockerBinary, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi").CombinedOutput(); err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
errchan := make(chan error)
|
||||
go func() {
|
||||
if out, err := exec.Command(dockerBinary, "kill", name).CombinedOutput(); err != nil {
|
||||
errchan <- fmt.Errorf("%v:\n%s", err, out)
|
||||
}
|
||||
close(errchan)
|
||||
}()
|
||||
select {
|
||||
case err := <-errchan:
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("Kill container timed out")
|
||||
}
|
||||
logDone("run - can kill container with pid-host and some childs of pid 1")
|
||||
}
|
||||
|
||||
+58
-59
@@ -5,7 +5,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/term/winconsole"
|
||||
)
|
||||
|
||||
@@ -22,49 +21,34 @@ type Winsize struct {
|
||||
y uint16
|
||||
}
|
||||
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
switch {
|
||||
case os.Getenv("ConEmuANSI") == "ON":
|
||||
// The ConEmu shell emulates ANSI well by default.
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
case os.Getenv("MSYSTEM") != "":
|
||||
// MSYS (mingw) does not emulate ANSI well.
|
||||
return winconsole.WinConsoleStreams()
|
||||
default:
|
||||
return winconsole.WinConsoleStreams()
|
||||
}
|
||||
}
|
||||
|
||||
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal.
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
return winconsole.GetHandleInfo(in)
|
||||
}
|
||||
|
||||
// GetWinsize retrieves the window size of the terminal connected to the passed file descriptor.
|
||||
// GetWinsize gets the window size of the given terminal
|
||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
||||
ws := &Winsize{}
|
||||
var info *winconsole.CONSOLE_SCREEN_BUFFER_INFO
|
||||
info, err := winconsole.GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(azlinux): Set the pixel width / height of the console (currently unused by any caller)
|
||||
return &Winsize{
|
||||
Width: uint16(info.Window.Right - info.Window.Left + 1),
|
||||
Height: uint16(info.Window.Bottom - info.Window.Top + 1),
|
||||
x: 0,
|
||||
y: 0}, nil
|
||||
ws.Width = uint16(info.Window.Right - info.Window.Left + 1)
|
||||
ws.Height = uint16(info.Window.Bottom - info.Window.Top + 1)
|
||||
|
||||
ws.x = 0 // todo azlinux -- this is the pixel size of the Window, and not currently used by any caller
|
||||
ws.y = 0
|
||||
|
||||
return ws, nil
|
||||
}
|
||||
|
||||
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
|
||||
// SetWinsize sets the terminal connected to the given file descriptor to a
|
||||
// given size.
|
||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||
// TODO(azlinux): Implement SetWinsize
|
||||
logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked")
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
return winconsole.IsConsole(fd)
|
||||
_, e := winconsole.GetConsoleMode(fd)
|
||||
return e == nil
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal connected to the given file descriptor to a
|
||||
@@ -73,7 +57,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
|
||||
return winconsole.SetConsoleMode(fd, state.mode)
|
||||
}
|
||||
|
||||
// SaveState saves the state of the terminal connected to the given file descriptor.
|
||||
// SaveState saves the state of the given console
|
||||
func SaveState(fd uintptr) (*State, error) {
|
||||
mode, e := winconsole.GetConsoleMode(fd)
|
||||
if e != nil {
|
||||
@@ -82,57 +66,72 @@ func SaveState(fd uintptr) (*State, error) {
|
||||
return &State{mode}, nil
|
||||
}
|
||||
|
||||
// DisableEcho disables echo for the terminal connected to the given file descriptor.
|
||||
// -- See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
// DisableEcho disbales the echo for given file descriptor and returns previous state
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
|
||||
func DisableEcho(fd uintptr, state *State) error {
|
||||
mode := state.mode
|
||||
mode &^= winconsole.ENABLE_ECHO_INPUT
|
||||
mode |= winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT
|
||||
// TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state.
|
||||
return winconsole.SetConsoleMode(fd, mode)
|
||||
state.mode &^= (winconsole.ENABLE_ECHO_INPUT)
|
||||
state.mode |= (winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT)
|
||||
return winconsole.SetConsoleMode(fd, state.mode)
|
||||
}
|
||||
|
||||
// SetRawTerminal puts the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
||||
state, err := MakeRaw(fd)
|
||||
oldState, err := MakeRaw(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state.
|
||||
return state, err
|
||||
// TODO (azlinux): implement handling interrupt and restore state of terminal
|
||||
return oldState, err
|
||||
}
|
||||
|
||||
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd uintptr) (*State, error) {
|
||||
var state *State
|
||||
state, err := SaveState(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// See
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
mode := state.mode
|
||||
|
||||
// Disable these modes
|
||||
mode &^= winconsole.ENABLE_ECHO_INPUT
|
||||
mode &^= winconsole.ENABLE_LINE_INPUT
|
||||
mode &^= winconsole.ENABLE_MOUSE_INPUT
|
||||
mode &^= winconsole.ENABLE_WINDOW_INPUT
|
||||
mode &^= winconsole.ENABLE_PROCESSED_INPUT
|
||||
|
||||
// Enable these modes
|
||||
mode |= winconsole.ENABLE_EXTENDED_FLAGS
|
||||
mode |= winconsole.ENABLE_INSERT_MODE
|
||||
mode |= winconsole.ENABLE_QUICK_EDIT_MODE
|
||||
|
||||
err = winconsole.SetConsoleMode(fd, mode)
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
// All three input modes, along with processed output mode, are designed to work together.
|
||||
// It is best to either enable or disable all of these modes as a group.
|
||||
// When all are enabled, the application is said to be in "cooked" mode, which means that most of the processing is handled for the application.
|
||||
// When all are disabled, the application is in "raw" mode, which means that input is unfiltered and any processing is left to the application.
|
||||
state.mode = 0
|
||||
err = winconsole.SetConsoleMode(fd, state.mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal
|
||||
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||
return winconsole.GetHandleInfo(in)
|
||||
}
|
||||
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
var shouldEmulateANSI bool
|
||||
switch {
|
||||
case os.Getenv("ConEmuANSI") == "ON":
|
||||
// ConEmu shell, ansi emulated by default and ConEmu does an extensively
|
||||
// good emulation.
|
||||
shouldEmulateANSI = false
|
||||
case os.Getenv("MSYSTEM") != "":
|
||||
// MSYS (mingw) cannot fully emulate well and still shows escape characters
|
||||
// mostly because it's still running on cmd.exe window.
|
||||
shouldEmulateANSI = true
|
||||
default:
|
||||
shouldEmulateANSI = true
|
||||
}
|
||||
|
||||
if shouldEmulateANSI {
|
||||
return winconsole.StdStreams()
|
||||
}
|
||||
|
||||
return os.Stdin, os.Stdout, os.Stderr
|
||||
}
|
||||
|
||||
@@ -12,22 +12,18 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// Consts for Get/SetConsoleMode function
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
ENABLE_PROCESSED_INPUT = 0x0001
|
||||
ENABLE_LINE_INPUT = 0x0002
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
|
||||
ENABLE_ECHO_INPUT = 0x0004
|
||||
ENABLE_WINDOW_INPUT = 0x0008
|
||||
ENABLE_MOUSE_INPUT = 0x0010
|
||||
ENABLE_INSERT_MODE = 0x0020
|
||||
ENABLE_LINE_INPUT = 0x0002
|
||||
ENABLE_MOUSE_INPUT = 0x0010
|
||||
ENABLE_PROCESSED_INPUT = 0x0001
|
||||
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||
|
||||
ENABLE_WINDOW_INPUT = 0x0008
|
||||
// If parameter is a screen buffer handle, additional values
|
||||
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||
@@ -101,27 +97,27 @@ const (
|
||||
VK_HOME = 0x24 // HOME key
|
||||
VK_LEFT = 0x25 // LEFT ARROW key
|
||||
VK_UP = 0x26 // UP ARROW key
|
||||
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||
VK_DOWN = 0x28 // DOWN ARROW key
|
||||
VK_SELECT = 0x29 // SELECT key
|
||||
VK_PRINT = 0x2A // PRINT key
|
||||
VK_EXECUTE = 0x2B // EXECUTE key
|
||||
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||
VK_INSERT = 0x2D // INS key
|
||||
VK_DELETE = 0x2E // DEL key
|
||||
VK_HELP = 0x2F // HELP key
|
||||
VK_F1 = 0x70 // F1 key
|
||||
VK_F2 = 0x71 // F2 key
|
||||
VK_F3 = 0x72 // F3 key
|
||||
VK_F4 = 0x73 // F4 key
|
||||
VK_F5 = 0x74 // F5 key
|
||||
VK_F6 = 0x75 // F6 key
|
||||
VK_F7 = 0x76 // F7 key
|
||||
VK_F8 = 0x77 // F8 key
|
||||
VK_F9 = 0x78 // F9 key
|
||||
VK_F10 = 0x79 // F10 key
|
||||
VK_F11 = 0x7A // F11 key
|
||||
VK_F12 = 0x7B // F12 key
|
||||
VK_RIGHT = 0x27 //RIGHT ARROW key
|
||||
VK_DOWN = 0x28 //DOWN ARROW key
|
||||
VK_SELECT = 0x29 //SELECT key
|
||||
VK_PRINT = 0x2A //PRINT key
|
||||
VK_EXECUTE = 0x2B //EXECUTE key
|
||||
VK_SNAPSHOT = 0x2C //PRINT SCREEN key
|
||||
VK_INSERT = 0x2D //INS key
|
||||
VK_DELETE = 0x2E //DEL key
|
||||
VK_HELP = 0x2F //HELP key
|
||||
VK_F1 = 0x70 //F1 key
|
||||
VK_F2 = 0x71 //F2 key
|
||||
VK_F3 = 0x72 //F3 key
|
||||
VK_F4 = 0x73 //F4 key
|
||||
VK_F5 = 0x74 //F5 key
|
||||
VK_F6 = 0x75 //F6 key
|
||||
VK_F7 = 0x76 //F7 key
|
||||
VK_F8 = 0x77 //F8 key
|
||||
VK_F9 = 0x78 //F9 key
|
||||
VK_F10 = 0x79 //F10 key
|
||||
VK_F11 = 0x7A //F11 key
|
||||
VK_F12 = 0x7B //F12 key
|
||||
)
|
||||
|
||||
var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||
@@ -144,12 +140,7 @@ var (
|
||||
// types for calling various windows API
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
|
||||
type (
|
||||
SHORT int16
|
||||
BOOL int32
|
||||
WORD uint16
|
||||
WCHAR uint16
|
||||
DWORD uint32
|
||||
|
||||
SHORT int16
|
||||
SMALL_RECT struct {
|
||||
Left SHORT
|
||||
Top SHORT
|
||||
@@ -162,6 +153,11 @@ type (
|
||||
Y SHORT
|
||||
}
|
||||
|
||||
BOOL int32
|
||||
WORD uint16
|
||||
WCHAR uint16
|
||||
DWORD uint32
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||
Size COORD
|
||||
CursorPosition COORD
|
||||
@@ -196,10 +192,6 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// TODO(azlinux): Basic type clean-up
|
||||
// -- Convert all uses of uintptr to syscall.Handle to be consistent with Windows syscall
|
||||
// -- Convert, as appropriate, types to use defined Windows types (e.g., DWORD instead of uint32)
|
||||
|
||||
// Implements the TerminalEmulator interface
|
||||
type WindowsTerminal struct {
|
||||
outMutex sync.Mutex
|
||||
@@ -219,14 +211,14 @@ func getStdHandle(stdhandle int) uintptr {
|
||||
return uintptr(handle)
|
||||
}
|
||||
|
||||
func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
|
||||
handler := &WindowsTerminal{
|
||||
inputBuffer: make([]byte, MAX_INPUT_BUFFER),
|
||||
inputEscapeSequence: []byte(KEY_ESC_CSI),
|
||||
inputEvents: make([]INPUT_RECORD, MAX_INPUT_EVENTS),
|
||||
}
|
||||
|
||||
if IsConsole(os.Stdin.Fd()) {
|
||||
if IsTerminal(os.Stdin.Fd()) {
|
||||
stdIn = &terminalReader{
|
||||
wrappedReader: os.Stdin,
|
||||
emulator: handler,
|
||||
@@ -237,7 +229,7 @@ func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
stdIn = os.Stdin
|
||||
}
|
||||
|
||||
if IsConsole(os.Stdout.Fd()) {
|
||||
if IsTerminal(os.Stdout.Fd()) {
|
||||
stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE)
|
||||
|
||||
// Save current screen buffer info
|
||||
@@ -261,7 +253,7 @@ func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
stdOut = os.Stdout
|
||||
}
|
||||
|
||||
if IsConsole(os.Stderr.Fd()) {
|
||||
if IsTerminal(os.Stderr.Fd()) {
|
||||
stdErr = &terminalWriter{
|
||||
wrappedWriter: os.Stderr,
|
||||
emulator: handler,
|
||||
@@ -275,21 +267,25 @@ func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
||||
return stdIn, stdOut, stdErr
|
||||
}
|
||||
|
||||
// GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
|
||||
// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal
|
||||
func GetHandleInfo(in interface{}) (uintptr, bool) {
|
||||
var inFd uintptr
|
||||
var isTerminalIn bool
|
||||
|
||||
switch t := in.(type) {
|
||||
case *terminalReader:
|
||||
in = t.wrappedReader
|
||||
case *terminalWriter:
|
||||
in = t.wrappedWriter
|
||||
}
|
||||
|
||||
if file, ok := in.(*os.File); ok {
|
||||
inFd = file.Fd()
|
||||
isTerminalIn = IsConsole(inFd)
|
||||
isTerminalIn = IsTerminal(inFd)
|
||||
}
|
||||
if tr, ok := in.(*terminalReader); ok {
|
||||
if file, ok := tr.wrappedReader.(*os.File); ok {
|
||||
inFd = file.Fd()
|
||||
isTerminalIn = IsTerminal(inFd)
|
||||
}
|
||||
}
|
||||
if tr, ok := in.(*terminalWriter); ok {
|
||||
if file, ok := tr.wrappedWriter.(*os.File); ok {
|
||||
inFd = file.Fd()
|
||||
isTerminalIn = IsTerminal(inFd)
|
||||
}
|
||||
}
|
||||
return inFd, isTerminalIn
|
||||
}
|
||||
@@ -322,12 +318,12 @@ func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||
// SetCursorVisible sets the cursor visbility
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx
|
||||
func SetCursorVisible(handle uintptr, isVisible BOOL) (bool, error) {
|
||||
var cursorInfo *CONSOLE_CURSOR_INFO = &CONSOLE_CURSOR_INFO{}
|
||||
if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil {
|
||||
var cursorInfo CONSOLE_CURSOR_INFO
|
||||
if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
cursorInfo.Visible = isVisible
|
||||
if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)); err != nil {
|
||||
if err := getError(setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
@@ -412,25 +408,25 @@ func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 {
|
||||
|
||||
var buffer []CHAR_INFO
|
||||
|
||||
func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
|
||||
func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
|
||||
var writeRegion SMALL_RECT
|
||||
writeRegion.Left = fromCoord.X
|
||||
writeRegion.Top = fromCoord.Y
|
||||
writeRegion.Left = fromCoord.X
|
||||
writeRegion.Right = toCoord.X
|
||||
writeRegion.Bottom = toCoord.Y
|
||||
|
||||
// allocate and initialize buffer
|
||||
width := toCoord.X - fromCoord.X + 1
|
||||
height := toCoord.Y - fromCoord.Y + 1
|
||||
size := uint32(width) * uint32(height)
|
||||
size := width * height
|
||||
if size > 0 {
|
||||
buffer := make([]CHAR_INFO, size)
|
||||
for i := range buffer {
|
||||
buffer[i] = CHAR_INFO{WCHAR(' '), attributes}
|
||||
for i := 0; i < int(size); i++ {
|
||||
buffer[i].UnicodeChar = WCHAR(fillChar)
|
||||
buffer[i].Attributes = attributes
|
||||
}
|
||||
|
||||
// Write to buffer
|
||||
r, err := writeConsoleOutput(handle, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &writeRegion)
|
||||
r, err := writeConsoleOutput(handle, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion)
|
||||
if !r {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -441,18 +437,18 @@ func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord
|
||||
return uint32(size), nil
|
||||
}
|
||||
|
||||
func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
|
||||
func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
|
||||
nw := uint32(0)
|
||||
// start and end on same line
|
||||
if fromCoord.Y == toCoord.Y {
|
||||
return clearDisplayRect(handle, attributes, fromCoord, toCoord)
|
||||
return clearDisplayRect(handle, fillChar, attributes, fromCoord, toCoord, windowSize)
|
||||
}
|
||||
// TODO(azlinux): if full screen, optimize
|
||||
|
||||
// spans more than one line
|
||||
if fromCoord.Y < toCoord.Y {
|
||||
// from start position till end of line for first line
|
||||
n, err := clearDisplayRect(handle, attributes, fromCoord, COORD{X: toCoord.X, Y: fromCoord.Y})
|
||||
n, err := clearDisplayRect(handle, fillChar, attributes, fromCoord, COORD{X: windowSize.X - 1, Y: fromCoord.Y}, windowSize)
|
||||
if err != nil {
|
||||
return nw, err
|
||||
}
|
||||
@@ -460,14 +456,14 @@ func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord
|
||||
// lines between
|
||||
linesBetween := toCoord.Y - fromCoord.Y - 1
|
||||
if linesBetween > 0 {
|
||||
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: toCoord.X, Y: toCoord.Y - 1})
|
||||
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: windowSize.X - 1, Y: toCoord.Y - 1}, windowSize)
|
||||
if err != nil {
|
||||
return nw, err
|
||||
}
|
||||
nw += n
|
||||
}
|
||||
// lines at end
|
||||
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord)
|
||||
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord, windowSize)
|
||||
if err != nil {
|
||||
return nw, err
|
||||
}
|
||||
@@ -497,7 +493,7 @@ func setConsoleCursorPosition(handle uintptr, isRelative bool, column int16, lin
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683207(v=vs.85).aspx
|
||||
func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) {
|
||||
var n DWORD
|
||||
var n WORD
|
||||
if err := getError(getNumberOfConsoleInputEventsProc.Call(handle, uintptr(unsafe.Pointer(&n)))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -506,7 +502,7 @@ func getNumberOfConsoleInputEvents(handle uintptr) (uint16, error) {
|
||||
|
||||
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx
|
||||
func readConsoleInputKey(handle uintptr, inputBuffer []INPUT_RECORD) (int, error) {
|
||||
var nr DWORD
|
||||
var nr WORD
|
||||
if err := getError(readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&inputBuffer[0])), uintptr(len(inputBuffer)), uintptr(unsafe.Pointer(&nr)))); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -595,7 +591,6 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
n = len(command)
|
||||
|
||||
parsedCommand := parseAnsiCommand(command)
|
||||
logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand)
|
||||
|
||||
// console settings changes need to happen in atomic way
|
||||
term.outMutex.Lock()
|
||||
@@ -641,17 +636,16 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
return n, err
|
||||
}
|
||||
if line > int16(screenBufferInfo.Window.Bottom) {
|
||||
line = int16(screenBufferInfo.Window.Bottom) + 1
|
||||
line = int16(screenBufferInfo.Window.Bottom)
|
||||
}
|
||||
column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if column > int16(screenBufferInfo.Window.Right) {
|
||||
column = int16(screenBufferInfo.Window.Right) + 1
|
||||
column = int16(screenBufferInfo.Window.Right)
|
||||
}
|
||||
// The numbers are not 0 based, but 1 based
|
||||
logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1)
|
||||
if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil {
|
||||
return n, err
|
||||
}
|
||||
@@ -719,9 +713,9 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
switch value {
|
||||
case 0:
|
||||
start = screenBufferInfo.CursorPosition
|
||||
// end of the buffer
|
||||
end.X = screenBufferInfo.Size.X - 1
|
||||
end.Y = screenBufferInfo.Size.Y - 1
|
||||
// end of the screen
|
||||
end.X = screenBufferInfo.MaximumWindowSize.X - 1
|
||||
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
|
||||
// cursor
|
||||
cursor = screenBufferInfo.CursorPosition
|
||||
case 1:
|
||||
@@ -737,21 +731,20 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
// start of the screen
|
||||
start.X = 0
|
||||
start.Y = 0
|
||||
// end of the buffer
|
||||
end.X = screenBufferInfo.Size.X - 1
|
||||
end.Y = screenBufferInfo.Size.Y - 1
|
||||
// end of the screen
|
||||
end.X = screenBufferInfo.MaximumWindowSize.X - 1
|
||||
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
|
||||
// cursor
|
||||
cursor.X = 0
|
||||
cursor.Y = 0
|
||||
}
|
||||
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
|
||||
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
|
||||
return n, err
|
||||
}
|
||||
// remember the the cursor position is 1 based
|
||||
if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
case "K":
|
||||
// [K
|
||||
// Clears all characters from the cursor position to the end of the line (including the character at the cursor position).
|
||||
@@ -771,7 +764,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
// start is where cursor is
|
||||
start = screenBufferInfo.CursorPosition
|
||||
// end of line
|
||||
end.X = screenBufferInfo.Size.X - 1
|
||||
end.X = screenBufferInfo.MaximumWindowSize.X - 1
|
||||
end.Y = screenBufferInfo.CursorPosition.Y
|
||||
// cursor remains the same
|
||||
cursor = screenBufferInfo.CursorPosition
|
||||
@@ -787,15 +780,15 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
|
||||
case 2:
|
||||
// start of the line
|
||||
start.X = 0
|
||||
start.Y = screenBufferInfo.CursorPosition.Y - 1
|
||||
start.Y = screenBufferInfo.MaximumWindowSize.Y - 1
|
||||
// end of the line
|
||||
end.X = screenBufferInfo.Size.X - 1
|
||||
end.Y = screenBufferInfo.CursorPosition.Y - 1
|
||||
end.X = screenBufferInfo.MaximumWindowSize.X - 1
|
||||
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
|
||||
// cursor
|
||||
cursor.X = 0
|
||||
cursor.Y = screenBufferInfo.CursorPosition.Y - 1
|
||||
cursor.Y = screenBufferInfo.MaximumWindowSize.Y - 1
|
||||
}
|
||||
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
|
||||
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
|
||||
return n, err
|
||||
}
|
||||
// remember the the cursor position is 1 based
|
||||
@@ -1042,12 +1035,12 @@ func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n
|
||||
}
|
||||
|
||||
func marshal(c COORD) uintptr {
|
||||
return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
|
||||
// works only on intel-endian machines
|
||||
return uintptr(uint32(uint32(uint16(c.Y))<<16 | uint32(uint16(c.X))))
|
||||
}
|
||||
|
||||
// IsConsole returns true if the given file descriptor is a terminal.
|
||||
// -- The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
|
||||
func IsConsole(fd uintptr) bool {
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
_, e := GetConsoleMode(fd)
|
||||
return e == nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package winconsole
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -207,21 +206,6 @@ func (c *ansiCommand) getParam(index int) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ac *ansiCommand) String() string {
|
||||
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||
bytesToHex(ac.CommandBytes),
|
||||
ac.Command,
|
||||
strings.Join(ac.Parameters, "\",\""))
|
||||
}
|
||||
|
||||
func bytesToHex(b []byte) string {
|
||||
hex := make([]string, len(b))
|
||||
for i, ch := range b {
|
||||
hex[i] = fmt.Sprintf("%X", ch)
|
||||
}
|
||||
return strings.Join(hex, "")
|
||||
}
|
||||
|
||||
func parseInt16OrDefault(s string, defaultValue int16) (n int16, err error) {
|
||||
if s == "" {
|
||||
return defaultValue, nil
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
bundles
|
||||
nsinit/nsinit
|
||||
|
||||
@@ -29,5 +29,3 @@ local:
|
||||
validate:
|
||||
hack/validate.sh
|
||||
|
||||
binary: all
|
||||
docker run --rm --privileged -v $(CURDIR)/bundles:/go/bin dockercore/libcontainer make direct-install
|
||||
|
||||
@@ -141,9 +141,6 @@ container.Resume()
|
||||
It is able to spawn new containers or join existing containers. A root
|
||||
filesystem must be provided for use along with a container configuration file.
|
||||
|
||||
To build `nsinit`, run `make binary`. It will save the binary into
|
||||
`bundles/nsinit`.
|
||||
|
||||
To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into
|
||||
the directory with your specified configuration. Environment, networking,
|
||||
and different capabilities for the container are specified in this file.
|
||||
|
||||
@@ -67,12 +67,12 @@ func generateProfile(out io.Writer) error {
|
||||
data := &data{
|
||||
Name: "docker-default",
|
||||
}
|
||||
if tunablesExists() {
|
||||
if tuntablesExists() {
|
||||
data.Imports = append(data.Imports, "#include <tunables/global>")
|
||||
} else {
|
||||
data.Imports = append(data.Imports, "@{PROC}=/proc/")
|
||||
}
|
||||
if abstractionsExists() {
|
||||
if abstrctionsEsists() {
|
||||
data.InnerImports = append(data.InnerImports, "#include <abstractions/base>")
|
||||
}
|
||||
if err := compiled.Execute(out, data); err != nil {
|
||||
@@ -82,13 +82,13 @@ func generateProfile(out io.Writer) error {
|
||||
}
|
||||
|
||||
// check if the tunables/global exist
|
||||
func tunablesExists() bool {
|
||||
func tuntablesExists() bool {
|
||||
_, err := os.Stat("/etc/apparmor.d/tunables/global")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// check if abstractions/base exist
|
||||
func abstractionsExists() bool {
|
||||
func abstrctionsEsists() bool {
|
||||
_, err := os.Stat("/etc/apparmor.d/abstractions/base")
|
||||
return err == nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -42,10 +41,6 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
case configs.Undefined:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Freezer))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/configs"
|
||||
)
|
||||
|
||||
func TestFreezerSetState(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("freezer", t)
|
||||
defer helper.cleanup()
|
||||
|
||||
helper.writeFileContents(map[string]string{
|
||||
"freezer.state": string(configs.Frozen),
|
||||
})
|
||||
|
||||
helper.CgroupData.c.Freezer = configs.Thawed
|
||||
freezer := &FreezerGroup{}
|
||||
if err := freezer.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value, err := getCgroupParamString(helper.CgroupPath, "freezer.state")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse freezer.state - %s", err)
|
||||
}
|
||||
if value != string(configs.Thawed) {
|
||||
t.Fatal("Got the wrong value, set freezer.state failed.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreezerSetInvalidState(t *testing.T) {
|
||||
helper := NewCgroupTestUtil("freezer", t)
|
||||
defer helper.cleanup()
|
||||
|
||||
const (
|
||||
invalidArg configs.FreezerState = "Invalid"
|
||||
)
|
||||
|
||||
helper.CgroupData.c.Freezer = invalidArg
|
||||
freezer := &FreezerGroup{}
|
||||
if err := freezer.Set(helper.CgroupPath, helper.CgroupData.c); err == nil {
|
||||
t.Fatal("Failed to return invalid argument error")
|
||||
}
|
||||
}
|
||||
+47
-28
@@ -3,6 +3,7 @@
|
||||
package systemd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -217,7 +218,16 @@ func (m *Manager) Apply(pid int) error {
|
||||
}
|
||||
|
||||
paths := make(map[string]string)
|
||||
for sysname := range subsystems {
|
||||
for _, sysname := range []string{
|
||||
"devices",
|
||||
"memory",
|
||||
"cpu",
|
||||
"cpuset",
|
||||
"cpuacct",
|
||||
"blkio",
|
||||
"perf_event",
|
||||
"freezer",
|
||||
} {
|
||||
subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
|
||||
if err != nil {
|
||||
// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
|
||||
@@ -246,21 +256,6 @@ func writeFile(dir, file, data string) error {
|
||||
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
||||
}
|
||||
|
||||
func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
|
||||
path, err := getSubsystemPath(c, subsystem)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||
return "", err
|
||||
}
|
||||
if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func joinCpu(c *configs.Cgroup, pid int) error {
|
||||
path, err := getSubsystemPath(c, "cpu")
|
||||
if err != nil {
|
||||
@@ -280,11 +275,16 @@ func joinCpu(c *configs.Cgroup, pid int) error {
|
||||
}
|
||||
|
||||
func joinFreezer(c *configs.Cgroup, pid int) error {
|
||||
if _, err := join(c, "freezer", pid); err != nil {
|
||||
path, err := getSubsystemPath(c, "freezer")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700)
|
||||
}
|
||||
|
||||
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
|
||||
@@ -312,15 +312,21 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
|
||||
return err
|
||||
}
|
||||
|
||||
prevState := m.Cgroups.Freezer
|
||||
m.Cgroups.Freezer = state
|
||||
|
||||
freezer := subsystems["freezer"]
|
||||
err = freezer.Set(path, m.Cgroups)
|
||||
if err != nil {
|
||||
m.Cgroups.Freezer = prevState
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
state_, err := ioutil.ReadFile(filepath.Join(path, "freezer.state"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if string(state) == string(bytes.TrimSpace(state_)) {
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
|
||||
m.Cgroups.Freezer = state
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -369,16 +375,29 @@ func getUnitName(c *configs.Cgroup) string {
|
||||
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
|
||||
// This happens at least for v208 when any sibling unit is started.
|
||||
func joinDevices(c *configs.Cgroup, pid int) error {
|
||||
path, err := join(c, "devices", pid)
|
||||
path, err := getSubsystemPath(c, "devices")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
devices := subsystems["devices"]
|
||||
if err := devices.Set(path, c); err != nil {
|
||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.AllowAllDevices {
|
||||
if err := writeFile(path, "devices.deny", "a"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, dev := range c.AllowedDevices {
|
||||
if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,6 @@ const (
|
||||
NEWUSER NamespaceType = "NEWUSER"
|
||||
)
|
||||
|
||||
func NamespaceTypes() []NamespaceType {
|
||||
return []NamespaceType{
|
||||
NEWNET,
|
||||
NEWPID,
|
||||
NEWNS,
|
||||
NEWUTS,
|
||||
NEWIPC,
|
||||
NEWUSER,
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace defines configuration for each namespace. It specifies an
|
||||
// alternate path that is able to be joined via setns.
|
||||
type Namespace struct {
|
||||
|
||||
@@ -140,9 +140,7 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
cmd.ExtraFiles = []*os.File{childPipe}
|
||||
// NOTE: when running a container with no PID namespace and the parent process spawning the container is
|
||||
// PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason
|
||||
// even with the parent still running.
|
||||
cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
|
||||
if c.config.ParentDeathSignal > 0 {
|
||||
cmd.SysProcAttr.Pdeathsig = syscall.Signal(c.config.ParentDeathSignal)
|
||||
}
|
||||
@@ -306,11 +304,5 @@ func (c *linuxContainer) currentState() (*State, error) {
|
||||
for _, ns := range c.config.Namespaces {
|
||||
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
||||
}
|
||||
for _, nsType := range configs.NamespaceTypes() {
|
||||
if _, ok := state.NamespacePaths[nsType]; !ok {
|
||||
ns := configs.Namespace{Type: nsType}
|
||||
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
||||
}
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
@@ -130,8 +130,7 @@ func TestGetContainerState(t *testing.T) {
|
||||
{Type: configs.NEWNS},
|
||||
{Type: configs.NEWNET, Path: expectedNetworkPath},
|
||||
{Type: configs.NEWUTS},
|
||||
// emulate host for IPC
|
||||
//{Type: configs.NEWIPC},
|
||||
{Type: configs.NEWIPC},
|
||||
},
|
||||
},
|
||||
initProcess: &mockProcess{
|
||||
|
||||
+1
-2
@@ -69,8 +69,7 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
|
||||
}, nil
|
||||
case initStandard:
|
||||
return &linuxStandardInit{
|
||||
parentPid: syscall.Getppid(),
|
||||
config: config,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown init type %q", t)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/cgroups/systemd"
|
||||
"github.com/docker/libcontainer/configs"
|
||||
)
|
||||
|
||||
@@ -482,17 +481,6 @@ func TestProcessCaps(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFreeze(t *testing.T) {
|
||||
testFreeze(t, false)
|
||||
}
|
||||
|
||||
func TestSystemdFreeze(t *testing.T) {
|
||||
if !systemd.UseSystemd() {
|
||||
t.Skip("Systemd is unsupported")
|
||||
}
|
||||
testFreeze(t, true)
|
||||
}
|
||||
|
||||
func testFreeze(t *testing.T, systemd bool) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
@@ -509,9 +497,6 @@ func testFreeze(t *testing.T, systemd bool) {
|
||||
defer remove(rootfs)
|
||||
|
||||
config := newTemplateConfig(rootfs)
|
||||
if systemd {
|
||||
config.Cgroups.Slice = "system.slice"
|
||||
}
|
||||
|
||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
||||
if err != nil {
|
||||
@@ -574,77 +559,3 @@ func testFreeze(t *testing.T, systemd bool) {
|
||||
t.Fatal(s.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerState(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
root, err := newTestRoot()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
rootfs, err := newRootfs()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer remove(rootfs)
|
||||
|
||||
l, err := os.Readlink("/proc/1/ns/ipc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
config := newTemplateConfig(rootfs)
|
||||
config.Namespaces = configs.Namespaces([]configs.Namespace{
|
||||
{Type: configs.NEWNS},
|
||||
{Type: configs.NEWUTS},
|
||||
// host for IPC
|
||||
//{Type: configs.NEWIPC},
|
||||
{Type: configs.NEWPID},
|
||||
{Type: configs.NEWNET},
|
||||
})
|
||||
|
||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
container, err := factory.Create("test", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer container.Destroy()
|
||||
|
||||
stdinR, stdinW, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := &libcontainer.Process{
|
||||
Args: []string{"cat"},
|
||||
Env: standardEnvironment,
|
||||
Stdin: stdinR,
|
||||
}
|
||||
err = container.Start(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stdinR.Close()
|
||||
defer p.Signal(os.Kill)
|
||||
|
||||
st, err := container.State()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l1, err := os.Readlink(st.NamespacePaths[configs.NEWIPC])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if l1 != l {
|
||||
t.Fatal("Container using non-host ipc namespace")
|
||||
}
|
||||
stdinW.Close()
|
||||
p.Wait()
|
||||
}
|
||||
|
||||
@@ -68,14 +68,9 @@ func copyBusybox(dest string) error {
|
||||
}
|
||||
|
||||
func newContainer(config *configs.Config) (libcontainer.Container, error) {
|
||||
cgm := libcontainer.Cgroupfs
|
||||
if config.Cgroups != nil && config.Cgroups.Slice == "system.slice" {
|
||||
cgm = libcontainer.SystemdCgroups
|
||||
}
|
||||
|
||||
factory, err := libcontainer.New(".",
|
||||
libcontainer.InitArgs(os.Args[0], "init", "--"),
|
||||
cgm,
|
||||
libcontainer.Cgroupfs,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+19
-29
@@ -5,15 +5,13 @@ It is able to spawn new containers or join existing containers.
|
||||
|
||||
### How to build?
|
||||
|
||||
First add the `libcontainer/vendor` into your GOPATH. It's because libcontainer
|
||||
vendors all its dependencies, so it can be built predictably.
|
||||
First to add the `libcontainer/vendor` into your GOPATH. It's because something related with this [issue](https://github.com/docker/libcontainer/issues/210).
|
||||
|
||||
```
|
||||
export GOPATH=$GOPATH:/your/path/to/libcontainer/vendor
|
||||
```
|
||||
|
||||
Then get into the nsinit folder and get the imported file. Use `make` command
|
||||
to make the nsinit binary.
|
||||
Then get into the nsinit folder and get the imported file. Use `make` command to make the nsinit binary.
|
||||
|
||||
```
|
||||
cd libcontainer/nsinit
|
||||
@@ -21,8 +19,7 @@ go get
|
||||
make
|
||||
```
|
||||
|
||||
We have finished compiling the nsinit package, but a root filesystem must be
|
||||
provided for use along with a container configuration file.
|
||||
We have finished compiling the nsinit package, but a root filesystem must be provided for use along with a container configuration file.
|
||||
|
||||
Choose a proper place to run your container. For example we use `/busybox`.
|
||||
|
||||
@@ -31,37 +28,30 @@ mkdir /busybox
|
||||
curl -sSL 'https://github.com/jpetazzo/docker-busybox/raw/buildroot-2014.11/rootfs.tar' | tar -xC /busybox
|
||||
```
|
||||
|
||||
Then you may need to write a configuration file named `container.json` in the
|
||||
`/busybox` folder. Environment, networking, and different capabilities for
|
||||
the container are specified in this file. The configuration is used for each
|
||||
process executed inside the container.
|
||||
|
||||
See the `sample_configs` folder for examples of what the container configuration
|
||||
should look like.
|
||||
Then you may need to write a configure file named `container.json` in the `/busybox` folder.
|
||||
Environment, networking, and different capabilities for the container are specified in this file.
|
||||
The configuration is used for each process executed inside the container
|
||||
See the `sample_configs` folder for examples of what the container configuration should look like.
|
||||
|
||||
```
|
||||
cp libcontainer/sample_configs/minimal.json /busybox/container.json
|
||||
cd /busybox
|
||||
```
|
||||
|
||||
You can customize `container.json` per your needs. After that, nsinit is
|
||||
ready to work.
|
||||
|
||||
To execute `/bin/bash` in the current directory as a container just run the
|
||||
following **as root**:
|
||||
|
||||
Now the nsinit is ready to work.
|
||||
To execute `/bin/bash` in the current directory as a container just run the following **as root**:
|
||||
```bash
|
||||
nsinit exec --tty --config container.json /bin/bash
|
||||
nsinit exec --tty /bin/bash
|
||||
```
|
||||
|
||||
If you wish to spawn another process inside the container while your current
|
||||
bash session is running, run the same command again to get another bash shell
|
||||
(or change the command). If the original process (PID 1) dies, all other
|
||||
processes spawned inside the container will be killed and the namespace will
|
||||
be removed.
|
||||
If you wish to spawn another process inside the container while your
|
||||
current bash session is running, run the same command again to
|
||||
get another bash shell (or change the command). If the original
|
||||
process (PID 1) dies, all other processes spawned inside the container
|
||||
will be killed and the namespace will be removed.
|
||||
|
||||
You can identify if a process is running in a container by looking to see if
|
||||
`state.json` is in the root of the directory.
|
||||
You can identify if a process is running in a container by
|
||||
looking to see if `state.json` is in the root of the directory.
|
||||
|
||||
You may also specify an alternate root directory from where the `container.json`
|
||||
file is read and where the `state.json` file will be saved.
|
||||
You may also specify an alternate root place where
|
||||
the `container.json` file is read and where the `state.json` file will be saved.
|
||||
|
||||
@@ -13,7 +13,7 @@ func main() {
|
||||
app.Version = "2"
|
||||
app.Author = "libcontainer maintainers"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "root", Value: "/var/run/nsinit", Usage: "root directory for containers"},
|
||||
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
|
||||
cli.StringFlag{Name: "log-file", Value: "", Usage: "set the log file to output logs to"},
|
||||
cli.BoolFlag{Name: "debug", Usage: "enable debug output in the logs"},
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ import (
|
||||
)
|
||||
|
||||
type linuxStandardInit struct {
|
||||
parentPid int
|
||||
config *initConfig
|
||||
config *initConfig
|
||||
}
|
||||
|
||||
func (l *linuxStandardInit) Init() error {
|
||||
@@ -86,10 +85,9 @@ func (l *linuxStandardInit) Init() error {
|
||||
if err := pdeath.Restore(); err != nil {
|
||||
return err
|
||||
}
|
||||
// compare the parent from the inital start of the init process and make sure that it did not change.
|
||||
// if the parent changes that means it died and we were reparened to something else so we should
|
||||
// just kill ourself and not cause problems for someone else.
|
||||
if syscall.Getppid() != l.parentPid {
|
||||
// Signal self if parent is already dead. Does nothing if running in a new
|
||||
// PID namespace, as Getppid will always return 0.
|
||||
if syscall.Getppid() == 1 {
|
||||
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
|
||||
}
|
||||
return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
|
||||
|
||||
Reference in New Issue
Block a user