This fixes criu behavior with mounted cgroups.
It includes also update of go-systemd dependecy.

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
This commit is contained in:
Alexander Morozov 2015-08-04 10:47:45 -07:00
Родитель c5e0ea02f7
Коммит a4ddf0e362
26 изменённых файлов: 603 добавлений и 301 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

33
vendor/src/github.com/coreos/go-systemd/util/util.go поставляемый Normal file
Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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