Compare commits

..

14 Commits

Author SHA1 Message Date
Jessica Frazelle f181f776c7 Bump version to v1.6.0
Docker-DCO-1.1-Signed-off-by: Jessie Frazelle <princess@docker.com> (github: jfrazelle)
2015-04-13 12:28:29 -07:00
Alexander Morozov 10affa8018 Get process list after PID 1 dead
Fix #11087

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ac8bd12b39)
2015-04-13 12:28:22 -07:00
Deng Guangxing ce27fa2716 move syslog-tag to syslog.New function
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit 4f91a333d5)
2015-04-13 12:17:26 -07:00
Brendan Dixon 8d83409e85 Turned off Ctrl+C processing by Windows shell
Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit c337bfd2e0)
2015-04-10 16:41:59 -07:00
Nathan LeClaire 3a73b6a2bf Allow SEO crawling from docs site
Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>

Docker-DCO-1.1-Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com> (github: nathanleclaire)

(cherry picked from commit de03f4797b)
2015-04-10 15:59:35 -07:00
Tianon Gravi f99269882f Commonalize more bits of install.sh (especially standardizing around "cat <<-EOF")
Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
(cherry picked from commit 6842bba163)
2015-04-10 11:20:15 -07:00
Eric Windisch 568a9703ac Wrap installer in a function
This will assure that the install script will not
begin executing until after it has been downloaded should
it be utilized in a 'curl | bash' workflow.

Signed-off-by: Eric Windisch <eric@windisch.us>
(cherry picked from commit fa961ce046)
2015-04-10 11:20:15 -07:00
Aaron Welch faaeb5162d add centos to supported distros
Signed-off-by: Aaron Welch <welch@packet.net>
(cherry picked from commit a6b8f2e3fe)
2015-04-10 11:20:15 -07:00
Brendan Dixon b5613baac2 Corrected int16 overflow and buffer sizes
Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit a264e1e83d)
2015-04-10 11:20:15 -07:00
Alexander Morozov c956efcd52 Update libcontainer to bd8ec36106086f72b66e1be85a81202b93503e44
Fix #12130

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit 2f853b9493)
2015-04-07 16:22:37 -07:00
Alexander Morozov 5455864187 Test case for network mode chain container -> container -> host
Issue #12130

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
(cherry picked from commit ce69dafe4d)
2015-04-07 16:22:37 -07:00
Ahmet Alp Balkan ceb72fab34 Swap width/height in GetWinsize and monitorTtySize
Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 6e44246fed)
2015-04-06 16:55:38 -07:00
Brendan Dixon c6ea062a26 Windows console fixes
Corrected integer size passed to Windows
Corrected DisableEcho / SetRawTerminal to not modify state
Cleaned up and made routines more idiomatic
Corrected raw mode state bits
Removed duplicate IsTerminal
Corrected off-by-one error
Minor idiomatic change

Signed-off-by: Brendan Dixon <brendand@microsoft.com>
(cherry picked from commit 1a36a113d4)
2015-04-06 11:48:33 -07:00
Ahmet Alp Balkan 0e045ab50c docs: Add new windows installation tutorials
Updated Windows installation documentation with newest
screencasts and Chocolatey instructions to install windows
client CLI.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
(cherry picked from commit 2b320a2309)
2015-04-03 13:51:53 -07:00
22 changed files with 640 additions and 418 deletions
+1 -1
View File
@@ -1 +1 @@
1.6.0-rc4
1.6.0-rc6
+3 -3
View File
@@ -281,16 +281,16 @@ func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
if runtime.GOOS == "windows" {
go func() {
prevW, prevH := cli.getTtySize()
prevH, prevW := cli.getTtySize()
for {
time.Sleep(time.Millisecond * 250)
w, h := cli.getTtySize()
h, w := cli.getTtySize()
if prevW != w || prevH != h {
cli.resizeTty(id, isExec)
}
prevW = w
prevH = h
prevW = w
}
}()
} else {
+29 -15
View File
@@ -190,6 +190,34 @@ func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
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()
@@ -197,8 +225,6 @@ 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 {
@@ -208,19 +234,7 @@ func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*o
}
s = execErr.ProcessState
}
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()
}
killCgroupProcs(c)
p.Wait()
return s, err
}
+3 -12
View File
@@ -17,29 +17,20 @@ type Syslog struct {
}
func New(tag string) (logger.Logger, error) {
log, err := syslog.New(syslog.LOG_USER, path.Base(os.Args[0]))
log, err := syslog.New(syslog.LOG_USER, fmt.Sprintf("%s: <%s> ", path.Base(os.Args[0]), tag))
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" {
if err := s.writer.Err(logMessage); err != nil {
return err
}
} else {
if err := s.writer.Info(logMessage); err != nil {
return err
}
return s.writer.Err(string(msg.Line))
}
return nil
return s.writer.Info(string(msg.Line))
}
func (s *Syslog) Close() error {
+11 -4
View File
@@ -22,10 +22,17 @@ EOF
}
create_robots_txt() {
cat > ./sources/robots.txt <<'EOF'
User-agent: *
Disallow: /
EOF
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
}
setup_s3() {
+8 -1
View File
@@ -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/oSHN8_uiZd4?rel=0" frameborder="0" allowfullscreen></iframe>
<iframe width="640" height="480" src="//www.youtube.com/embed/TjMU3bDX4vo?rel=0" frameborder="0" allowfullscreen></iframe>
## Installation
@@ -147,3 +147,10 @@ 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).
+213 -196
View File
@@ -20,213 +20,230 @@ command_exists() {
command -v "$@" > /dev/null 2>&1
}
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
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
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
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:
user="$(id -un 2>/dev/null || true)"
sudo usermod -aG docker $your_user
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
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 )
fi
fi
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
user="$(id -un 2>/dev/null || true)"
# 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'
)
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
(
set -x
$sh_c 'sleep 3; yum -y -q install docker-io'
)
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
;;
ubuntu|debian|linuxmint)
export DEBIAN_FRONTEND=noninteractive
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
}
# 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.'
( 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
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'
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
$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
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
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
fi
fi
(
set -x
$sh_c 'sleep 3; emerge app-emulation/docker'
)
exit 0
;;
esac
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
cat >&2 <<'EOF'
# 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
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:
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'
)
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
;;
https://docs.docker.com/en/latest/installation/
ubuntu|debian|linuxmint)
export DEBIAN_FRONTEND=noninteractive
EOF
exit 1
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
}
# 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.'
( 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
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'
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
$sh_c 'docker version'
) || true
fi
echo_docker_as_nonroot
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'
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:'
https://github.com/tianon/docker-overlay#using-this-overlay'
After adding the "docker" overlay, you should be able to:'
emerge -av =app-emulation/docker-9999'
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
+1 -1
View File
@@ -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 d00b8369852285d6a830a8d3b966608b2ed89705
clone git github.com/docker/libcontainer bd8ec36106086f72b66e1be85a81202b93503e44
# 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')"
+54
View File
@@ -3237,6 +3237,35 @@ 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()
@@ -3382,3 +3411,28 @@ 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")
}
+59 -58
View File
@@ -5,6 +5,7 @@ import (
"io"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/term/winconsole"
)
@@ -21,34 +22,49 @@ type Winsize struct {
y uint16
}
// GetWinsize gets the window size of the given terminal
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.
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
}
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
// 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
}
// SetWinsize sets the terminal connected to the given file descriptor to a
// given size.
// SetWinsize sets the size of the given terminal connected to the passed file descriptor.
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 {
_, e := winconsole.GetConsoleMode(fd)
return e == nil
return winconsole.IsConsole(fd)
}
// RestoreTerminal restores the terminal connected to the given file descriptor to a
@@ -57,7 +73,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
return winconsole.SetConsoleMode(fd, state.mode)
}
// SaveState saves the state of the given console
// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
mode, e := winconsole.GetConsoleMode(fd)
if e != nil {
@@ -66,72 +82,57 @@ func SaveState(fd uintptr) (*State, error) {
return &State{mode}, nil
}
// 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
// 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
func DisableEcho(fd uintptr, state *State) error {
state.mode &^= (winconsole.ENABLE_ECHO_INPUT)
state.mode |= (winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT)
return winconsole.SetConsoleMode(fd, state.mode)
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)
}
// 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) {
oldState, err := MakeRaw(fd)
state, err := MakeRaw(fd)
if err != nil {
return nil, err
}
// TODO (azlinux): implement handling interrupt and restore state of terminal
return oldState, err
// TODO(azlinux): Core code registers a goroutine to catch os.Interrupt and reset the terminal state.
return state, 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
}
// 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)
// 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)
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
}
+94 -87
View File
@@ -12,18 +12,22 @@ import (
"sync"
"syscall"
"unsafe"
"github.com/Sirupsen/logrus"
)
const (
// Consts for Get/SetConsoleMode function
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
ENABLE_ECHO_INPUT = 0x0004
ENABLE_INSERT_MODE = 0x0020
ENABLE_LINE_INPUT = 0x0002
ENABLE_MOUSE_INPUT = 0x0010
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
// If parameter is a screen buffer handle, additional values
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
@@ -97,27 +101,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")
@@ -140,7 +144,12 @@ 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
SHORT int16
BOOL int32
WORD uint16
WCHAR uint16
DWORD uint32
SMALL_RECT struct {
Left SHORT
Top SHORT
@@ -153,11 +162,6 @@ type (
Y SHORT
}
BOOL int32
WORD uint16
WCHAR uint16
DWORD uint32
CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD
CursorPosition COORD
@@ -192,6 +196,10 @@ 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
@@ -211,14 +219,14 @@ func getStdHandle(stdhandle int) uintptr {
return uintptr(handle)
}
func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
func WinConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
handler := &WindowsTerminal{
inputBuffer: make([]byte, MAX_INPUT_BUFFER),
inputEscapeSequence: []byte(KEY_ESC_CSI),
inputEvents: make([]INPUT_RECORD, MAX_INPUT_EVENTS),
}
if IsTerminal(os.Stdin.Fd()) {
if IsConsole(os.Stdin.Fd()) {
stdIn = &terminalReader{
wrappedReader: os.Stdin,
emulator: handler,
@@ -229,7 +237,7 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
stdIn = os.Stdin
}
if IsTerminal(os.Stdout.Fd()) {
if IsConsole(os.Stdout.Fd()) {
stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE)
// Save current screen buffer info
@@ -253,7 +261,7 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
stdOut = os.Stdout
}
if IsTerminal(os.Stderr.Fd()) {
if IsConsole(os.Stderr.Fd()) {
stdErr = &terminalWriter{
wrappedWriter: os.Stderr,
emulator: handler,
@@ -267,25 +275,21 @@ func StdStreams() (stdIn io.ReadCloser, stdOut io.Writer, stdErr io.Writer) {
return stdIn, stdOut, stdErr
}
// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal
// GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
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 = 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)
}
isTerminalIn = IsConsole(inFd)
}
return inFd, isTerminalIn
}
@@ -318,12 +322,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
if err := getError(getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(&cursorInfo)), 0)); err != nil {
var cursorInfo *CONSOLE_CURSOR_INFO = &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
@@ -408,25 +412,25 @@ func getNumberOfChars(fromCoord COORD, toCoord COORD, screenSize COORD) uint32 {
var buffer []CHAR_INFO
func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
func clearDisplayRect(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
var writeRegion SMALL_RECT
writeRegion.Top = fromCoord.Y
writeRegion.Left = fromCoord.X
writeRegion.Top = fromCoord.Y
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 := width * height
size := uint32(width) * uint32(height)
if size > 0 {
for i := 0; i < int(size); i++ {
buffer[i].UnicodeChar = WCHAR(fillChar)
buffer[i].Attributes = attributes
buffer := make([]CHAR_INFO, size)
for i := range buffer {
buffer[i] = CHAR_INFO{WCHAR(' '), attributes}
}
// Write to buffer
r, err := writeConsoleOutput(handle, buffer[:size], windowSize, COORD{X: 0, Y: 0}, &writeRegion)
r, err := writeConsoleOutput(handle, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &writeRegion)
if !r {
if err != nil {
return 0, err
@@ -437,18 +441,18 @@ func clearDisplayRect(handle uintptr, fillChar rune, attributes WORD, fromCoord
return uint32(size), nil
}
func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord COORD, toCoord COORD, windowSize COORD) (uint32, error) {
func clearDisplayRange(handle uintptr, attributes WORD, fromCoord COORD, toCoord COORD) (uint32, error) {
nw := uint32(0)
// start and end on same line
if fromCoord.Y == toCoord.Y {
return clearDisplayRect(handle, fillChar, attributes, fromCoord, toCoord, windowSize)
return clearDisplayRect(handle, attributes, fromCoord, toCoord)
}
// 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, fillChar, attributes, fromCoord, COORD{X: windowSize.X - 1, Y: fromCoord.Y}, windowSize)
n, err := clearDisplayRect(handle, attributes, fromCoord, COORD{X: toCoord.X, Y: fromCoord.Y})
if err != nil {
return nw, err
}
@@ -456,14 +460,14 @@ func clearDisplayRange(handle uintptr, fillChar rune, attributes WORD, fromCoord
// lines between
linesBetween := toCoord.Y - fromCoord.Y - 1
if linesBetween > 0 {
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: windowSize.X - 1, Y: toCoord.Y - 1}, windowSize)
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: fromCoord.Y + 1}, COORD{X: toCoord.X, Y: toCoord.Y - 1})
if err != nil {
return nw, err
}
nw += n
}
// lines at end
n, err = clearDisplayRect(handle, fillChar, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord, windowSize)
n, err = clearDisplayRect(handle, attributes, COORD{X: 0, Y: toCoord.Y}, toCoord)
if err != nil {
return nw, err
}
@@ -493,7 +497,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 WORD
var n DWORD
if err := getError(getNumberOfConsoleInputEventsProc.Call(handle, uintptr(unsafe.Pointer(&n)))); err != nil {
return 0, err
}
@@ -502,7 +506,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 WORD
var nr DWORD
if err := getError(readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&inputBuffer[0])), uintptr(len(inputBuffer)), uintptr(unsafe.Pointer(&nr)))); err != nil {
return 0, err
}
@@ -591,6 +595,7 @@ 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()
@@ -636,16 +641,17 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
return n, err
}
if line > int16(screenBufferInfo.Window.Bottom) {
line = int16(screenBufferInfo.Window.Bottom)
line = int16(screenBufferInfo.Window.Bottom) + 1
}
column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1)
if err != nil {
return n, err
}
if column > int16(screenBufferInfo.Window.Right) {
column = int16(screenBufferInfo.Window.Right)
column = int16(screenBufferInfo.Window.Right) + 1
}
// 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
}
@@ -713,9 +719,9 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
switch value {
case 0:
start = screenBufferInfo.CursorPosition
// end of the screen
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
// end of the buffer
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor = screenBufferInfo.CursorPosition
case 1:
@@ -731,20 +737,21 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start of the screen
start.X = 0
start.Y = 0
// end of the screen
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
// end of the buffer
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.Size.Y - 1
// cursor
cursor.X = 0
cursor.Y = 0
}
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); 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).
@@ -764,7 +771,7 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
// start is where cursor is
start = screenBufferInfo.CursorPosition
// end of line
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.CursorPosition.Y
// cursor remains the same
cursor = screenBufferInfo.CursorPosition
@@ -780,15 +787,15 @@ func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte)
case 2:
// start of the line
start.X = 0
start.Y = screenBufferInfo.MaximumWindowSize.Y - 1
start.Y = screenBufferInfo.CursorPosition.Y - 1
// end of the line
end.X = screenBufferInfo.MaximumWindowSize.X - 1
end.Y = screenBufferInfo.MaximumWindowSize.Y - 1
end.X = screenBufferInfo.Size.X - 1
end.Y = screenBufferInfo.CursorPosition.Y - 1
// cursor
cursor.X = 0
cursor.Y = screenBufferInfo.MaximumWindowSize.Y - 1
cursor.Y = screenBufferInfo.CursorPosition.Y - 1
}
if _, err := clearDisplayRange(uintptr(handle), ' ', term.screenBufferInfo.Attributes, start, end, screenBufferInfo.MaximumWindowSize); err != nil {
if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil {
return n, err
}
// remember the the cursor position is 1 based
@@ -1035,12 +1042,12 @@ func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n
}
func marshal(c COORD) uintptr {
// works only on intel-endian machines
return uintptr(uint32(uint32(uint16(c.Y))<<16 | uint32(uint16(c.X))))
return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
// 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 {
_, e := GetConsoleMode(fd)
return e == nil
}
+16
View File
@@ -1,6 +1,7 @@
package winconsole
import (
"fmt"
"io"
"strconv"
"strings"
@@ -206,6 +207,21 @@ 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 +1,2 @@
bundles
nsinit/nsinit
+2
View File
@@ -29,3 +29,5 @@ local:
validate:
hack/validate.sh
binary: all
docker run --rm --privileged -v $(CURDIR)/bundles:/go/bin dockercore/libcontainer make direct-install
+3
View File
@@ -141,6 +141,9 @@ 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.
@@ -3,7 +3,6 @@
package systemd
import (
"bytes"
"fmt"
"io/ioutil"
"os"
@@ -247,6 +246,21 @@ 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 {
@@ -266,16 +280,11 @@ func joinCpu(c *configs.Cgroup, pid int) error {
}
func joinFreezer(c *configs.Cgroup, pid int) error {
path, err := getSubsystemPath(c, "freezer")
if err != nil {
if _, err := join(c, "freezer", pid); err != nil {
return err
}
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)
return nil
}
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
@@ -303,21 +312,15 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
return err
}
if err := ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0); err != nil {
prevState := m.Cgroups.Freezer
m.Cgroups.Freezer = state
freezer := subsystems["freezer"]
err = freezer.Set(path, m.Cgroups)
if err != nil {
m.Cgroups.Freezer = prevState
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
}
@@ -366,29 +369,16 @@ 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 := getSubsystemPath(c, "devices")
path, err := join(c, "devices", pid)
if err != nil {
return err
}
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
devices := subsystems["devices"]
if err := devices.Set(path, c); err != nil {
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,6 +16,17 @@ 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 {
@@ -306,5 +306,11 @@ 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,7 +130,8 @@ func TestGetContainerState(t *testing.T) {
{Type: configs.NEWNS},
{Type: configs.NEWNET, Path: expectedNetworkPath},
{Type: configs.NEWUTS},
{Type: configs.NEWIPC},
// emulate host for IPC
//{Type: configs.NEWIPC},
},
},
initProcess: &mockProcess{
@@ -9,6 +9,7 @@ import (
"testing"
"github.com/docker/libcontainer"
"github.com/docker/libcontainer/cgroups/systemd"
"github.com/docker/libcontainer/configs"
)
@@ -481,6 +482,17 @@ 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
}
@@ -497,6 +509,9 @@ func TestFreeze(t *testing.T) {
defer remove(rootfs)
config := newTemplateConfig(rootfs)
if systemd {
config.Cgroups.Slice = "system.slice"
}
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
if err != nil {
@@ -559,3 +574,77 @@ func TestFreeze(t *testing.T) {
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,9 +68,14 @@ 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", "--"),
libcontainer.Cgroupfs,
cgm,
)
if err != nil {
return nil, err
+1 -1
View File
@@ -13,7 +13,7 @@ func main() {
app.Version = "2"
app.Author = "libcontainer maintainers"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
cli.StringFlag{Name: "root", Value: "/var/run/nsinit", 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"},
}