mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update libcontainer to c8512754166539461fd860451ff
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
2742bf5cbc
commit
17ecbcf8ff
9 changed files with 215 additions and 24 deletions
|
@ -75,7 +75,7 @@ rm -rf src/github.com/docker/distribution
|
||||||
mkdir -p src/github.com/docker/distribution
|
mkdir -p src/github.com/docker/distribution
|
||||||
mv tmp-digest src/github.com/docker/distribution/digest
|
mv tmp-digest src/github.com/docker/distribution/digest
|
||||||
|
|
||||||
clone git github.com/docker/libcontainer a6044b701c166fe538fc760f9e2dcea3d737cd2a
|
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)
|
# 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
|
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')"
|
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli' | grep -v 'github.com/Sirupsen/logrus')"
|
||||||
|
|
|
@ -220,16 +220,16 @@ func getCgroupData(c *configs.Cgroup, pid int) (*data, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (raw *data) parent(subsystem string) (string, error) {
|
func (raw *data) parent(subsystem, mountpoint string) (string, error) {
|
||||||
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(raw.root, subsystem, initPath), nil
|
return filepath.Join(mountpoint, initPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (raw *data) path(subsystem string) (string, error) {
|
func (raw *data) path(subsystem string) (string, error) {
|
||||||
_, err := cgroups.FindCgroupMountpoint(subsystem)
|
mnt, err := cgroups.FindCgroupMountpoint(subsystem)
|
||||||
// If we didn't mount the subsystem, there is no point we make the path.
|
// If we didn't mount the subsystem, there is no point we make the path.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -240,7 +240,7 @@ func (raw *data) path(subsystem string) (string, error) {
|
||||||
return filepath.Join(raw.root, subsystem, raw.cgroup), nil
|
return filepath.Join(raw.root, subsystem, raw.cgroup), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, err := raw.parent(subsystem)
|
parent, err := raw.parent(subsystem, mnt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,10 @@ var subsystems = map[string]subsystem{
|
||||||
"freezer": &fs.FreezerGroup{},
|
"freezer": &fs.FreezerGroup{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
testScopeWait = 4
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
theConn *systemd.Conn
|
theConn *systemd.Conn
|
||||||
|
@ -86,16 +90,41 @@ func UseSystemd() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the scope name we use doesn't exist. Use the Pid to
|
||||||
|
// avoid collisions between multiple libcontainer users on a
|
||||||
|
// single host.
|
||||||
|
scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
|
||||||
|
testScopeExists := true
|
||||||
|
for i := 0; i <= testScopeWait; i++ {
|
||||||
|
if _, err := theConn.StopUnit(scope, "replace"); err != nil {
|
||||||
|
if dbusError, ok := err.(dbus.Error); ok {
|
||||||
|
if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
|
||||||
|
testScopeExists = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail out if we can't kill this scope without testing for DefaultDependencies
|
||||||
|
if testScopeExists {
|
||||||
|
return hasStartTransientUnit
|
||||||
|
}
|
||||||
|
|
||||||
// Assume StartTransientUnit on a scope allows DefaultDependencies
|
// Assume StartTransientUnit on a scope allows DefaultDependencies
|
||||||
hasTransientDefaultDependencies = true
|
hasTransientDefaultDependencies = true
|
||||||
ddf := newProp("DefaultDependencies", false)
|
ddf := newProp("DefaultDependencies", false)
|
||||||
if _, err := theConn.StartTransientUnit("docker-systemd-test-default-dependencies.scope", "replace", ddf); err != nil {
|
if _, err := theConn.StartTransientUnit(scope, "replace", ddf); err != nil {
|
||||||
if dbusError, ok := err.(dbus.Error); ok {
|
if dbusError, ok := err.(dbus.Error); ok {
|
||||||
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
|
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
|
||||||
hasTransientDefaultDependencies = false
|
hasTransientDefaultDependencies = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not critical because of the stop unit logic above.
|
||||||
|
theConn.StopUnit(scope, "replace")
|
||||||
}
|
}
|
||||||
return hasStartTransientUnit
|
return hasStartTransientUnit
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,12 +193,13 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe,
|
||||||
|
|
||||||
func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
|
func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
|
||||||
return &initConfig{
|
return &initConfig{
|
||||||
Config: c.config,
|
Config: c.config,
|
||||||
Args: process.Args,
|
Args: process.Args,
|
||||||
Env: process.Env,
|
Env: process.Env,
|
||||||
User: process.User,
|
User: process.User,
|
||||||
Cwd: process.Cwd,
|
Cwd: process.Cwd,
|
||||||
Console: process.consolePath,
|
Console: process.consolePath,
|
||||||
|
Capabilities: process.Capabilities,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,14 @@ type network struct {
|
||||||
|
|
||||||
// initConfig is used for transferring parameters from Exec() to Init()
|
// initConfig is used for transferring parameters from Exec() to Init()
|
||||||
type initConfig struct {
|
type initConfig struct {
|
||||||
Args []string `json:"args"`
|
Args []string `json:"args"`
|
||||||
Env []string `json:"env"`
|
Env []string `json:"env"`
|
||||||
Cwd string `json:"cwd"`
|
Cwd string `json:"cwd"`
|
||||||
User string `json:"user"`
|
Capabilities []string `json:"capabilities"`
|
||||||
Config *configs.Config `json:"config"`
|
User string `json:"user"`
|
||||||
Console string `json:"console"`
|
Config *configs.Config `json:"config"`
|
||||||
Networks []*network `json:"network"`
|
Console string `json:"console"`
|
||||||
|
Networks []*network `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type initer interface {
|
type initer interface {
|
||||||
|
@ -99,7 +100,12 @@ func finalizeNamespace(config *initConfig) error {
|
||||||
if err := utils.CloseExecFrom(3); err != nil {
|
if err := utils.CloseExecFrom(3); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w, err := newCapWhitelist(config.Config.Capabilities)
|
|
||||||
|
capabilities := config.Config.Capabilities
|
||||||
|
if config.Capabilities != nil {
|
||||||
|
capabilities = config.Capabilities
|
||||||
|
}
|
||||||
|
w, err := newCapWhitelist(capabilities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -395,6 +396,90 @@ func TestProcessEnv(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessCaps(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)
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
processCaps := append(config.Capabilities, "NET_ADMIN")
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
pconfig := libcontainer.Process{
|
||||||
|
Args: []string{"sh", "-c", "cat /proc/self/status"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Capabilities: processCaps,
|
||||||
|
Stdin: nil,
|
||||||
|
Stdout: &stdout,
|
||||||
|
}
|
||||||
|
err = container.Start(&pconfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for process
|
||||||
|
waitProcess(&pconfig, t)
|
||||||
|
|
||||||
|
outputStatus := string(stdout.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(outputStatus, "\n")
|
||||||
|
|
||||||
|
effectiveCapsLine := ""
|
||||||
|
for _, l := range lines {
|
||||||
|
line := strings.TrimSpace(l)
|
||||||
|
if strings.Contains(line, "CapEff:") {
|
||||||
|
effectiveCapsLine = line
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if effectiveCapsLine == "" {
|
||||||
|
t.Fatal("Couldn't find effective caps: ", outputStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(effectiveCapsLine, ":")
|
||||||
|
effectiveCapsStr := strings.TrimSpace(parts[1])
|
||||||
|
|
||||||
|
effectiveCaps, err := strconv.ParseUint(effectiveCapsStr, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Could not parse effective caps", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var netAdminMask uint64
|
||||||
|
var netAdminBit uint
|
||||||
|
netAdminBit = 12 // from capability.h
|
||||||
|
netAdminMask = 1 << netAdminBit
|
||||||
|
if effectiveCaps&netAdminMask != netAdminMask {
|
||||||
|
t.Fatal("CAP_NET_ADMIN is not set as expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFreeze(t *testing.T) {
|
func TestFreeze(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
|
|
57
vendor/src/github.com/docker/libcontainer/nsinit/README.md
vendored
Normal file
57
vendor/src/github.com/docker/libcontainer/nsinit/README.md
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
## nsinit
|
||||||
|
|
||||||
|
`nsinit` is a cli application which demonstrates the use of libcontainer.
|
||||||
|
It is able to spawn new containers or join existing containers.
|
||||||
|
|
||||||
|
### How to build?
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd libcontainer/nsinit
|
||||||
|
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.
|
||||||
|
|
||||||
|
Choose a proper place to run your container. For example we use `/busybox`.
|
||||||
|
|
||||||
|
```
|
||||||
|
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 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
|
||||||
|
```
|
||||||
|
|
||||||
|
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 /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.
|
||||||
|
|
||||||
|
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 place where
|
||||||
|
the `container.json` file is read and where the `state.json` file will be saved.
|
|
@ -41,6 +41,10 @@ type Process struct {
|
||||||
// consolePath is the path to the console allocated to the container.
|
// consolePath is the path to the console allocated to the container.
|
||||||
consolePath string
|
consolePath string
|
||||||
|
|
||||||
|
// Capabilities specify the capabilities to keep when executing the process inside the container
|
||||||
|
// All capbilities not specified will be dropped from the processes capability mask
|
||||||
|
Capabilities []string
|
||||||
|
|
||||||
ops processOperations
|
ops processOperations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ package libcontainer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -44,8 +45,12 @@ func (p *setnsProcess) startTime() (string, error) {
|
||||||
return system.GetProcessStartTime(p.pid())
|
return system.GetProcessStartTime(p.pid())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *setnsProcess) signal(s os.Signal) error {
|
func (p *setnsProcess) signal(sig os.Signal) error {
|
||||||
return p.cmd.Process.Signal(s)
|
s, ok := sig.(syscall.Signal)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("os: unsupported signal type")
|
||||||
|
}
|
||||||
|
return syscall.Kill(p.cmd.Process.Pid, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *setnsProcess) start() (err error) {
|
func (p *setnsProcess) start() (err error) {
|
||||||
|
@ -235,6 +240,10 @@ func (p *initProcess) createNetworkInterfaces() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *initProcess) signal(s os.Signal) error {
|
func (p *initProcess) signal(sig os.Signal) error {
|
||||||
return p.cmd.Process.Signal(s)
|
s, ok := sig.(syscall.Signal)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("os: unsupported signal type")
|
||||||
|
}
|
||||||
|
return syscall.Kill(p.cmd.Process.Pid, s)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue