From c93754a0f9aab2e8b88a68db63e1b070509d6cc5 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Thu, 26 Nov 2015 00:44:44 +0100 Subject: [PATCH] vendor: bump deps bump runc/libcontainer to v0.0.5 bump runc deps to latest bump docker/libnetwork to 04cc1fa0a89f8c407b7be8cab883d4b17531ea7d Signed-off-by: Antonio Murdaca Upstream-commit: 65900d7603368f045c904d178fab05a13c44a066 Component: engine --- components/engine/hack/vendor.sh | 14 +- .../github.com/coreos/go-systemd/dbus/dbus.go | 42 +++- .../journal/{send.go => journal.go} | 22 +- .../docker/libnetwork/.dockerignore | 1 + .../github.com/docker/libnetwork/.gitignore | 3 +- .../docker/libnetwork/Dockerfile.build | 8 + .../src/github.com/docker/libnetwork/Makefile | 88 ++++---- .../docker/libnetwork/bitseq/sequence.go | 2 +- .../github.com/docker/libnetwork/circle.yml | 18 +- .../libnetwork/drivers/bridge/bridge.go | 46 ++-- .../drivers/bridge/setup_ip_tables.go | 10 +- .../docker/libnetwork/endpoint_info.go | 6 +- .../docker/libnetwork/iptables/firewalld.go | 2 +- .../docker/libnetwork/iptables/iptables.go | 24 ++- .../docker/libnetwork/netutils/utils.go | 38 ---- .../docker/libnetwork/netutils/utils_linux.go | 50 +++++ .../github.com/docker/libnetwork/network.go | 6 + .../docker/libnetwork/sandbox_externalkey.go | 175 +-------------- .../libnetwork/sandbox_externalkey_unix.go | 177 +++++++++++++++ .../libnetwork/sandbox_externalkey_windows.go | 45 ++++ .../vendor/src/github.com/godbus/dbus/LICENSE | 2 +- .../github.com/godbus/dbus/README.markdown | 3 + .../vendor/src/github.com/godbus/dbus/call.go | 111 ---------- .../vendor/src/github.com/godbus/dbus/conn.go | 48 +++-- .../src/github.com/godbus/dbus/encoder.go | 41 +++- .../src/github.com/godbus/dbus/export.go | 203 ++++++++++++++---- .../src/github.com/godbus/dbus/object.go | 126 +++++++++++ .../github.com/golang/protobuf/proto/Makefile | 2 +- .../golang/protobuf/proto/encode.go | 10 +- .../github.com/golang/protobuf/proto/lib.go | 57 ++--- .../golang/protobuf/proto/properties.go | 7 +- .../opencontainers/runc/libcontainer/SPEC.md | 12 +- .../runc/libcontainer/cgroups/fs/apply_raw.go | 115 +++++----- .../runc/libcontainer/cgroups/fs/blkio.go | 10 +- .../runc/libcontainer/cgroups/fs/cpu.go | 10 +- .../runc/libcontainer/cgroups/fs/cpuacct.go | 8 +- .../runc/libcontainer/cgroups/fs/cpuset.go | 21 +- .../runc/libcontainer/cgroups/fs/devices.go | 10 +- .../runc/libcontainer/cgroups/fs/freezer.go | 10 +- .../runc/libcontainer/cgroups/fs/hugetlb.go | 10 +- .../runc/libcontainer/cgroups/fs/memory.go | 41 ++-- .../runc/libcontainer/cgroups/fs/name.go | 11 +- .../runc/libcontainer/cgroups/fs/net_cls.go | 12 +- .../runc/libcontainer/cgroups/fs/net_prio.go | 12 +- .../libcontainer/cgroups/fs/perf_event.go | 8 +- .../runc/libcontainer/cgroups/fs/utils.go | 11 +- .../cgroups/systemd/apply_systemd.go | 100 +++++---- .../configs/{cgroup.go => cgroup_unix.go} | 5 +- .../libcontainer/configs/cgroup_windows.go | 6 + .../runc/libcontainer/configs/config.go | 8 +- ...s_windows.go => namespaces_unsupported.go} | 2 + .../runc/libcontainer/container.go | 59 +---- .../runc/libcontainer/container_linux.go | 121 ++++++++++- .../runc/libcontainer/container_windows.go | 20 ++ .../{criu_opts.go => criu_opts_unix.go} | 2 + .../runc/libcontainer/criu_opts_windows.go | 6 + .../devices/devices_unsupported.go | 3 + .../libcontainer/devices/devices_windows.go | 16 -- .../runc/libcontainer/factory_linux.go | 11 +- .../runc/libcontainer/process_linux.go | 8 +- .../runc/libcontainer/rootfs_linux.go | 32 +-- .../runc/libcontainer/seccomp/config.go | 74 ++++--- .../libcontainer/seccomp/seccomp_linux.go | 3 + .../runc/libcontainer/utils/utils.go | 2 +- .../gocapability/capability/syscall_linux.go | 6 +- 65 files changed, 1344 insertions(+), 828 deletions(-) rename components/engine/vendor/src/github.com/coreos/go-systemd/journal/{send.go => journal.go} (81%) create mode 100644 components/engine/vendor/src/github.com/docker/libnetwork/.dockerignore create mode 100644 components/engine/vendor/src/github.com/docker/libnetwork/Dockerfile.build create mode 100644 components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils_linux.go create mode 100644 components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go create mode 100644 components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_windows.go create mode 100644 components/engine/vendor/src/github.com/godbus/dbus/object.go rename components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/{cgroup.go => cgroup_unix.go} (96%) create mode 100644 components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go rename components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/{namespaces_windows.go => namespaces_unsupported.go} (86%) create mode 100644 components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_windows.go rename components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/{criu_opts.go => criu_opts_unix.go} (98%) create mode 100644 components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go create mode 100644 components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go delete mode 100644 components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_windows.go diff --git a/components/engine/hack/vendor.sh b/components/engine/hack/vendor.sh index 2199c8baa8..c09f8f90df 100755 --- a/components/engine/hack/vendor.sh +++ b/components/engine/hack/vendor.sh @@ -22,7 +22,7 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://github.com/golang/net.git #get libnetwork packages -clone git github.com/docker/libnetwork b4ddf18317b19d6e4bcc821145589749206a7d00 +clone git github.com/docker/libnetwork 04cc1fa0a89f8c407b7be8cab883d4b17531ea7d clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 @@ -49,14 +49,14 @@ clone git github.com/miekg/pkcs11 80f102b5cac759de406949c47f0928b99bd64cdf clone git github.com/jfrazelle/go v1.5.1-1 clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c -# this runc commit from branch relabel_fix_docker_1.9.1, pls remove it when you -# update next time -clone git github.com/opencontainers/runc 1349b37bd56f4f5ce2690b5b2c0f53f88a261c67 # libcontainer +clone git github.com/opencontainers/runc v0.0.5 # libcontainer # libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) clone git github.com/coreos/go-systemd v4 -clone git github.com/godbus/dbus v2 -clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49fb -clone git github.com/golang/protobuf 655cdfa588ea +clone git github.com/godbus/dbus v3 +clone git github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 +clone git github.com/golang/protobuf f7137ae6b19afbfd61a94b746fda3b3fe0491874 + +# gelf logging driver deps clone git github.com/Graylog2/go-gelf 6c62a85f1d47a67f2a5144c0e745b325889a8120 clone git github.com/fluent/fluent-logger-golang v1.0.0 diff --git a/components/engine/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go b/components/engine/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go index 625a32b8e6..5dd748e60f 100644 --- a/components/engine/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go +++ b/components/engine/vendor/src/github.com/coreos/go-systemd/dbus/dbus.go @@ -64,11 +64,11 @@ func PathBusEscape(path string) string { type Conn struct { // sysconn/sysobj are only used to call dbus methods sysconn *dbus.Conn - sysobj *dbus.Object + sysobj dbus.BusObject // sigconn/sigobj are only used to receive dbus signals sigconn *dbus.Conn - sigobj *dbus.Object + sigobj dbus.BusObject jobListener struct { jobs map[dbus.ObjectPath]chan<- string @@ -86,14 +86,30 @@ type Conn struct { // New establishes a connection to the system bus and authenticates. // Callers should call Close() when done with the connection. func New() (*Conn, error) { - return newConnection(dbus.SystemBusPrivate) + return newConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(dbus.SystemBusPrivate) + }) } // 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) + return newConnection(func() (*dbus.Conn, error) { + return dbusAuthHelloConnection(dbus.SessionBusPrivate) + }) +} + +// NewSystemdConnection establishes a private, direct connection to systemd. +// This can be used for communicating with systemd without a dbus daemon. +// Callers should call Close() when done with the connection. +func NewSystemdConnection() (*Conn, error) { + return newConnection(func() (*dbus.Conn, error) { + // We skip Hello when talking directly to systemd. + return dbusAuthConnection(func() (*dbus.Conn, error) { + return dbus.Dial("unix:path=/run/systemd/private") + }) + }) } // Close closes an established connection @@ -103,12 +119,12 @@ func (c *Conn) Close() { } func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := dbusConnection(createBus) + sysconn, err := createBus() if err != nil { return nil, err } - sigconn, err := dbusConnection(createBus) + sigconn, err := createBus() if err != nil { sysconn.Close() return nil, err @@ -132,7 +148,7 @@ func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { return c, nil } -func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { +func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { conn, err := createBus() if err != nil { return nil, err @@ -149,8 +165,16 @@ func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { return nil, err } - err = conn.Hello() + return conn, nil +} + +func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := dbusAuthConnection(createBus) if err != nil { + return nil, err + } + + if err = conn.Hello(); err != nil { conn.Close() return nil, err } @@ -158,6 +182,6 @@ func dbusConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { return conn, nil } -func systemdObject(conn *dbus.Conn) *dbus.Object { +func systemdObject(conn *dbus.Conn) dbus.BusObject { return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) } diff --git a/components/engine/vendor/src/github.com/coreos/go-systemd/journal/send.go b/components/engine/vendor/src/github.com/coreos/go-systemd/journal/journal.go similarity index 81% rename from components/engine/vendor/src/github.com/coreos/go-systemd/journal/send.go rename to components/engine/vendor/src/github.com/coreos/go-systemd/journal/journal.go index 1620ae94a8..6c3f5b94df 100644 --- a/components/engine/vendor/src/github.com/coreos/go-systemd/journal/send.go +++ b/components/engine/vendor/src/github.com/coreos/go-systemd/journal/journal.go @@ -12,7 +12,14 @@ // 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 provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html package journal import ( @@ -53,14 +60,14 @@ func init() { } } -// Enabled returns true iff the systemd journal is available for logging +// Enabled returns true if the local systemd journal is available for logging func Enabled() bool { return conn != nil } -// Send a message to the systemd journal. vars is a map of journald fields to -// values. Fields must be composed of uppercase letters, numbers, and -// underscores, but must not start with an underscore. Within these +// Send a message to the local systemd journal. vars is a map of journald +// fields to values. Fields must be composed of uppercase letters, numbers, +// and underscores, but must not start with an underscore. Within these // restrictions, any arbitrary field name may be used. Some names have special // significance: see the journalctl documentation // (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) @@ -102,6 +109,11 @@ func Send(message string, priority Priority, vars map[string]string) error { return nil } +// Print prints a message to the local systemd journal using Send(). +func Print(priority Priority, format string, a ...interface{}) error { + return Send(fmt.Sprintf(format, a...), priority, nil) +} + func appendVariable(w io.Writer, name, value string) { if !validVarName(name) { journalError("variable name contains invalid character, ignoring") diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/.dockerignore b/components/engine/vendor/src/github.com/docker/libnetwork/.dockerignore new file mode 100644 index 0000000000..72e8ffc0db --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libnetwork/.dockerignore @@ -0,0 +1 @@ +* diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/.gitignore b/components/engine/vendor/src/github.com/docker/libnetwork/.gitignore index 0e0d489204..08e11d78e2 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/.gitignore +++ b/components/engine/vendor/src/github.com/docker/libnetwork/.gitignore @@ -2,6 +2,7 @@ *.o *.a *.so +bin/ # Folders integration-tmp/ @@ -33,4 +34,4 @@ cmd/dnet/dnet .project .settings/ -libnetwork-build.created +libnetworkbuild.created diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/Dockerfile.build b/components/engine/vendor/src/github.com/docker/libnetwork/Dockerfile.build new file mode 100644 index 0000000000..f43d4805cc --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libnetwork/Dockerfile.build @@ -0,0 +1,8 @@ +FROM golang:1.4-cross +RUN apt-get update && apt-get -y install iptables +RUN go get github.com/tools/godep \ + github.com/golang/lint/golint \ + golang.org/x/tools/cmd/vet \ + golang.org/x/tools/cmd/goimports \ + golang.org/x/tools/cmd/cover\ + github.com/mattn/goveralls diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/Makefile b/components/engine/vendor/src/github.com/docker/libnetwork/Makefile index b1eabf5223..73c5887320 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/Makefile +++ b/components/engine/vendor/src/github.com/docker/libnetwork/Makefile @@ -1,33 +1,20 @@ -.PHONY: all all-local build build-local check check-code check-format run-tests check-local integration-tests install-deps coveralls circle-ci start-services clean +.PHONY: all all-local build build-local clean cross cross-local check check-code check-format run-tests integration-tests check-local coveralls circle-ci-cross circle-ci-build circle-ci-check circle-ci SHELL=/bin/bash build_image=libnetworkbuild dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork container_env = -e "INSIDECONTAINER=-incontainer=true" -docker = docker run --rm -it ${dockerargs} ${container_env} ${build_image} +docker = docker run --rm -it ${dockerargs} $$EXTRA_ARGS ${container_env} ${build_image} ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true" -cidocker = docker run ${ciargs} ${dockerargs} golang:1.4 +cidocker = docker run ${dockerargs} ${ciargs} ${container_env} ${build_image} +CROSS_PLATFORMS = linux/amd64 linux/386 linux/arm windows/amd64 windows/386 + +${build_image}.created: + docker build -f Dockerfile.build -t ${build_image} . + touch ${build_image}.created all: ${build_image}.created build check integration-tests clean -integration-tests: ./cmd/dnet/dnet - @./test/integration/dnet/run-integration-tests.sh - -./cmd/dnet/dnet: - make build - -clean: - @if [ -e ./cmd/dnet/dnet ]; then \ - echo "Removing dnet binary"; \ - rm -rf ./cmd/dnet/dnet; \ - fi - -all-local: check-local build-local - -${build_image}.created: - docker run --name=libnetworkbuild -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork golang:1.4 make install-deps - docker commit libnetworkbuild ${build_image} - docker rm libnetworkbuild - touch ${build_image}.created +all-local: build-local check-local integration-tests-local clean build: ${build_image}.created @echo "Building code... " @@ -35,8 +22,25 @@ build: ${build_image}.created @echo "Done building code" build-local: - @$(shell which godep) go build ./... - @$(shell which godep) go build -o ./cmd/dnet/dnet ./cmd/dnet + @mkdir -p "bin" + $(shell which godep) go build -o "bin/dnet" ./cmd/dnet + +clean: + @if [ -d bin ]; then \ + echo "Removing dnet binaries"; \ + rm -rf bin; \ + fi + +cross: ${build_image}.created + @mkdir -p "bin" + @for platform in ${CROSS_PLATFORMS}; do \ + EXTRA_ARGS="-e GOOS=$${platform%/*} -e GOARCH=$${platform##*/}" ; \ + echo "$${platform}..." ; \ + ${docker} make cross-local ; \ + done + +cross-local: + $(shell which godep) go build -o "bin/dnet-$$GOOS-$$GOARCH" ./cmd/dnet check: ${build_image}.created @${docker} ./wrapmake.sh check-local @@ -71,27 +75,31 @@ run-tests: done @echo "Done running tests" -check-local: check-format check-code start-services run-tests +check-local: check-format check-code run-tests -install-deps: - apt-get update && apt-get -y install iptables zookeeperd - git clone https://github.com/golang/tools /go/src/golang.org/x/tools - go install golang.org/x/tools/cmd/vet - go install golang.org/x/tools/cmd/goimports - go install golang.org/x/tools/cmd/cover - go get github.com/tools/godep - go get github.com/golang/lint/golint - go get github.com/mattn/goveralls +integration-tests: ./bin/dnet + @./test/integration/dnet/run-integration-tests.sh + +./bin/dnet: + make build coveralls: -@goveralls -service circleci -coverprofile=coverage.coverprofile -repotoken $$COVERALLS_TOKEN # CircleCI's Docker fails when cleaning up using the --rm flag -# The following target is a workaround for this +# The following targets are a workaround for this +circle-ci-cross: ${build_image}.created + @mkdir -p "bin" + @for platform in ${CROSS_PLATFORMS}; do \ + EXTRA_ARGS="-e GOOS=$${platform%/*} -e GOARCH=$${platform##*/}" ; \ + echo "$${platform}..." ; \ + ${cidocker} make cross-local ; \ + done -circle-ci: - @${cidocker} make install-deps build-local check-local coveralls - make integration-tests +circle-ci-check: ${build_image}.created + @${cidocker} make check-local coveralls -start-services: - service zookeeper start +circle-ci-build: ${build_image}.created + @${cidocker} make build-local + +circle-ci: circle-ci-check circle-ci-build integration-tests diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go b/components/engine/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go index 14304e3400..553e150c26 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go @@ -552,7 +552,7 @@ func pushReservation(bytePos, bitPos uint64, head *sequence, release bool) *sequ } removeCurrentIfEmpty(&newHead, newSequence, current) mergeSequences(previous) - } else if precBlocks == current.count-2 { // Last in sequence (B) + } else if precBlocks == current.count { // Last in sequence (B) newSequence.next = current.next current.next = newSequence mergeSequences(current) diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/circle.yml b/components/engine/vendor/src/github.com/docker/libnetwork/circle.yml index d02f6a92ed..edeee1ceec 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/circle.yml +++ b/components/engine/vendor/src/github.com/docker/libnetwork/circle.yml @@ -1,12 +1,18 @@ machine: - services: - - docker + services: + - docker dependencies: - override: - - echo "Nothing to install" + override: + - sudo apt-get update; sudo apt-get install -y iptables zookeeperd + - go get golang.org/x/tools/cmd/vet + - go get golang.org/x/tools/cmd/goimports + - go get golang.org/x/tools/cmd/cover + - go get github.com/tools/godep + - go get github.com/golang/lint/golint + - go get github.com/mattn/goveralls test: - override: - - make circle-ci + override: + - make circle-ci diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 8cc26f951f..7991c6f67c 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -41,6 +41,9 @@ const ( DefaultGatewayV6AuxKey = "DefaultGatewayIPv6" ) +type iptableCleanFunc func() error +type iptablesCleanFuncs []iptableCleanFunc + // configuration info for the "bridge" driver. type configuration struct { EnableIPForwarding bool @@ -92,12 +95,13 @@ type bridgeEndpoint struct { } type bridgeNetwork struct { - id string - bridge *bridgeInterface // The bridge's L3 interface - config *networkConfiguration - endpoints map[string]*bridgeEndpoint // key: endpoint id - portMapper *portmapper.PortMapper - driver *driver // The network's driver + id string + bridge *bridgeInterface // The bridge's L3 interface + config *networkConfiguration + endpoints map[string]*bridgeEndpoint // key: endpoint id + portMapper *portmapper.PortMapper + driver *driver // The network's driver + iptCleanFuncs iptablesCleanFuncs sync.Mutex } @@ -236,6 +240,10 @@ func parseErr(label, value, errString string) error { return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString) } +func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) { + n.iptCleanFuncs = append(n.iptCleanFuncs, clean) +} + func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, error) { n.Lock() defer n.Unlock() @@ -604,6 +612,10 @@ func (d *driver) createNetwork(config *networkConfiguration) error { } return err } + network.registerIptCleanFunc(func() error { + nwList := d.getNetworks() + return network.isolateNetwork(nwList, false) + }) return nil } @@ -722,22 +734,6 @@ func (d *driver) DeleteNetwork(nid string) error { return err } - // In case of failures after this point, restore the network isolation rules - nwList := d.getNetworks() - defer func() { - if err != nil { - if err := n.isolateNetwork(nwList, true); err != nil { - logrus.Warnf("Failed on restoring the inter-network iptables rules on cleanup: %v", err) - } - } - }() - - // Remove inter-network communication rules. - err = n.isolateNetwork(nwList, false) - if err != nil { - return err - } - // We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior. if !config.DefaultBridge { if err := netlink.LinkDel(n.bridge.Link); err != nil { @@ -745,6 +741,12 @@ func (d *driver) DeleteNetwork(nid string) error { } } + // clean all relevant iptables rules + for _, cleanFunc := range n.iptCleanFuncs { + if errClean := cleanFunc(); errClean != nil { + logrus.Warnf("Failed to clean iptables rules for bridge network: %v", errClean) + } + } return d.storeDelete(config) } diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go b/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go index f597f67b7f..6b1c5dcb11 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go @@ -68,21 +68,27 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil { return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) } + n.registerIptCleanFunc(func() error { + return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) + }) natChain, filterChain, err := n.getDriverChains() if err != nil { return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error()) } - err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode) + err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true) if err != nil { return fmt.Errorf("Failed to program NAT chain: %s", err.Error()) } - err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode) + err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true) if err != nil { return fmt.Errorf("Failed to program FILTER chain: %s", err.Error()) } + n.registerIptCleanFunc(func() error { + return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false) + }) n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName()) diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/endpoint_info.go b/components/engine/vendor/src/github.com/docker/libnetwork/endpoint_info.go index db23eb738f..1028308557 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/endpoint_info.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/endpoint_info.go @@ -159,7 +159,11 @@ func (ep *endpoint) Info() EndpointInfo { return ep } - return sb.getEndpoint(ep.ID()) + if epi := sb.getEndpoint(ep.ID()); epi != nil { + return epi + } + + return nil } func (ep *endpoint) DriverInfo() (map[string]interface{}, error) { diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/iptables/firewalld.go b/components/engine/vendor/src/github.com/docker/libnetwork/iptables/firewalld.go index 1227647b74..246ce4d7a1 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/iptables/firewalld.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/iptables/firewalld.go @@ -27,7 +27,7 @@ const ( // Conn is a connection to firewalld dbus endpoint. type Conn struct { sysconn *dbus.Conn - sysobj *dbus.Object + sysobj dbus.BusObject signal chan *dbus.Signal } diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/iptables/iptables.go b/components/engine/vendor/src/github.com/docker/libnetwork/iptables/iptables.go index 4e24c3ac52..be7725f85d 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/iptables/iptables.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/iptables/iptables.go @@ -95,7 +95,7 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) { } // ProgramChain is used to add rules to a chain -func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode bool) error { +func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error { if c.Name == "" { return fmt.Errorf("Could not program chain, missing chain name.") } @@ -106,10 +106,14 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode bool) error { "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name} - if !Exists(Nat, "PREROUTING", preroute...) { + if !Exists(Nat, "PREROUTING", preroute...) && enable { if err := c.Prerouting(Append, preroute...); err != nil { return fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err) } + } else if Exists(Nat, "PREROUTING", preroute...) && !enable { + if err := c.Prerouting(Delete, preroute...); err != nil { + return fmt.Errorf("Failed to remove docker in PREROUTING chain: %s", err) + } } output := []string{ "-m", "addrtype", @@ -118,10 +122,14 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode bool) error { if !hairpinMode { output = append(output, "!", "--dst", "127.0.0.0/8") } - if !Exists(Nat, "OUTPUT", output...) { + if !Exists(Nat, "OUTPUT", output...) && enable { if err := c.Output(Append, output...); err != nil { return fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err) } + } else if Exists(Nat, "OUTPUT", output...) && !enable { + if err := c.Output(Delete, output...); err != nil { + return fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err) + } } case Filter: if bridgeName == "" { @@ -131,13 +139,21 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode bool) error { link := []string{ "-o", bridgeName, "-j", c.Name} - if !Exists(Filter, "FORWARD", link...) { + if !Exists(Filter, "FORWARD", link...) && enable { insert := append([]string{string(Insert), "FORWARD"}, link...) if output, err := Raw(insert...); err != nil { return err } else if len(output) != 0 { return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output) } + } else if Exists(Filter, "FORWARD", link...) && !enable { + del := append([]string{string(Delete), "FORWARD"}, link...) + if output, err := Raw(del...); err != nil { + return err + } else if len(output) != 0 { + return fmt.Errorf("Could not delete linking rule from %s/%s: %s", c.Table, c.Name, output) + } + } } return nil diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils.go b/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils.go index a1ead3618c..19ea2fddfb 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils.go @@ -9,10 +9,8 @@ import ( "fmt" "io" "net" - "strings" "github.com/docker/libnetwork/types" - "github.com/vishvananda/netlink" ) var ( @@ -22,8 +20,6 @@ var ( ErrNetworkOverlaps = errors.New("requested network overlaps with existing network") // ErrNoDefaultRoute preformatted error ErrNoDefaultRoute = errors.New("no default route") - - networkGetRoutesFct = netlink.RouteList ) // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers @@ -42,21 +38,6 @@ func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error { return nil } -// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes -func CheckRouteOverlaps(toCheck *net.IPNet) error { - networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4) - if err != nil { - return err - } - - for _, network := range networks { - if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) { - return ErrNetworkOverlaps - } - } - return nil -} - // NetworkOverlaps detects overlap between one IPNet and another func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool { return netX.Contains(netY.IP) || netY.Contains(netX.IP) @@ -151,22 +132,3 @@ func GenerateRandomName(prefix string, size int) (string, error) { } return prefix + hex.EncodeToString(id)[:size], nil } - -// GenerateIfaceName returns an interface name using the passed in -// prefix and the length of random bytes. The api ensures that the -// there are is no interface which exists with that name. -func GenerateIfaceName(prefix string, len int) (string, error) { - for i := 0; i < 3; i++ { - name, err := GenerateRandomName(prefix, len) - if err != nil { - continue - } - if _, err := netlink.LinkByName(name); err != nil { - if strings.Contains(err.Error(), "not found") { - return name, nil - } - return "", err - } - } - return "", types.InternalErrorf("could not generate interface name") -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils_linux.go b/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils_linux.go new file mode 100644 index 0000000000..782e542a52 --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libnetwork/netutils/utils_linux.go @@ -0,0 +1,50 @@ +// +build linux +// Network utility functions. + +package netutils + +import ( + "net" + "strings" + + "github.com/docker/libnetwork/types" + "github.com/vishvananda/netlink" +) + +var ( + networkGetRoutesFct = netlink.RouteList +) + +// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes +func CheckRouteOverlaps(toCheck *net.IPNet) error { + networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4) + if err != nil { + return err + } + + for _, network := range networks { + if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) { + return ErrNetworkOverlaps + } + } + return nil +} + +// GenerateIfaceName returns an interface name using the passed in +// prefix and the length of random bytes. The api ensures that the +// there are is no interface which exists with that name. +func GenerateIfaceName(prefix string, len int) (string, error) { + for i := 0; i < 3; i++ { + name, err := GenerateRandomName(prefix, len) + if err != nil { + continue + } + if _, err := netlink.LinkByName(name); err != nil { + if strings.Contains(err.Error(), "not found") { + return name, nil + } + return "", err + } + } + return "", types.InternalErrorf("could not generate interface name") +} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/network.go b/components/engine/vendor/src/github.com/docker/libnetwork/network.go index 00061ea016..378cd80f20 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/network.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/network.go @@ -671,6 +671,12 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi ep.processOptions(options...) + if opt, ok := ep.generic[netlabel.MacAddress]; ok { + if mac, ok := opt.(net.HardwareAddr); ok { + ep.iface.mac = mac + } + } + if err = ep.assignAddress(true, !n.postIPv6); err != nil { return nil, err } diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go index 0b2385b3bf..3c362f30d6 100644 --- a/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go +++ b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go @@ -1,19 +1,6 @@ package libnetwork -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "os" - - "github.com/Sirupsen/logrus" - "github.com/docker/docker/pkg/reexec" - "github.com/docker/libnetwork/types" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/configs" -) +import "github.com/docker/docker/pkg/reexec" type setKeyData struct { ContainerID string @@ -23,163 +10,3 @@ type setKeyData struct { func init() { reexec.Register("libnetwork-setkey", processSetKeyReexec) } - -const udsBase = "/var/lib/docker/network/files/" -const success = "success" - -// processSetKeyReexec is a private function that must be called only on an reexec path -// It expects 3 args { [0] = "libnetwork-setkey", [1] = , [2] = } -// It also expects libcontainer.State as a json string in -// Refer to https://github.com/opencontainers/runc/pull/160/ for more information -func processSetKeyReexec() { - var err error - - // Return a failure to the calling process via ExitCode - defer func() { - if err != nil { - logrus.Fatalf("%v", err) - } - }() - - // expecting 3 args {[0]="libnetwork-setkey", [1]=, [2]= } - if len(os.Args) < 3 { - err = fmt.Errorf("Re-exec expects 3 args, received : %d", len(os.Args)) - return - } - containerID := os.Args[1] - - // We expect libcontainer.State as a json string in - stateBuf, err := ioutil.ReadAll(os.Stdin) - if err != nil { - return - } - var state libcontainer.State - if err = json.Unmarshal(stateBuf, &state); err != nil { - return - } - - controllerID := os.Args[2] - key := state.NamespacePaths[configs.NamespaceType("NEWNET")] - - err = SetExternalKey(controllerID, containerID, key) - return -} - -// SetExternalKey provides a convenient way to set an External key to a sandbox -func SetExternalKey(controllerID string, containerID string, key string) error { - keyData := setKeyData{ - ContainerID: containerID, - Key: key} - - c, err := net.Dial("unix", udsBase+controllerID+".sock") - if err != nil { - return err - } - defer c.Close() - - if err = sendKey(c, keyData); err != nil { - return fmt.Errorf("sendKey failed with : %v", err) - } - return processReturn(c) -} - -func sendKey(c net.Conn, data setKeyData) error { - var err error - defer func() { - if err != nil { - c.Close() - } - }() - - var b []byte - if b, err = json.Marshal(data); err != nil { - return err - } - - _, err = c.Write(b) - return err -} - -func processReturn(r io.Reader) error { - buf := make([]byte, 1024) - n, err := r.Read(buf[:]) - if err != nil { - return fmt.Errorf("failed to read buf in processReturn : %v", err) - } - if string(buf[0:n]) != success { - return fmt.Errorf(string(buf[0:n])) - } - return nil -} - -func (c *controller) startExternalKeyListener() error { - if err := os.MkdirAll(udsBase, 0600); err != nil { - return err - } - uds := udsBase + c.id + ".sock" - l, err := net.Listen("unix", uds) - if err != nil { - return err - } - if err := os.Chmod(uds, 0600); err != nil { - l.Close() - return err - } - c.Lock() - c.extKeyListener = l - c.Unlock() - - go c.acceptClientConnections(uds, l) - return nil -} - -func (c *controller) acceptClientConnections(sock string, l net.Listener) { - for { - conn, err := l.Accept() - if err != nil { - if _, err1 := os.Stat(sock); os.IsNotExist(err1) { - logrus.Debugf("Unix socket %s doesnt exist. cannot accept client connections", sock) - return - } - logrus.Errorf("Error accepting connection %v", err) - continue - } - go func() { - err := c.processExternalKey(conn) - ret := success - if err != nil { - ret = err.Error() - } - - _, err = conn.Write([]byte(ret)) - if err != nil { - logrus.Errorf("Error returning to the client %v", err) - } - }() - } -} - -func (c *controller) processExternalKey(conn net.Conn) error { - buf := make([]byte, 1280) - nr, err := conn.Read(buf) - if err != nil { - return err - } - var s setKeyData - if err = json.Unmarshal(buf[0:nr], &s); err != nil { - return err - } - - var sandbox Sandbox - search := SandboxContainerWalker(&sandbox, s.ContainerID) - c.WalkSandboxes(search) - if sandbox == nil { - return types.BadRequestErrorf("no sandbox present for %s", s.ContainerID) - } - - return sandbox.SetKey(s.Key) -} - -func (c *controller) stopExternalKeyListener() { - c.extKeyListener.Close() -} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go new file mode 100644 index 0000000000..74ae2af78e --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go @@ -0,0 +1,177 @@ +// +build !windows + +package libnetwork + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net" + "os" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/types" + "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/configs" +) + +const udsBase = "/var/lib/docker/network/files/" +const success = "success" + +// processSetKeyReexec is a private function that must be called only on an reexec path +// It expects 3 args { [0] = "libnetwork-setkey", [1] = , [2] = } +// It also expects libcontainer.State as a json string in +// Refer to https://github.com/opencontainers/runc/pull/160/ for more information +func processSetKeyReexec() { + var err error + + // Return a failure to the calling process via ExitCode + defer func() { + if err != nil { + logrus.Fatalf("%v", err) + } + }() + + // expecting 3 args {[0]="libnetwork-setkey", [1]=, [2]= } + if len(os.Args) < 3 { + err = fmt.Errorf("Re-exec expects 3 args, received : %d", len(os.Args)) + return + } + containerID := os.Args[1] + + // We expect libcontainer.State as a json string in + stateBuf, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return + } + var state libcontainer.State + if err = json.Unmarshal(stateBuf, &state); err != nil { + return + } + + controllerID := os.Args[2] + key := state.NamespacePaths[configs.NamespaceType("NEWNET")] + + err = SetExternalKey(controllerID, containerID, key) + return +} + +// SetExternalKey provides a convenient way to set an External key to a sandbox +func SetExternalKey(controllerID string, containerID string, key string) error { + keyData := setKeyData{ + ContainerID: containerID, + Key: key} + + c, err := net.Dial("unix", udsBase+controllerID+".sock") + if err != nil { + return err + } + defer c.Close() + + if err = sendKey(c, keyData); err != nil { + return fmt.Errorf("sendKey failed with : %v", err) + } + return processReturn(c) +} + +func sendKey(c net.Conn, data setKeyData) error { + var err error + defer func() { + if err != nil { + c.Close() + } + }() + + var b []byte + if b, err = json.Marshal(data); err != nil { + return err + } + + _, err = c.Write(b) + return err +} + +func processReturn(r io.Reader) error { + buf := make([]byte, 1024) + n, err := r.Read(buf[:]) + if err != nil { + return fmt.Errorf("failed to read buf in processReturn : %v", err) + } + if string(buf[0:n]) != success { + return fmt.Errorf(string(buf[0:n])) + } + return nil +} + +func (c *controller) startExternalKeyListener() error { + if err := os.MkdirAll(udsBase, 0600); err != nil { + return err + } + uds := udsBase + c.id + ".sock" + l, err := net.Listen("unix", uds) + if err != nil { + return err + } + if err := os.Chmod(uds, 0600); err != nil { + l.Close() + return err + } + c.Lock() + c.extKeyListener = l + c.Unlock() + + go c.acceptClientConnections(uds, l) + return nil +} + +func (c *controller) acceptClientConnections(sock string, l net.Listener) { + for { + conn, err := l.Accept() + if err != nil { + if _, err1 := os.Stat(sock); os.IsNotExist(err1) { + logrus.Debugf("Unix socket %s doesnt exist. cannot accept client connections", sock) + return + } + logrus.Errorf("Error accepting connection %v", err) + continue + } + go func() { + err := c.processExternalKey(conn) + ret := success + if err != nil { + ret = err.Error() + } + + _, err = conn.Write([]byte(ret)) + if err != nil { + logrus.Errorf("Error returning to the client %v", err) + } + }() + } +} + +func (c *controller) processExternalKey(conn net.Conn) error { + buf := make([]byte, 1280) + nr, err := conn.Read(buf) + if err != nil { + return err + } + var s setKeyData + if err = json.Unmarshal(buf[0:nr], &s); err != nil { + return err + } + + var sandbox Sandbox + search := SandboxContainerWalker(&sandbox, s.ContainerID) + c.WalkSandboxes(search) + if sandbox == nil { + return types.BadRequestErrorf("no sandbox present for %s", s.ContainerID) + } + + return sandbox.SetKey(s.Key) +} + +func (c *controller) stopExternalKeyListener() { + c.extKeyListener.Close() +} diff --git a/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_windows.go b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_windows.go new file mode 100644 index 0000000000..3c4113e252 --- /dev/null +++ b/components/engine/vendor/src/github.com/docker/libnetwork/sandbox_externalkey_windows.go @@ -0,0 +1,45 @@ +// +build windows + +package libnetwork + +import ( + "io" + "net" + + "github.com/docker/libnetwork/types" +) + +// processSetKeyReexec is a private function that must be called only on an reexec path +// It expects 3 args { [0] = "libnetwork-setkey", [1] = , [2] = } +// It also expects libcontainer.State as a json string in +// Refer to https://github.com/opencontainers/runc/pull/160/ for more information +func processSetKeyReexec() { +} + +// SetExternalKey provides a convenient way to set an External key to a sandbox +func SetExternalKey(controllerID string, containerID string, key string) error { + return types.NotImplementedErrorf("SetExternalKey isn't supported on non linux systems") +} + +func sendKey(c net.Conn, data setKeyData) error { + return types.NotImplementedErrorf("sendKey isn't supported on non linux systems") +} + +func processReturn(r io.Reader) error { + return types.NotImplementedErrorf("processReturn isn't supported on non linux systems") +} + +// no-op on non linux systems +func (c *controller) startExternalKeyListener() error { + return nil +} + +func (c *controller) acceptClientConnections(sock string, l net.Listener) { +} + +func (c *controller) processExternalKey(conn net.Conn) error { + return types.NotImplementedErrorf("processExternalKey isn't supported on non linux systems") +} + +func (c *controller) stopExternalKeyListener() { +} diff --git a/components/engine/vendor/src/github.com/godbus/dbus/LICENSE b/components/engine/vendor/src/github.com/godbus/dbus/LICENSE index 06b252bcbc..670d88fcaa 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/LICENSE +++ b/components/engine/vendor/src/github.com/godbus/dbus/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013, Georg Reinke () +Copyright (c) 2013, Georg Reinke (), Google All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/components/engine/vendor/src/github.com/godbus/dbus/README.markdown b/components/engine/vendor/src/github.com/godbus/dbus/README.markdown index 3ab2116651..0a6e7e5bfb 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/README.markdown +++ b/components/engine/vendor/src/github.com/godbus/dbus/README.markdown @@ -27,6 +27,9 @@ The complete package documentation and some simple examples are available at [_examples](https://github.com/godbus/dbus/tree/master/_examples) directory gives a short overview over the basic usage. +#### Projects using godbus +- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. + Please note that the API is considered unstable for now and may change without further notice. diff --git a/components/engine/vendor/src/github.com/godbus/dbus/call.go b/components/engine/vendor/src/github.com/godbus/dbus/call.go index 1d2fbc7efd..ba6e73f607 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/call.go +++ b/components/engine/vendor/src/github.com/godbus/dbus/call.go @@ -2,7 +2,6 @@ package dbus import ( "errors" - "strings" ) // Call represents a pending or completed method call. @@ -35,113 +34,3 @@ func (c *Call) Store(retvalues ...interface{}) error { return Store(c.Body, retvalues...) } - -// Object represents a remote object on which methods can be invoked. -type Object struct { - conn *Conn - dest string - path ObjectPath -} - -// Call calls a method with (*Object).Go and waits for its reply. -func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { - return <-o.Go(method, flags, make(chan *Call, 1), args...).Done -} - -// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given -// object. The property name must be given in interface.member notation. -func (o *Object) GetProperty(p string) (Variant, error) { - idx := strings.LastIndex(p, ".") - if idx == -1 || idx+1 == len(p) { - return Variant{}, errors.New("dbus: invalid property " + p) - } - - iface := p[:idx] - prop := p[idx+1:] - - result := Variant{} - err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) - - if err != nil { - return Variant{}, err - } - - return result, nil -} - -// Go calls a method with the given arguments asynchronously. It returns a -// Call structure representing this method call. The passed channel will -// return the same value once the call is done. If ch is nil, a new channel -// will be allocated. Otherwise, ch has to be buffered or Go will panic. -// -// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure -// is returned of which only the Err member is valid. -// -// If the method parameter contains a dot ('.'), the part before the last dot -// specifies the interface on which the method is called. -func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { - iface := "" - i := strings.LastIndex(method, ".") - if i != -1 { - iface = method[:i] - } - method = method[i+1:] - msg := new(Message) - msg.Type = TypeMethodCall - msg.serial = o.conn.getSerial() - msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) - msg.Headers = make(map[HeaderField]Variant) - msg.Headers[FieldPath] = MakeVariant(o.path) - msg.Headers[FieldDestination] = MakeVariant(o.dest) - msg.Headers[FieldMember] = MakeVariant(method) - if iface != "" { - msg.Headers[FieldInterface] = MakeVariant(iface) - } - msg.Body = args - if len(args) > 0 { - msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) - } - if msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 10) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Object).Go") - } - call := &Call{ - Destination: o.dest, - Path: o.path, - Method: method, - Args: args, - Done: ch, - } - o.conn.callsLck.Lock() - o.conn.calls[msg.serial] = call - o.conn.callsLck.Unlock() - o.conn.outLck.RLock() - if o.conn.closed { - call.Err = ErrClosed - call.Done <- call - } else { - o.conn.out <- msg - } - o.conn.outLck.RUnlock() - return call - } - o.conn.outLck.RLock() - defer o.conn.outLck.RUnlock() - if o.conn.closed { - return &Call{Err: ErrClosed} - } - o.conn.out <- msg - return &Call{Err: nil} -} - -// Destination returns the destination that calls on o are sent to. -func (o *Object) Destination() string { - return o.dest -} - -// Path returns the path that calls on o are sent to. -func (o *Object) Path() ObjectPath { - return o.path -} diff --git a/components/engine/vendor/src/github.com/godbus/dbus/conn.go b/components/engine/vendor/src/github.com/godbus/dbus/conn.go index 18027a096a..a4f5394010 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/conn.go +++ b/components/engine/vendor/src/github.com/godbus/dbus/conn.go @@ -32,7 +32,7 @@ var ErrClosed = errors.New("dbus: connection closed by user") type Conn struct { transport - busObj *Object + busObj BusObject unixFD bool uuid string @@ -46,7 +46,7 @@ type Conn struct { calls map[uint32]*Call callsLck sync.RWMutex - handlers map[ObjectPath]map[string]interface{} + handlers map[ObjectPath]map[string]exportWithMapping handlersLck sync.RWMutex out chan *Message @@ -157,7 +157,7 @@ func newConn(tr transport) (*Conn, error) { conn.transport = tr conn.calls = make(map[uint32]*Call) conn.out = make(chan *Message, 10) - conn.handlers = make(map[ObjectPath]map[string]interface{}) + conn.handlers = make(map[ObjectPath]map[string]exportWithMapping) conn.nextSerial = 1 conn.serialUsed = map[uint32]bool{0: true} conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") @@ -166,7 +166,7 @@ func newConn(tr transport) (*Conn, error) { // BusObject returns the object owned by the bus daemon which handles // administrative requests. -func (conn *Conn) BusObject() *Object { +func (conn *Conn) BusObject() BusObject { return conn.busObj } @@ -303,18 +303,33 @@ func (conn *Conn) inWorker() { // as per http://dbus.freedesktop.org/doc/dbus-specification.html , // sender is optional for signals. sender, _ := msg.Headers[FieldSender].value.(string) - if iface == "org.freedesktop.DBus" && member == "NameLost" && - sender == "org.freedesktop.DBus" { - - name, _ := msg.Body[0].(string) - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - copy(conn.names[i:], conn.names[i+1:]) - conn.names = conn.names[:len(conn.names)-1] + if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" { + if member == "NameLost" { + // If we lost the name on the bus, remove it from our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the lost name") } + conn.namesLck.Lock() + for i, v := range conn.names { + if v == name { + conn.names = append(conn.names[:i], + conn.names[i+1:]...) + } + } + conn.namesLck.Unlock() + } else if member == "NameAcquired" { + // If we acquired the name on the bus, add it to our + // tracking list. + name, ok := msg.Body[0].(string) + if !ok { + panic("Unable to read the acquired name") + } + conn.namesLck.Lock() + conn.names = append(conn.names, name) + conn.namesLck.Unlock() } - conn.namesLck.Unlock() } signal := &Signal{ Sender: sender, @@ -360,7 +375,7 @@ func (conn *Conn) Names() []string { } // Object returns the object identified by the given destination name and path. -func (conn *Conn) Object(dest string, path ObjectPath) *Object { +func (conn *Conn) Object(dest string, path ObjectPath) BusObject { return &Object{conn, dest, path} } @@ -554,7 +569,7 @@ type transport interface { } var ( - transports map[string]func(string) (transport, error) = make(map[string]func(string) (transport, error)) + transports = make(map[string]func(string) (transport, error)) ) func getTransport(address string) (transport, error) { @@ -571,6 +586,7 @@ func getTransport(address string) (transport, error) { f := transports[v[:i]] if f == nil { err = errors.New("dbus: invalid bus address (invalid or unsupported transport)") + continue } t, err = f(v[i+1:]) if err == nil { diff --git a/components/engine/vendor/src/github.com/godbus/dbus/encoder.go b/components/engine/vendor/src/github.com/godbus/dbus/encoder.go index f9d2f05716..9f0a9e89ea 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/encoder.go +++ b/components/engine/vendor/src/github.com/godbus/dbus/encoder.go @@ -16,24 +16,43 @@ type encoder struct { // NewEncoder returns a new encoder that writes to out in the given byte order. func newEncoder(out io.Writer, order binary.ByteOrder) *encoder { + return newEncoderAtOffset(out, 0, order) +} + +// newEncoderAtOffset returns a new encoder that writes to out in the given +// byte order. Specify the offset to initialize pos for proper alignment +// computation. +func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder { enc := new(encoder) enc.out = out enc.order = order + enc.pos = offset return enc } // Aligns the next output to be on a multiple of n. Panics on write errors. func (enc *encoder) align(n int) { - if enc.pos%n != 0 { - newpos := (enc.pos + n - 1) & ^(n - 1) - empty := make([]byte, newpos-enc.pos) + pad := enc.padding(0, n) + if pad > 0 { + empty := make([]byte, pad) if _, err := enc.out.Write(empty); err != nil { panic(err) } - enc.pos = newpos + enc.pos += pad } } +// pad returns the number of bytes of padding, based on current position and additional offset. +// and alignment. +func (enc *encoder) padding(offset, algn int) int { + abs := enc.pos + offset + if abs%algn != 0 { + newabs := (abs + algn - 1) & ^(algn - 1) + return newabs - abs + } + return 0 +} + // Calls binary.Write(enc.out, enc.order, v) and panics on write errors. func (enc *encoder) binwrite(v interface{}) { if err := binary.Write(enc.out, enc.order, v); err != nil { @@ -108,8 +127,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) { if depth >= 64 { panic(FormatError("input exceeds container depth limit")) } + // Lookahead offset: 4 bytes for uint32 length (with alignment), + // plus alignment for elements. + n := enc.padding(0, 4) + 4 + offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem())) + var buf bytes.Buffer - bufenc := newEncoder(&buf, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order) for i := 0; i < v.Len(); i++ { bufenc.encode(v.Index(i), depth+1) @@ -159,8 +183,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) { panic(InvalidTypeError{v.Type()}) } keys := v.MapKeys() + // Lookahead offset: 4 bytes for uint32 length (with alignment), + // plus 8-byte alignment + n := enc.padding(0, 4) + 4 + offset := enc.pos + n + enc.padding(n, 8) + var buf bytes.Buffer - bufenc := newEncoder(&buf, enc.order) + bufenc := newEncoderAtOffset(&buf, offset, enc.order) for _, k := range keys { bufenc.align(8) bufenc.encode(k, depth+2) diff --git a/components/engine/vendor/src/github.com/godbus/dbus/export.go b/components/engine/vendor/src/github.com/godbus/dbus/export.go index 1dd1591528..c6440a7416 100644 --- a/components/engine/vendor/src/github.com/godbus/dbus/export.go +++ b/components/engine/vendor/src/github.com/godbus/dbus/export.go @@ -2,9 +2,9 @@ package dbus import ( "errors" + "fmt" "reflect" "strings" - "unicode" ) var ( @@ -22,16 +22,52 @@ var ( } ) +// exportWithMapping represents an exported struct along with a method name +// mapping to allow for exporting lower-case methods, etc. +type exportWithMapping struct { + export interface{} + + // Method name mapping; key -> struct method, value -> dbus method. + mapping map[string]string + + // Whether or not this export is for the entire subtree + includeSubtree bool +} + // Sender is a type which can be used in exported methods to receive the message // sender. type Sender string -func exportedMethod(v interface{}, name string) reflect.Value { - if v == nil { +func exportedMethod(export exportWithMapping, name string) reflect.Value { + if export.export == nil { return reflect.Value{} } - m := reflect.ValueOf(v).MethodByName(name) - if !m.IsValid() { + + // If a mapping was included in the export, check the map to see if we + // should be looking for a different method in the export. + if export.mapping != nil { + for key, value := range export.mapping { + if value == name { + name = key + break + } + + // Catch the case where a method is aliased but the client is calling + // the original, e.g. the "Foo" method was exported mapped to + // "foo," and dbus client called the original "Foo." + if key == name { + return reflect.Value{} + } + } + } + + value := reflect.ValueOf(export.export) + m := value.MethodByName(name) + + // Catch the case of attempting to call an unexported method + method, ok := value.Type().MethodByName(name) + + if !m.IsValid() || !ok || method.PkgPath != "" { return reflect.Value{} } t := m.Type() @@ -43,6 +79,42 @@ func exportedMethod(v interface{}, name string) reflect.Value { return m } +// searchHandlers will look through all registered handlers looking for one +// to handle the given path. If a verbatim one isn't found, it will check for +// a subtree registration for the path as well. +func (conn *Conn) searchHandlers(path ObjectPath) (map[string]exportWithMapping, bool) { + conn.handlersLck.RLock() + defer conn.handlersLck.RUnlock() + + handlers, ok := conn.handlers[path] + if ok { + return handlers, ok + } + + // If handlers weren't found for this exact path, look for a matching subtree + // registration + handlers = make(map[string]exportWithMapping) + path = path[:strings.LastIndex(string(path), "/")] + for len(path) > 0 { + var subtreeHandlers map[string]exportWithMapping + subtreeHandlers, ok = conn.handlers[path] + if ok { + for iface, handler := range subtreeHandlers { + // Only include this handler if it registered for the subtree + if handler.includeSubtree { + handlers[iface] = handler + } + } + + break + } + + path = path[:strings.LastIndex(string(path), "/")] + } + + return handlers, ok +} + // handleCall handles the given method call (i.e. looks if it's one of the // pre-implemented ones and searches for a corresponding handler if not). func (conn *Conn) handleCall(msg *Message) { @@ -62,40 +134,35 @@ func (conn *Conn) handleCall(msg *Message) { } return } - if len(name) == 0 || unicode.IsLower([]rune(name)[0]) { + if len(name) == 0 { conn.sendError(errmsgUnknownMethod, sender, serial) } + + // Find the exported handler (if any) for this path + handlers, ok := conn.searchHandlers(path) + if !ok { + conn.sendError(errmsgNoObject, sender, serial) + return + } + var m reflect.Value if hasIface { - conn.handlersLck.RLock() - obj, ok := conn.handlers[path] - if !ok { - conn.sendError(errmsgNoObject, sender, serial) - conn.handlersLck.RUnlock() - return - } - iface := obj[ifaceName] - conn.handlersLck.RUnlock() + iface := handlers[ifaceName] m = exportedMethod(iface, name) } else { - conn.handlersLck.RLock() - if _, ok := conn.handlers[path]; !ok { - conn.sendError(errmsgNoObject, sender, serial) - conn.handlersLck.RUnlock() - return - } - for _, v := range conn.handlers[path] { + for _, v := range handlers { m = exportedMethod(v, name) if m.IsValid() { break } } - conn.handlersLck.RUnlock() } + if !m.IsValid() { conn.sendError(errmsgUnknownMethod, sender, serial) return } + t := m.Type() vs := msg.Body pointers := make([]interface{}, t.NumIn()) @@ -106,27 +173,36 @@ func (conn *Conn) handleCall(msg *Message) { pointers[i] = val.Interface() if tp == reflect.TypeOf((*Sender)(nil)).Elem() { val.Elem().SetString(sender) + } else if tp == reflect.TypeOf((*Message)(nil)).Elem() { + val.Elem().Set(reflect.ValueOf(*msg)) } else { decode = append(decode, pointers[i]) } } + if len(decode) != len(vs) { conn.sendError(errmsgInvalidArg, sender, serial) return } + if err := Store(vs, decode...); err != nil { conn.sendError(errmsgInvalidArg, sender, serial) return } + + // Extract parameters params := make([]reflect.Value, len(pointers)) for i := 0; i < len(pointers); i++ { params[i] = reflect.ValueOf(pointers[i]).Elem() } + + // Call method ret := m.Call(params) if em := ret[t.NumOut()-1].Interface().(*Error); em != nil { conn.sendError(*em, sender, serial) return } + if msg.Flags&FlagNoReplyExpected == 0 { reply := new(Message) reply.Type = TypeMethodReply @@ -203,6 +279,10 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro // contribute to the dbus signature of the method (i.e. the method is exposed // as if the parameters of type Sender were not there). // +// Similarly, any parameters with the type Message are set to the raw message +// received on the bus. Again, parameters of this type do not contribute to the +// dbus signature of the method. +// // Every method call is executed in a new goroutine, so the method may be called // in multiple goroutines at once. // @@ -214,10 +294,51 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro // // Export returns an error if path is not a valid path name. func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { + return conn.ExportWithMap(v, nil, path, iface) +} + +// ExportWithMap works exactly like Export but provides the ability to remap +// method names (e.g. export a lower-case method). +// +// The keys in the map are the real method names (exported on the struct), and +// the values are the method names to be exported on DBus. +func (conn *Conn) ExportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { + return conn.exportWithMap(v, mapping, path, iface, false) +} + +// ExportSubtree works exactly like Export but registers the given value for +// an entire subtree rather under the root path provided. +// +// In order to make this useful, one parameter in each of the value's exported +// methods should be a Message, in which case it will contain the raw message +// (allowing one to get access to the path that caused the method to be called). +// +// Note that more specific export paths take precedence over less specific. For +// example, a method call using the ObjectPath /foo/bar/baz will call a method +// exported on /foo/bar before a method exported on /foo. +func (conn *Conn) ExportSubtree(v interface{}, path ObjectPath, iface string) error { + return conn.ExportSubtreeWithMap(v, nil, path, iface) +} + +// ExportSubtreeWithMap works exactly like ExportSubtree but provides the +// ability to remap method names (e.g. export a lower-case method). +// +// The keys in the map are the real method names (exported on the struct), and +// the values are the method names to be exported on DBus. +func (conn *Conn) ExportSubtreeWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string) error { + return conn.exportWithMap(v, mapping, path, iface, true) +} + +// exportWithMap is the worker function for all exports/registrations. +func (conn *Conn) exportWithMap(v interface{}, mapping map[string]string, path ObjectPath, iface string, includeSubtree bool) error { if !path.IsValid() { - return errors.New("dbus: invalid path name") + return fmt.Errorf(`dbus: Invalid path name: "%s"`, path) } + conn.handlersLck.Lock() + defer conn.handlersLck.Unlock() + + // Remove a previous export if the interface is nil if v == nil { if _, ok := conn.handlers[path]; ok { delete(conn.handlers[path], iface) @@ -225,51 +346,39 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { delete(conn.handlers, path) } } + return nil } + + // If this is the first handler for this path, make a new map to hold all + // handlers for this path. if _, ok := conn.handlers[path]; !ok { - conn.handlers[path] = make(map[string]interface{}) + conn.handlers[path] = make(map[string]exportWithMapping) } - conn.handlers[path][iface] = v - conn.handlersLck.Unlock() + + // Finally, save this handler + conn.handlers[path][iface] = exportWithMapping{export: v, mapping: mapping, includeSubtree: includeSubtree} + return nil } -// ReleaseName calls org.freedesktop.DBus.ReleaseName. You should use only this -// method to release a name (see below). +// ReleaseName calls org.freedesktop.DBus.ReleaseName and awaits a response. func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) { var r uint32 err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r) if err != nil { return 0, err } - if r == uint32(ReleaseNameReplyReleased) { - conn.namesLck.Lock() - for i, v := range conn.names { - if v == name { - copy(conn.names[i:], conn.names[i+1:]) - conn.names = conn.names[:len(conn.names)-1] - } - } - conn.namesLck.Unlock() - } return ReleaseNameReply(r), nil } -// RequestName calls org.freedesktop.DBus.RequestName. You should use only this -// method to request a name because package dbus needs to keep track of all -// names that the connection has. +// RequestName calls org.freedesktop.DBus.RequestName and awaits a response. func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) { var r uint32 err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r) if err != nil { return 0, err } - if r == uint32(RequestNameReplyPrimaryOwner) { - conn.namesLck.Lock() - conn.names = append(conn.names, name) - conn.namesLck.Unlock() - } return RequestNameReply(r), nil } diff --git a/components/engine/vendor/src/github.com/godbus/dbus/object.go b/components/engine/vendor/src/github.com/godbus/dbus/object.go new file mode 100644 index 0000000000..7ef45da4c8 --- /dev/null +++ b/components/engine/vendor/src/github.com/godbus/dbus/object.go @@ -0,0 +1,126 @@ +package dbus + +import ( + "errors" + "strings" +) + +// BusObject is the interface of a remote object on which methods can be +// invoked. +type BusObject interface { + Call(method string, flags Flags, args ...interface{}) *Call + Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call + GetProperty(p string) (Variant, error) + Destination() string + Path() ObjectPath +} + +// Object represents a remote object on which methods can be invoked. +type Object struct { + conn *Conn + dest string + path ObjectPath +} + +// Call calls a method with (*Object).Go and waits for its reply. +func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { + return <-o.Go(method, flags, make(chan *Call, 1), args...).Done +} + +// Go calls a method with the given arguments asynchronously. It returns a +// Call structure representing this method call. The passed channel will +// return the same value once the call is done. If ch is nil, a new channel +// will be allocated. Otherwise, ch has to be buffered or Go will panic. +// +// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure +// is returned of which only the Err member is valid. +// +// If the method parameter contains a dot ('.'), the part before the last dot +// specifies the interface on which the method is called. +func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { + iface := "" + i := strings.LastIndex(method, ".") + if i != -1 { + iface = method[:i] + } + method = method[i+1:] + msg := new(Message) + msg.Type = TypeMethodCall + msg.serial = o.conn.getSerial() + msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) + msg.Headers = make(map[HeaderField]Variant) + msg.Headers[FieldPath] = MakeVariant(o.path) + msg.Headers[FieldDestination] = MakeVariant(o.dest) + msg.Headers[FieldMember] = MakeVariant(method) + if iface != "" { + msg.Headers[FieldInterface] = MakeVariant(iface) + } + msg.Body = args + if len(args) > 0 { + msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) + } + if msg.Flags&FlagNoReplyExpected == 0 { + if ch == nil { + ch = make(chan *Call, 10) + } else if cap(ch) == 0 { + panic("dbus: unbuffered channel passed to (*Object).Go") + } + call := &Call{ + Destination: o.dest, + Path: o.path, + Method: method, + Args: args, + Done: ch, + } + o.conn.callsLck.Lock() + o.conn.calls[msg.serial] = call + o.conn.callsLck.Unlock() + o.conn.outLck.RLock() + if o.conn.closed { + call.Err = ErrClosed + call.Done <- call + } else { + o.conn.out <- msg + } + o.conn.outLck.RUnlock() + return call + } + o.conn.outLck.RLock() + defer o.conn.outLck.RUnlock() + if o.conn.closed { + return &Call{Err: ErrClosed} + } + o.conn.out <- msg + return &Call{Err: nil} +} + +// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given +// object. The property name must be given in interface.member notation. +func (o *Object) GetProperty(p string) (Variant, error) { + idx := strings.LastIndex(p, ".") + if idx == -1 || idx+1 == len(p) { + return Variant{}, errors.New("dbus: invalid property " + p) + } + + iface := p[:idx] + prop := p[idx+1:] + + result := Variant{} + err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) + + if err != nil { + return Variant{}, err + } + + return result, nil +} + +// Destination returns the destination that calls on o are sent to. +func (o *Object) Destination() string { + return o.dest +} + +// Path returns the path that calls on o are sent to. +func (o *Object) Path() ObjectPath { + return o.path +} diff --git a/components/engine/vendor/src/github.com/golang/protobuf/proto/Makefile b/components/engine/vendor/src/github.com/golang/protobuf/proto/Makefile index f1f06564a1..fb838ed2d7 100644 --- a/components/engine/vendor/src/github.com/golang/protobuf/proto/Makefile +++ b/components/engine/vendor/src/github.com/golang/protobuf/proto/Makefile @@ -39,5 +39,5 @@ test: install generate-test-pbs generate-test-pbs: make install make -C testdata - protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto + make -C proto3_proto make diff --git a/components/engine/vendor/src/github.com/golang/protobuf/proto/encode.go b/components/engine/vendor/src/github.com/golang/protobuf/proto/encode.go index d1abc3328d..cd826e9b1a 100644 --- a/components/engine/vendor/src/github.com/golang/protobuf/proto/encode.go +++ b/components/engine/vendor/src/github.com/golang/protobuf/proto/encode.go @@ -1128,12 +1128,10 @@ func size_new_map(p *Properties, base structPointer) int { keycopy.Set(key) valcopy.Set(val) - // Tag codes for key and val are the responsibility of the sub-sizer. - keysize := p.mkeyprop.size(p.mkeyprop, keybase) - valsize := p.mvalprop.size(p.mvalprop, valbase) - entry := keysize + valsize - // Add on tag code and length of map entry itself. - n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry + // Tag codes are two bytes per map entry. + n += 2 + n += p.mkeyprop.size(p.mkeyprop, keybase) + n += p.mvalprop.size(p.mvalprop, valbase) } return n } diff --git a/components/engine/vendor/src/github.com/golang/protobuf/proto/lib.go b/components/engine/vendor/src/github.com/golang/protobuf/proto/lib.go index fb139f6b74..f81052f2ae 100644 --- a/components/engine/vendor/src/github.com/golang/protobuf/proto/lib.go +++ b/components/engine/vendor/src/github.com/golang/protobuf/proto/lib.go @@ -607,15 +607,13 @@ func setDefaults(v reflect.Value, recur, zeros bool) { for _, ni := range dm.nested { f := v.Field(ni) - // f is *T or []*T or map[T]*T - switch f.Kind() { - case reflect.Ptr: - if f.IsNil() { - continue - } + if f.IsNil() { + continue + } + // f is *T or []*T + if f.Kind() == reflect.Ptr { setDefaults(f, recur, zeros) - - case reflect.Slice: + } else { for i := 0; i < f.Len(); i++ { e := f.Index(i) if e.IsNil() { @@ -623,15 +621,6 @@ func setDefaults(v reflect.Value, recur, zeros bool) { } setDefaults(e, recur, zeros) } - - case reflect.Map: - for _, k := range f.MapKeys() { - e := f.MapIndex(k) - if e.IsNil() { - continue - } - setDefaults(e, recur, zeros) - } } } } @@ -657,6 +646,10 @@ type scalarField struct { value interface{} // the proto-declared default value, or nil } +func ptrToStruct(t reflect.Type) bool { + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + // t is a struct type. func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { sprop := GetProperties(t) @@ -668,33 +661,9 @@ func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { } ft := t.Field(fi).Type - var canHaveDefault, nestedMessage bool - switch ft.Kind() { - case reflect.Ptr: - if ft.Elem().Kind() == reflect.Struct { - nestedMessage = true - } else { - canHaveDefault = true // proto2 scalar field - } - - case reflect.Slice: - switch ft.Elem().Kind() { - case reflect.Ptr: - nestedMessage = true // repeated message - case reflect.Uint8: - canHaveDefault = true // bytes field - } - - case reflect.Map: - if ft.Elem().Kind() == reflect.Ptr { - nestedMessage = true // map with message values - } - } - - if !canHaveDefault { - if nestedMessage { - dm.nested = append(dm.nested, fi) - } + // nested messages + if ptrToStruct(ft) || (ft.Kind() == reflect.Slice && ptrToStruct(ft.Elem())) { + dm.nested = append(dm.nested, fi) continue } diff --git a/components/engine/vendor/src/github.com/golang/protobuf/proto/properties.go b/components/engine/vendor/src/github.com/golang/protobuf/proto/properties.go index d74844ab2a..7216544815 100644 --- a/components/engine/vendor/src/github.com/golang/protobuf/proto/properties.go +++ b/components/engine/vendor/src/github.com/golang/protobuf/proto/properties.go @@ -440,12 +440,7 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock p.enc = (*Buffer).enc_slice_byte p.dec = (*Buffer).dec_slice_byte p.size = size_slice_byte - // This is a []byte, which is either a bytes field, - // or the value of a map field. In the latter case, - // we always encode an empty []byte, so we should not - // use the proto3 enc/size funcs. - // f == nil iff this is the key/value of a map field. - if p.proto3 && f != nil { + if p.proto3 { p.enc = (*Buffer).enc_proto3_slice_byte p.size = size_proto3_slice_byte } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/SPEC.md b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/SPEC.md index 430a31fe08..fad1dd72a2 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/SPEC.md +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/SPEC.md @@ -97,12 +97,12 @@ that is local to the container's rootfs. After the container has `/proc` mounted a few standard symlinks are setup within `/dev/` for the io. -| Source | Destination | -| ------------ | ----------- | -| /proc/1/fd | /dev/fd | -| /proc/1/fd/0 | /dev/stdin | -| /proc/1/fd/1 | /dev/stdout | -| /proc/1/fd/2 | /dev/stderr | +| Source | Destination | +| --------------- | ----------- | +| /proc/self/fd | /dev/fd | +| /proc/self/fd/0 | /dev/stdin | +| /proc/self/fd/1 | /dev/stdout | +| /proc/self/fd/2 | /dev/stderr | A `pivot_root` is used to change the root for the process, effectively jailing the process inside the rootfs. diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go index a0a93a4aac..68ebcfefbf 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go @@ -3,6 +3,7 @@ package fs import ( + "errors" "fmt" "io" "io/ioutil" @@ -16,30 +17,45 @@ import ( ) var ( - subsystems = map[string]subsystem{ - "devices": &DevicesGroup{}, - "memory": &MemoryGroup{}, - "cpu": &CpuGroup{}, - "cpuset": &CpusetGroup{}, - "cpuacct": &CpuacctGroup{}, - "blkio": &BlkioGroup{}, - "hugetlb": &HugetlbGroup{}, - "net_cls": &NetClsGroup{}, - "net_prio": &NetPrioGroup{}, - "perf_event": &PerfEventGroup{}, - "freezer": &FreezerGroup{}, + subsystems = subsystemSet{ + &CpusetGroup{}, + &DevicesGroup{}, + &MemoryGroup{}, + &CpuGroup{}, + &CpuacctGroup{}, + &BlkioGroup{}, + &HugetlbGroup{}, + &NetClsGroup{}, + &NetPrioGroup{}, + &PerfEventGroup{}, + &FreezerGroup{}, } CgroupProcesses = "cgroup.procs" HugePageSizes, _ = cgroups.GetHugePageSize() ) +var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist") + +type subsystemSet []subsystem + +func (s subsystemSet) Get(name string) (subsystem, error) { + for _, ss := range s { + if ss.Name() == name { + return ss, nil + } + } + return nil, errSubsystemDoesNotExist +} + type subsystem interface { + // Name returns the name of the subsystem. + Name() string // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. GetStats(path string, stats *cgroups.Stats) error - // Removes the cgroup represented by 'data'. - Remove(*data) error - // Creates and joins the cgroup represented by data. - Apply(*data) error + // Removes the cgroup represented by 'cgroupData'. + Remove(*cgroupData) error + // Creates and joins the cgroup represented by 'cgroupData'. + Apply(*cgroupData) error // Set the cgroup represented by cgroup. Set(path string, cgroup *configs.Cgroup) error } @@ -76,10 +92,11 @@ func getCgroupRoot() (string, error) { return cgroupRoot, nil } -type data struct { +type cgroupData struct { root string - cgroup string - c *configs.Cgroup + parent string + name string + config *configs.Cgroup pid int } @@ -101,21 +118,21 @@ func (m *Manager) Apply(pid int) (err error) { cgroups.RemovePaths(paths) } }() - for name, sys := range subsystems { + for _, sys := range subsystems { if err := sys.Apply(d); err != nil { return err } // TODO: Apply should, ideally, be reentrant or be broken up into a separate // create and join phase so that the cgroup hierarchy for a container can be // created then join consists of writing the process pids to cgroup.procs - p, err := d.path(name) + p, err := d.path(sys.Name()) if err != nil { if cgroups.IsNotFound(err) { continue } return err } - paths[name] = p + paths[sys.Name()] = p } m.Paths = paths @@ -150,29 +167,27 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { - sys, ok := subsystems[name] - if !ok || !cgroups.PathExists(path) { + sys, err := subsystems.Get(name) + if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } if err := sys.GetStats(path, stats); err != nil { return nil, err } } - return stats, nil } func (m *Manager) Set(container *configs.Config) error { for name, path := range m.Paths { - sys, ok := subsystems[name] - if !ok || !cgroups.PathExists(path) { + sys, err := subsystems.Get(name) + if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } if err := sys.Set(path, container.Cgroups); err != nil { return err } } - return nil } @@ -183,22 +198,21 @@ func (m *Manager) Freeze(state configs.FreezerState) error { if err != nil { return err } - dir, err := d.path("freezer") if err != nil { return err } - prevState := m.Cgroups.Freezer m.Cgroups.Freezer = state - - freezer := subsystems["freezer"] + freezer, err := subsystems.Get("freezer") + if err != nil { + return err + } err = freezer.Set(dir, m.Cgroups) if err != nil { m.Cgroups.Freezer = prevState return err } - return nil } @@ -216,30 +230,31 @@ func (m *Manager) GetPids() ([]int, error) { return cgroups.GetPids(dir) } -func getCgroupData(c *configs.Cgroup, pid int) (*data, error) { +func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) { root, err := getCgroupRoot() if err != nil { return nil, err } - cgroup := c.Name - if c.Parent != "" { - cgroup = filepath.Join(c.Parent, cgroup) - } - - return &data{ + return &cgroupData{ root: root, - cgroup: cgroup, - c: c, + parent: c.Parent, + name: c.Name, + config: c, pid: pid, }, nil } -func (raw *data) parent(subsystem, mountpoint, root string) (string, error) { +func (raw *cgroupData) parentPath(subsystem, mountpoint, root string) (string, error) { + // Use GetThisCgroupDir instead of GetInitCgroupDir, because the creating + // process could in container and shared pid namespace with host, and + // /proc/1/cgroup could point to whole other world of cgroups. initPath, err := cgroups.GetThisCgroupDir(subsystem) if err != nil { return "", err } + // This is needed for nested containers, because in /proc/self/cgroup we + // see pathes from host, which don't exist in container. relDir, err := filepath.Rel(root, initPath) if err != nil { return "", err @@ -247,27 +262,29 @@ func (raw *data) parent(subsystem, mountpoint, root string) (string, error) { return filepath.Join(mountpoint, relDir), nil } -func (raw *data) path(subsystem string) (string, error) { +func (raw *cgroupData) path(subsystem string) (string, error) { mnt, root, err := cgroups.FindCgroupMountpointAndRoot(subsystem) // If we didn't mount the subsystem, there is no point we make the path. if err != nil { return "", err } + cgPath := filepath.Join(raw.parent, raw.name) // 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, filepath.Base(mnt), raw.cgroup), nil + if filepath.IsAbs(cgPath) { + // Sometimes subsystems can be mounted togethger as 'cpu,cpuacct'. + return filepath.Join(raw.root, filepath.Base(mnt), cgPath), nil } - parent, err := raw.parent(subsystem, mnt, root) + parentPath, err := raw.parentPath(subsystem, mnt, root) if err != nil { return "", err } - return filepath.Join(parent, raw.cgroup), nil + return filepath.Join(parentPath, cgPath), nil } -func (raw *data) join(subsystem string) (string, error) { +func (raw *cgroupData) join(subsystem string) (string, error) { path, err := raw.path(subsystem) if err != nil { return "", err diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go index db886bcf1d..eddba0bf8b 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go @@ -17,13 +17,17 @@ import ( type BlkioGroup struct { } -func (s *BlkioGroup) Apply(d *data) error { +func (s *BlkioGroup) Name() string { + return "blkio" +} + +func (s *BlkioGroup) Apply(d *cgroupData) error { dir, err := d.join("blkio") if err != nil && !cgroups.IsNotFound(err) { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -74,7 +78,7 @@ func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *BlkioGroup) Remove(d *data) error { +func (s *BlkioGroup) Remove(d *cgroupData) error { return removePath(d.path("blkio")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go index 5afd5b8d13..762a68fe80 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go @@ -15,7 +15,11 @@ import ( type CpuGroup struct { } -func (s *CpuGroup) Apply(d *data) error { +func (s *CpuGroup) Name() string { + return "cpu" +} + +func (s *CpuGroup) Apply(d *cgroupData) error { // We always want to join the cpu group, to allow fair cpu scheduling // on a container basis dir, err := d.join("cpu") @@ -23,7 +27,7 @@ func (s *CpuGroup) Apply(d *data) error { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -60,7 +64,7 @@ func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *CpuGroup) Remove(d *data) error { +func (s *CpuGroup) Remove(d *cgroupData) error { return removePath(d.path("cpu")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go index 4ff4fefea3..53afbaddf1 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go @@ -24,7 +24,11 @@ var clockTicks = uint64(system.GetClockTicks()) type CpuacctGroup struct { } -func (s *CpuacctGroup) Apply(d *data) error { +func (s *CpuacctGroup) Name() string { + return "cpuacct" +} + +func (s *CpuacctGroup) Apply(d *cgroupData) error { // we just want to join this group even though we don't set anything if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) { return err @@ -37,7 +41,7 @@ func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *CpuacctGroup) Remove(d *data) error { +func (s *CpuacctGroup) Remove(d *cgroupData) error { return removePath(d.path("cpuacct")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go index f3ec2c3e79..088a665b97 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go @@ -16,12 +16,16 @@ import ( type CpusetGroup struct { } -func (s *CpusetGroup) Apply(d *data) error { +func (s *CpusetGroup) Name() string { + return "cpuset" +} + +func (s *CpusetGroup) Apply(d *cgroupData) error { dir, err := d.path("cpuset") if err != nil && !cgroups.IsNotFound(err) { return err } - return s.ApplyDir(dir, d.c, d.pid) + return s.ApplyDir(dir, d.config, d.pid) } func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error { @@ -38,7 +42,7 @@ func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *CpusetGroup) Remove(d *data) error { +func (s *CpusetGroup) Remove(d *cgroupData) error { return removePath(d.path("cpuset")) } @@ -59,17 +63,16 @@ func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) erro if err := s.ensureParent(dir, root); err != nil { return err } - // because we are not using d.join we need to place the pid into the procs file - // unlike the other subsystems - if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil { - return err - } - // the default values inherit from parent cgroup are already set in // s.ensureParent, cover these if we have our own if err := s.Set(dir, cgroup); err != nil { return err } + // because we are not using d.join we need to place the pid into the procs file + // unlike the other subsystems + if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil { + return err + } return nil } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go index d621d275c0..1e39618a46 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go @@ -10,7 +10,11 @@ import ( type DevicesGroup struct { } -func (s *DevicesGroup) Apply(d *data) error { +func (s *DevicesGroup) Name() string { + return "devices" +} + +func (s *DevicesGroup) Apply(d *cgroupData) error { dir, err := d.join("devices") if err != nil { // We will return error even it's `not found` error, devices @@ -18,7 +22,7 @@ func (s *DevicesGroup) Apply(d *data) error { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -52,7 +56,7 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *DevicesGroup) Remove(d *data) error { +func (s *DevicesGroup) Remove(d *cgroupData) error { return removePath(d.path("devices")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go index 47f7439549..8960ec789c 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go @@ -14,13 +14,17 @@ import ( type FreezerGroup struct { } -func (s *FreezerGroup) Apply(d *data) error { +func (s *FreezerGroup) Name() string { + return "freezer" +} + +func (s *FreezerGroup) Apply(d *cgroupData) error { dir, err := d.join("freezer") if err != nil && !cgroups.IsNotFound(err) { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -53,7 +57,7 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *FreezerGroup) Remove(d *data) error { +func (s *FreezerGroup) Remove(d *cgroupData) error { return removePath(d.path("freezer")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go index a7d3a8700d..b11365370f 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go @@ -14,13 +14,17 @@ import ( type HugetlbGroup struct { } -func (s *HugetlbGroup) Apply(d *data) error { +func (s *HugetlbGroup) Name() string { + return "hugetlb" +} + +func (s *HugetlbGroup) Apply(d *cgroupData) error { dir, err := d.join("hugetlb") if err != nil && !cgroups.IsNotFound(err) { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -37,7 +41,7 @@ func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *HugetlbGroup) Remove(d *data) error { +func (s *HugetlbGroup) Remove(d *cgroupData) error { return removePath(d.path("hugetlb")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go index 23c68f8372..e5ffde4b6d 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go @@ -17,16 +17,25 @@ import ( type MemoryGroup struct { } -func (s *MemoryGroup) Apply(d *data) (err error) { +func (s *MemoryGroup) Name() string { + return "memory" +} + +func (s *MemoryGroup) Apply(d *cgroupData) (err error) { path, err := d.path("memory") - if err != nil { - if cgroups.IsNotFound(err) { - return nil - } + if err != nil && !cgroups.IsNotFound(err) { return err } - if err := os.MkdirAll(path, 0755); err != nil { - return err + if memoryAssigned(d.config) { + if path != "" { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + } + + if err := s.Set(path, d.config); err != nil { + return err + } } defer func() { @@ -35,13 +44,10 @@ func (s *MemoryGroup) Apply(d *data) (err error) { } }() - if err := s.Set(path, d.c); err != nil { - return err - } - // We need to join memory cgroup after set memory limits, because // kmem.limit_in_bytes can only be set when the cgroup is empty. - if _, err = d.join("memory"); err != nil { + _, err = d.join("memory") + if err != nil && !cgroups.IsNotFound(err) { return err } @@ -88,7 +94,7 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *MemoryGroup) Remove(d *data) error { +func (s *MemoryGroup) Remove(d *cgroupData) error { return removePath(d.path("memory")) } @@ -132,6 +138,15 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { return nil } +func memoryAssigned(cgroup *configs.Cgroup) bool { + return cgroup.Memory != 0 || + cgroup.MemoryReservation != 0 || + cgroup.MemorySwap > 0 || + cgroup.KernelMemory > 0 || + cgroup.OomKillDisable || + cgroup.MemorySwappiness != -1 +} + func getMemoryData(path, name string) (cgroups.MemoryData, error) { memoryData := cgroups.MemoryData{} diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go index 99913802cf..0e423f667d 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go @@ -1,3 +1,5 @@ +// +build linux + package fs import ( @@ -6,9 +8,14 @@ import ( ) type NameGroup struct { + GroupName string } -func (s *NameGroup) Apply(d *data) error { +func (s *NameGroup) Name() string { + return s.GroupName +} + +func (s *NameGroup) Apply(d *cgroupData) error { return nil } @@ -16,7 +23,7 @@ func (s *NameGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *NameGroup) Remove(d *data) error { +func (s *NameGroup) Remove(d *cgroupData) error { return nil } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go index 23335dd7b8..b09a1760e4 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go @@ -1,3 +1,5 @@ +// +build linux + package fs import ( @@ -8,13 +10,17 @@ import ( type NetClsGroup struct { } -func (s *NetClsGroup) Apply(d *data) error { +func (s *NetClsGroup) Name() string { + return "net_cls" +} + +func (s *NetClsGroup) Apply(d *cgroupData) error { dir, err := d.join("net_cls") if err != nil && !cgroups.IsNotFound(err) { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -31,7 +37,7 @@ func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *NetClsGroup) Remove(d *data) error { +func (s *NetClsGroup) Remove(d *cgroupData) error { return removePath(d.path("net_cls")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go index 88f2ea8baa..59117cad91 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go @@ -1,3 +1,5 @@ +// +build linux + package fs import ( @@ -8,13 +10,17 @@ import ( type NetPrioGroup struct { } -func (s *NetPrioGroup) Apply(d *data) error { +func (s *NetPrioGroup) Name() string { + return "net_prio" +} + +func (s *NetPrioGroup) Apply(d *cgroupData) error { dir, err := d.join("net_prio") if err != nil && !cgroups.IsNotFound(err) { return err } - if err := s.Set(dir, d.c); err != nil { + if err := s.Set(dir, d.config); err != nil { return err } @@ -31,7 +37,7 @@ func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *NetPrioGroup) Remove(d *data) error { +func (s *NetPrioGroup) Remove(d *cgroupData) error { return removePath(d.path("net_prio")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go index 30be9e5682..5693676d3a 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go @@ -10,7 +10,11 @@ import ( type PerfEventGroup struct { } -func (s *PerfEventGroup) Apply(d *data) error { +func (s *PerfEventGroup) Name() string { + return "perf_event" +} + +func (s *PerfEventGroup) Apply(d *cgroupData) error { // we just want to join this group even though we don't set anything if _, err := d.join("perf_event"); err != nil && !cgroups.IsNotFound(err) { return err @@ -22,7 +26,7 @@ func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error { return nil } -func (s *PerfEventGroup) Remove(d *data) error { +func (s *PerfEventGroup) Remove(d *cgroupData) error { return removePath(d.path("perf_event")) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go index 3a6eec79ff..852b18391d 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/fs/utils.go @@ -44,7 +44,7 @@ func getCgroupParamKeyValue(t string) (string, uint64, error) { case 2: value, err := parseUint(parts[1], 10, 64) if err != nil { - return "", 0, fmt.Errorf("Unable to convert param value (%q) to uint64: %v", parts[1], err) + return "", 0, fmt.Errorf("unable to convert param value (%q) to uint64: %v", parts[1], err) } return parts[0], value, nil @@ -55,12 +55,17 @@ func getCgroupParamKeyValue(t string) (string, uint64, error) { // Gets a single uint64 value from the specified cgroup file. func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) { - contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile)) + fileName := filepath.Join(cgroupPath, cgroupFile) + contents, err := ioutil.ReadFile(fileName) if err != nil { return 0, err } - return parseUint(strings.TrimSpace(string(contents)), 10, 64) + res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64) + if err != nil { + return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName) + } + return res, nil } // Gets a string value from the specified cgroup file diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go index d878be9cb9..7a422b3c79 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go @@ -3,6 +3,7 @@ package systemd import ( + "errors" "fmt" "io/ioutil" "os" @@ -27,25 +28,40 @@ type Manager struct { } type subsystem interface { + // Name returns the name of the subsystem. + Name() string // Returns the stats, as 'stats', corresponding to the cgroup under 'path'. GetStats(path string, stats *cgroups.Stats) error // Set the cgroup represented by cgroup. Set(path string, cgroup *configs.Cgroup) error } -var subsystems = map[string]subsystem{ - "devices": &fs.DevicesGroup{}, - "memory": &fs.MemoryGroup{}, - "cpu": &fs.CpuGroup{}, - "cpuset": &fs.CpusetGroup{}, - "cpuacct": &fs.CpuacctGroup{}, - "blkio": &fs.BlkioGroup{}, - "hugetlb": &fs.HugetlbGroup{}, - "perf_event": &fs.PerfEventGroup{}, - "freezer": &fs.FreezerGroup{}, - "net_prio": &fs.NetPrioGroup{}, - "net_cls": &fs.NetClsGroup{}, - "name=systemd": &fs.NameGroup{}, +var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist") + +type subsystemSet []subsystem + +func (s subsystemSet) Get(name string) (subsystem, error) { + for _, ss := range s { + if ss.Name() == name { + return ss, nil + } + } + return nil, errSubsystemDoesNotExist +} + +var subsystems = subsystemSet{ + &fs.CpusetGroup{}, + &fs.DevicesGroup{}, + &fs.MemoryGroup{}, + &fs.CpuGroup{}, + &fs.CpuacctGroup{}, + &fs.BlkioGroup{}, + &fs.HugetlbGroup{}, + &fs.PerfEventGroup{}, + &fs.FreezerGroup{}, + &fs.NetPrioGroup{}, + &fs.NetClsGroup{}, + &fs.NameGroup{GroupName: "name=systemd"}, } const ( @@ -249,8 +265,8 @@ func (m *Manager) Apply(pid int) error { } paths := make(map[string]string) - for sysname := range subsystems { - subsystemPath, err := getSubsystemPath(m.Cgroups, sysname) + for _, s := range subsystems { + subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) if err != nil { // Don't fail if a cgroup hierarchy was not found, just skip this subsystem if cgroups.IsNotFound(err) { @@ -258,7 +274,7 @@ func (m *Manager) Apply(pid int) error { } return err } - paths[sysname] = subsystemPath + paths[s.Name()] = subsystemPath } m.Paths = paths @@ -347,8 +363,10 @@ func joinFreezer(c *configs.Cgroup, pid int) error { if err != nil && !cgroups.IsNotFound(err) { return err } - - freezer := subsystems["freezer"] + freezer, err := subsystems.Get("freezer") + if err != nil { + return err + } return freezer.Set(path, c) } @@ -357,8 +375,10 @@ func joinNetPrio(c *configs.Cgroup, pid int) error { if err != nil && !cgroups.IsNotFound(err) { return err } - netPrio := subsystems["net_prio"] - + netPrio, err := subsystems.Get("net_prio") + if err != nil { + return err + } return netPrio.Set(path, c) } @@ -367,8 +387,10 @@ func joinNetCls(c *configs.Cgroup, pid int) error { if err != nil && !cgroups.IsNotFound(err) { return err } - netcls := subsystems["net_cls"] - + netcls, err := subsystems.Get("net_cls") + if err != nil { + return err + } return netcls.Set(path, c) } @@ -396,17 +418,17 @@ func (m *Manager) Freeze(state configs.FreezerState) error { if err != nil { return err } - prevState := m.Cgroups.Freezer m.Cgroups.Freezer = state - - freezer := subsystems["freezer"] + freezer, err := subsystems.Get("freezer") + if err != nil { + return err + } err = freezer.Set(path, m.Cgroups) if err != nil { m.Cgroups.Freezer = prevState return err } - return nil } @@ -423,8 +445,8 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { defer m.mu.Unlock() stats := cgroups.NewStats() for name, path := range m.Paths { - sys, ok := subsystems[name] - if !ok || !cgroups.PathExists(path) { + sys, err := subsystems.Get(name) + if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } if err := sys.GetStats(path, stats); err != nil { @@ -437,8 +459,8 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { func (m *Manager) Set(container *configs.Config) error { for name, path := range m.Paths { - sys, ok := subsystems[name] - if !ok || !cgroups.PathExists(path) { + sys, err := subsystems.Get(name) + if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { continue } if err := sys.Set(path, container.Cgroups); err != nil { @@ -471,8 +493,10 @@ func joinDevices(c *configs.Cgroup, pid int) error { if err != nil { return err } - - devices := subsystems["devices"] + devices, err := subsystems.Get("devices") + if err != nil { + return err + } return devices.Set(path, c) } @@ -600,8 +624,10 @@ func joinHugetlb(c *configs.Cgroup, pid int) error { if err != nil && !cgroups.IsNotFound(err) { return err } - - hugetlb := subsystems["hugetlb"] + hugetlb, err := subsystems.Get("hugetlb") + if err != nil { + return err + } return hugetlb.Set(path, c) } @@ -610,7 +636,9 @@ func joinPerfEvent(c *configs.Cgroup, pid int) error { if err != nil && !cgroups.IsNotFound(err) { return err } - - perfEvent := subsystems["perf_event"] + perfEvent, err := subsystems.Get("perf_event") + if err != nil { + return err + } return perfEvent.Set(path, c) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go similarity index 96% rename from components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup.go rename to components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go index bad86b036a..24f93c1ad6 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_unix.go @@ -1,3 +1,5 @@ +// +build linux freebsd + package configs type FreezerState string @@ -8,9 +10,6 @@ const ( Thawed FreezerState = "THAWED" ) -// TODO Windows: This can be factored out in the future as Cgroups are not -// supported on the Windows platform. - type Cgroup struct { Name string `json:"name"` diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go new file mode 100644 index 0000000000..d74847b0db --- /dev/null +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/cgroup_windows.go @@ -0,0 +1,6 @@ +package configs + +// TODO Windows: This can ultimately be entirely factored out on Windows as +// cgroups are a Unix-specific construct. +type Cgroup struct { +} diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go index 7fd311db42..069daae293 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/config.go @@ -33,17 +33,18 @@ type Seccomp struct { type Action int const ( - Kill Action = iota - 4 + Kill Action = iota + 1 Errno Trap Allow + Trace ) // A comparison operator to be used when matching syscall arguments in Seccomp type Operator int const ( - EqualTo Operator = iota + EqualTo Operator = iota + 1 NotEqualTo GreaterThan GreaterThanOrEqualTo @@ -183,6 +184,9 @@ type Hooks struct { // but before the user supplied command is executed from init. Prestart []Hook + // Poststart commands are executed after the container init process starts. + Poststart []Hook + // Poststop commands are executed after the container init process exits. Poststop []Hook } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_windows.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go similarity index 86% rename from components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_windows.go rename to components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go index f8fe47a86d..9a74033cea 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_windows.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go @@ -1,3 +1,5 @@ +// +build !linux,!freebsd + package configs // Namespace defines configuration for each namespace. It specifies an diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container.go index a24b71b845..6292fd1852 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container.go @@ -30,8 +30,9 @@ const ( Destroyed ) -// State represents a running container's state -type State struct { +// BaseState represents the platform agnostic pieces relating to a +// running container's state +type BaseState struct { // ID is the container ID. ID string `json:"id"` @@ -41,27 +42,16 @@ type State struct { // InitProcessStartTime is the init process start time. InitProcessStartTime string `json:"init_process_start"` - // Path to all the cgroups setup for a container. Key is cgroup subsystem name - // with the value as the path. - CgroupPaths map[string]string `json:"cgroup_paths"` - - // NamespacePaths are filepaths to the container's namespaces. Key is the namespace type - // with the value as the path. - NamespacePaths map[configs.NamespaceType]string `json:"namespace_paths"` - // Config is the container's configuration. Config configs.Config `json:"config"` - - // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore - ExternalDescriptors []string `json:"external_descriptors,omitempty"` } // A libcontainer container object. // // Each container is thread-safe within the same process. Since a container can // be destroyed by a separate process, any function may return that the container -// was not found. -type Container interface { +// was not found. BaseContainer includes methods that are platform agnostic. +type BaseContainer interface { // Returns the ID of the container ID() string @@ -98,7 +88,7 @@ type Container interface { // Systemerror - System error. Stats() (*Stats, error) - // Set cgroup resources of container as configured + // Set resources of container as configured // // We can use this to change resources when containers are running. // @@ -116,18 +106,6 @@ type Container interface { // Systemerror - System error. Start(process *Process) (err error) - // Checkpoint checkpoints the running container's state to disk using the criu(8) utility. - // - // errors: - // Systemerror - System error. - Checkpoint(criuOpts *CriuOpts) error - - // Restore restores the checkpointed container to a running state using the criu(8) utiity. - // - // errors: - // Systemerror - System error. - Restore(process *Process, criuOpts *CriuOpts) error - // Destroys the container after killing all running processes. // // Any event registrations are removed before the container is destroyed. @@ -137,31 +115,6 @@ type Container interface { // Systemerror - System error. Destroy() error - // If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses - // the execution of any user processes. Asynchronously, when the container finished being paused the - // state is changed to PAUSED. - // If the Container state is PAUSED, do nothing. - // - // errors: - // ContainerDestroyed - Container no longer exists, - // Systemerror - System error. - Pause() error - - // If the Container state is PAUSED, resumes the execution of any user processes in the - // Container before setting the Container state to RUNNING. - // If the Container state is RUNNING, do nothing. - // - // errors: - // ContainerDestroyed - Container no longer exists, - // Systemerror - System error. - Resume() error - - // NotifyOOM returns a read-only channel signaling when the container receives an OOM notification. - // - // errors: - // Systemerror - System error. - NotifyOOM() (<-chan struct{}, error) - // Signal sends the provided signal code to the container's initial process. // // errors: diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go index 19c4701e61..912673a34b 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "strings" "sync" "syscall" @@ -32,6 +33,73 @@ type linuxContainer struct { initProcess parentProcess criuPath string m sync.Mutex + criuVersion int +} + +// State represents a running container's state +type State struct { + BaseState + + // Platform specific fields below here + + // Path to all the cgroups setup for a container. Key is cgroup subsystem name + // with the value as the path. + CgroupPaths map[string]string `json:"cgroup_paths"` + + // NamespacePaths are filepaths to the container's namespaces. Key is the namespace type + // with the value as the path. + NamespacePaths map[configs.NamespaceType]string `json:"namespace_paths"` + + // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore + ExternalDescriptors []string `json:"external_descriptors,omitempty"` +} + +// A libcontainer container object. +// +// Each container is thread-safe within the same process. Since a container can +// be destroyed by a separate process, any function may return that the container +// was not found. +type Container interface { + BaseContainer + + // Methods below here are platform specific + + // Checkpoint checkpoints the running container's state to disk using the criu(8) utility. + // + // errors: + // Systemerror - System error. + Checkpoint(criuOpts *CriuOpts) error + + // Restore restores the checkpointed container to a running state using the criu(8) utiity. + // + // errors: + // Systemerror - System error. + Restore(process *Process, criuOpts *CriuOpts) error + + // If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses + // the execution of any user processes. Asynchronously, when the container finished being paused the + // state is changed to PAUSED. + // If the Container state is PAUSED, do nothing. + // + // errors: + // ContainerDestroyed - Container no longer exists, + // Systemerror - System error. + Pause() error + + // If the Container state is PAUSED, resumes the execution of any user processes in the + // Container before setting the Container state to RUNNING. + // If the Container state is RUNNING, do nothing. + // + // errors: + // ContainerDestroyed - Container no longer exists, + // Systemerror - System error. + Resume() error + + // NotifyOOM returns a read-only channel signaling when the container receives an OOM notification. + // + // errors: + // Systemerror - System error. + NotifyOOM() (<-chan struct{}, error) } // ID returns the container's unique ID @@ -111,10 +179,25 @@ func (c *linuxContainer) Start(process *Process) error { } return newSystemError(err) } - process.ops = parent if doInit { c.updateState(parent) } + if c.config.Hooks != nil { + s := configs.HookState{ + Version: c.config.Version, + ID: c.id, + Pid: parent.pid(), + Root: c.config.Rootfs, + } + for _, hook := range c.config.Hooks.Poststart { + if err := hook.Run(s); err != nil { + if err := parent.terminate(); err != nil { + logrus.Warn(err) + } + return newSystemError(err) + } + } + } return nil } @@ -186,6 +269,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c manager: c.cgroupManager, config: c.newInitConfig(p), container: c, + process: p, }, nil } @@ -204,6 +288,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe: childPipe, parentPipe: parentPipe, config: c.newInitConfig(p), + process: p, } } @@ -337,7 +422,9 @@ func (c *linuxContainer) checkCriuVersion(min_version string) error { } } - if x*10000+y*100+z < versionReq { + c.criuVersion = x*10000 + y*100 + z + + if c.criuVersion < versionReq { return fmt.Errorf("CRIU version must be %s or higher", min_version) } @@ -665,6 +752,8 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * defer criuServer.Close() args := []string{"swrk", "3"} + logrus.Debugf("Using CRIU %d at: %s", c.criuVersion, c.criuPath) + logrus.Debugf("Using CRIU with following args: %s", args) cmd := exec.Command(c.criuPath, args...) if process != nil { cmd.Stdin = process.Stdin @@ -701,6 +790,18 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * } } + logrus.Debugf("Using CRIU in %s mode", req.GetType().String()) + val := reflect.ValueOf(req.GetOpts()) + v := reflect.Indirect(val) + for i := 0; i < v.NumField(); i++ { + st := v.Type() + name := st.Field(i).Name + if strings.HasPrefix(name, "XXX_") { + continue + } + value := val.MethodByName("Get" + name).Call([]reflect.Value{}) + logrus.Debugf("CRIU option %s with value %v", name, value[0]) + } data, err := proto.Marshal(req) if err != nil { return err @@ -899,13 +1000,15 @@ func (c *linuxContainer) currentState() (*State, error) { return nil, newSystemError(err) } state := &State{ - ID: c.ID(), - Config: *c.config, - InitProcessPid: c.initProcess.pid(), - InitProcessStartTime: startTime, - CgroupPaths: c.cgroupManager.GetPaths(), - NamespacePaths: make(map[configs.NamespaceType]string), - ExternalDescriptors: c.initProcess.externalDescriptors(), + BaseState: BaseState{ + ID: c.ID(), + Config: *c.config, + InitProcessPid: c.initProcess.pid(), + InitProcessStartTime: startTime, + }, + CgroupPaths: c.cgroupManager.GetPaths(), + NamespacePaths: make(map[configs.NamespaceType]string), + ExternalDescriptors: c.initProcess.externalDescriptors(), } for _, ns := range c.config.Namespaces { state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid()) diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_windows.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_windows.go new file mode 100644 index 0000000000..bb84ff7402 --- /dev/null +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/container_windows.go @@ -0,0 +1,20 @@ +package libcontainer + +// State represents a running container's state +type State struct { + BaseState + + // Platform specific fields below here +} + +// A libcontainer container object. +// +// Each container is thread-safe within the same process. Since a container can +// be destroyed by a separate process, any function may return that the container +// was not found. +type Container interface { + BaseContainer + + // Methods below here are platform specific + +} diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go similarity index 98% rename from components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts.go rename to components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go index 6d6062a8cd..a2a816bd95 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_unix.go @@ -1,3 +1,5 @@ +// +build linux freebsd + package libcontainer // cgroup restoring strategy provided by criu diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go new file mode 100644 index 0000000000..bc9207703a --- /dev/null +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/criu_opts_windows.go @@ -0,0 +1,6 @@ +package libcontainer + +// TODO Windows: This can ultimately be entirely factored out as criu is +// a Unix concept not relevant on Windows. +type CriuOpts struct { +} diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go new file mode 100644 index 0000000000..1e84033daf --- /dev/null +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go @@ -0,0 +1,3 @@ +// +build windows + +package devices diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_windows.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_windows.go deleted file mode 100644 index b2a9aa34af..0000000000 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/devices/devices_windows.go +++ /dev/null @@ -1,16 +0,0 @@ -package devices - -import ( - "github.com/opencontainers/runc/libcontainer/configs" -) - -// TODO Windows. This can be factored out further - Devices are not supported -// by Windows Containers. - -func DeviceFromPath(path, permissions string) (*configs.Device, error) { - return nil, nil -} - -func HostDevices() ([]*configs.Device, error) { - return nil, nil -} diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go index 0f7ba67824..70513f7b67 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -159,7 +159,7 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err } containerRoot := filepath.Join(l.Root, id) if _, err := os.Stat(containerRoot); err == nil { - return nil, newGenericError(fmt.Errorf("Container with id exists: %v", id), IdInUse) + return nil, newGenericError(fmt.Errorf("container with id exists: %v", id), IdInUse) } else if !os.IsNotExist(err) { return nil, newGenericError(err, SystemError) } @@ -210,9 +210,10 @@ func (l *LinuxFactory) Type() string { // StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state // This is a low level implementation detail of the reexec and should not be consumed externally func (l *LinuxFactory) StartInitialization() (err error) { - pipefd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_INITPIPE")) + fdStr := os.Getenv("_LIBCONTAINER_INITPIPE") + pipefd, err := strconv.Atoi(fdStr) if err != nil { - return err + return fmt.Errorf("error converting env var _LIBCONTAINER_INITPIPE(%q) to an int: %s", fdStr, err) } var ( pipe = os.NewFile(uintptr(pipefd), "pipe") @@ -260,10 +261,10 @@ func (l *LinuxFactory) loadState(root string) (*State, error) { func (l *LinuxFactory) validateID(id string) error { if !idRegex.MatchString(id) { - return newGenericError(fmt.Errorf("Invalid id format: %v", id), InvalidIdFormat) + return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) } if len(id) > maxIdLen { - return newGenericError(fmt.Errorf("Invalid id format: %v", id), InvalidIdFormat) + return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) } return nil } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go index 01021f759b..4d17cbc576 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -47,6 +47,7 @@ type setnsProcess struct { cgroupPaths map[string]string config *initConfig fds []string + process *Process } func (p *setnsProcess) startTime() (string, error) { @@ -87,7 +88,6 @@ func (p *setnsProcess) start() (err error) { p.wait() return newSystemError(ierr) } - return nil } @@ -115,13 +115,12 @@ func (p *setnsProcess) execSetns() error { p.cmd.Wait() return newSystemError(err) } - process, err := os.FindProcess(pid.Pid) if err != nil { return err } - p.cmd.Process = process + p.process.ops = p return nil } @@ -165,6 +164,7 @@ type initProcess struct { manager cgroups.Manager container *linuxContainer fds []string + process *Process } func (p *initProcess) pid() int { @@ -178,8 +178,10 @@ func (p *initProcess) externalDescriptors() []string { func (p *initProcess) start() (err error) { defer p.parentPipe.Close() err = p.cmd.Start() + p.process.ops = p p.childPipe.Close() if err != nil { + p.process.ops = nil return newSystemError(err) } // Save the standard descriptor names before the container process diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go index 65c404f140..5a2fad8818 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -29,7 +29,7 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { return newSystemError(err) } - setupDev := len(config.Devices) == 0 + setupDev := len(config.Devices) != 0 for _, m := range config.Mounts { for _, precmd := range m.PremountCmds { if err := mountCmd(precmd); err != nil { @@ -46,7 +46,7 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { } } } - if !setupDev { + if setupDev { if err := createDevices(config); err != nil { return newSystemError(err) } @@ -68,7 +68,7 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { if err != nil { return newSystemError(err) } - if !setupDev { + if setupDev { if err := reOpenDevNull(); err != nil { return newSystemError(err) } @@ -290,8 +290,7 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { return binds, nil } -// checkMountDestination checks to ensure that the mount destination is not over the -// top of /proc or /sys. +// checkMountDestination checks to ensure that the mount destination is not over the top of /proc. // dest is required to be an abs path and have any symlinks resolved before calling this function. func checkMountDestination(rootfs, dest string) error { if filepath.Clean(rootfs) == filepath.Clean(dest) { @@ -379,6 +378,17 @@ func createDevices(config *configs.Config) error { return nil } +func bindMountDeviceNode(dest string, node *configs.Device) error { + f, err := os.Create(dest) + if err != nil && !os.IsExist(err) { + return err + } + if f != nil { + f.Close() + } + return syscall.Mount(node.Path, dest, "bind", syscall.MS_BIND, "") +} + // Creates the device node in the rootfs of the container. func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { dest := filepath.Join(rootfs, node.Path) @@ -387,18 +397,13 @@ func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { } if bind { - f, err := os.Create(dest) - if err != nil && !os.IsExist(err) { - return err - } - if f != nil { - f.Close() - } - return syscall.Mount(node.Path, dest, "bind", syscall.MS_BIND, "") + return bindMountDeviceNode(dest, node) } if err := mknodDevice(dest, node); err != nil { if os.IsExist(err) { return nil + } else if os.IsPermission(err) { + return bindMountDeviceNode(dest, node) } return err } @@ -634,7 +639,6 @@ func remount(m *configs.Mount, rootfs string) error { if !strings.HasPrefix(dest, rootfs) { dest = filepath.Join(rootfs, dest) } - if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil { return err } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/config.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/config.go index 8bac3357b2..3b9a7595f2 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/config.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/config.go @@ -6,29 +6,47 @@ import ( "github.com/opencontainers/runc/libcontainer/configs" ) +var operators = map[string]configs.Operator{ + "SCMP_CMP_NE": configs.NotEqualTo, + "SCMP_CMP_LT": configs.LessThan, + "SCMP_CMP_LE": configs.LessThanOrEqualTo, + "SCMP_CMP_EQ": configs.EqualTo, + "SCMP_CMP_GE": configs.GreaterThanOrEqualTo, + "SCMP_CMP_GT": configs.GreaterThan, + "SCMP_CMP_MASKED_EQ": configs.MaskEqualTo, +} + +var actions = map[string]configs.Action{ + "SCMP_ACT_KILL": configs.Kill, + "SCMP_ACT_ERRNO": configs.Errno, + "SCMP_ACT_TRAP": configs.Trap, + "SCMP_ACT_ALLOW": configs.Allow, + "SCMP_ACT_TRACE": configs.Trace, +} + +var archs = map[string]string{ + "SCMP_ARCH_X86": "x86", + "SCMP_ARCH_X86_64": "amd64", + "SCMP_ARCH_X32": "x32", + "SCMP_ARCH_ARM": "arm", + "SCMP_ARCH_AARCH64": "arm64", + "SCMP_ARCH_MIPS": "mips", + "SCMP_ARCH_MIPS64": "mips64", + "SCMP_ARCH_MIPS64N32": "mips64n32", + "SCMP_ARCH_MIPSEL": "mipsel", + "SCMP_ARCH_MIPSEL64": "mipsel64", + "SCMP_ARCH_MIPSEL64N32": "mipsel64n32", +} + // ConvertStringToOperator converts a string into a Seccomp comparison operator. // Comparison operators use the names they are assigned by Libseccomp's header. // Attempting to convert a string that is not a valid operator results in an // error. func ConvertStringToOperator(in string) (configs.Operator, error) { - switch in { - case "SCMP_CMP_NE": - return configs.NotEqualTo, nil - case "SCMP_CMP_LT": - return configs.LessThan, nil - case "SCMP_CMP_LE": - return configs.LessThanOrEqualTo, nil - case "SCMP_CMP_EQ": - return configs.EqualTo, nil - case "SCMP_CMP_GE": - return configs.GreaterThan, nil - case "SCMP_CMP_GT": - return configs.GreaterThanOrEqualTo, nil - case "SCMP_CMP_MASKED_EQ": - return configs.MaskEqualTo, nil - default: - return 0, fmt.Errorf("string %s is not a valid operator for seccomp", in) + if op, ok := operators[in]; ok == true { + return op, nil } + return 0, fmt.Errorf("string %s is not a valid operator for seccomp", in) } // ConvertStringToAction converts a string into a Seccomp rule match action. @@ -38,16 +56,16 @@ func ConvertStringToOperator(in string) (configs.Operator, error) { // Attempting to convert a string that is not a valid action results in an // error. func ConvertStringToAction(in string) (configs.Action, error) { - switch in { - case "SCMP_ACT_KILL": - return configs.Kill, nil - case "SCMP_ACT_ERRNO": - return configs.Errno, nil - case "SCMP_ACT_TRAP": - return configs.Trap, nil - case "SCMP_ACT_ALLOW": - return configs.Allow, nil - default: - return 0, fmt.Errorf("string %s is not a valid action for seccomp", in) + if act, ok := actions[in]; ok == true { + return act, nil } + return 0, fmt.Errorf("string %s is not a valid action for seccomp", in) +} + +// ConvertStringToArch converts a string into a Seccomp comparison arch. +func ConvertStringToArch(in string) (string, error) { + if arch, ok := archs[in]; ok == true { + return arch, nil + } + return "", fmt.Errorf("string %s is not a valid arch for seccomp", in) } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go index 1e9ccf8f2d..aff1b63a53 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go @@ -15,6 +15,7 @@ var ( actAllow = libseccomp.ActAllow actTrap = libseccomp.ActTrap actKill = libseccomp.ActKill + actTrace = libseccomp.ActTrace.SetReturnCode(int16(syscall.EPERM)) actErrno = libseccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)) ) @@ -83,6 +84,8 @@ func getAction(act configs.Action) (libseccomp.ScmpAction, error) { return actTrap, nil case configs.Allow: return actAllow, nil + case configs.Trace: + return actTrace, nil default: return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule") } diff --git a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go index 266836f55f..86cf1d65e7 100644 --- a/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/components/engine/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -36,7 +36,7 @@ func ResolveRootfs(uncleanRootfs string) (string, error) { } // ExitStatus returns the correct exit status for a process based on if it -// was signaled or existed cleanly. +// was signaled or exited cleanly. func ExitStatus(status syscall.WaitStatus) int { if status.Signaled() { return exitSignalOffset + int(status.Signal()) diff --git a/components/engine/vendor/src/github.com/syndtr/gocapability/capability/syscall_linux.go b/components/engine/vendor/src/github.com/syndtr/gocapability/capability/syscall_linux.go index c18e6f6918..dd6f454065 100644 --- a/components/engine/vendor/src/github.com/syndtr/gocapability/capability/syscall_linux.go +++ b/components/engine/vendor/src/github.com/syndtr/gocapability/capability/syscall_linux.go @@ -86,6 +86,10 @@ func getVfsCap(path string, dest *vfscapData) (err error) { } r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) if e1 != 0 { + if e1 == syscall.ENODATA { + dest.version = 2 + return + } err = e1 } switch dest.magic & vfsCapVerMask { @@ -128,8 +132,6 @@ func setVfsCap(path string, data *vfscapData) (err error) { data.magic = vfsCapVer2 if data.effective[0] != 0 || data.effective[1] != 0 { data.magic |= vfsCapFlageffective - data.data[0].permitted |= data.effective[0] - data.data[1].permitted |= data.effective[1] } size = vfscapDataSizeV2 } else {