diff --git a/hack/vendor.sh b/hack/vendor.sh index 9bd10bde12..d8f15d1809 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -44,9 +44,9 @@ clone git github.com/endophage/gotuf 89ceb27829b9353dfee5ccccf7a3a9bb77008b05 clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337 clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c -clone git github.com/opencontainers/runc v0.0.2 # libcontainer +clone git github.com/opencontainers/runc v0.0.3 # libcontainer # libcontainer deps (see src/github.com/docker/libcontainer/update-vendor.sh) -clone git github.com/coreos/go-systemd v2 +clone git github.com/coreos/go-systemd v3 clone git github.com/godbus/dbus v2 clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb clone git github.com/golang/protobuf 655cdfa588ea diff --git a/vendor/src/github.com/coreos/go-systemd/activation/files.go b/vendor/src/github.com/coreos/go-systemd/activation/files.go index 74b4fc10f3..c8e85fcd58 100644 --- a/vendor/src/github.com/coreos/go-systemd/activation/files.go +++ b/vendor/src/github.com/coreos/go-systemd/activation/files.go @@ -1,18 +1,16 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package activation implements primitives for systemd socket activation. package activation @@ -30,10 +28,8 @@ const ( func Files(unsetEnv bool) []*os.File { if unsetEnv { - // there is no way to unset env in golang os package for now - // https://code.google.com/p/go/issues/detail?id=6423 - defer os.Setenv("LISTEN_PID", "") - defer os.Setenv("LISTEN_FDS", "") + defer os.Unsetenv("LISTEN_PID") + defer os.Unsetenv("LISTEN_FDS") } pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) @@ -46,7 +42,7 @@ func Files(unsetEnv bool) []*os.File { return nil } - var files []*os.File + files := make([]*os.File, 0, nfds) for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { syscall.CloseOnExec(fd) files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) diff --git a/vendor/src/github.com/coreos/go-systemd/activation/listeners.go b/vendor/src/github.com/coreos/go-systemd/activation/listeners.go index cdb2cf4bb4..a30cb89395 100644 --- a/vendor/src/github.com/coreos/go-systemd/activation/listeners.go +++ b/vendor/src/github.com/coreos/go-systemd/activation/listeners.go @@ -1,38 +1,37 @@ -/* -Copyright 2014 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package activation import ( - "fmt" "net" ) -// Listeners returns net.Listeners for all socket activated fds passed to this process. +// Listeners returns a slice containing a net.Listener for each matching socket type +// passed to this process. +// +// The order of the file descriptors is preserved in the returned slice. +// Nil values are used to fill any gaps. For example if systemd were to return file descriptors +// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener} func Listeners(unsetEnv bool) ([]net.Listener, error) { files := Files(unsetEnv) listeners := make([]net.Listener, len(files)) for i, f := range files { - var err error - listeners[i], err = net.FileListener(f) - if err != nil { - return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error()) + if pc, err := net.FileListener(f); err == nil { + listeners[i] = pc } } - return listeners, nil } diff --git a/vendor/src/github.com/coreos/go-systemd/activation/packetconns.go b/vendor/src/github.com/coreos/go-systemd/activation/packetconns.go new file mode 100644 index 0000000000..48b2ca029d --- /dev/null +++ b/vendor/src/github.com/coreos/go-systemd/activation/packetconns.go @@ -0,0 +1,37 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package activation + +import ( + "net" +) + +// PacketConns returns a slice containing a net.PacketConn for each matching socket type +// passed to this process. +// +// The order of the file descriptors is preserved in the returned slice. +// Nil values are used to fill any gaps. For example if systemd were to return file descriptors +// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn} +func PacketConns(unsetEnv bool) ([]net.PacketConn, error) { + files := Files(unsetEnv) + conns := make([]net.PacketConn, len(files)) + + for i, f := range files { + if pc, err := net.FilePacketConn(f); err == nil { + conns[i] = pc + } + } + return conns, nil +} diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go index 91d7112145..625a32b8e6 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go @@ -1,23 +1,22 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ package dbus import ( + "fmt" "os" "strconv" "strings" @@ -26,24 +25,53 @@ import ( "github.com/godbus/dbus" ) -const signalBuffer = 100 +const ( + alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` + num = `0123456789` + alphanum = alpha + num + signalBuffer = 100 +) -// ObjectPath creates a dbus.ObjectPath using the rules that systemd uses for -// serializing special characters. -func ObjectPath(path string) dbus.ObjectPath { - path = strings.Replace(path, ".", "_2e", -1) - path = strings.Replace(path, "-", "_2d", -1) - path = strings.Replace(path, "@", "_40", -1) - - return dbus.ObjectPath(path) +// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped +func needsEscape(i int, b byte) bool { + // Escape everything that is not a-z-A-Z-0-9 + // Also escape 0-9 if it's the first character + return strings.IndexByte(alphanum, b) == -1 || + (i == 0 && strings.IndexByte(num, b) != -1) } -// Conn is a connection to systemds dbus endpoint. +// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the +// rules that systemd uses for serializing special characters. +func PathBusEscape(path string) string { + // Special case the empty string + if len(path) == 0 { + return "_" + } + n := []byte{} + for i := 0; i < len(path); i++ { + c := path[i] + if needsEscape(i, c) { + e := fmt.Sprintf("_%x", c) + n = append(n, []byte(e)...) + } else { + n = append(n, c) + } + } + return string(n) +} + +// Conn is a connection to systemd's dbus endpoint. type Conn struct { - sysconn *dbus.Conn - sysobj *dbus.Object + // sysconn/sysobj are only used to call dbus methods + sysconn *dbus.Conn + sysobj *dbus.Object + + // sigconn/sigobj are only used to receive dbus signals + sigconn *dbus.Conn + sigobj *dbus.Object + jobListener struct { - jobs map[dbus.ObjectPath]chan string + jobs map[dbus.ObjectPath]chan<- string sync.Mutex } subscriber struct { @@ -53,26 +81,61 @@ type Conn struct { ignore map[dbus.ObjectPath]int64 cleanIgnore int64 } - dispatch map[string]func(dbus.Signal) } -// New() establishes a connection to the system bus and authenticates. +// New establishes a connection to the system bus and authenticates. +// Callers should call Close() when done with the connection. func New() (*Conn, error) { - c := new(Conn) + return newConnection(dbus.SystemBusPrivate) +} - if err := c.initConnection(); err != nil { +// NewUserConnection establishes a connection to the session bus and +// authenticates. This can be used to connect to systemd user instances. +// Callers should call Close() when done with the connection. +func NewUserConnection() (*Conn, error) { + return newConnection(dbus.SessionBusPrivate) +} + +// Close closes an established connection +func (c *Conn) Close() { + c.sysconn.Close() + c.sigconn.Close() +} + +func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { + sysconn, err := dbusConnection(createBus) + if err != nil { return nil, err } - c.initJobs() + sigconn, err := dbusConnection(createBus) + if err != nil { + sysconn.Close() + return nil, err + } + + c := &Conn{ + sysconn: sysconn, + sysobj: systemdObject(sysconn), + sigconn: sigconn, + sigobj: systemdObject(sigconn), + } + + c.subscriber.ignore = make(map[dbus.ObjectPath]int64) + c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) + + // Setup the listeners on jobs so that we can get completions + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") + + c.dispatch() return c, nil } -func (c *Conn) initConnection() error { - var err error - c.sysconn, err = dbus.SystemBusPrivate() +func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus() if err != nil { - return err + return nil, err } // Only use EXTERNAL method, and hardcode the uid (not username) @@ -80,25 +143,21 @@ func (c *Conn) initConnection() error { // libc) methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))} - err = c.sysconn.Auth(methods) + err = conn.Auth(methods) if err != nil { - c.sysconn.Close() - return err + conn.Close() + return nil, err } - err = c.sysconn.Hello() + err = conn.Hello() if err != nil { - c.sysconn.Close() - return err + conn.Close() + return nil, err } - c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) - - // Setup the listeners on jobs so that we can get completions - c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") - c.initSubscription() - c.initDispatch() - - return nil + return conn, nil +} + +func systemdObject(conn *dbus.Conn) *dbus.Object { + return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) } diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/methods.go b/vendor/src/github.com/coreos/go-systemd/dbus/methods.go index a60de059e6..ab614c7c63 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/methods.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/methods.go @@ -1,30 +1,27 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package dbus import ( "errors" + "path" + "strconv" + "github.com/godbus/dbus" ) -func (c *Conn) initJobs() { - c.jobListener.jobs = make(map[dbus.ObjectPath]chan string) -} - func (c *Conn) jobComplete(signal *dbus.Signal) { var id uint32 var job dbus.ObjectPath @@ -40,29 +37,29 @@ func (c *Conn) jobComplete(signal *dbus.Signal) { c.jobListener.Unlock() } -func (c *Conn) startJob(job string, args ...interface{}) (<-chan string, error) { - c.jobListener.Lock() - defer c.jobListener.Unlock() - - ch := make(chan string, 1) - var path dbus.ObjectPath - err := c.sysobj.Call(job, 0, args...).Store(&path) - if err != nil { - return nil, err +func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { + if ch != nil { + c.jobListener.Lock() + defer c.jobListener.Unlock() } - c.jobListener.jobs[path] = ch - return ch, nil + + var p dbus.ObjectPath + err := c.sysobj.Call(job, 0, args...).Store(&p) + if err != nil { + return 0, err + } + + if ch != nil { + c.jobListener.jobs[p] = ch + } + + // ignore error since 0 is fine if conversion fails + jobID, _ := strconv.Atoi(path.Base(string(p))) + + return jobID, nil } -func (c *Conn) runJob(job string, args ...interface{}) (string, error) { - respCh, err := c.startJob(job, args...) - if err != nil { - return "", err - } - return <-respCh, nil -} - -// StartUnit enqeues a start job and depending jobs, if any (unless otherwise +// StartUnit enqueues a start job and depending jobs, if any (unless otherwise // specified by the mode string). // // Takes the unit to activate, plus a mode string. The mode needs to be one of @@ -77,50 +74,58 @@ func (c *Conn) runJob(job string, args ...interface{}) (string, error) { // requirement dependencies. It is not recommended to make use of the latter // two options. // -// Result string: one of done, canceled, timeout, failed, dependency, skipped. +// If the provided channel is non-nil, a result string will be sent to it upon +// job completion: one of done, canceled, timeout, failed, dependency, skipped. // done indicates successful execution of a job. canceled indicates that a job // has been canceled before it finished execution. timeout indicates that the // job timeout was reached. failed indicates that the job failed. dependency // indicates that a job this job has been depending on failed and the job hence // has been removed too. skipped indicates that a job was skipped because it // didn't apply to the units current state. -func (c *Conn) StartUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.StartUnit", name, mode) +// +// If no error occurs, the ID of the underlying systemd job will be returned. There +// does exist the possibility for no error to be returned, but for the returned job +// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint +// should not be considered authoritative. +// +// If an error does occur, it will be returned to the user alongside a job ID of 0. +func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) } // StopUnit is similar to StartUnit but stops the specified unit rather // than starting it. -func (c *Conn) StopUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.StopUnit", name, mode) +func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) } // ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. -func (c *Conn) ReloadUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) +func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) } // RestartUnit restarts a service. If a service is restarted that isn't // running it will be started. -func (c *Conn) RestartUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.RestartUnit", name, mode) +func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) } // TryRestartUnit is like RestartUnit, except that a service that isn't running // is not affected by the restart. -func (c *Conn) TryRestartUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) +func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) } // ReloadOrRestart attempts a reload if the unit supports it and use a restart // otherwise. -func (c *Conn) ReloadOrRestartUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) +func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) } // ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" // flavored restart otherwise. -func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) +func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) } // StartTransientUnit() may be used to create and start a transient unit, which @@ -128,8 +133,8 @@ func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) // system is rebooted. name is the unit name including suffix, and must be // unique. mode is the same as in StartUnit(), properties contains properties // of the unit. -func (c *Conn) StartTransientUnit(name string, mode string, properties ...Property) (string, error) { - return c.runJob("org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) +func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { + return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) } // KillUnit takes the unit name and a UNIX signal number to send. All of the unit's @@ -138,12 +143,17 @@ func (c *Conn) KillUnit(name string, signal int32) { c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() } +// ResetFailedUnit resets the "failed" state of a specific unit. +func (c *Conn) ResetFailedUnit(name string) error { + return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() +} + // getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) { var err error var props map[string]dbus.Variant - path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit) + path := unitPath(unit) if !path.IsValid() { return nil, errors.New("invalid unit name: " + unit) } @@ -171,7 +181,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin var err error var prop dbus.Variant - path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit) + path := unitPath(unit) if !path.IsValid() { return nil, errors.New("invalid unit name: " + unit) } @@ -208,7 +218,7 @@ func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Proper } func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1." + unitType, propertyName) + return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) } // ListUnits returns an array with all currently loaded units. Note that @@ -394,3 +404,7 @@ type DisableUnitFileChange struct { func (c *Conn) Reload() error { return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() } + +func unitPath(name string) dbus.ObjectPath { + return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) +} diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/properties.go b/vendor/src/github.com/coreos/go-systemd/dbus/properties.go index a06ccda761..7520011564 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/properties.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/properties.go @@ -1,18 +1,16 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package dbus diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/set.go b/vendor/src/github.com/coreos/go-systemd/dbus/set.go index 45ad1fb399..f92e6fbed1 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/set.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/set.go @@ -1,3 +1,17 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package dbus type set struct { @@ -17,17 +31,17 @@ func (s *set) Contains(value string) (exists bool) { return } -func (s *set) Length() (int) { +func (s *set) Length() int { return len(s.data) } func (s *set) Values() (values []string) { - for val, _ := range s.data { + for val, _ := range s.data { values = append(values, val) - } - return + } + return } -func newSet() (*set) { - return &set{make(map[string] bool)} +func newSet() *set { + return &set{make(map[string]bool)} } diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/subscription.go b/vendor/src/github.com/coreos/go-systemd/dbus/subscription.go index fcd29b6e8f..996451445c 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/subscription.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/subscription.go @@ -1,18 +1,16 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package dbus @@ -33,12 +31,12 @@ const ( // systemd will automatically stop sending signals so there is no need to // explicitly call Unsubscribe(). func (c *Conn) Subscribe() error { - c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") - c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, + c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() + err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() if err != nil { return err } @@ -48,7 +46,7 @@ func (c *Conn) Subscribe() error { // Unsubscribe this connection from systemd dbus events. func (c *Conn) Unsubscribe() error { - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() + err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() if err != nil { return err } @@ -56,14 +54,10 @@ func (c *Conn) Unsubscribe() error { return nil } -func (c *Conn) initSubscription() { - c.subscriber.ignore = make(map[dbus.ObjectPath]int64) -} - -func (c *Conn) initDispatch() { +func (c *Conn) dispatch() { ch := make(chan *dbus.Signal, signalBuffer) - c.sysconn.Signal(ch) + c.sigconn.Signal(ch) go func() { for { @@ -72,24 +66,32 @@ func (c *Conn) initDispatch() { return } + if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" { + c.jobComplete(signal) + } + + if c.subscriber.updateCh == nil { + continue + } + + var unitPath dbus.ObjectPath switch signal.Name { case "org.freedesktop.systemd1.Manager.JobRemoved": - c.jobComplete(signal) - unitName := signal.Body[2].(string) - var unitPath dbus.ObjectPath c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) - if unitPath != dbus.ObjectPath("") { - c.sendSubStateUpdate(unitPath) - } case "org.freedesktop.systemd1.Manager.UnitNew": - c.sendSubStateUpdate(signal.Body[1].(dbus.ObjectPath)) + unitPath = signal.Body[1].(dbus.ObjectPath) case "org.freedesktop.DBus.Properties.PropertiesChanged": if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { - // we only care about SubState updates, which are a Unit property - c.sendSubStateUpdate(signal.Path) + unitPath = signal.Path } } + + if unitPath == dbus.ObjectPath("") { + continue + } + + c.sendSubStateUpdate(unitPath) } }() } @@ -103,7 +105,7 @@ func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitSt // SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer // size of the channels, the comparison function for detecting changes and a filter // function for cutting down on the noise that your channel receives. -func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func (string) bool) (<-chan map[string]*UnitStatus, <-chan error) { +func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { old := make(map[string]*UnitStatus) statusChan := make(chan map[string]*UnitStatus, buffer) errChan := make(chan error, buffer) @@ -176,9 +178,6 @@ func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { c.subscriber.Lock() defer c.subscriber.Unlock() - if c.subscriber.updateCh == nil { - return - } if c.shouldIgnore(path) { return diff --git a/vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go b/vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go index 2625786052..5b408d5847 100644 --- a/vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go +++ b/vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go @@ -1,3 +1,17 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package dbus import ( @@ -11,7 +25,6 @@ type SubscriptionSet struct { conn *Conn } - func (s *SubscriptionSet) filter(unit string) bool { return !s.Contains(unit) } @@ -21,12 +34,24 @@ func (s *SubscriptionSet) filter(unit string) bool { func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { // TODO: Make fully evented by using systemd 209 with properties changed values return s.conn.SubscribeUnitsCustom(time.Second, 0, - func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, + mismatchUnitStatus, func(unit string) bool { return s.filter(unit) }, ) } // NewSubscriptionSet returns a new subscription set. -func (conn *Conn) NewSubscriptionSet() (*SubscriptionSet) { +func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { return &SubscriptionSet{newSet(), conn} } + +// mismatchUnitStatus returns true if the provided UnitStatus objects +// are not equivalent. false is returned if the objects are equivalent. +// Only the Name, Description and state-related fields are used in +// the comparison. +func mismatchUnitStatus(u1, u2 *UnitStatus) bool { + return u1.Name != u2.Name || + u1.Description != u2.Description || + u1.LoadState != u2.LoadState || + u1.ActiveState != u2.ActiveState || + u1.SubState != u2.SubState +} diff --git a/vendor/src/github.com/coreos/go-systemd/journal/send.go b/vendor/src/github.com/coreos/go-systemd/journal/send.go index b52e120988..1620ae94a8 100644 --- a/vendor/src/github.com/coreos/go-systemd/journal/send.go +++ b/vendor/src/github.com/coreos/go-systemd/journal/send.go @@ -1,18 +1,16 @@ -/* -Copyright 2013 CoreOS Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package journal provides write bindings to the systemd journal package journal diff --git a/vendor/src/github.com/coreos/go-systemd/util/util.go b/vendor/src/github.com/coreos/go-systemd/util/util.go new file mode 100644 index 0000000000..33832a1ed4 --- /dev/null +++ b/vendor/src/github.com/coreos/go-systemd/util/util.go @@ -0,0 +1,33 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package util contains utility functions related to systemd that applications +// can use to check things like whether systemd is running. +package util + +import ( + "os" +) + +// IsRunningSystemd checks whether the host was booted with systemd as its init +// system. This functions similar to systemd's `sd_booted(3)`: internally, it +// checks whether /run/systemd/system/ exists and is a directory. +// http://www.freedesktop.org/software/systemd/man/sd_booted.html +func IsRunningSystemd() bool { + fi, err := os.Lstat("/run/systemd/system") + if err != nil { + return false + } + return fi.IsDir() +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go index 1954357b6c..f75dab1be8 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go @@ -256,7 +256,7 @@ func (raw *data) path(subsystem string) (string, error) { // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. if filepath.IsAbs(raw.cgroup) { - return filepath.Join(raw.root, subsystem, raw.cgroup), nil + return filepath.Join(raw.root, filepath.Base(mnt), raw.cgroup), nil } parent, err := raw.parent(subsystem, mnt, src) @@ -272,7 +272,7 @@ func (raw *data) join(subsystem string) (string, error) { if err != nil { return "", err } - if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { return "", err } if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go index b6c04b0c49..f3ec2c3e79 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go @@ -95,7 +95,7 @@ func (s *CpusetGroup) ensureParent(current, root string) error { if err := s.ensureParent(parent, root); err != nil { return err } - if err := os.MkdirAll(current, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(current, 0755); err != nil { return err } return s.copyIfNeeded(current, parent) diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index 8206b1472b..1fa8bd74c1 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -25,7 +25,7 @@ func (s *MemoryGroup) Apply(d *data) error { } return err } - if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { return err } if err := s.Set(path, d.c); err != nil { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go index 8c27f11ac3..7b523da9be 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go @@ -12,7 +12,8 @@ import ( "sync" "time" - systemd "github.com/coreos/go-systemd/dbus" + systemdDbus "github.com/coreos/go-systemd/dbus" + systemdUtil "github.com/coreos/go-systemd/util" "github.com/godbus/dbus" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" @@ -52,21 +53,20 @@ const ( var ( connLock sync.Mutex - theConn *systemd.Conn + theConn *systemdDbus.Conn hasStartTransientUnit bool hasTransientDefaultDependencies bool ) -func newProp(name string, units interface{}) systemd.Property { - return systemd.Property{ +func newProp(name string, units interface{}) systemdDbus.Property { + return systemdDbus.Property{ Name: name, Value: dbus.MakeVariant(units), } } func UseSystemd() bool { - s, err := os.Stat("/run/systemd/system") - if err != nil || !s.IsDir() { + if !systemdUtil.IsRunningSystemd() { return false } @@ -75,7 +75,7 @@ func UseSystemd() bool { if theConn == nil { var err error - theConn, err = systemd.New() + theConn, err = systemdDbus.New() if err != nil { return false } @@ -84,7 +84,7 @@ func UseSystemd() bool { hasStartTransientUnit = true // But if we get UnknownMethod error we don't - if _, err := theConn.StartTransientUnit("test.scope", "invalid"); err != nil { + if _, err := theConn.StartTransientUnit("test.scope", "invalid", nil, nil); err != nil { if dbusError, ok := err.(dbus.Error); ok { if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" { hasStartTransientUnit = false @@ -99,7 +99,7 @@ func UseSystemd() bool { 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 _, err := theConn.StopUnit(scope, "replace", nil); err != nil { if dbusError, ok := err.(dbus.Error); ok { if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") { testScopeExists = false @@ -118,7 +118,7 @@ func UseSystemd() bool { // Assume StartTransientUnit on a scope allows DefaultDependencies hasTransientDefaultDependencies = true ddf := newProp("DefaultDependencies", false) - if _, err := theConn.StartTransientUnit(scope, "replace", ddf); err != nil { + if _, err := theConn.StartTransientUnit(scope, "replace", []systemdDbus.Property{ddf}, nil); err != nil { if dbusError, ok := err.(dbus.Error); ok { if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") { hasTransientDefaultDependencies = false @@ -127,7 +127,7 @@ func UseSystemd() bool { } // Not critical because of the stop unit logic above. - theConn.StopUnit(scope, "replace") + theConn.StopUnit(scope, "replace", nil) } return hasStartTransientUnit } @@ -147,7 +147,7 @@ func (m *Manager) Apply(pid int) error { c = m.Cgroups unitName = getUnitName(c) slice = "system.slice" - properties []systemd.Property + properties []systemdDbus.Property ) if c.Slice != "" { @@ -155,8 +155,8 @@ func (m *Manager) Apply(pid int) error { } properties = append(properties, - systemd.PropSlice(slice), - systemd.PropDescription("docker container "+c.Name), + systemdDbus.PropSlice(slice), + systemdDbus.PropDescription("docker container "+c.Name), newProp("PIDs", []uint32{uint32(pid)}), ) @@ -198,7 +198,7 @@ func (m *Manager) Apply(pid int) error { } } - if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil { + if _, err := theConn.StartTransientUnit(unitName, "replace", properties, nil); err != nil { return err } @@ -269,7 +269,7 @@ func (m *Manager) Apply(pid int) error { func (m *Manager) Destroy() error { m.mu.Lock() defer m.mu.Unlock() - theConn.StopUnit(getUnitName(m.Cgroups), "replace") + theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil) if err := cgroups.RemovePaths(m.Paths); err != nil { return err } @@ -298,7 +298,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { if err != nil { return "", err } - if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { return "", err } if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil { @@ -478,7 +478,7 @@ func setKernelMemory(c *configs.Cgroup) error { return err } - if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(path, 0755); err != nil { return err } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go index 92438a07f7..1d0cb502cd 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/utils.go @@ -25,6 +25,8 @@ func FindCgroupMountpoint(subsystem string) (string, error) { if err != nil { return "", err } + defer f.Close() + scanner := bufio.NewScanner(f) for scanner.Scan() { txt := scanner.Text() @@ -47,6 +49,8 @@ func FindCgroupMountpointAndSource(subsystem string) (string, string, error) { if err != nil { return "", "", err } + defer f.Close() + scanner := bufio.NewScanner(f) for scanner.Scan() { txt := scanner.Text() diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go new file mode 100644 index 0000000000..c7bdf1f60a --- /dev/null +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go @@ -0,0 +1,10 @@ +// +build linux,!go1.5 + +package libcontainer + +import "syscall" + +// GidMappingsEnableSetgroups was added in Go 1.5, so do nothing when building +// with earlier versions +func enableSetgroups(sys *syscall.SysProcAttr) { +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container.go index 567fc68155..a24b71b845 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/container.go @@ -5,6 +5,8 @@ package libcontainer import ( + "os" + "github.com/opencontainers/runc/libcontainer/configs" ) @@ -159,4 +161,10 @@ type Container interface { // errors: // Systemerror - System error. NotifyOOM() (<-chan struct{}, error) + + // Signal sends the provided signal code to the container's initial process. + // + // errors: + // Systemerror - System error. + Signal(s os.Signal) error } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go index 7d9fa71aaf..9a27eb432f 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -118,6 +118,13 @@ func (c *linuxContainer) Start(process *Process) error { return nil } +func (c *linuxContainer) Signal(s os.Signal) error { + if err := c.initProcess.signal(s); err != nil { + return newSystemError(err) + } + return nil +} + func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) { parentPipe, childPipe, err := newPipe() if err != nil { @@ -164,6 +171,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c // user mappings are not supported return nil, err } + enableSetgroups(cmd.SysProcAttr) // Default to root user when user namespaces are enabled. if cmd.SysProcAttr.Credential == nil { cmd.SysProcAttr.Credential = &syscall.Credential{} @@ -273,7 +281,7 @@ func (c *linuxContainer) checkCriuVersion() error { out, err := exec.Command(c.criuPath, "-V").Output() if err != nil { - return err + return fmt.Errorf("Unable to execute CRIU command: %s", c.criuPath) } n, err := fmt.Sscanf(string(out), "Version: %d.%d.%d\n", &x, &y, &z) // 1.5.2 @@ -293,6 +301,19 @@ func (c *linuxContainer) checkCriuVersion() error { const descriptors_filename = "descriptors.json" +func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := m.Destination + if strings.HasPrefix(mountDest, c.config.Rootfs) { + mountDest = mountDest[len(c.config.Rootfs):] + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(mountDest), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() @@ -356,22 +377,25 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { } t := criurpc.CriuReqType_DUMP - req := criurpc.CriuReq{ + req := &criurpc.CriuReq{ Type: &t, Opts: &rpcOpts, } for _, m := range c.config.Mounts { - if m.Device == "bind" { - mountDest := m.Destination - if strings.HasPrefix(mountDest, c.config.Rootfs) { - mountDest = mountDest[len(c.config.Rootfs):] + switch m.Device { + case "bind": + c.addCriuDumpMount(req, m) + break + case "cgroup": + binds, err := getCgroupMounts(m) + if err != nil { + return err } - - extMnt := new(criurpc.ExtMountMap) - extMnt.Key = proto.String(mountDest) - extMnt.Val = proto.String(mountDest) - req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + for _, b := range binds { + c.addCriuDumpMount(req, b) + } + break } } @@ -387,13 +411,26 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { return err } - err = c.criuSwrk(nil, &req, criuOpts) + err = c.criuSwrk(nil, req, criuOpts) if err != nil { return err } return nil } +func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := m.Destination + if strings.HasPrefix(mountDest, c.config.Rootfs) { + mountDest = mountDest[len(c.config.Rootfs):] + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(m.Source), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() @@ -449,7 +486,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { defer syscall.Unmount(root, syscall.MNT_DETACH) t := criurpc.CriuReqType_RESTORE - req := criurpc.CriuReq{ + req := &criurpc.CriuReq{ Type: &t, Opts: &criurpc.CriuOpts{ ImagesDirFd: proto.Int32(int32(imageDir.Fd())), @@ -468,16 +505,19 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { }, } for _, m := range c.config.Mounts { - if m.Device == "bind" { - mountDest := m.Destination - if strings.HasPrefix(mountDest, c.config.Rootfs) { - mountDest = mountDest[len(c.config.Rootfs):] + switch m.Device { + case "bind": + c.addCriuRestoreMount(req, m) + break + case "cgroup": + binds, err := getCgroupMounts(m) + if err != nil { + return err } - - extMnt := new(criurpc.ExtMountMap) - extMnt.Key = proto.String(mountDest) - extMnt.Val = proto.String(m.Source) - req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + for _, b := range binds { + c.addCriuRestoreMount(req, b) + } + break } } for _, iface := range c.config.Networks { @@ -515,7 +555,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { } } - err = c.criuSwrk(process, &req, criuOpts) + err = c.criuSwrk(process, req, criuOpts) if err != nil { return err } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go index 5eb561f698..0f7ba67824 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -46,7 +46,7 @@ func InitArgs(args ...string) func(*LinuxFactory) error { } name = abs } - l.InitPath = name + l.InitPath = "/proc/self/exe" l.InitArgs = append([]string{name}, args[1:]...) return nil } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go index a21d1a7e6d..fd124f6de0 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -34,7 +34,7 @@ type pid struct { type network struct { configs.Network - // TempVethPeerName is a unique tempory veth peer name that was placed into + // TempVethPeerName is a unique temporary veth peer name that was placed into // the container's namespace. TempVethPeerName string `json:"temp_veth_peer_name"` } diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go b/vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go index 89dfa041ea..a96f4ca5f5 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/restored_process.go @@ -106,7 +106,11 @@ func (p *nonChildProcess) startTime() (string, error) { } func (p *nonChildProcess) signal(s os.Signal) error { - return newGenericError(fmt.Errorf("restored process cannot be signaled"), SystemError) + proc, err := os.FindProcess(p.processPid) + if err != nil { + return err + } + return proc.Signal(s) } func (p *nonChildProcess) externalDescriptors() []string { diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index a211d8de9d..88aa77d517 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -98,12 +98,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { switch m.Device { case "proc", "sysfs": - if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(dest, 0755); err != nil { return err } return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "") case "mqueue": - if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(dest, 0755); err != nil { return err } if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil { @@ -113,7 +113,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { case "tmpfs": stat, err := os.Stat(dest) if err != nil { - if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(dest, 0755); err != nil { return err } } @@ -127,7 +127,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } return nil case "devpts": - if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(dest, 0755); err != nil { return err } return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data) @@ -170,32 +170,23 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } } case "cgroup": - mounts, err := cgroups.GetCgroupMounts() + binds, err := getCgroupMounts(m) if err != nil { return err } - var binds []*configs.Mount - for _, mm := range mounts { - dir, err := mm.GetThisCgroupDir() - if err != nil { - return err + var merged []string + for _, b := range binds { + ss := filepath.Base(b.Destination) + if strings.Contains(ss, ",") { + merged = append(merged, ss) } - relDir, err := filepath.Rel(mm.Root, dir) - if err != nil { - return err - } - binds = append(binds, &configs.Mount{ - Device: "bind", - Source: filepath.Join(mm.Mountpoint, relDir), - Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")), - Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags, - }) } tmpfs := &configs.Mount{ Source: "tmpfs", Device: "tmpfs", Destination: m.Destination, Flags: defaultMountFlags, + Data: "mode=755", } if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil { return err @@ -205,12 +196,70 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { return err } } + // create symlinks for merged cgroups + cwd, err := os.Getwd() + if err != nil { + return err + } + if err := os.Chdir(filepath.Join(rootfs, m.Destination)); err != nil { + return err + } + for _, mc := range merged { + for _, ss := range strings.Split(mc, ",") { + if err := os.Symlink(mc, ss); err != nil { + // if cgroup already exists, then okay(it could have been created before) + if os.IsExist(err) { + continue + } + os.Chdir(cwd) + return err + } + } + } + if err := os.Chdir(cwd); err != nil { + return err + } + if m.Flags&syscall.MS_RDONLY != 0 { + // remount cgroup root as readonly + rootfsCgroup := filepath.Join(rootfs, m.Destination) + if err := syscall.Mount("", rootfsCgroup, "", defaultMountFlags|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil { + return err + } + } default: return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination) } return nil } +func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { + mounts, err := cgroups.GetCgroupMounts() + if err != nil { + return nil, err + } + + var binds []*configs.Mount + + for _, mm := range mounts { + dir, err := mm.GetThisCgroupDir() + if err != nil { + return nil, err + } + relDir, err := filepath.Rel(mm.Root, dir) + if err != nil { + return nil, err + } + binds = append(binds, &configs.Mount{ + Device: "bind", + Source: filepath.Join(mm.Mountpoint, relDir), + Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")), + Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags, + }) + } + + return binds, nil +} + // checkMountDestination checks to ensure that the mount destination is not over the // top of /proc or /sys. // dest is required to be an abs path and have any symlinks resolved before calling this function. diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go new file mode 100644 index 0000000000..c7bdb605aa --- /dev/null +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go @@ -0,0 +1,11 @@ +// +build linux,go1.5 + +package libcontainer + +import "syscall" + +// Set the GidMappingsEnableSetgroups member to true, so the process's +// setgroups proc entry wont be set to 'deny' if GidMappings are set +func enableSetgroups(sys *syscall.SysProcAttr) { + sys.GidMappingsEnableSetgroups = true +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go b/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go index 15b3482ccc..5ee6e37a3a 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go @@ -9,13 +9,17 @@ func Capture(userSkip int) Stacktrace { var ( skip = userSkip + 1 // add one for our own function frames []Frame + prevPc uintptr = 0 ) for i := skip; ; i++ { pc, file, line, ok := runtime.Caller(i) - if !ok { + //detect if caller is repeated to avoid loop, gccgo + //currently runs into a loop without this check + if !ok || pc == prevPc { break } frames = append(frames, NewFrame(pc, file, line)) + prevPc = pc } return Stacktrace{ Frames: frames,