зеркало из https://github.com/microsoft/docker.git
Merge pull request #15302 from LK4D4/update_libcontainer
Update runc to v0.0.3
This commit is contained in:
Коммит
7b077c16d6
|
@ -44,9 +44,9 @@ clone git github.com/endophage/gotuf 89ceb27829b9353dfee5ccccf7a3a9bb77008b05
|
||||||
clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337
|
clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337
|
||||||
clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
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)
|
# 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/godbus/dbus v2
|
||||||
clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb
|
clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb
|
||||||
clone git github.com/golang/protobuf 655cdfa588ea
|
clone git github.com/golang/protobuf 655cdfa588ea
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package activation implements primitives for systemd socket activation.
|
// Package activation implements primitives for systemd socket activation.
|
||||||
package activation
|
package activation
|
||||||
|
@ -30,10 +28,8 @@ const (
|
||||||
|
|
||||||
func Files(unsetEnv bool) []*os.File {
|
func Files(unsetEnv bool) []*os.File {
|
||||||
if unsetEnv {
|
if unsetEnv {
|
||||||
// there is no way to unset env in golang os package for now
|
defer os.Unsetenv("LISTEN_PID")
|
||||||
// https://code.google.com/p/go/issues/detail?id=6423
|
defer os.Unsetenv("LISTEN_FDS")
|
||||||
defer os.Setenv("LISTEN_PID", "")
|
|
||||||
defer os.Setenv("LISTEN_FDS", "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
||||||
|
@ -46,7 +42,7 @@ func Files(unsetEnv bool) []*os.File {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var files []*os.File
|
files := make([]*os.File, 0, nfds)
|
||||||
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
||||||
syscall.CloseOnExec(fd)
|
syscall.CloseOnExec(fd)
|
||||||
files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
|
files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
|
||||||
|
|
|
@ -1,38 +1,37 @@
|
||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package activation
|
package activation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"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) {
|
func Listeners(unsetEnv bool) ([]net.Listener, error) {
|
||||||
files := Files(unsetEnv)
|
files := Files(unsetEnv)
|
||||||
listeners := make([]net.Listener, len(files))
|
listeners := make([]net.Listener, len(files))
|
||||||
|
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
var err error
|
if pc, err := net.FileListener(f); err == nil {
|
||||||
listeners[i], err = net.FileListener(f)
|
listeners[i] = pc
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners, nil
|
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 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/
|
// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/
|
||||||
package dbus
|
package dbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -26,24 +25,53 @@ import (
|
||||||
"github.com/godbus/dbus"
|
"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
|
// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped
|
||||||
// serializing special characters.
|
func needsEscape(i int, b byte) bool {
|
||||||
func ObjectPath(path string) dbus.ObjectPath {
|
// Escape everything that is not a-z-A-Z-0-9
|
||||||
path = strings.Replace(path, ".", "_2e", -1)
|
// Also escape 0-9 if it's the first character
|
||||||
path = strings.Replace(path, "-", "_2d", -1)
|
return strings.IndexByte(alphanum, b) == -1 ||
|
||||||
path = strings.Replace(path, "@", "_40", -1)
|
(i == 0 && strings.IndexByte(num, b) != -1)
|
||||||
|
|
||||||
return dbus.ObjectPath(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
type Conn struct {
|
||||||
sysconn *dbus.Conn
|
// sysconn/sysobj are only used to call dbus methods
|
||||||
sysobj *dbus.Object
|
sysconn *dbus.Conn
|
||||||
|
sysobj *dbus.Object
|
||||||
|
|
||||||
|
// sigconn/sigobj are only used to receive dbus signals
|
||||||
|
sigconn *dbus.Conn
|
||||||
|
sigobj *dbus.Object
|
||||||
|
|
||||||
jobListener struct {
|
jobListener struct {
|
||||||
jobs map[dbus.ObjectPath]chan string
|
jobs map[dbus.ObjectPath]chan<- string
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
subscriber struct {
|
subscriber struct {
|
||||||
|
@ -53,26 +81,61 @@ type Conn struct {
|
||||||
ignore map[dbus.ObjectPath]int64
|
ignore map[dbus.ObjectPath]int64
|
||||||
cleanIgnore 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) {
|
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
|
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
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) initConnection() error {
|
func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
|
||||||
var err error
|
conn, err := createBus()
|
||||||
c.sysconn, err = dbus.SystemBusPrivate()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only use EXTERNAL method, and hardcode the uid (not username)
|
// Only use EXTERNAL method, and hardcode the uid (not username)
|
||||||
|
@ -80,25 +143,21 @@ func (c *Conn) initConnection() error {
|
||||||
// libc)
|
// libc)
|
||||||
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
||||||
|
|
||||||
err = c.sysconn.Auth(methods)
|
err = conn.Auth(methods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sysconn.Close()
|
conn.Close()
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.sysconn.Hello()
|
err = conn.Hello()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sysconn.Close()
|
conn.Close()
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
|
return conn, nil
|
||||||
|
}
|
||||||
// Setup the listeners on jobs so that we can get completions
|
|
||||||
c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
func systemdObject(conn *dbus.Conn) *dbus.Object {
|
||||||
"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
|
return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
|
||||||
c.initSubscription()
|
|
||||||
c.initDispatch()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,27 @@
|
||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package dbus
|
package dbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/godbus/dbus"
|
"github.com/godbus/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) initJobs() {
|
|
||||||
c.jobListener.jobs = make(map[dbus.ObjectPath]chan string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) jobComplete(signal *dbus.Signal) {
|
func (c *Conn) jobComplete(signal *dbus.Signal) {
|
||||||
var id uint32
|
var id uint32
|
||||||
var job dbus.ObjectPath
|
var job dbus.ObjectPath
|
||||||
|
@ -40,29 +37,29 @@ func (c *Conn) jobComplete(signal *dbus.Signal) {
|
||||||
c.jobListener.Unlock()
|
c.jobListener.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) startJob(job string, args ...interface{}) (<-chan string, error) {
|
func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) {
|
||||||
c.jobListener.Lock()
|
if ch != nil {
|
||||||
defer c.jobListener.Unlock()
|
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
|
|
||||||
}
|
}
|
||||||
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) {
|
// StartUnit enqueues a start job and depending jobs, if any (unless otherwise
|
||||||
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
|
|
||||||
// specified by the mode string).
|
// specified by the mode string).
|
||||||
//
|
//
|
||||||
// Takes the unit to activate, plus a mode string. The mode needs to be one of
|
// 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
|
// requirement dependencies. It is not recommended to make use of the latter
|
||||||
// two options.
|
// 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
|
// done indicates successful execution of a job. canceled indicates that a job
|
||||||
// has been canceled before it finished execution. timeout indicates that the
|
// has been canceled before it finished execution. timeout indicates that the
|
||||||
// job timeout was reached. failed indicates that the job failed. dependency
|
// 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
|
// 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
|
// has been removed too. skipped indicates that a job was skipped because it
|
||||||
// didn't apply to the units current state.
|
// 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
|
// StopUnit is similar to StartUnit but stops the specified unit rather
|
||||||
// than starting it.
|
// than starting it.
|
||||||
func (c *Conn) StopUnit(name string, mode string) (string, error) {
|
func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.StopUnit", name, mode)
|
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.
|
// 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) {
|
func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestartUnit restarts a service. If a service is restarted that isn't
|
// RestartUnit restarts a service. If a service is restarted that isn't
|
||||||
// running it will be started.
|
// running it will be started.
|
||||||
func (c *Conn) RestartUnit(name string, mode string) (string, error) {
|
func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryRestartUnit is like RestartUnit, except that a service that isn't running
|
// TryRestartUnit is like RestartUnit, except that a service that isn't running
|
||||||
// is not affected by the restart.
|
// is not affected by the restart.
|
||||||
func (c *Conn) TryRestartUnit(name string, mode string) (string, error) {
|
func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
|
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func (c *Conn) ReloadOrRestartUnit(name string, mode string) (string, error) {
|
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
|
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
|
||||||
// flavored restart otherwise.
|
// flavored restart otherwise.
|
||||||
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) {
|
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartTransientUnit() may be used to create and start a transient unit, which
|
// 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
|
// system is rebooted. name is the unit name including suffix, and must be
|
||||||
// unique. mode is the same as in StartUnit(), properties contains properties
|
// unique. mode is the same as in StartUnit(), properties contains properties
|
||||||
// of the unit.
|
// of the unit.
|
||||||
func (c *Conn) StartTransientUnit(name string, mode string, properties ...Property) (string, error) {
|
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
|
||||||
return c.runJob("org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
|
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
|
// 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()
|
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
|
// 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) {
|
func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
var props map[string]dbus.Variant
|
var props map[string]dbus.Variant
|
||||||
|
|
||||||
path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
|
path := unitPath(unit)
|
||||||
if !path.IsValid() {
|
if !path.IsValid() {
|
||||||
return nil, errors.New("invalid unit name: " + unit)
|
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 err error
|
||||||
var prop dbus.Variant
|
var prop dbus.Variant
|
||||||
|
|
||||||
path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
|
path := unitPath(unit)
|
||||||
if !path.IsValid() {
|
if !path.IsValid() {
|
||||||
return nil, errors.New("invalid unit name: " + unit)
|
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) {
|
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
|
// ListUnits returns an array with all currently loaded units. Note that
|
||||||
|
@ -394,3 +404,7 @@ type DisableUnitFileChange struct {
|
||||||
func (c *Conn) Reload() error {
|
func (c *Conn) Reload() error {
|
||||||
return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
|
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 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package dbus
|
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
|
package dbus
|
||||||
|
|
||||||
type set struct {
|
type set struct {
|
||||||
|
@ -17,17 +31,17 @@ func (s *set) Contains(value string) (exists bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *set) Length() (int) {
|
func (s *set) Length() int {
|
||||||
return len(s.data)
|
return len(s.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *set) Values() (values []string) {
|
func (s *set) Values() (values []string) {
|
||||||
for val, _ := range s.data {
|
for val, _ := range s.data {
|
||||||
values = append(values, val)
|
values = append(values, val)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSet() (*set) {
|
func newSet() *set {
|
||||||
return &set{make(map[string] bool)}
|
return &set{make(map[string]bool)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package dbus
|
package dbus
|
||||||
|
|
||||||
|
@ -33,12 +31,12 @@ const (
|
||||||
// systemd will automatically stop sending signals so there is no need to
|
// systemd will automatically stop sending signals so there is no need to
|
||||||
// explicitly call Unsubscribe().
|
// explicitly call Unsubscribe().
|
||||||
func (c *Conn) Subscribe() error {
|
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'")
|
"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'")
|
"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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +46,7 @@ func (c *Conn) Subscribe() error {
|
||||||
|
|
||||||
// Unsubscribe this connection from systemd dbus events.
|
// Unsubscribe this connection from systemd dbus events.
|
||||||
func (c *Conn) Unsubscribe() error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -56,14 +54,10 @@ func (c *Conn) Unsubscribe() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) initSubscription() {
|
func (c *Conn) dispatch() {
|
||||||
c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) initDispatch() {
|
|
||||||
ch := make(chan *dbus.Signal, signalBuffer)
|
ch := make(chan *dbus.Signal, signalBuffer)
|
||||||
|
|
||||||
c.sysconn.Signal(ch)
|
c.sigconn.Signal(ch)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -72,24 +66,32 @@ func (c *Conn) initDispatch() {
|
||||||
return
|
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 {
|
switch signal.Name {
|
||||||
case "org.freedesktop.systemd1.Manager.JobRemoved":
|
case "org.freedesktop.systemd1.Manager.JobRemoved":
|
||||||
c.jobComplete(signal)
|
|
||||||
|
|
||||||
unitName := signal.Body[2].(string)
|
unitName := signal.Body[2].(string)
|
||||||
var unitPath dbus.ObjectPath
|
|
||||||
c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
|
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":
|
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":
|
case "org.freedesktop.DBus.Properties.PropertiesChanged":
|
||||||
if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
|
if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
|
||||||
// we only care about SubState updates, which are a Unit property
|
unitPath = signal.Path
|
||||||
c.sendSubStateUpdate(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
|
// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
|
||||||
// size of the channels, the comparison function for detecting changes and a filter
|
// size of the channels, the comparison function for detecting changes and a filter
|
||||||
// function for cutting down on the noise that your channel receives.
|
// 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)
|
old := make(map[string]*UnitStatus)
|
||||||
statusChan := make(chan map[string]*UnitStatus, buffer)
|
statusChan := make(chan map[string]*UnitStatus, buffer)
|
||||||
errChan := make(chan error, 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) {
|
func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
|
||||||
c.subscriber.Lock()
|
c.subscriber.Lock()
|
||||||
defer c.subscriber.Unlock()
|
defer c.subscriber.Unlock()
|
||||||
if c.subscriber.updateCh == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.shouldIgnore(path) {
|
if c.shouldIgnore(path) {
|
||||||
return
|
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
|
package dbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -11,7 +25,6 @@ type SubscriptionSet struct {
|
||||||
conn *Conn
|
conn *Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *SubscriptionSet) filter(unit string) bool {
|
func (s *SubscriptionSet) filter(unit string) bool {
|
||||||
return !s.Contains(unit)
|
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) {
|
func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
|
||||||
// TODO: Make fully evented by using systemd 209 with properties changed values
|
// TODO: Make fully evented by using systemd 209 with properties changed values
|
||||||
return s.conn.SubscribeUnitsCustom(time.Second, 0,
|
return s.conn.SubscribeUnitsCustom(time.Second, 0,
|
||||||
func(u1, u2 *UnitStatus) bool { return *u1 != *u2 },
|
mismatchUnitStatus,
|
||||||
func(unit string) bool { return s.filter(unit) },
|
func(unit string) bool { return s.filter(unit) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubscriptionSet returns a new subscription set.
|
// NewSubscriptionSet returns a new subscription set.
|
||||||
func (conn *Conn) NewSubscriptionSet() (*SubscriptionSet) {
|
func (conn *Conn) NewSubscriptionSet() *SubscriptionSet {
|
||||||
return &SubscriptionSet{newSet(), conn}
|
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 2015 CoreOS, Inc.
|
||||||
Copyright 2013 CoreOS Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package journal provides write bindings to the systemd journal
|
// Package journal provides write bindings to the systemd journal
|
||||||
package journal
|
package journal
|
||||||
|
|
|
@ -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 the cgroup name/path is absolute do not look relative to the cgroup of the init process.
|
||||||
if filepath.IsAbs(raw.cgroup) {
|
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)
|
parent, err := raw.parent(subsystem, mnt, src)
|
||||||
|
@ -272,7 +272,7 @@ func (raw *data) join(subsystem string) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := writeFile(path, CgroupProcesses, strconv.Itoa(raw.pid)); err != nil {
|
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 {
|
if err := s.ensureParent(parent, root); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(current, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(current, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.copyIfNeeded(current, parent)
|
return s.copyIfNeeded(current, parent)
|
||||||
|
|
|
@ -25,7 +25,7 @@ func (s *MemoryGroup) Apply(d *data) error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.Set(path, d.c); err != nil {
|
if err := s.Set(path, d.c); err != nil {
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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/godbus/dbus"
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||||
|
@ -52,21 +53,20 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
theConn *systemd.Conn
|
theConn *systemdDbus.Conn
|
||||||
hasStartTransientUnit bool
|
hasStartTransientUnit bool
|
||||||
hasTransientDefaultDependencies bool
|
hasTransientDefaultDependencies bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func newProp(name string, units interface{}) systemd.Property {
|
func newProp(name string, units interface{}) systemdDbus.Property {
|
||||||
return systemd.Property{
|
return systemdDbus.Property{
|
||||||
Name: name,
|
Name: name,
|
||||||
Value: dbus.MakeVariant(units),
|
Value: dbus.MakeVariant(units),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UseSystemd() bool {
|
func UseSystemd() bool {
|
||||||
s, err := os.Stat("/run/systemd/system")
|
if !systemdUtil.IsRunningSystemd() {
|
||||||
if err != nil || !s.IsDir() {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ func UseSystemd() bool {
|
||||||
|
|
||||||
if theConn == nil {
|
if theConn == nil {
|
||||||
var err error
|
var err error
|
||||||
theConn, err = systemd.New()
|
theConn, err = systemdDbus.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func UseSystemd() bool {
|
||||||
hasStartTransientUnit = true
|
hasStartTransientUnit = true
|
||||||
|
|
||||||
// But if we get UnknownMethod error we don't
|
// 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, ok := err.(dbus.Error); ok {
|
||||||
if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
|
if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
|
||||||
hasStartTransientUnit = false
|
hasStartTransientUnit = false
|
||||||
|
@ -99,7 +99,7 @@ func UseSystemd() bool {
|
||||||
scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
|
scope := fmt.Sprintf("libcontainer-%d-systemd-test-default-dependencies.scope", os.Getpid())
|
||||||
testScopeExists := true
|
testScopeExists := true
|
||||||
for i := 0; i <= testScopeWait; i++ {
|
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 dbusError, ok := err.(dbus.Error); ok {
|
||||||
if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
|
if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
|
||||||
testScopeExists = false
|
testScopeExists = false
|
||||||
|
@ -118,7 +118,7 @@ func UseSystemd() bool {
|
||||||
// Assume StartTransientUnit on a scope allows DefaultDependencies
|
// Assume StartTransientUnit on a scope allows DefaultDependencies
|
||||||
hasTransientDefaultDependencies = true
|
hasTransientDefaultDependencies = true
|
||||||
ddf := newProp("DefaultDependencies", false)
|
ddf := newProp("DefaultDependencies", false)
|
||||||
if _, err := theConn.StartTransientUnit(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 dbusError, ok := err.(dbus.Error); ok {
|
||||||
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
|
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") {
|
||||||
hasTransientDefaultDependencies = false
|
hasTransientDefaultDependencies = false
|
||||||
|
@ -127,7 +127,7 @@ func UseSystemd() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not critical because of the stop unit logic above.
|
// Not critical because of the stop unit logic above.
|
||||||
theConn.StopUnit(scope, "replace")
|
theConn.StopUnit(scope, "replace", nil)
|
||||||
}
|
}
|
||||||
return hasStartTransientUnit
|
return hasStartTransientUnit
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func (m *Manager) Apply(pid int) error {
|
||||||
c = m.Cgroups
|
c = m.Cgroups
|
||||||
unitName = getUnitName(c)
|
unitName = getUnitName(c)
|
||||||
slice = "system.slice"
|
slice = "system.slice"
|
||||||
properties []systemd.Property
|
properties []systemdDbus.Property
|
||||||
)
|
)
|
||||||
|
|
||||||
if c.Slice != "" {
|
if c.Slice != "" {
|
||||||
|
@ -155,8 +155,8 @@ func (m *Manager) Apply(pid int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
properties = append(properties,
|
properties = append(properties,
|
||||||
systemd.PropSlice(slice),
|
systemdDbus.PropSlice(slice),
|
||||||
systemd.PropDescription("docker container "+c.Name),
|
systemdDbus.PropDescription("docker container "+c.Name),
|
||||||
newProp("PIDs", []uint32{uint32(pid)}),
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ func (m *Manager) Apply(pid int) error {
|
||||||
func (m *Manager) Destroy() error {
|
func (m *Manager) Destroy() error {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
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 {
|
if err := cgroups.RemovePaths(m.Paths); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
||||||
|
@ -478,7 +478,7 @@ func setKernelMemory(c *configs.Cgroup) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ func FindCgroupMountpoint(subsystem string) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
txt := scanner.Text()
|
txt := scanner.Text()
|
||||||
|
@ -47,6 +49,8 @@ func FindCgroupMountpointAndSource(subsystem string) (string, string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
txt := scanner.Text()
|
txt := scanner.Text()
|
||||||
|
|
10
vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go
поставляемый
Normal file
10
vendor/src/github.com/opencontainers/runc/libcontainer/compat_1.5_linux.go
поставляемый
Normal file
|
@ -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
|
package libcontainer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -159,4 +161,10 @@ type Container interface {
|
||||||
// errors:
|
// errors:
|
||||||
// Systemerror - System error.
|
// Systemerror - System error.
|
||||||
NotifyOOM() (<-chan struct{}, 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
|
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) {
|
func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
|
||||||
parentPipe, childPipe, err := newPipe()
|
parentPipe, childPipe, err := newPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -164,6 +171,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c
|
||||||
// user mappings are not supported
|
// user mappings are not supported
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
enableSetgroups(cmd.SysProcAttr)
|
||||||
// Default to root user when user namespaces are enabled.
|
// Default to root user when user namespaces are enabled.
|
||||||
if cmd.SysProcAttr.Credential == nil {
|
if cmd.SysProcAttr.Credential == nil {
|
||||||
cmd.SysProcAttr.Credential = &syscall.Credential{}
|
cmd.SysProcAttr.Credential = &syscall.Credential{}
|
||||||
|
@ -273,7 +281,7 @@ func (c *linuxContainer) checkCriuVersion() error {
|
||||||
|
|
||||||
out, err := exec.Command(c.criuPath, "-V").Output()
|
out, err := exec.Command(c.criuPath, "-V").Output()
|
||||||
if err != nil {
|
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
|
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"
|
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 {
|
func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
|
@ -356,22 +377,25 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
t := criurpc.CriuReqType_DUMP
|
t := criurpc.CriuReqType_DUMP
|
||||||
req := criurpc.CriuReq{
|
req := &criurpc.CriuReq{
|
||||||
Type: &t,
|
Type: &t,
|
||||||
Opts: &rpcOpts,
|
Opts: &rpcOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range c.config.Mounts {
|
for _, m := range c.config.Mounts {
|
||||||
if m.Device == "bind" {
|
switch m.Device {
|
||||||
mountDest := m.Destination
|
case "bind":
|
||||||
if strings.HasPrefix(mountDest, c.config.Rootfs) {
|
c.addCriuDumpMount(req, m)
|
||||||
mountDest = mountDest[len(c.config.Rootfs):]
|
break
|
||||||
|
case "cgroup":
|
||||||
|
binds, err := getCgroupMounts(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
for _, b := range binds {
|
||||||
extMnt := new(criurpc.ExtMountMap)
|
c.addCriuDumpMount(req, b)
|
||||||
extMnt.Key = proto.String(mountDest)
|
}
|
||||||
extMnt.Val = proto.String(mountDest)
|
break
|
||||||
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,13 +411,26 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.criuSwrk(nil, &req, criuOpts)
|
err = c.criuSwrk(nil, req, criuOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||||
c.m.Lock()
|
c.m.Lock()
|
||||||
defer c.m.Unlock()
|
defer c.m.Unlock()
|
||||||
|
@ -449,7 +486,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||||
defer syscall.Unmount(root, syscall.MNT_DETACH)
|
defer syscall.Unmount(root, syscall.MNT_DETACH)
|
||||||
|
|
||||||
t := criurpc.CriuReqType_RESTORE
|
t := criurpc.CriuReqType_RESTORE
|
||||||
req := criurpc.CriuReq{
|
req := &criurpc.CriuReq{
|
||||||
Type: &t,
|
Type: &t,
|
||||||
Opts: &criurpc.CriuOpts{
|
Opts: &criurpc.CriuOpts{
|
||||||
ImagesDirFd: proto.Int32(int32(imageDir.Fd())),
|
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 {
|
for _, m := range c.config.Mounts {
|
||||||
if m.Device == "bind" {
|
switch m.Device {
|
||||||
mountDest := m.Destination
|
case "bind":
|
||||||
if strings.HasPrefix(mountDest, c.config.Rootfs) {
|
c.addCriuRestoreMount(req, m)
|
||||||
mountDest = mountDest[len(c.config.Rootfs):]
|
break
|
||||||
|
case "cgroup":
|
||||||
|
binds, err := getCgroupMounts(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
for _, b := range binds {
|
||||||
extMnt := new(criurpc.ExtMountMap)
|
c.addCriuRestoreMount(req, b)
|
||||||
extMnt.Key = proto.String(mountDest)
|
}
|
||||||
extMnt.Val = proto.String(m.Source)
|
break
|
||||||
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, iface := range c.config.Networks {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func InitArgs(args ...string) func(*LinuxFactory) error {
|
||||||
}
|
}
|
||||||
name = abs
|
name = abs
|
||||||
}
|
}
|
||||||
l.InitPath = name
|
l.InitPath = "/proc/self/exe"
|
||||||
l.InitArgs = append([]string{name}, args[1:]...)
|
l.InitArgs = append([]string{name}, args[1:]...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type pid struct {
|
||||||
type network struct {
|
type network struct {
|
||||||
configs.Network
|
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.
|
// the container's namespace.
|
||||||
TempVethPeerName string `json:"temp_veth_peer_name"`
|
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 {
|
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 {
|
func (p *nonChildProcess) externalDescriptors() []string {
|
||||||
|
|
|
@ -98,12 +98,12 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
||||||
|
|
||||||
switch m.Device {
|
switch m.Device {
|
||||||
case "proc", "sysfs":
|
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 err
|
||||||
}
|
}
|
||||||
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
|
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
|
||||||
case "mqueue":
|
case "mqueue":
|
||||||
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(dest, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil {
|
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":
|
case "tmpfs":
|
||||||
stat, err := os.Stat(dest)
|
stat, err := os.Stat(dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(dest, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case "devpts":
|
case "devpts":
|
||||||
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(dest, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), data)
|
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":
|
case "cgroup":
|
||||||
mounts, err := cgroups.GetCgroupMounts()
|
binds, err := getCgroupMounts(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var binds []*configs.Mount
|
var merged []string
|
||||||
for _, mm := range mounts {
|
for _, b := range binds {
|
||||||
dir, err := mm.GetThisCgroupDir()
|
ss := filepath.Base(b.Destination)
|
||||||
if err != nil {
|
if strings.Contains(ss, ",") {
|
||||||
return err
|
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{
|
tmpfs := &configs.Mount{
|
||||||
Source: "tmpfs",
|
Source: "tmpfs",
|
||||||
Device: "tmpfs",
|
Device: "tmpfs",
|
||||||
Destination: m.Destination,
|
Destination: m.Destination,
|
||||||
Flags: defaultMountFlags,
|
Flags: defaultMountFlags,
|
||||||
|
Data: "mode=755",
|
||||||
}
|
}
|
||||||
if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
|
if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -205,12 +196,70 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
||||||
return err
|
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:
|
default:
|
||||||
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
||||||
}
|
}
|
||||||
return nil
|
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
|
// checkMountDestination checks to ensure that the mount destination is not over the
|
||||||
// top of /proc or /sys.
|
// top of /proc or /sys.
|
||||||
// dest is required to be an abs path and have any symlinks resolved before calling this function.
|
// dest is required to be an abs path and have any symlinks resolved before calling this function.
|
||||||
|
|
11
vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go
поставляемый
Normal file
11
vendor/src/github.com/opencontainers/runc/libcontainer/setgroups_linux.go
поставляемый
Normal file
|
@ -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 (
|
var (
|
||||||
skip = userSkip + 1 // add one for our own function
|
skip = userSkip + 1 // add one for our own function
|
||||||
frames []Frame
|
frames []Frame
|
||||||
|
prevPc uintptr = 0
|
||||||
)
|
)
|
||||||
for i := skip; ; i++ {
|
for i := skip; ; i++ {
|
||||||
pc, file, line, ok := runtime.Caller(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
|
break
|
||||||
}
|
}
|
||||||
frames = append(frames, NewFrame(pc, file, line))
|
frames = append(frames, NewFrame(pc, file, line))
|
||||||
|
prevPc = pc
|
||||||
}
|
}
|
||||||
return Stacktrace{
|
return Stacktrace{
|
||||||
Frames: frames,
|
Frames: frames,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче