mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #8988 from crosbymichael/update-libcontainer-nov1
Update libcontainer to fd6df76562137aa3b18e44b790c
This commit is contained in:
commit
68a25a5b74
35 changed files with 477 additions and 363 deletions
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -48,12 +47,7 @@ func initializer() {
|
|||
writeError(err)
|
||||
}
|
||||
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(*pipe))
|
||||
if err != nil {
|
||||
writeError(err)
|
||||
}
|
||||
|
||||
if err := namespaces.Init(container, rootfs, *console, syncPipe, flag.Args()); err != nil {
|
||||
if err := namespaces.Init(container, rootfs, *console, os.NewFile(uintptr(*pipe), "child"), flag.Args()); err != nil {
|
||||
writeError(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
func findUserArgs() []string {
|
||||
|
@ -21,15 +21,9 @@ func findUserArgs() []string {
|
|||
// loadConfigFromFd loads a container's config from the sync pipe that is provided by
|
||||
// fd 3 when running a process
|
||||
func loadConfigFromFd() (*libcontainer.Config, error) {
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config *libcontainer.Config
|
||||
if err := syncPipe.ReadFromParent(&config); err != nil {
|
||||
if err := json.NewDecoder(os.NewFile(3, "child")).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ if [ "$1" = '--go' ]; then
|
|||
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
||||
fi
|
||||
|
||||
clone git github.com/docker/libcontainer f60d7b9195f8dc0b5d343abbc3293da7c17bb11c
|
||||
clone git github.com/docker/libcontainer fd6df76562137aa3b18e44b790cb484fe2b6fa0b
|
||||
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
|
||||
rm -rf src/github.com/docker/libcontainer/vendor
|
||||
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
|
||||
|
|
88
vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go
vendored
Normal file
88
vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// smallFields is a small size data set for benchmarking
|
||||
var smallFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
}
|
||||
|
||||
// largeFields is a large size data set for benchmarking
|
||||
var largeFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
"five": "six",
|
||||
"seven": "eight",
|
||||
"nine": "ten",
|
||||
"eleven": "twelve",
|
||||
"thirteen": "fourteen",
|
||||
"fifteen": "sixteen",
|
||||
"seventeen": "eighteen",
|
||||
"nineteen": "twenty",
|
||||
"a": "b",
|
||||
"c": "d",
|
||||
"e": "f",
|
||||
"g": "h",
|
||||
"i": "j",
|
||||
"k": "l",
|
||||
"m": "n",
|
||||
"o": "p",
|
||||
"q": "r",
|
||||
"s": "t",
|
||||
"u": "v",
|
||||
"w": "x",
|
||||
"y": "z",
|
||||
"this": "will",
|
||||
"make": "thirty",
|
||||
"entries": "yeah",
|
||||
}
|
||||
|
||||
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||
}
|
||||
|
||||
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||
entry := &Entry{
|
||||
Time: time.Time{},
|
||||
Level: InfoLevel,
|
||||
Message: "message",
|
||||
Data: fields,
|
||||
}
|
||||
var d []byte
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
d, err = formatter.Format(entry)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(d)))
|
||||
}
|
||||
}
|
28
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
vendored
Normal file
28
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||
|
||||
[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
|
||||
|
||||
In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
|
||||
|
||||
## Usage
|
||||
|
||||
You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
|
||||
|
||||
For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/papertrail"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
54
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
vendored
Normal file
54
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
format = "Jan 2 15:04:05"
|
||||
)
|
||||
|
||||
// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
|
||||
type PapertrailHook struct {
|
||||
Host string
|
||||
Port int
|
||||
AppName string
|
||||
UDPConn net.Conn
|
||||
}
|
||||
|
||||
// NewPapertrailHook creates a hook to be added to an instance of logger.
|
||||
func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
|
||||
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
|
||||
return &PapertrailHook{host, port, appName, conn}, err
|
||||
}
|
||||
|
||||
// Fire is called when a log event is fired.
|
||||
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||
date := time.Now().Format(format)
|
||||
payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Data["level"], entry.Message)
|
||||
|
||||
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Levels returns the available logging levels.
|
||||
func (hook *PapertrailHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
26
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
vendored
Normal file
26
vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/stvp/go-udp-testing"
|
||||
)
|
||||
|
||||
func TestWritingToUDP(t *testing.T) {
|
||||
port := 16661
|
||||
udp.SetAddr(fmt.Sprintf(":%d", port))
|
||||
|
||||
hook, err := NewPapertrailHook("localhost", port, "test")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local UDP server.")
|
||||
}
|
||||
|
||||
log := logrus.New()
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
udp.ShouldReceive(t, "foo", func() {
|
||||
log.Info("foo")
|
||||
})
|
||||
}
|
9
vendor/src/github.com/docker/libcontainer/.drone.yml
vendored
Executable file
9
vendor/src/github.com/docker/libcontainer/.drone.yml
vendored
Executable file
|
@ -0,0 +1,9 @@
|
|||
image: dockercore/libcontainer
|
||||
script:
|
||||
# Setup the DockerInDocker environment.
|
||||
- /dind
|
||||
- sed -i 's!docker/docker!docker/libcontainer!' /go/src/github.com/docker/docker/hack/make/.validate
|
||||
- bash /go/src/github.com/docker/docker/hack/make/validate-dco
|
||||
- bash /go/src/github.com/docker/docker/hack/make/validate-gofmt
|
||||
- export GOPATH="$GOPATH:/go:$(pwd)/vendor" # Drone mucks with our GOPATH
|
||||
- make direct-test
|
|
@ -1,36 +0,0 @@
|
|||
language: go
|
||||
go: 1.3
|
||||
|
||||
# let us have pretty experimental Docker-based Travis workers
|
||||
sudo: false
|
||||
|
||||
env:
|
||||
- TRAVIS_GLOBAL_WTF=1
|
||||
- _GOOS=linux _GOARCH=amd64 CGO_ENABLED=1
|
||||
- _GOOS=linux _GOARCH=amd64 CGO_ENABLED=0
|
||||
# - _GOOS=linux _GOARCH=386 CGO_ENABLED=1 # TODO add this once Travis can handle it (https://github.com/travis-ci/travis-ci/issues/2207#issuecomment-49625061)
|
||||
- _GOOS=linux _GOARCH=386 CGO_ENABLED=0
|
||||
- _GOOS=linux _GOARCH=arm CGO_ENABLED=0
|
||||
|
||||
install:
|
||||
- go get code.google.com/p/go.tools/cmd/cover
|
||||
- mkdir -pv "${GOPATH%%:*}/src/github.com/docker" && [ -d "${GOPATH%%:*}/src/github.com/docker/libcontainer" ] || ln -sv "$(readlink -f .)" "${GOPATH%%:*}/src/github.com/docker/libcontainer"
|
||||
- if [ -z "$TRAVIS_GLOBAL_WTF" ]; then
|
||||
gvm cross "$_GOOS" "$_GOARCH";
|
||||
export GOOS="$_GOOS" GOARCH="$_GOARCH";
|
||||
fi
|
||||
- export GOPATH="$GOPATH:$(pwd)/vendor"
|
||||
- if [ -z "$TRAVIS_GLOBAL_WTF" ]; then go env; fi
|
||||
- go get -d -v ./... # TODO remove this if /docker/docker gets purged from our includes
|
||||
- if [ "$TRAVIS_GLOBAL_WTF" ]; then
|
||||
export DOCKER_PATH="${GOPATH%%:*}/src/github.com/docker/docker";
|
||||
mkdir -p "$DOCKER_PATH/hack/make";
|
||||
( cd "$DOCKER_PATH/hack/make" && wget -c 'https://raw.githubusercontent.com/docker/docker/master/hack/make/'{.validate,validate-dco,validate-gofmt} );
|
||||
sed -i 's!docker/docker!docker/libcontainer!' "$DOCKER_PATH/hack/make/.validate";
|
||||
fi
|
||||
|
||||
script:
|
||||
- if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-dco"; fi
|
||||
- if [ "$TRAVIS_GLOBAL_WTF" ]; then bash "$DOCKER_PATH/hack/make/validate-gofmt"; fi
|
||||
- if [ -z "$TRAVIS_GLOBAL_WTF" ]; then make direct-build; fi
|
||||
- if [ -z "$TRAVIS_GLOBAL_WTF" -a "$GOARCH" != 'arm' ]; then make direct-test-short; fi
|
|
@ -2,5 +2,4 @@ Michael Crosby <michael@docker.com> (@crosbymichael)
|
|||
Rohit Jnagal <jnagal@google.com> (@rjnagal)
|
||||
Victor Marmol <vmarmol@google.com> (@vmarmol)
|
||||
Mrunal Patel <mpatel@redhat.com> (@mrunalp)
|
||||
.travis.yml: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||
update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## libcontainer - reference implementation for containers [![Build Status](https://travis-ci.org/docker/libcontainer.png?branch=master)](https://travis-ci.org/docker/libcontainer)
|
||||
## libcontainer - reference implementation for containers [![Build Status](https://ci.dockerproject.com/github.com/docker/libcontainer/status.svg?branch=master)](https://ci.dockerproject.com/github.com/docker/libcontainer)
|
||||
|
||||
### Note on API changes:
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if value != 0 {
|
||||
t.Fatalf("Expected %d to equal %f", value, 0)
|
||||
t.Fatalf("Expected %d to equal %d", value, 0)
|
||||
}
|
||||
|
||||
// Success with negative values lesser than min int64
|
||||
|
@ -70,7 +70,7 @@ func TestGetCgroupParamsInt(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if value != 0 {
|
||||
t.Fatalf("Expected %d to equal %f", value, 0)
|
||||
t.Fatalf("Expected %d to equal %d", value, 0)
|
||||
}
|
||||
|
||||
// Not a float.
|
||||
|
|
|
@ -43,6 +43,13 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func newProp(name string, units interface{}) systemd.Property {
|
||||
return systemd.Property{
|
||||
Name: name,
|
||||
Value: dbus.MakeVariant(units),
|
||||
}
|
||||
}
|
||||
|
||||
func UseSystemd() bool {
|
||||
s, err := os.Stat("/run/systemd/system")
|
||||
if err != nil || !s.IsDir() {
|
||||
|
@ -99,27 +106,27 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
|
|||
}
|
||||
|
||||
properties = append(properties,
|
||||
systemd.Property{"Slice", dbus.MakeVariant(slice)},
|
||||
systemd.Property{"Description", dbus.MakeVariant("docker container " + c.Name)},
|
||||
systemd.Property{"PIDs", dbus.MakeVariant([]uint32{uint32(pid)})},
|
||||
systemd.PropSlice(slice),
|
||||
systemd.PropDescription("docker container "+c.Name),
|
||||
newProp("PIDs", []uint32{uint32(pid)}),
|
||||
)
|
||||
|
||||
// Always enable accounting, this gets us the same behaviour as the fs implementation,
|
||||
// plus the kernel has some problems with joining the memory cgroup at a later time.
|
||||
properties = append(properties,
|
||||
systemd.Property{"MemoryAccounting", dbus.MakeVariant(true)},
|
||||
systemd.Property{"CPUAccounting", dbus.MakeVariant(true)},
|
||||
systemd.Property{"BlockIOAccounting", dbus.MakeVariant(true)})
|
||||
newProp("MemoryAccounting", true),
|
||||
newProp("CPUAccounting", true),
|
||||
newProp("BlockIOAccounting", true))
|
||||
|
||||
if c.Memory != 0 {
|
||||
properties = append(properties,
|
||||
systemd.Property{"MemoryLimit", dbus.MakeVariant(uint64(c.Memory))})
|
||||
newProp("MemoryLimit", uint64(c.Memory)))
|
||||
}
|
||||
// TODO: MemoryReservation and MemorySwap not available in systemd
|
||||
|
||||
if c.CpuShares != 0 {
|
||||
properties = append(properties,
|
||||
systemd.Property{"CPUShares", dbus.MakeVariant(uint64(c.CpuShares))})
|
||||
newProp("CPUShares", uint64(c.CpuShares)))
|
||||
}
|
||||
|
||||
if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
|
||||
|
|
|
@ -103,7 +103,7 @@ func getDeviceNodes(path string) ([]*Device, error) {
|
|||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
case "pts", "shm", "fd":
|
||||
case "pts", "shm", "fd", "mqueue":
|
||||
continue
|
||||
default:
|
||||
sub, err := getDeviceNodes(filepath.Join(path, f.Name()))
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
// init runs the libcontainer initialization code because of the busybox style needs
|
||||
|
@ -27,12 +26,7 @@ func init() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create sync pipe: %s", err)
|
||||
}
|
||||
|
||||
if err := namespaces.Init(container, rootfs, "", syncPipe, os.Args[3:]); err != nil {
|
||||
if err := namespaces.Init(container, rootfs, "", os.NewFile(3, "pipe"), os.Args[3:]); err != nil {
|
||||
log.Fatalf("unable to initialize for container: %s", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
|
|
|
@ -43,3 +43,15 @@ func ReserveLabel(label string) error {
|
|||
func UnreserveLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DupSecOpt takes an process label and returns security options that
|
||||
// can be used to set duplicate labels on future container processes
|
||||
func DupSecOpt(src string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can disable labeling
|
||||
// support for future container processes
|
||||
func DisableSecOpt() []string {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ func InitLabels(options []string) (string, string, error) {
|
|||
if !selinux.SelinuxEnabled() {
|
||||
return "", "", nil
|
||||
}
|
||||
var err error
|
||||
processLabel, mountLabel := selinux.GetLxcContexts()
|
||||
if processLabel != "" {
|
||||
pcon := selinux.NewContext(processLabel)
|
||||
|
@ -38,7 +37,7 @@ func InitLabels(options []string) (string, string, error) {
|
|||
processLabel = pcon.Get()
|
||||
mountLabel = mcon.Get()
|
||||
}
|
||||
return processLabel, mountLabel, err
|
||||
return processLabel, mountLabel, nil
|
||||
}
|
||||
|
||||
// DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
|
||||
|
@ -130,3 +129,15 @@ func UnreserveLabel(label string) error {
|
|||
selinux.FreeLxcContexts(label)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DupSecOpt takes an process label and returns security options that
|
||||
// can be used to set duplicate labels on future container processes
|
||||
func DupSecOpt(src string) []string {
|
||||
return selinux.DupSecOpt(src)
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can disable labeling
|
||||
// support for future container processes
|
||||
func DisableSecOpt() []string {
|
||||
return selinux.DisableSecOpt()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package label
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/selinux"
|
||||
|
@ -33,7 +34,7 @@ func TestInit(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" {
|
||||
t.Log("InitLabels User Failed")
|
||||
t.Log("InitLabels User Match Failed")
|
||||
t.Log(plabel, mlabel)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -46,3 +47,43 @@ func TestInit(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
func TestDuplicateLabel(t *testing.T) {
|
||||
secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2")
|
||||
t.Log(secopt)
|
||||
for _, opt := range secopt {
|
||||
con := strings.SplitN(opt, ":", 3)
|
||||
if len(con) != 3 || con[0] != "label" {
|
||||
t.Errorf("Invalid DupSecOpt return value")
|
||||
continue
|
||||
}
|
||||
if con[1] == "user" {
|
||||
if con[2] != "system_u" {
|
||||
t.Errorf("DupSecOpt Failed user incorrect")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if con[1] == "role" {
|
||||
if con[2] != "system_r" {
|
||||
t.Errorf("DupSecOpt Failed role incorrect")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if con[1] == "type" {
|
||||
if con[2] != "svirt_lxc_net_t" {
|
||||
t.Errorf("DupSecOpt Failed type incorrect")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if con[1] == "level" {
|
||||
if con[2] != "s0:c1,c2" {
|
||||
t.Errorf("DupSecOpt Failed level incorrect")
|
||||
}
|
||||
continue
|
||||
}
|
||||
t.Errorf("DupSecOpt Failed invalid field %q", con[1])
|
||||
}
|
||||
secopt = DisableSecOpt()
|
||||
if secopt[0] != "label:disable" {
|
||||
t.Errorf("DisableSecOpt Failed level incorrect")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ func InitializeMountNamespace(rootfs, console string, sysReadonly bool, mountCon
|
|||
return nil
|
||||
}
|
||||
|
||||
// mountSystem sets up linux specific system mounts like sys, proc, shm, and devpts
|
||||
// mountSystem sets up linux specific system mounts like mqueue, sys, proc, shm, and devpts
|
||||
// inside the mount namespace
|
||||
func mountSystem(rootfs string, sysReadonly bool, mountConfig *MountConfig) error {
|
||||
for _, m := range newSystemMounts(rootfs, mountConfig.MountLabel, sysReadonly) {
|
||||
|
@ -168,6 +168,7 @@ func newSystemMounts(rootfs, mountLabel string, sysReadonly bool) []mount {
|
|||
{source: "proc", path: filepath.Join(rootfs, "proc"), device: "proc", flags: defaultMountFlags},
|
||||
{source: "tmpfs", path: filepath.Join(rootfs, "dev"), device: "tmpfs", flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME, data: label.FormatMountLabel("mode=755", mountLabel)},
|
||||
{source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1777,size=65536k", mountLabel)},
|
||||
{source: "mqueue", path: filepath.Join(rootfs, "dev", "mqueue"), device: "mqueue", flags: defaultMountFlags},
|
||||
{source: "devpts", path: filepath.Join(rootfs, "dev", "pts"), device: "devpts", flags: syscall.MS_NOSUID | syscall.MS_NOEXEC, data: label.FormatMountLabel("newinstance,ptmxmode=0666,mode=620,gid=5", mountLabel)},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package namespaces
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -13,7 +14,6 @@ import (
|
|||
"github.com/docker/libcontainer/cgroups/fs"
|
||||
"github.com/docker/libcontainer/cgroups/systemd"
|
||||
"github.com/docker/libcontainer/network"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
"github.com/docker/libcontainer/system"
|
||||
)
|
||||
|
||||
|
@ -22,19 +22,17 @@ import (
|
|||
// Exec performs setup outside of a namespace so that a container can be
|
||||
// executed. Exec is a high level function for working with container namespaces.
|
||||
func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
var err error
|
||||
|
||||
// create a pipe so that we can syncronize with the namespaced process and
|
||||
// pass the veth name to the child
|
||||
syncPipe, err := syncpipe.NewSyncPipe()
|
||||
// pass the state and configuration to the child process
|
||||
parent, child, err := newInitPipe()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer syncPipe.Close()
|
||||
defer parent.Close()
|
||||
|
||||
command := createCommand(container, console, dataPath, os.Args[0], syncPipe.Child(), args)
|
||||
command := createCommand(container, console, dataPath, os.Args[0], child, args)
|
||||
// Note: these are only used in non-tty mode
|
||||
// if there is a tty for the container it will be opened within the namespace and the
|
||||
// fds will be duped to stdin, stdiout, and stderr
|
||||
|
@ -43,39 +41,47 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
|
|||
command.Stderr = stderr
|
||||
|
||||
if err := command.Start(); err != nil {
|
||||
child.Close()
|
||||
return -1, err
|
||||
}
|
||||
child.Close()
|
||||
|
||||
// Now we passed the pipe to the child, close our side
|
||||
syncPipe.CloseChild()
|
||||
terminate := func(terr error) (int, error) {
|
||||
// TODO: log the errors for kill and wait
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, terr
|
||||
}
|
||||
|
||||
started, err := system.GetProcessStartTime(command.Process.Pid)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
// Do this before syncing with child so that no children
|
||||
// can escape the cgroup
|
||||
cgroupRef, err := SetupCgroups(container, command.Process.Pid)
|
||||
if err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
return terminate(err)
|
||||
}
|
||||
defer cgroupRef.Cleanup()
|
||||
|
||||
cgroupPaths, err := cgroupRef.Paths()
|
||||
if err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
var networkState network.NetworkState
|
||||
if err := InitializeNetworking(container, command.Process.Pid, syncPipe, &networkState); err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
if err := InitializeNetworking(container, command.Process.Pid, &networkState); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
// send the state to the container's init process then shutdown writes for the parent
|
||||
if err := json.NewEncoder(parent).Encode(networkState); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
// shutdown writes for the parent side of the pipe
|
||||
if err := syscall.Shutdown(int(parent.Fd()), syscall.SHUT_WR); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
state := &libcontainer.State{
|
||||
|
@ -86,17 +92,18 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
|
|||
}
|
||||
|
||||
if err := libcontainer.SaveState(dataPath, state); err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
return terminate(err)
|
||||
}
|
||||
defer libcontainer.DeleteState(dataPath)
|
||||
|
||||
// Sync with child
|
||||
if err := syncPipe.ReadFromChild(); err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
// wait for the child process to fully complete and receive an error message
|
||||
// if one was encoutered
|
||||
var ierr *initError
|
||||
if err := json.NewDecoder(parent).Decode(&ierr); err != nil && err != io.EOF {
|
||||
return terminate(err)
|
||||
}
|
||||
if ierr != nil {
|
||||
return terminate(ierr)
|
||||
}
|
||||
|
||||
if startCallback != nil {
|
||||
|
@ -108,7 +115,6 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
|
|||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
|
||||
}
|
||||
|
||||
|
@ -129,16 +135,6 @@ func DefaultCreateCommand(container *libcontainer.Config, console, dataPath, ini
|
|||
"data_path=" + dataPath,
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: move user and wd into env
|
||||
if user != "" {
|
||||
env = append(env, "user="+user)
|
||||
}
|
||||
if workingDir != "" {
|
||||
env = append(env, "wd="+workingDir)
|
||||
}
|
||||
*/
|
||||
|
||||
command := exec.Command(init, append([]string{"init", "--"}, args...)...)
|
||||
// make sure the process is executed inside the context of the rootfs
|
||||
command.Dir = container.RootFs
|
||||
|
@ -173,7 +169,7 @@ func SetupCgroups(container *libcontainer.Config, nspid int) (cgroups.ActiveCgro
|
|||
|
||||
// InitializeNetworking creates the container's network stack outside of the namespace and moves
|
||||
// interfaces into the container's net namespaces if necessary
|
||||
func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncpipe.SyncPipe, networkState *network.NetworkState) error {
|
||||
func InitializeNetworking(container *libcontainer.Config, nspid int, networkState *network.NetworkState) error {
|
||||
for _, config := range container.Networks {
|
||||
strategy, err := network.GetStrategy(config.Type)
|
||||
if err != nil {
|
||||
|
@ -183,18 +179,5 @@ func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncp
|
|||
return err
|
||||
}
|
||||
}
|
||||
return pipe.SendToChild(networkState)
|
||||
}
|
||||
|
||||
// GetNamespaceFlags parses the container's Namespaces options to set the correct
|
||||
// flags on clone, unshare, and setns
|
||||
func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
|
||||
for key, enabled := range namespaces {
|
||||
if enabled {
|
||||
if ns := GetNamespace(key); ns != nil {
|
||||
flag |= ns.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package namespaces
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -15,7 +16,6 @@ import (
|
|||
"github.com/docker/libcontainer/apparmor"
|
||||
"github.com/docker/libcontainer/cgroups"
|
||||
"github.com/docker/libcontainer/label"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
"github.com/docker/libcontainer/system"
|
||||
)
|
||||
|
||||
|
@ -41,11 +41,11 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
|
|||
}
|
||||
}
|
||||
|
||||
pipe, err := syncpipe.NewSyncPipe()
|
||||
parent, child, err := newInitPipe()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer pipe.Close()
|
||||
defer parent.Close()
|
||||
|
||||
// Note: these are only used in non-tty mode
|
||||
// if there is a tty for the container it will be opened within the namespace and the
|
||||
|
@ -53,23 +53,28 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
|
|||
cmd.Stdin = stdin
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
|
||||
cmd.ExtraFiles = []*os.File{pipe.Child()}
|
||||
cmd.ExtraFiles = []*os.File{child}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
child.Close()
|
||||
return -1, err
|
||||
}
|
||||
pipe.CloseChild()
|
||||
child.Close()
|
||||
|
||||
terminate := func(terr error) (int, error) {
|
||||
// TODO: log the errors for kill and wait
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
return -1, terr
|
||||
}
|
||||
|
||||
// Enter cgroups.
|
||||
if err := EnterCgroups(state, cmd.Process.Pid); err != nil {
|
||||
return -1, err
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
if err := pipe.SendToChild(container); err != nil {
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
return -1, err
|
||||
if err := json.NewEncoder(parent).Encode(container); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
|
||||
if startCallback != nil {
|
||||
|
@ -81,7 +86,6 @@ func ExecIn(container *libcontainer.Config, state *libcontainer.State, userArgs
|
|||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
return cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
package namespaces
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
@ -18,7 +20,6 @@ import (
|
|||
"github.com/docker/libcontainer/network"
|
||||
"github.com/docker/libcontainer/security/capabilities"
|
||||
"github.com/docker/libcontainer/security/restrict"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
"github.com/docker/libcontainer/system"
|
||||
"github.com/docker/libcontainer/user"
|
||||
"github.com/docker/libcontainer/utils"
|
||||
|
@ -30,11 +31,22 @@ import (
|
|||
// and other options required for the new container.
|
||||
// The caller of Init function has to ensure that the go runtime is locked to an OS thread
|
||||
// (using runtime.LockOSThread) else system calls like setns called within Init may not work as intended.
|
||||
func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syncPipe *syncpipe.SyncPipe, args []string) (err error) {
|
||||
func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, pipe *os.File, args []string) (err error) {
|
||||
defer func() {
|
||||
// if we have an error during the initialization of the container's init then send it back to the
|
||||
// parent process in the form of an initError.
|
||||
if err != nil {
|
||||
syncPipe.ReportChildError(err)
|
||||
// ensure that any data sent from the parent is consumed so it doesn't
|
||||
// receive ECONNRESET when the child writes to the pipe.
|
||||
ioutil.ReadAll(pipe)
|
||||
if err := json.NewEncoder(pipe).Encode(initError{
|
||||
Message: err.Error(),
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
// ensure that this pipe is always closed
|
||||
pipe.Close()
|
||||
}()
|
||||
|
||||
rootfs, err := utils.ResolveRootfs(uncleanRootfs)
|
||||
|
@ -50,7 +62,7 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, syn
|
|||
|
||||
// We always read this as it is a way to sync with the parent as well
|
||||
var networkState *network.NetworkState
|
||||
if err := syncPipe.ReadFromParent(&networkState); err != nil {
|
||||
if err := json.NewDecoder(pipe).Decode(&networkState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -164,11 +176,11 @@ func SetupUser(u string) error {
|
|||
return fmt.Errorf("setgroups %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Setgid(gid); err != nil {
|
||||
if err := system.Setgid(gid); err != nil {
|
||||
return fmt.Errorf("setgid %s", err)
|
||||
}
|
||||
|
||||
if err := syscall.Setuid(uid); err != nil {
|
||||
if err := system.Setuid(uid); err != nil {
|
||||
return fmt.Errorf("setuid %s", err)
|
||||
}
|
||||
|
||||
|
|
38
vendor/src/github.com/docker/libcontainer/namespaces/utils.go
vendored
Normal file
38
vendor/src/github.com/docker/libcontainer/namespaces/utils.go
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// +build linux
|
||||
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type initError struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (i initError) Error() string {
|
||||
return i.Message
|
||||
}
|
||||
|
||||
// New returns a newly initialized Pipe for communication between processes
|
||||
func newInitPipe() (parent *os.File, child *os.File, err error) {
|
||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
|
||||
}
|
||||
|
||||
// GetNamespaceFlags parses the container's Namespaces options to set the correct
|
||||
// flags on clone, unshare, and setns
|
||||
func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
|
||||
for key, enabled := range namespaces {
|
||||
if enabled {
|
||||
if ns := GetNamespace(key); ns != nil {
|
||||
flag |= ns.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
@ -1204,6 +1205,28 @@ func SetMacAddress(name, addr string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func SetHairpinMode(iface *net.Interface, enabled bool) error {
|
||||
sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode")
|
||||
|
||||
sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sysFile.Close()
|
||||
|
||||
var writeVal []byte
|
||||
if enabled {
|
||||
writeVal = []byte("1")
|
||||
} else {
|
||||
writeVal = []byte("0")
|
||||
}
|
||||
if _, err := sysFile.Write(writeVal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ChangeName(iface *net.Interface, newName string) error {
|
||||
if len(newName) >= IFNAMSIZ {
|
||||
return fmt.Errorf("Interface name %s too long", newName)
|
||||
|
@ -1224,5 +1247,6 @@ func ChangeName(iface *net.Interface, newName string) error {
|
|||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
|
||||
return errno
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ func TestNetworkSetMacAddress(t *testing.T) {
|
|||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface: err", macaddr, tl, err)
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface: %s", macaddr, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
@ -140,7 +140,7 @@ func TestNetworkSetMTU(t *testing.T) {
|
|||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
|
||||
t.Fatalf("Could not set %d MTU on %#v interface: err", mtu, tl, err)
|
||||
t.Fatalf("Could not set %d MTU on %#v interface: %s", mtu, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
|
|
@ -95,3 +95,11 @@ func SetMtu(name string, mtu int) error {
|
|||
}
|
||||
return netlink.NetworkSetMTU(iface, mtu)
|
||||
}
|
||||
|
||||
func SetHairpinMode(name string, enabled bool) error {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return netlink.SetHairpinMode(iface, enabled)
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error {
|
|||
if err := SetMtu(name1, n.Mtu); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetHairpinMode(name1, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := InterfaceUp(name1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/libcontainer/namespaces"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -41,12 +40,8 @@ func initAction(context *cli.Context) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, uintptr(pipeFd))
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create sync pipe: %s", err)
|
||||
}
|
||||
|
||||
if err := namespaces.Init(container, rootfs, console, syncPipe, []string(context.Args())); err != nil {
|
||||
pipe := os.NewFile(uintptr(pipeFd), "pipe")
|
||||
if err := namespaces.Init(container, rootfs, console, pipe, []string(context.Args())); err != nil {
|
||||
log.Fatalf("unable to initialize for container: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/syncpipe"
|
||||
)
|
||||
|
||||
// rFunc is a function registration for calling after an execin
|
||||
|
@ -59,16 +58,13 @@ func findUserArgs() []string {
|
|||
// loadConfigFromFd loads a container's config from the sync pipe that is provided by
|
||||
// fd 3 when running a process
|
||||
func loadConfigFromFd() (*libcontainer.Config, error) {
|
||||
syncPipe, err := syncpipe.NewSyncPipeFromFd(0, 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pipe := os.NewFile(3, "pipe")
|
||||
defer pipe.Close()
|
||||
|
||||
var config *libcontainer.Config
|
||||
if err := syncPipe.ReadFromParent(&config); err != nil {
|
||||
if err := json.NewDecoder(pipe).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -434,3 +434,28 @@ func Chcon(fpath string, scon string, recurse bool) error {
|
|||
|
||||
return Setfilecon(fpath, scon)
|
||||
}
|
||||
|
||||
// DupSecOpt takes an SELinux process label and returns security options that
|
||||
// can will set the SELinux Type and Level for future container processes
|
||||
func DupSecOpt(src string) []string {
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
con := NewContext(src)
|
||||
if con["user"] == "" ||
|
||||
con["role"] == "" ||
|
||||
con["type"] == "" ||
|
||||
con["level"] == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{"label:user:" + con["user"],
|
||||
"label:role:" + con["role"],
|
||||
"label:type:" + con["type"],
|
||||
"label:level:" + con["level"]}
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can be used to disabling SELinux
|
||||
// labeling support for future container processes
|
||||
func DisableSecOpt() []string {
|
||||
return []string{"label:disable"}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func TestSELinux(t *testing.T) {
|
|||
t.Log("getenforce ", selinux.SelinuxGetEnforce())
|
||||
t.Log("getenforcemode ", selinux.SelinuxGetEnforceMode())
|
||||
pid := os.Getpid()
|
||||
t.Log("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
|
||||
t.Logf("PID:%d MCS:%s\n", pid, selinux.IntToMcs(pid, 1023))
|
||||
err = selinux.Setfscreatecon("unconfined_u:unconfined_r:unconfined_t:s0")
|
||||
if err == nil {
|
||||
t.Log(selinux.Getfscreatecon())
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
package syncpipe
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SyncPipe allows communication to and from the child processes
|
||||
// to it's parent and allows the two independent processes to
|
||||
// syncronize their state.
|
||||
type SyncPipe struct {
|
||||
parent, child *os.File
|
||||
}
|
||||
|
||||
func NewSyncPipeFromFd(parentFd, childFd uintptr) (*SyncPipe, error) {
|
||||
s := &SyncPipe{}
|
||||
|
||||
if parentFd > 0 {
|
||||
s.parent = os.NewFile(parentFd, "parentPipe")
|
||||
} else if childFd > 0 {
|
||||
s.child = os.NewFile(childFd, "childPipe")
|
||||
} else {
|
||||
return nil, fmt.Errorf("no valid sync pipe fd specified")
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *SyncPipe) Child() *os.File {
|
||||
return s.child
|
||||
}
|
||||
|
||||
func (s *SyncPipe) Parent() *os.File {
|
||||
return s.parent
|
||||
}
|
||||
|
||||
func (s *SyncPipe) SendToChild(v interface{}) error {
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.parent.Write(data)
|
||||
|
||||
return syscall.Shutdown(int(s.parent.Fd()), syscall.SHUT_WR)
|
||||
}
|
||||
|
||||
func (s *SyncPipe) ReadFromChild() error {
|
||||
data, err := ioutil.ReadAll(s.parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
return fmt.Errorf("%s", data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SyncPipe) ReadFromParent(v interface{}) error {
|
||||
data, err := ioutil.ReadAll(s.child)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading from sync pipe %s", err)
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
if err := json.Unmarshal(data, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SyncPipe) ReportChildError(err error) {
|
||||
// ensure that any data sent from the parent is consumed so it doesn't
|
||||
// receive ECONNRESET when the child writes to the pipe.
|
||||
ioutil.ReadAll(s.child)
|
||||
|
||||
s.child.Write([]byte(err.Error()))
|
||||
s.CloseChild()
|
||||
}
|
||||
|
||||
func (s *SyncPipe) Close() error {
|
||||
if s.parent != nil {
|
||||
s.parent.Close()
|
||||
}
|
||||
|
||||
if s.child != nil {
|
||||
s.child.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SyncPipe) CloseChild() {
|
||||
if s.child != nil {
|
||||
s.child.Close()
|
||||
s.child = nil
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package syncpipe
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func NewSyncPipe() (s *SyncPipe, err error) {
|
||||
s = &SyncPipe{}
|
||||
|
||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.child = os.NewFile(uintptr(fds[0]), "child syncpipe")
|
||||
s.parent = os.NewFile(uintptr(fds[1]), "parent syncpipe")
|
||||
|
||||
return s, nil
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package syncpipe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testStruct struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func TestSendErrorFromChild(t *testing.T) {
|
||||
pipe, err := NewSyncPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := pipe.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
childfd, err := syscall.Dup(int(pipe.Child().Fd()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
childPipe, _ := NewSyncPipeFromFd(0, uintptr(childfd))
|
||||
|
||||
pipe.CloseChild()
|
||||
pipe.SendToChild(nil)
|
||||
|
||||
expected := "something bad happened"
|
||||
childPipe.ReportChildError(fmt.Errorf(expected))
|
||||
|
||||
childError := pipe.ReadFromChild()
|
||||
if childError == nil {
|
||||
t.Fatal("expected an error to be returned but did not receive anything")
|
||||
}
|
||||
|
||||
if childError.Error() != expected {
|
||||
t.Fatalf("expected %q but received error message %q", expected, childError.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendPayloadToChild(t *testing.T) {
|
||||
pipe, err := NewSyncPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := pipe.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
expected := "libcontainer"
|
||||
|
||||
if err := pipe.SendToChild(testStruct{Name: expected}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var s *testStruct
|
||||
if err := pipe.ReadFromParent(&s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if s.Name != expected {
|
||||
t.Fatalf("expected name %q but received %q", expected, s.Name)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
// +build linux,amd64
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
|
|
Loading…
Add table
Reference in a new issue