Merge pull request #682 from vmarmol/update-libcontainer
Update libcontainer godep
This commit is contained in:
commit
ed19fa9c98
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
@ -97,8 +97,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/libcontainer",
|
"ImportPath": "github.com/docker/libcontainer",
|
||||||
"Comment": "v1.4.0-412-g4ea9039",
|
"Comment": "v1.4.0-501-ga1fe3f1",
|
||||||
"Rev": "4ea9039ff269fc8675409df7f1a192c94eab2f52"
|
"Rev": "a1fe3f1c7ad2e8eebe6d59e573f04d2b10961cf6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/fsouza/go-dockerclient",
|
"ImportPath": "github.com/fsouza/go-dockerclient",
|
||||||
@ -178,7 +178,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/syndtr/gocapability/capability",
|
"ImportPath": "github.com/syndtr/gocapability/capability",
|
||||||
"Rev": "3c85049eaeb429febe7788d9c7aac42322a377fe"
|
"Rev": "8e4cdcb3c22b40d5e330ade0b68cb2e2a3cf6f98"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/exp/inotify",
|
"ImportPath": "golang.org/x/exp/inotify",
|
||||||
|
1
Godeps/_workspace/src/github.com/docker/libcontainer/.gitignore
generated
vendored
1
Godeps/_workspace/src/github.com/docker/libcontainer/.gitignore
generated
vendored
@ -1 +1,2 @@
|
|||||||
|
bundles
|
||||||
nsinit/nsinit
|
nsinit/nsinit
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/Makefile
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/Makefile
generated
vendored
@ -29,3 +29,5 @@ local:
|
|||||||
validate:
|
validate:
|
||||||
hack/validate.sh
|
hack/validate.sh
|
||||||
|
|
||||||
|
binary: all
|
||||||
|
docker run --rm --privileged -v $(CURDIR)/bundles:/go/bin dockercore/libcontainer make direct-install
|
||||||
|
3
Godeps/_workspace/src/github.com/docker/libcontainer/README.md
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/README.md
generated
vendored
@ -141,6 +141,9 @@ container.Resume()
|
|||||||
It is able to spawn new containers or join existing containers. A root
|
It is able to spawn new containers or join existing containers. A root
|
||||||
filesystem must be provided for use along with a container configuration file.
|
filesystem must be provided for use along with a container configuration file.
|
||||||
|
|
||||||
|
To build `nsinit`, run `make binary`. It will save the binary into
|
||||||
|
`bundles/nsinit`.
|
||||||
|
|
||||||
To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into
|
To use `nsinit`, cd into a Linux rootfs and copy a `container.json` file into
|
||||||
the directory with your specified configuration. Environment, networking,
|
the directory with your specified configuration. Environment, networking,
|
||||||
and different capabilities for the container are specified in this file.
|
and different capabilities for the container are specified in this file.
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/apparmor.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/apparmor.go
generated
vendored
@ -14,9 +14,11 @@ import (
|
|||||||
|
|
||||||
func IsEnabled() bool {
|
func IsEnabled() bool {
|
||||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
|
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
|
||||||
|
if _, err = os.Stat("/sbin/apparmor_parser"); err == nil {
|
||||||
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
||||||
return err == nil && len(buf) > 1 && buf[0] == 'Y'
|
return err == nil && len(buf) > 1 && buf[0] == 'Y'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/gen.go
generated
vendored
8
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/gen.go
generated
vendored
@ -67,12 +67,12 @@ func generateProfile(out io.Writer) error {
|
|||||||
data := &data{
|
data := &data{
|
||||||
Name: "docker-default",
|
Name: "docker-default",
|
||||||
}
|
}
|
||||||
if tuntablesExists() {
|
if tunablesExists() {
|
||||||
data.Imports = append(data.Imports, "#include <tunables/global>")
|
data.Imports = append(data.Imports, "#include <tunables/global>")
|
||||||
} else {
|
} else {
|
||||||
data.Imports = append(data.Imports, "@{PROC}=/proc/")
|
data.Imports = append(data.Imports, "@{PROC}=/proc/")
|
||||||
}
|
}
|
||||||
if abstrctionsEsists() {
|
if abstractionsExists() {
|
||||||
data.InnerImports = append(data.InnerImports, "#include <abstractions/base>")
|
data.InnerImports = append(data.InnerImports, "#include <abstractions/base>")
|
||||||
}
|
}
|
||||||
if err := compiled.Execute(out, data); err != nil {
|
if err := compiled.Execute(out, data); err != nil {
|
||||||
@ -82,13 +82,13 @@ func generateProfile(out io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if the tunables/global exist
|
// check if the tunables/global exist
|
||||||
func tuntablesExists() bool {
|
func tunablesExists() bool {
|
||||||
_, err := os.Stat("/etc/apparmor.d/tunables/global")
|
_, err := os.Stat("/etc/apparmor.d/tunables/global")
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if abstractions/base exist
|
// check if abstractions/base exist
|
||||||
func abstrctionsEsists() bool {
|
func abstractionsExists() bool {
|
||||||
_, err := os.Stat("/etc/apparmor.d/abstractions/base")
|
_, err := os.Stat("/etc/apparmor.d/abstractions/base")
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
1
Godeps/_workspace/src/github.com/docker/libcontainer/capabilities_linux.go
generated
vendored
1
Godeps/_workspace/src/github.com/docker/libcontainer/capabilities_linux.go
generated
vendored
@ -49,6 +49,7 @@ var capabilityList = map[string]capability.Cap{
|
|||||||
"SETFCAP": capability.CAP_SETFCAP,
|
"SETFCAP": capability.CAP_SETFCAP,
|
||||||
"WAKE_ALARM": capability.CAP_WAKE_ALARM,
|
"WAKE_ALARM": capability.CAP_WAKE_ALARM,
|
||||||
"BLOCK_SUSPEND": capability.CAP_BLOCK_SUSPEND,
|
"BLOCK_SUSPEND": capability.CAP_BLOCK_SUSPEND,
|
||||||
|
"AUDIT_READ": capability.CAP_AUDIT_READ,
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCapWhitelist(caps []string) (*whitelist, error) {
|
func newCapWhitelist(caps []string) (*whitelist, error) {
|
||||||
|
3
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/cgroups.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/cgroups.go
generated
vendored
@ -34,9 +34,6 @@ type Manager interface {
|
|||||||
|
|
||||||
// Set the cgroup as configured.
|
// Set the cgroup as configured.
|
||||||
Set(container *configs.Config) error
|
Set(container *configs.Config) error
|
||||||
|
|
||||||
// Enters the specified process into these cgroups.
|
|
||||||
EnterProcess(pid int) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotFoundError struct {
|
type NotFoundError struct {
|
||||||
|
63
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
63
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
@ -1,6 +1,8 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -19,6 +21,7 @@ var (
|
|||||||
"cpuset": &CpusetGroup{},
|
"cpuset": &CpusetGroup{},
|
||||||
"cpuacct": &CpuacctGroup{},
|
"cpuacct": &CpuacctGroup{},
|
||||||
"blkio": &BlkioGroup{},
|
"blkio": &BlkioGroup{},
|
||||||
|
"hugetlb": &HugetlbGroup{},
|
||||||
"perf_event": &PerfEventGroup{},
|
"perf_event": &PerfEventGroup{},
|
||||||
"freezer": &FreezerGroup{},
|
"freezer": &FreezerGroup{},
|
||||||
}
|
}
|
||||||
@ -75,10 +78,13 @@ type data struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Apply(pid int) error {
|
func (m *Manager) Apply(pid int) error {
|
||||||
|
|
||||||
if m.Cgroups == nil {
|
if m.Cgroups == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var c = m.Cgroups
|
||||||
|
|
||||||
d, err := getCgroupData(m.Cgroups, pid)
|
d, err := getCgroupData(m.Cgroups, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -108,6 +114,12 @@ func (m *Manager) Apply(pid int) error {
|
|||||||
}
|
}
|
||||||
m.Paths = paths
|
m.Paths = paths
|
||||||
|
|
||||||
|
if paths["cpu"] != "" {
|
||||||
|
if err := CheckCpushares(paths["cpu"], c.CpuShares); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,19 +131,6 @@ func (m *Manager) GetPaths() map[string]string {
|
|||||||
return m.Paths
|
return m.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symmetrical public function to update device based cgroups. Also available
|
|
||||||
// in the systemd implementation.
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
d, err := getCgroupData(c, pid)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
devices := subsystems["devices"]
|
|
||||||
|
|
||||||
return devices.Apply(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
||||||
stats := cgroups.NewStats()
|
stats := cgroups.NewStats()
|
||||||
for name, path := range m.Paths {
|
for name, path := range m.Paths {
|
||||||
@ -161,20 +160,6 @@ func (m *Manager) Set(container *configs.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) EnterProcess(pid int) error {
|
|
||||||
for name, path := range m.Paths {
|
|
||||||
_, ok := subsystems[name]
|
|
||||||
if !ok || !cgroups.PathExists(path) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := writeFile(path, CgroupProcesses, strconv.Itoa(pid)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Freeze toggles the container's freezer cgroup depending on the state
|
// Freeze toggles the container's freezer cgroup depending on the state
|
||||||
// provided
|
// provided
|
||||||
func (m *Manager) Freeze(state configs.FreezerState) error {
|
func (m *Manager) Freeze(state configs.FreezerState) error {
|
||||||
@ -294,3 +279,27 @@ func removePath(p string, err error) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckCpushares(path string, c int64) error {
|
||||||
|
var cpuShares int64
|
||||||
|
|
||||||
|
fd, err := os.Open(filepath.Join(path, "cpu.shares"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
_, err = fmt.Fscanf(fd, "%d", &cpuShares)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c != 0 {
|
||||||
|
if c > cpuShares {
|
||||||
|
return fmt.Errorf("The maximum allowed cpu-shares is %d", cpuShares)
|
||||||
|
} else if c < cpuShares {
|
||||||
|
return fmt.Errorf("The minimum allowed cpu-shares is %d", cpuShares)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
26
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
26
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
@ -35,6 +35,32 @@ func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cgroup.BlkioWeightDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.weight_device", cgroup.BlkioWeightDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleReadBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_bps_device", cgroup.BlkioThrottleReadBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleWriteBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_bps_device", cgroup.BlkioThrottleWriteBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleReadIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_iops_device", cgroup.BlkioThrottleReadIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleWriteIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_iops_device", cgroup.BlkioThrottleWriteIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
124
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go
generated
vendored
124
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio_test.go
generated
vendored
@ -67,6 +67,8 @@ Total 22061056`
|
|||||||
252:0 Async 164
|
252:0 Async 164
|
||||||
252:0 Total 164
|
252:0 Total 164
|
||||||
Total 328`
|
Total 328`
|
||||||
|
throttleBefore = `8:0 1024`
|
||||||
|
throttleAfter = `8:0 2048`
|
||||||
)
|
)
|
||||||
|
|
||||||
func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, minor, value uint64, op string) {
|
func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, minor, value uint64, op string) {
|
||||||
@ -102,6 +104,35 @@ func TestBlkioSetWeight(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlkioSetWeightDevice(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
const (
|
||||||
|
weightDeviceBefore = "8:0 400"
|
||||||
|
weightDeviceAfter = "8:0 500"
|
||||||
|
)
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"blkio.weight_device": weightDeviceBefore,
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.BlkioWeightDevice = weightDeviceAfter
|
||||||
|
blkio := &BlkioGroup{}
|
||||||
|
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "blkio.weight_device")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse blkio.weight_device - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != weightDeviceAfter {
|
||||||
|
t.Fatal("Got the wrong value, set blkio.weight_device failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBlkioStats(t *testing.T) {
|
func TestBlkioStats(t *testing.T) {
|
||||||
helper := NewCgroupTestUtil("blkio", t)
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
defer helper.cleanup()
|
defer helper.cleanup()
|
||||||
@ -442,3 +473,96 @@ func TestNonCFQBlkioStats(t *testing.T) {
|
|||||||
|
|
||||||
expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats)
|
expectBlkioStatsEquals(t, expectedStats, actualStats.BlkioStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBlkioSetThrottleReadBpsDevice(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"blkio.throttle.read_bps_device": throttleBefore,
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.BlkioThrottleReadBpsDevice = throttleAfter
|
||||||
|
blkio := &BlkioGroup{}
|
||||||
|
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.read_bps_device")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse blkio.throttle.read_bps_device - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != throttleAfter {
|
||||||
|
t.Fatal("Got the wrong value, set blkio.throttle.read_bps_device failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestBlkioSetThrottleWriteBpsDevice(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"blkio.throttle.write_bps_device": throttleBefore,
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.BlkioThrottleWriteBpsDevice = throttleAfter
|
||||||
|
blkio := &BlkioGroup{}
|
||||||
|
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.write_bps_device")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse blkio.throttle.write_bps_device - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != throttleAfter {
|
||||||
|
t.Fatal("Got the wrong value, set blkio.throttle.write_bps_device failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestBlkioSetThrottleReadIOpsDevice(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"blkio.throttle.read_iops_device": throttleBefore,
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.BlkioThrottleReadIOpsDevice = throttleAfter
|
||||||
|
blkio := &BlkioGroup{}
|
||||||
|
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.read_iops_device")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse blkio.throttle.read_iops_device - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != throttleAfter {
|
||||||
|
t.Fatal("Got the wrong value, set blkio.throttle.read_iops_device failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestBlkioSetThrottleWriteIOpsDevice(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("blkio", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"blkio.throttle.write_iops_device": throttleBefore,
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.BlkioThrottleWriteIOpsDevice = throttleAfter
|
||||||
|
blkio := &BlkioGroup{}
|
||||||
|
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "blkio.throttle.write_iops_device")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse blkio.throttle.write_iops_device - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != throttleAfter {
|
||||||
|
t.Fatal("Got the wrong value, set blkio.throttle.write_iops_device failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices.go
generated
vendored
11
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices.go
generated
vendored
@ -32,6 +32,17 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeFile(path, "devices.allow", "a"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dev := range cgroup.DeniedDevices {
|
||||||
|
if err := writeFile(path, "devices.deny", dev.CgroupString()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
36
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices_test.go
generated
vendored
36
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices_test.go
generated
vendored
@ -18,6 +18,17 @@ var (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
allowedList = "c 1:5 rwm"
|
allowedList = "c 1:5 rwm"
|
||||||
|
deniedDevices = []*configs.Device{
|
||||||
|
{
|
||||||
|
Path: "/dev/null",
|
||||||
|
Type: 'c',
|
||||||
|
Major: 1,
|
||||||
|
Minor: 3,
|
||||||
|
Permissions: "rwm",
|
||||||
|
FileMode: 0666,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
deniedList = "c 1:3 rwm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDevicesSetAllow(t *testing.T) {
|
func TestDevicesSetAllow(t *testing.T) {
|
||||||
@ -44,3 +55,28 @@ func TestDevicesSetAllow(t *testing.T) {
|
|||||||
t.Fatal("Got the wrong value, set devices.allow failed.")
|
t.Fatal("Got the wrong value, set devices.allow failed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDevicesSetDeny(t *testing.T) {
|
||||||
|
helper := NewCgroupTestUtil("devices", t)
|
||||||
|
defer helper.cleanup()
|
||||||
|
|
||||||
|
helper.writeFileContents(map[string]string{
|
||||||
|
"devices.allow": "a",
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.CgroupData.c.AllowAllDevices = true
|
||||||
|
helper.CgroupData.c.DeniedDevices = deniedDevices
|
||||||
|
devices := &DevicesGroup{}
|
||||||
|
if err := devices.Set(helper.CgroupPath, helper.CgroupData.c); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := getCgroupParamString(helper.CgroupPath, "devices.deny")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse devices.deny - %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value != deniedList {
|
||||||
|
t.Fatal("Got the wrong value, set devices.deny failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
29
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
Normal file
29
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/libcontainer/cgroups"
|
||||||
|
"github.com/docker/libcontainer/configs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HugetlbGroup struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Apply(d *data) error {
|
||||||
|
// we just want to join this group even though we don't set anything
|
||||||
|
if _, err := d.join("hugetlb"); err != nil && !cgroups.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Remove(d *data) error {
|
||||||
|
return removePath(d.path("hugetlb"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||||
|
return nil
|
||||||
|
}
|
1
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/memory.go
generated
vendored
1
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/memory.go
generated
vendored
@ -95,6 +95,7 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
|
|||||||
return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
|
return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
|
||||||
}
|
}
|
||||||
stats.MemoryStats.Usage = value
|
stats.MemoryStats.Usage = value
|
||||||
|
stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"]
|
||||||
value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
|
value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
|
return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/memory_test.go
generated
vendored
@ -128,7 +128,7 @@ func TestMemoryStats(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
expectedStats := cgroups.MemoryStats{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
|
expectedStats := cgroups.MemoryStats{Usage: 2048, Cache: 512, MaxUsage: 4096, Failcnt: 100, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
|
||||||
expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats)
|
expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/stats_util_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/stats_util_test.go
generated
vendored
@ -2,9 +2,9 @@ package fs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/stats.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/stats.go
generated
vendored
@ -33,6 +33,8 @@ type CpuStats struct {
|
|||||||
type MemoryStats struct {
|
type MemoryStats struct {
|
||||||
// current res_counter usage for memory
|
// current res_counter usage for memory
|
||||||
Usage uint64 `json:"usage,omitempty"`
|
Usage uint64 `json:"usage,omitempty"`
|
||||||
|
// memory used for cache
|
||||||
|
Cache uint64 `json:"cache,omitempty"`
|
||||||
// maximum usage ever recorded.
|
// maximum usage ever recorded.
|
||||||
MaxUsage uint64 `json:"max_usage,omitempty"`
|
MaxUsage uint64 `json:"max_usage,omitempty"`
|
||||||
// TODO(vishh): Export these as stronger types.
|
// TODO(vishh): Export these as stronger types.
|
||||||
|
@ -42,18 +42,10 @@ func (m *Manager) Set(container *configs.Config) error {
|
|||||||
return nil, fmt.Errorf("Systemd not supported")
|
return nil, fmt.Errorf("Systemd not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) EnterProcess(pid int) error {
|
|
||||||
return nil, fmt.Errorf("Systemd not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) Freeze(state configs.FreezerState) error {
|
func (m *Manager) Freeze(state configs.FreezerState) error {
|
||||||
return fmt.Errorf("Systemd not supported")
|
return fmt.Errorf("Systemd not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
return fmt.Errorf("Systemd not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
|
func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
|
||||||
return fmt.Errorf("Systemd not supported")
|
return fmt.Errorf("Systemd not supported")
|
||||||
}
|
}
|
||||||
|
138
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go
generated
vendored
138
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go
generated
vendored
@ -3,7 +3,6 @@
|
|||||||
package systemd
|
package systemd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -39,6 +38,7 @@ var subsystems = map[string]subsystem{
|
|||||||
"cpuset": &fs.CpusetGroup{},
|
"cpuset": &fs.CpusetGroup{},
|
||||||
"cpuacct": &fs.CpuacctGroup{},
|
"cpuacct": &fs.CpuacctGroup{},
|
||||||
"blkio": &fs.BlkioGroup{},
|
"blkio": &fs.BlkioGroup{},
|
||||||
|
"hugetlb": &fs.HugetlbGroup{},
|
||||||
"perf_event": &fs.PerfEventGroup{},
|
"perf_event": &fs.PerfEventGroup{},
|
||||||
"freezer": &fs.FreezerGroup{},
|
"freezer": &fs.FreezerGroup{},
|
||||||
}
|
}
|
||||||
@ -217,6 +217,13 @@ func (m *Manager) Apply(pid int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Systemd does have `BlockIODeviceWeight` property, but we got problem
|
||||||
|
// using that (at least on systemd 208, see https://github.com/docker/libcontainer/pull/354),
|
||||||
|
// so use fs work around for now.
|
||||||
|
if err := joinBlkio(c, pid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
paths := make(map[string]string)
|
paths := make(map[string]string)
|
||||||
for sysname := range subsystems {
|
for sysname := range subsystems {
|
||||||
subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
|
subsystemPath, err := getSubsystemPath(m.Cgroups, sysname)
|
||||||
@ -229,9 +236,14 @@ func (m *Manager) Apply(pid int) error {
|
|||||||
}
|
}
|
||||||
paths[sysname] = subsystemPath
|
paths[sysname] = subsystemPath
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Paths = paths
|
m.Paths = paths
|
||||||
|
|
||||||
|
if paths["cpu"] != "" {
|
||||||
|
if err := fs.CheckCpushares(paths["cpu"], c.CpuShares); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +259,21 @@ func writeFile(dir, file, data string) error {
|
|||||||
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
|
||||||
|
path, err := getSubsystemPath(c, subsystem)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := writeFile(path, "cgroup.procs", strconv.Itoa(pid)); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
func joinCpu(c *configs.Cgroup, pid int) error {
|
func joinCpu(c *configs.Cgroup, pid int) error {
|
||||||
path, err := getSubsystemPath(c, "cpu")
|
path, err := getSubsystemPath(c, "cpu")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -266,16 +293,11 @@ func joinCpu(c *configs.Cgroup, pid int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func joinFreezer(c *configs.Cgroup, pid int) error {
|
func joinFreezer(c *configs.Cgroup, pid int) error {
|
||||||
path, err := getSubsystemPath(c, "freezer")
|
if _, err := join(c, "freezer", pid); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
|
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
|
||||||
@ -303,22 +325,16 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(path, "freezer.state"), []byte(state), 0); err != nil {
|
prevState := m.Cgroups.Freezer
|
||||||
return err
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
state_, err := ioutil.ReadFile(filepath.Join(path, "freezer.state"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if string(state) == string(bytes.TrimSpace(state_)) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Cgroups.Freezer = state
|
m.Cgroups.Freezer = state
|
||||||
|
|
||||||
|
freezer := subsystems["freezer"]
|
||||||
|
err = freezer.Set(path, m.Cgroups)
|
||||||
|
if err != nil {
|
||||||
|
m.Cgroups.Freezer = prevState
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,16 +363,12 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Set(container *configs.Config) error {
|
func (m *Manager) Set(container *configs.Config) error {
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) EnterProcess(pid int) error {
|
|
||||||
for name, path := range m.Paths {
|
for name, path := range m.Paths {
|
||||||
_, ok := subsystems[name]
|
sys, ok := subsystems[name]
|
||||||
if !ok || !cgroups.PathExists(path) {
|
if !ok || !cgroups.PathExists(path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := writeFile(path, fs.CgroupProcesses, strconv.Itoa(pid)); err != nil {
|
if err := sys.Set(path, container.Cgroups); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,43 +385,20 @@ func getUnitName(c *configs.Cgroup) string {
|
|||||||
// * Support for wildcards to allow /dev/pts support
|
// * Support for wildcards to allow /dev/pts support
|
||||||
//
|
//
|
||||||
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
|
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
|
||||||
// in wide use. When both these are availalable we will be able to switch, but need to keep the old
|
// in wide use. When both these are available we will be able to switch, but need to keep the old
|
||||||
// implementation for backwards compat.
|
// implementation for backwards compat.
|
||||||
//
|
//
|
||||||
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
|
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
|
||||||
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
|
// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
|
||||||
// This happens at least for v208 when any sibling unit is started.
|
// This happens at least for v208 when any sibling unit is started.
|
||||||
func joinDevices(c *configs.Cgroup, pid int) error {
|
func joinDevices(c *configs.Cgroup, pid int) error {
|
||||||
path, err := getSubsystemPath(c, "devices")
|
path, err := join(c, "devices", pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
|
devices := subsystems["devices"]
|
||||||
return err
|
return devices.Set(path, c)
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.AllowAllDevices {
|
|
||||||
if err := writeFile(path, "devices.deny", "a"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, dev := range c.AllowedDevices {
|
|
||||||
if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symmetrical public function to update device based cgroups. Also available
|
|
||||||
// in the fs implementation.
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
return joinDevices(c, pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinMemory(c *configs.Cgroup, pid int) error {
|
func joinMemory(c *configs.Cgroup, pid int) error {
|
||||||
@ -441,3 +430,40 @@ func joinCpuset(c *configs.Cgroup, pid int) error {
|
|||||||
|
|
||||||
return s.ApplyDir(path, c, pid)
|
return s.ApplyDir(path, c, pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `BlockIODeviceWeight` property of systemd does not work properly, and systemd
|
||||||
|
// expects device path instead of major minor numbers, which is also confusing
|
||||||
|
// for users. So we use fs work around for now.
|
||||||
|
func joinBlkio(c *configs.Cgroup, pid int) error {
|
||||||
|
path, err := getSubsystemPath(c, "blkio")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.BlkioWeightDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.weight_device", c.BlkioWeightDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleReadBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_bps_device", c.BlkioThrottleReadBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleWriteBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_bps_device", c.BlkioThrottleWriteBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleReadIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_iops_device", c.BlkioThrottleReadIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleWriteIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_iops_device", c.BlkioThrottleWriteIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
17
Godeps/_workspace/src/github.com/docker/libcontainer/configs/cgroup.go
generated
vendored
17
Godeps/_workspace/src/github.com/docker/libcontainer/configs/cgroup.go
generated
vendored
@ -19,6 +19,8 @@ type Cgroup struct {
|
|||||||
|
|
||||||
AllowedDevices []*Device `json:"allowed_devices"`
|
AllowedDevices []*Device `json:"allowed_devices"`
|
||||||
|
|
||||||
|
DeniedDevices []*Device `json:"denied_devices"`
|
||||||
|
|
||||||
// Memory limit (in bytes)
|
// Memory limit (in bytes)
|
||||||
Memory int64 `json:"memory"`
|
Memory int64 `json:"memory"`
|
||||||
|
|
||||||
@ -43,9 +45,24 @@ type Cgroup struct {
|
|||||||
// MEM to use
|
// MEM to use
|
||||||
CpusetMems string `json:"cpuset_mems"`
|
CpusetMems string `json:"cpuset_mems"`
|
||||||
|
|
||||||
|
// IO read rate limit per cgroup per device, bytes per second.
|
||||||
|
BlkioThrottleReadBpsDevice string `json:"blkio_throttle_read_bps_device"`
|
||||||
|
|
||||||
|
// IO write rate limit per cgroup per divice, bytes per second.
|
||||||
|
BlkioThrottleWriteBpsDevice string `json:"blkio_throttle_write_bps_device"`
|
||||||
|
|
||||||
|
// IO read rate limit per cgroup per device, IO per second.
|
||||||
|
BlkioThrottleReadIOpsDevice string `json:"blkio_throttle_read_iops_device"`
|
||||||
|
|
||||||
|
// IO write rate limit per cgroup per device, IO per second.
|
||||||
|
BlkioThrottleWriteIOpsDevice string `json:"blkio_throttle_write_iops_device"`
|
||||||
|
|
||||||
// Specifies per cgroup weight, range is from 10 to 1000.
|
// Specifies per cgroup weight, range is from 10 to 1000.
|
||||||
BlkioWeight int64 `json:"blkio_weight"`
|
BlkioWeight int64 `json:"blkio_weight"`
|
||||||
|
|
||||||
|
// Weight per cgroup per device, can override BlkioWeight.
|
||||||
|
BlkioWeightDevice string `json:"blkio_weight_device"`
|
||||||
|
|
||||||
// set the freeze value for the process
|
// set the freeze value for the process
|
||||||
Freezer FreezerState `json:"freezer"`
|
Freezer FreezerState `json:"freezer"`
|
||||||
|
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/configs/config.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/configs/config.go
generated
vendored
@ -37,6 +37,9 @@ type Config struct {
|
|||||||
// bind mounts are writtable.
|
// bind mounts are writtable.
|
||||||
Readonlyfs bool `json:"readonlyfs"`
|
Readonlyfs bool `json:"readonlyfs"`
|
||||||
|
|
||||||
|
// Privatefs will mount the container's rootfs as private where mount points from the parent will not propogate
|
||||||
|
Privatefs bool `json:"privatefs"`
|
||||||
|
|
||||||
// Mounts specify additional source and destination paths that will be mounted inside the container's
|
// Mounts specify additional source and destination paths that will be mounted inside the container's
|
||||||
// rootfs and mount namespace if specified
|
// rootfs and mount namespace if specified
|
||||||
Mounts []*Mount `json:"mounts"`
|
Mounts []*Mount `json:"mounts"`
|
||||||
@ -96,6 +99,10 @@ type Config struct {
|
|||||||
// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
|
// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
|
||||||
// so that these files prevent any writes.
|
// so that these files prevent any writes.
|
||||||
ReadonlyPaths []string `json:"readonly_paths"`
|
ReadonlyPaths []string `json:"readonly_paths"`
|
||||||
|
|
||||||
|
// SystemProperties is a map of properties and their values. It is the equivalent of using
|
||||||
|
// sysctl -w my.property.name value in Linux.
|
||||||
|
SystemProperties map[string]string `json:"system_properties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the root uid for the process on host which could be non-zero
|
// Gets the root uid for the process on host which could be non-zero
|
||||||
|
13
Godeps/_workspace/src/github.com/docker/libcontainer/configs/mount.go
generated
vendored
13
Godeps/_workspace/src/github.com/docker/libcontainer/configs/mount.go
generated
vendored
@ -18,4 +18,17 @@ type Mount struct {
|
|||||||
|
|
||||||
// Relabel source if set, "z" indicates shared, "Z" indicates unshared.
|
// Relabel source if set, "z" indicates shared, "Z" indicates unshared.
|
||||||
Relabel string `json:"relabel"`
|
Relabel string `json:"relabel"`
|
||||||
|
|
||||||
|
// Optional Command to be run before Source is mounted.
|
||||||
|
PremountCmds []Command `json:"premount_cmds"`
|
||||||
|
|
||||||
|
// Optional Command to be run after Source is mounted.
|
||||||
|
PostmountCmds []Command `json:"postmount_cmds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Args []string `json:"args"`
|
||||||
|
Env []string `json:"env"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
}
|
}
|
||||||
|
42
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces.go
generated
vendored
42
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces.go
generated
vendored
@ -1,9 +1,6 @@
|
|||||||
package configs
|
package configs
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NamespaceType string
|
type NamespaceType string
|
||||||
|
|
||||||
@ -16,6 +13,17 @@ const (
|
|||||||
NEWUSER NamespaceType = "NEWUSER"
|
NEWUSER NamespaceType = "NEWUSER"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NamespaceTypes() []NamespaceType {
|
||||||
|
return []NamespaceType{
|
||||||
|
NEWNET,
|
||||||
|
NEWPID,
|
||||||
|
NEWNS,
|
||||||
|
NEWUTS,
|
||||||
|
NEWIPC,
|
||||||
|
NEWUSER,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Namespace defines configuration for each namespace. It specifies an
|
// Namespace defines configuration for each namespace. It specifies an
|
||||||
// alternate path that is able to be joined via setns.
|
// alternate path that is able to be joined via setns.
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
@ -23,10 +31,6 @@ type Namespace struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Namespace) Syscall() int {
|
|
||||||
return namespaceInfo[n.Type]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) GetPath(pid int) string {
|
func (n *Namespace) GetPath(pid int) string {
|
||||||
if n.Path != "" {
|
if n.Path != "" {
|
||||||
return n.Path
|
return n.Path
|
||||||
@ -85,25 +89,3 @@ func (n *Namespaces) index(t NamespaceType) int {
|
|||||||
func (n *Namespaces) Contains(t NamespaceType) bool {
|
func (n *Namespaces) Contains(t NamespaceType) bool {
|
||||||
return n.index(t) != -1
|
return n.index(t) != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespaceInfo = map[NamespaceType]int{
|
|
||||||
NEWNET: syscall.CLONE_NEWNET,
|
|
||||||
NEWNS: syscall.CLONE_NEWNS,
|
|
||||||
NEWUSER: syscall.CLONE_NEWUSER,
|
|
||||||
NEWIPC: syscall.CLONE_NEWIPC,
|
|
||||||
NEWUTS: syscall.CLONE_NEWUTS,
|
|
||||||
NEWPID: syscall.CLONE_NEWPID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloneFlags parses the container's Namespaces options to set the correct
|
|
||||||
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
|
||||||
func (n *Namespaces) CloneFlags() uintptr {
|
|
||||||
var flag int
|
|
||||||
for _, v := range *n {
|
|
||||||
if v.Path != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
flag |= namespaceInfo[v.Type]
|
|
||||||
}
|
|
||||||
return uintptr(flag)
|
|
||||||
}
|
|
||||||
|
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall.go
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package configs
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func (n *Namespace) Syscall() int {
|
||||||
|
return namespaceInfo[n.Type]
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespaceInfo = map[NamespaceType]int{
|
||||||
|
NEWNET: syscall.CLONE_NEWNET,
|
||||||
|
NEWNS: syscall.CLONE_NEWNS,
|
||||||
|
NEWUSER: syscall.CLONE_NEWUSER,
|
||||||
|
NEWIPC: syscall.CLONE_NEWIPC,
|
||||||
|
NEWUTS: syscall.CLONE_NEWUTS,
|
||||||
|
NEWPID: syscall.CLONE_NEWPID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneFlags parses the container's Namespaces options to set the correct
|
||||||
|
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
||||||
|
func (n *Namespaces) CloneFlags() uintptr {
|
||||||
|
var flag int
|
||||||
|
for _, v := range *n {
|
||||||
|
if v.Path != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
flag |= namespaceInfo[v.Type]
|
||||||
|
}
|
||||||
|
return uintptr(flag)
|
||||||
|
}
|
15
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall_unsupported.go
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package configs
|
||||||
|
|
||||||
|
func (n *Namespace) Syscall() int {
|
||||||
|
panic("No namespace syscall support")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneFlags parses the container's Namespaces options to set the correct
|
||||||
|
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
||||||
|
func (n *Namespaces) CloneFlags() uintptr {
|
||||||
|
panic("No namespace syscall support")
|
||||||
|
return uintptr(0)
|
||||||
|
}
|
4
Godeps/_workspace/src/github.com/docker/libcontainer/configs/network.go
generated
vendored
4
Godeps/_workspace/src/github.com/docker/libcontainer/configs/network.go
generated
vendored
@ -2,7 +2,7 @@ package configs
|
|||||||
|
|
||||||
// Network defines configuration for a container's networking stack
|
// Network defines configuration for a container's networking stack
|
||||||
//
|
//
|
||||||
// The network configuration can be omited from a container causing the
|
// The network configuration can be omitted from a container causing the
|
||||||
// container to be setup with the host's networking stack
|
// container to be setup with the host's networking stack
|
||||||
type Network struct {
|
type Network struct {
|
||||||
// Type sets the networks type, commonly veth and loopback
|
// Type sets the networks type, commonly veth and loopback
|
||||||
@ -53,7 +53,7 @@ type Network struct {
|
|||||||
// Routes can be specified to create entries in the route table as the container is started
|
// Routes can be specified to create entries in the route table as the container is started
|
||||||
//
|
//
|
||||||
// All of destination, source, and gateway should be either IPv4 or IPv6.
|
// All of destination, source, and gateway should be either IPv4 or IPv6.
|
||||||
// One of the three options must be present, and ommitted entries will use their
|
// One of the three options must be present, and omitted entries will use their
|
||||||
// IP family default for the route table. For IPv4 for example, setting the
|
// IP family default for the route table. For IPv4 for example, setting the
|
||||||
// gateway to 1.2.3.4 and the interface to eth0 will set up a standard
|
// gateway to 1.2.3.4 and the interface to eth0 will set up a standard
|
||||||
// destination of 0.0.0.0(or *) when viewed in the route table.
|
// destination of 0.0.0.0(or *) when viewed in the route table.
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/console_linux.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/console_linux.go
generated
vendored
@ -38,7 +38,7 @@ func newConsole(uid, gid int) (Console, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newConsoleFromPath is an internal fucntion returning an initialzied console for use inside
|
// newConsoleFromPath is an internal function returning an initialized console for use inside
|
||||||
// a container's MNT namespace.
|
// a container's MNT namespace.
|
||||||
func newConsoleFromPath(slavePath string) *linuxConsole {
|
func newConsoleFromPath(slavePath string) *linuxConsole {
|
||||||
return &linuxConsole{
|
return &linuxConsole{
|
||||||
|
10
Godeps/_workspace/src/github.com/docker/libcontainer/container.go
generated
vendored
10
Godeps/_workspace/src/github.com/docker/libcontainer/container.go
generated
vendored
@ -67,7 +67,7 @@ type Container interface {
|
|||||||
// State returns the current container's state information.
|
// State returns the current container's state information.
|
||||||
//
|
//
|
||||||
// errors:
|
// errors:
|
||||||
// Systemerror - System erroor.
|
// Systemerror - System error.
|
||||||
State() (*State, error)
|
State() (*State, error)
|
||||||
|
|
||||||
// Returns the current config of the container.
|
// Returns the current config of the container.
|
||||||
@ -108,14 +108,6 @@ type Container interface {
|
|||||||
// Systemerror - System error.
|
// Systemerror - System error.
|
||||||
Start(process *Process) (err error)
|
Start(process *Process) (err error)
|
||||||
|
|
||||||
// Charge the resource usage of the specified process to this container.
|
|
||||||
// Does not join the namespaces of the container.
|
|
||||||
//
|
|
||||||
// errors:
|
|
||||||
// ContainerDestroyed - Container no longer exists,
|
|
||||||
// Systemerror - System error.
|
|
||||||
ChargeProcess(pid int) error
|
|
||||||
|
|
||||||
// Destroys the container after killing all running processes.
|
// Destroys the container after killing all running processes.
|
||||||
//
|
//
|
||||||
// Any event registrations are removed before the container is destroyed.
|
// Any event registrations are removed before the container is destroyed.
|
||||||
|
22
Godeps/_workspace/src/github.com/docker/libcontainer/container_linux.go
generated
vendored
22
Godeps/_workspace/src/github.com/docker/libcontainer/container_linux.go
generated
vendored
@ -16,6 +16,8 @@ import (
|
|||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const stdioFdCount = 3
|
||||||
|
|
||||||
type linuxContainer struct {
|
type linuxContainer struct {
|
||||||
id string
|
id string
|
||||||
root string
|
root string
|
||||||
@ -112,10 +114,6 @@ func (c *linuxContainer) Start(process *Process) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) ChargeProcess(pid int) error {
|
|
||||||
return c.cgroupManager.EnterProcess(pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
|
func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
|
||||||
parentPipe, childPipe, err := newPipe()
|
parentPipe, childPipe, err := newPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -143,8 +141,11 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
|
|||||||
if cmd.SysProcAttr == nil {
|
if cmd.SysProcAttr == nil {
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||||
}
|
}
|
||||||
cmd.ExtraFiles = []*os.File{childPipe}
|
cmd.ExtraFiles = append(p.ExtraFiles, childPipe)
|
||||||
cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
|
cmd.Env = append(cmd.Env, fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", stdioFdCount+len(cmd.ExtraFiles)-1))
|
||||||
|
// NOTE: when running a container with no PID namespace and the parent process spawning the container is
|
||||||
|
// PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason
|
||||||
|
// even with the parent still running.
|
||||||
if c.config.ParentDeathSignal > 0 {
|
if c.config.ParentDeathSignal > 0 {
|
||||||
cmd.SysProcAttr.Pdeathsig = syscall.Signal(c.config.ParentDeathSignal)
|
cmd.SysProcAttr.Pdeathsig = syscall.Signal(c.config.ParentDeathSignal)
|
||||||
}
|
}
|
||||||
@ -180,11 +181,9 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe,
|
|||||||
fmt.Sprintf("_LIBCONTAINER_INITPID=%d", c.initProcess.pid()),
|
fmt.Sprintf("_LIBCONTAINER_INITPID=%d", c.initProcess.pid()),
|
||||||
"_LIBCONTAINER_INITTYPE=setns",
|
"_LIBCONTAINER_INITTYPE=setns",
|
||||||
)
|
)
|
||||||
|
|
||||||
if p.consolePath != "" {
|
if p.consolePath != "" {
|
||||||
cmd.Env = append(cmd.Env, "_LIBCONTAINER_CONSOLE_PATH="+p.consolePath)
|
cmd.Env = append(cmd.Env, "_LIBCONTAINER_CONSOLE_PATH="+p.consolePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: set on container for process management
|
// TODO: set on container for process management
|
||||||
return &setnsProcess{
|
return &setnsProcess{
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
@ -204,6 +203,7 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
|
|||||||
Cwd: process.Cwd,
|
Cwd: process.Cwd,
|
||||||
Console: process.consolePath,
|
Console: process.consolePath,
|
||||||
Capabilities: process.Capabilities,
|
Capabilities: process.Capabilities,
|
||||||
|
PassedFilesCount: len(process.ExtraFiles),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,5 +308,11 @@ func (c *linuxContainer) currentState() (*State, error) {
|
|||||||
for _, ns := range c.config.Namespaces {
|
for _, ns := range c.config.Namespaces {
|
||||||
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
||||||
}
|
}
|
||||||
|
for _, nsType := range configs.NamespaceTypes() {
|
||||||
|
if _, ok := state.NamespacePaths[nsType]; !ok {
|
||||||
|
ns := configs.Namespace{Type: nsType}
|
||||||
|
state.NamespacePaths[ns.Type] = ns.GetPath(c.initProcess.pid())
|
||||||
|
}
|
||||||
|
}
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/container_linux_test.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/container_linux_test.go
generated
vendored
@ -33,10 +33,6 @@ func (m *mockCgroupManager) Set(container *configs.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockCgroupManager) ChargeProcess(pid int) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockCgroupManager) Destroy() error {
|
func (m *mockCgroupManager) Destroy() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -134,7 +130,8 @@ func TestGetContainerState(t *testing.T) {
|
|||||||
{Type: configs.NEWNS},
|
{Type: configs.NEWNS},
|
||||||
{Type: configs.NEWNET, Path: expectedNetworkPath},
|
{Type: configs.NEWNET, Path: expectedNetworkPath},
|
||||||
{Type: configs.NEWUTS},
|
{Type: configs.NEWUTS},
|
||||||
{Type: configs.NEWIPC},
|
// emulate host for IPC
|
||||||
|
//{Type: configs.NEWIPC},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
initProcess: &mockProcess{
|
initProcess: &mockProcess{
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
@ -21,7 +21,7 @@ var (
|
|||||||
ioutilReadDir = ioutil.ReadDir
|
ioutilReadDir = ioutil.ReadDir
|
||||||
)
|
)
|
||||||
|
|
||||||
// Given the path to a device and it's cgroup_permissions(which cannot be easilly queried) look up the information about a linux device and return that information as a Device struct.
|
// Given the path to a device and it's cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
|
||||||
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
||||||
fileInfo, err := osLstat(path)
|
fileInfo, err := osLstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
12
Godeps/_workspace/src/github.com/docker/libcontainer/factory.go
generated
vendored
12
Godeps/_workspace/src/github.com/docker/libcontainer/factory.go
generated
vendored
@ -32,15 +32,13 @@ type Factory interface {
|
|||||||
// System error
|
// System error
|
||||||
Load(id string) (Container, error)
|
Load(id string) (Container, error)
|
||||||
|
|
||||||
// StartInitialization is an internal API to libcontainer used during the rexec of the
|
// StartInitialization is an internal API to libcontainer used during the reexec of the
|
||||||
// container. pipefd is the fd to the child end of the pipe used to syncronize the
|
// container.
|
||||||
// parent and child process providing state and configuration to the child process and
|
|
||||||
// returning any errors during the init of the container
|
|
||||||
//
|
//
|
||||||
// Errors:
|
// Errors:
|
||||||
// pipe connection error
|
// Pipe connection error
|
||||||
// system error
|
// System error
|
||||||
StartInitialization(pipefd uintptr) error
|
StartInitialization() error
|
||||||
|
|
||||||
// Type returns info string about factory type (e.g. lxc, libcontainer...)
|
// Type returns info string about factory type (e.g. lxc, libcontainer...)
|
||||||
Type() string
|
Type() string
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/factory_linux.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/factory_linux.go
generated
vendored
@ -10,6 +10,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
@ -194,7 +195,11 @@ func (l *LinuxFactory) Type() string {
|
|||||||
|
|
||||||
// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
|
// 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
|
// This is a low level implementation detail of the reexec and should not be consumed externally
|
||||||
func (l *LinuxFactory) StartInitialization(pipefd uintptr) (err error) {
|
func (l *LinuxFactory) StartInitialization() (err error) {
|
||||||
|
pipefd, err := strconv.Atoi(os.Getenv("_LIBCONTAINER_INITPIPE"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
pipe = os.NewFile(uintptr(pipefd), "pipe")
|
pipe = os.NewFile(uintptr(pipefd), "pipe")
|
||||||
it = initType(os.Getenv("_LIBCONTAINER_INITTYPE"))
|
it = initType(os.Getenv("_LIBCONTAINER_INITTYPE"))
|
||||||
|
6
Godeps/_workspace/src/github.com/docker/libcontainer/init_linux.go
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/init_linux.go
generated
vendored
@ -48,6 +48,7 @@ type initConfig struct {
|
|||||||
Config *configs.Config `json:"config"`
|
Config *configs.Config `json:"config"`
|
||||||
Console string `json:"console"`
|
Console string `json:"console"`
|
||||||
Networks []*network `json:"network"`
|
Networks []*network `json:"network"`
|
||||||
|
PassedFilesCount int `json:"passed_files_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type initer interface {
|
type initer interface {
|
||||||
@ -69,6 +70,7 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
case initStandard:
|
case initStandard:
|
||||||
return &linuxStandardInit{
|
return &linuxStandardInit{
|
||||||
|
parentPid: syscall.Getppid(),
|
||||||
config: config,
|
config: config,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -94,10 +96,10 @@ func populateProcessEnvironment(env []string) error {
|
|||||||
// and working dir, and closes any leaked file descriptors
|
// and working dir, and closes any leaked file descriptors
|
||||||
// before executing the command inside the namespace
|
// before executing the command inside the namespace
|
||||||
func finalizeNamespace(config *initConfig) error {
|
func finalizeNamespace(config *initConfig) error {
|
||||||
// Ensure that all non-standard fds we may have accidentally
|
// Ensure that all unwanted fds we may have accidentally
|
||||||
// inherited are marked close-on-exec so they stay out of the
|
// inherited are marked close-on-exec so they stay out of the
|
||||||
// container
|
// container
|
||||||
if err := utils.CloseExecFrom(3); err != nil {
|
if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
480
Godeps/_workspace/src/github.com/docker/libcontainer/integration/exec_test.go
generated
vendored
480
Godeps/_workspace/src/github.com/docker/libcontainer/integration/exec_test.go
generated
vendored
@ -4,11 +4,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
|
"github.com/docker/libcontainer/cgroups/systemd"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,9 +31,7 @@ func testExecPS(t *testing.T, userns bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
if userns {
|
if userns {
|
||||||
@ -63,21 +64,15 @@ func TestIPCPrivate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
l, err := os.Readlink("/proc/1/ns/ipc")
|
l, err := os.Readlink("/proc/1/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
||||||
@ -94,22 +89,16 @@ func TestIPCHost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
l, err := os.Readlink("/proc/1/ns/ipc")
|
l, err := os.Readlink("/proc/1/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
config.Namespaces.Remove(configs.NEWIPC)
|
config.Namespaces.Remove(configs.NEWIPC)
|
||||||
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
||||||
@ -126,23 +115,17 @@ func TestIPCJoinPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
l, err := os.Readlink("/proc/1/ns/ipc")
|
l, err := os.Readlink("/proc/1/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
config.Namespaces.Add(configs.NEWIPC, "/proc/1/ns/ipc")
|
config.Namespaces.Add(configs.NEWIPC, "/proc/1/ns/ipc")
|
||||||
|
|
||||||
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
|
||||||
@ -159,9 +142,7 @@ func TestIPCBadPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
@ -179,16 +160,12 @@ func TestRlimit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n")
|
out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n")
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if limit := strings.TrimSpace(out.Stdout.String()); limit != "1025" {
|
if limit := strings.TrimSpace(out.Stdout.String()); limit != "1025" {
|
||||||
t.Fatalf("expected rlimit to be 1025, got %s", limit)
|
t.Fatalf("expected rlimit to be 1025, got %s", limit)
|
||||||
}
|
}
|
||||||
@ -207,9 +184,7 @@ func newTestRoot() (string, error) {
|
|||||||
|
|
||||||
func waitProcess(p *libcontainer.Process, t *testing.T) {
|
func waitProcess(p *libcontainer.Process, t *testing.T) {
|
||||||
status, err := p.Wait()
|
status, err := p.Wait()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !status.Success() {
|
if !status.Success() {
|
||||||
t.Fatal(status)
|
t.Fatal(status)
|
||||||
}
|
}
|
||||||
@ -220,35 +195,22 @@ func TestEnter(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
root, err := newTestRoot()
|
root, err := newTestRoot()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
|
|
||||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := factory.Create("test", config)
|
container, err := factory.Create("test", config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
// Execute a first process in the container
|
// Execute a first process in the container
|
||||||
stdinR, stdinW, err := os.Pipe()
|
stdinR, stdinW, err := os.Pipe()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stdout, stdout2 bytes.Buffer
|
var stdout, stdout2 bytes.Buffer
|
||||||
|
|
||||||
@ -261,19 +223,13 @@ func TestEnter(t *testing.T) {
|
|||||||
err = container.Start(&pconfig)
|
err = container.Start(&pconfig)
|
||||||
stdinR.Close()
|
stdinR.Close()
|
||||||
defer stdinW.Close()
|
defer stdinW.Close()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
pid, err := pconfig.Pid()
|
pid, err := pconfig.Pid()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute another process in the container
|
// Execute another process in the container
|
||||||
stdinR2, stdinW2, err := os.Pipe()
|
stdinR2, stdinW2, err := os.Pipe()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
pconfig2 := libcontainer.Process{
|
pconfig2 := libcontainer.Process{
|
||||||
Env: standardEnvironment,
|
Env: standardEnvironment,
|
||||||
}
|
}
|
||||||
@ -284,19 +240,13 @@ func TestEnter(t *testing.T) {
|
|||||||
err = container.Start(&pconfig2)
|
err = container.Start(&pconfig2)
|
||||||
stdinR2.Close()
|
stdinR2.Close()
|
||||||
defer stdinW2.Close()
|
defer stdinW2.Close()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pid2, err := pconfig2.Pid()
|
pid2, err := pconfig2.Pid()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
processes, err := container.Processes()
|
processes, err := container.Processes()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
for i := range processes {
|
for i := range processes {
|
||||||
@ -317,14 +267,10 @@ func TestEnter(t *testing.T) {
|
|||||||
|
|
||||||
// Check that both processes live in the same pidns
|
// Check that both processes live in the same pidns
|
||||||
pidns := string(stdout.Bytes())
|
pidns := string(stdout.Bytes())
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pidns2 := string(stdout2.Bytes())
|
pidns2 := string(stdout2.Bytes())
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pidns != pidns2 {
|
if pidns != pidns2 {
|
||||||
t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2)
|
t.Fatal("The second process isn't in the required pid namespace", pidns, pidns2)
|
||||||
@ -336,28 +282,17 @@ func TestProcessEnv(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
root, err := newTestRoot()
|
root, err := newTestRoot()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
|
|
||||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := factory.Create("test", config)
|
container, err := factory.Create("test", config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
var stdout bytes.Buffer
|
var stdout bytes.Buffer
|
||||||
@ -373,17 +308,12 @@ func TestProcessEnv(t *testing.T) {
|
|||||||
Stdout: &stdout,
|
Stdout: &stdout,
|
||||||
}
|
}
|
||||||
err = container.Start(&pconfig)
|
err = container.Start(&pconfig)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for process
|
// Wait for process
|
||||||
waitProcess(&pconfig, t)
|
waitProcess(&pconfig, t)
|
||||||
|
|
||||||
outputEnv := string(stdout.Bytes())
|
outputEnv := string(stdout.Bytes())
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the environment has the key/value pair we added
|
// Check that the environment has the key/value pair we added
|
||||||
if !strings.Contains(outputEnv, "FOO=BAR") {
|
if !strings.Contains(outputEnv, "FOO=BAR") {
|
||||||
@ -401,28 +331,17 @@ func TestProcessCaps(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
root, err := newTestRoot()
|
root, err := newTestRoot()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(root)
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
|
|
||||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := factory.Create("test", config)
|
container, err := factory.Create("test", config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
processCaps := append(config.Capabilities, "NET_ADMIN")
|
processCaps := append(config.Capabilities, "NET_ADMIN")
|
||||||
@ -436,17 +355,12 @@ func TestProcessCaps(t *testing.T) {
|
|||||||
Stdout: &stdout,
|
Stdout: &stdout,
|
||||||
}
|
}
|
||||||
err = container.Start(&pconfig)
|
err = container.Start(&pconfig)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for process
|
// Wait for process
|
||||||
waitProcess(&pconfig, t)
|
waitProcess(&pconfig, t)
|
||||||
|
|
||||||
outputStatus := string(stdout.Bytes())
|
outputStatus := string(stdout.Bytes())
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := strings.Split(outputStatus, "\n")
|
lines := strings.Split(outputStatus, "\n")
|
||||||
|
|
||||||
@ -481,6 +395,108 @@ func TestProcessCaps(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFreeze(t *testing.T) {
|
func TestFreeze(t *testing.T) {
|
||||||
|
testFreeze(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSystemdFreeze(t *testing.T) {
|
||||||
|
if !systemd.UseSystemd() {
|
||||||
|
t.Skip("Systemd is unsupported")
|
||||||
|
}
|
||||||
|
testFreeze(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFreeze(t *testing.T, systemd bool) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root, err := newTestRoot()
|
||||||
|
ok(t, err)
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
ok(t, err)
|
||||||
|
defer remove(rootfs)
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
f := factory
|
||||||
|
if systemd {
|
||||||
|
f = systemdFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
container, err := f.Create("test", config)
|
||||||
|
ok(t, err)
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
stdinR, stdinW, err := os.Pipe()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
pconfig := libcontainer.Process{
|
||||||
|
Args: []string{"cat"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: stdinR,
|
||||||
|
}
|
||||||
|
err = container.Start(&pconfig)
|
||||||
|
stdinR.Close()
|
||||||
|
defer stdinW.Close()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
pid, err := pconfig.Pid()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
err = container.Pause()
|
||||||
|
ok(t, err)
|
||||||
|
state, err := container.Status()
|
||||||
|
ok(t, err)
|
||||||
|
err = container.Resume()
|
||||||
|
ok(t, err)
|
||||||
|
if state != libcontainer.Paused {
|
||||||
|
t.Fatal("Unexpected state: ", state)
|
||||||
|
}
|
||||||
|
|
||||||
|
stdinW.Close()
|
||||||
|
s, err := process.Wait()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
if !s.Success() {
|
||||||
|
t.Fatal(s.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCpuShares(t *testing.T) {
|
||||||
|
testCpuShares(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSystemdCpuShares(t *testing.T) {
|
||||||
|
if !systemd.UseSystemd() {
|
||||||
|
t.Skip("Systemd is unsupported")
|
||||||
|
}
|
||||||
|
testCpuShares(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCpuShares(t *testing.T, systemd bool) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
ok(t, err)
|
||||||
|
defer remove(rootfs)
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
if systemd {
|
||||||
|
config.Cgroups.Slice = "system.slice"
|
||||||
|
}
|
||||||
|
config.Cgroups.CpuShares = 1
|
||||||
|
|
||||||
|
_, _, err = runContainer(config, "", "ps")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("runContainer should failed with invalid CpuShares")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerState(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -496,13 +512,21 @@ func TestFreeze(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
|
|
||||||
config := newTemplateConfig(rootfs)
|
l, err := os.Readlink("/proc/1/ns/ipc")
|
||||||
|
|
||||||
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
config.Namespaces = configs.Namespaces([]configs.Namespace{
|
||||||
|
{Type: configs.NEWNS},
|
||||||
|
{Type: configs.NEWUTS},
|
||||||
|
// host for IPC
|
||||||
|
//{Type: configs.NEWIPC},
|
||||||
|
{Type: configs.NEWPID},
|
||||||
|
{Type: configs.NEWNET},
|
||||||
|
})
|
||||||
|
|
||||||
container, err := factory.Create("test", config)
|
container, err := factory.Create("test", config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -513,49 +537,199 @@ func TestFreeze(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
p := &libcontainer.Process{
|
||||||
pconfig := libcontainer.Process{
|
|
||||||
Args: []string{"cat"},
|
Args: []string{"cat"},
|
||||||
Env: standardEnvironment,
|
Env: standardEnvironment,
|
||||||
Stdin: stdinR,
|
Stdin: stdinR,
|
||||||
}
|
}
|
||||||
err = container.Start(&pconfig)
|
err = container.Start(p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
stdinR.Close()
|
stdinR.Close()
|
||||||
defer stdinW.Close()
|
defer p.Signal(os.Kill)
|
||||||
|
|
||||||
|
st, err := container.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pid, err := pconfig.Pid()
|
l1, err := os.Readlink(st.NamespacePaths[configs.NEWIPC])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if l1 != l {
|
||||||
process, err := os.FindProcess(pid)
|
t.Fatal("Container using non-host ipc namespace")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.Pause(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
state, err := container.Status()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := container.Resume(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if state != libcontainer.Paused {
|
|
||||||
t.Fatal("Unexpected state: ", state)
|
|
||||||
}
|
|
||||||
|
|
||||||
stdinW.Close()
|
stdinW.Close()
|
||||||
s, err := process.Wait()
|
p.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPassExtraFiles(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !s.Success() {
|
defer remove(rootfs)
|
||||||
t.Fatal(s.String())
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
|
||||||
|
container, err := factory.Create("test", config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
pipeout1, pipein1, err := os.Pipe()
|
||||||
|
pipeout2, pipein2, err := os.Pipe()
|
||||||
|
process := libcontainer.Process{
|
||||||
|
Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"},
|
||||||
|
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||||
|
ExtraFiles: []*os.File{pipein1, pipein2},
|
||||||
|
Stdin: nil,
|
||||||
|
Stdout: &stdout,
|
||||||
|
}
|
||||||
|
err = container.Start(&process)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
waitProcess(&process, t)
|
||||||
|
|
||||||
|
out := string(stdout.Bytes())
|
||||||
|
// fd 5 is the directory handle for /proc/$$/fd
|
||||||
|
if out != "0 1 2 3 4 5" {
|
||||||
|
t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to init, got '%s'", out)
|
||||||
|
}
|
||||||
|
var buf = []byte{0}
|
||||||
|
_, err = pipeout1.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
out1 := string(buf)
|
||||||
|
if out1 != "1" {
|
||||||
|
t.Fatalf("expected first pipe to receive '1', got '%s'", out1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = pipeout2.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
out2 := string(buf)
|
||||||
|
if out2 != "2" {
|
||||||
|
t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMountCmds(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root, err := newTestRoot()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer remove(rootfs)
|
||||||
|
|
||||||
|
tmpDir, err := ioutil.TempDir("", "tmpdir")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
config.Mounts = append(config.Mounts, &configs.Mount{
|
||||||
|
Source: tmpDir,
|
||||||
|
Destination: filepath.Join(rootfs, "tmp"),
|
||||||
|
Device: "bind",
|
||||||
|
Flags: syscall.MS_BIND | syscall.MS_REC,
|
||||||
|
PremountCmds: []configs.Command{
|
||||||
|
{Path: "touch", Args: []string{filepath.Join(tmpDir, "hello")}},
|
||||||
|
{Path: "touch", Args: []string{filepath.Join(tmpDir, "world")}},
|
||||||
|
},
|
||||||
|
PostmountCmds: []configs.Command{
|
||||||
|
{Path: "cp", Args: []string{filepath.Join(rootfs, "tmp", "hello"), filepath.Join(rootfs, "tmp", "hello-backup")}},
|
||||||
|
{Path: "cp", Args: []string{filepath.Join(rootfs, "tmp", "world"), filepath.Join(rootfs, "tmp", "world-backup")}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
container, err := factory.Create("test", config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
pconfig := libcontainer.Process{
|
||||||
|
Args: []string{"sh", "-c", "env"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
}
|
||||||
|
err = container.Start(&pconfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for process
|
||||||
|
waitProcess(&pconfig, t)
|
||||||
|
|
||||||
|
entries, err := ioutil.ReadDir(tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expected := []string{"hello", "hello-backup", "world", "world-backup"}
|
||||||
|
for i, e := range entries {
|
||||||
|
if e.Name() != expected[i] {
|
||||||
|
t.Errorf("Got(%s), expect %s", e.Name(), expected[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSystemProperties(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root, err := newTestRoot()
|
||||||
|
ok(t, err)
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
ok(t, err)
|
||||||
|
defer remove(rootfs)
|
||||||
|
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
config.SystemProperties = map[string]string{
|
||||||
|
"kernel.shmmni": "8192",
|
||||||
|
}
|
||||||
|
|
||||||
|
container, err := factory.Create("test", config)
|
||||||
|
ok(t, err)
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
pconfig := libcontainer.Process{
|
||||||
|
Args: []string{"sh", "-c", "cat /proc/sys/kernel/shmmni"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: nil,
|
||||||
|
Stdout: &stdout,
|
||||||
|
}
|
||||||
|
err = container.Start(&pconfig)
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
// Wait for process
|
||||||
|
waitProcess(&pconfig, t)
|
||||||
|
|
||||||
|
shmmniOutput := strings.TrimSpace(string(stdout.Bytes()))
|
||||||
|
if shmmniOutput != "8192" {
|
||||||
|
t.Fatalf("kernel.shmmni property expected to be 8192, but is %s", shmmniOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
310
Godeps/_workspace/src/github.com/docker/libcontainer/integration/execin_test.go
generated
vendored
310
Godeps/_workspace/src/github.com/docker/libcontainer/integration/execin_test.go
generated
vendored
@ -16,22 +16,16 @@ func TestExecIn(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
container, err := newContainer(config)
|
container, err := newContainer(config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
// Execute a first process in the container
|
// Execute a first process in the container
|
||||||
stdinR, stdinW, err := os.Pipe()
|
stdinR, stdinW, err := os.Pipe()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
process := &libcontainer.Process{
|
process := &libcontainer.Process{
|
||||||
Args: []string{"cat"},
|
Args: []string{"cat"},
|
||||||
Env: standardEnvironment,
|
Env: standardEnvironment,
|
||||||
@ -40,9 +34,7 @@ func TestExecIn(t *testing.T) {
|
|||||||
err = container.Start(process)
|
err = container.Start(process)
|
||||||
stdinR.Close()
|
stdinR.Close()
|
||||||
defer stdinW.Close()
|
defer stdinW.Close()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers := newStdBuffers()
|
buffers := newStdBuffers()
|
||||||
ps := &libcontainer.Process{
|
ps := &libcontainer.Process{
|
||||||
@ -53,12 +45,9 @@ func TestExecIn(t *testing.T) {
|
|||||||
Stderr: buffers.Stderr,
|
Stderr: buffers.Stderr,
|
||||||
}
|
}
|
||||||
err = container.Start(ps)
|
err = container.Start(ps)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
_, err = ps.Wait()
|
||||||
}
|
ok(t, err)
|
||||||
if _, err := ps.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
stdinW.Close()
|
stdinW.Close()
|
||||||
if _, err := process.Wait(); err != nil {
|
if _, err := process.Wait(); err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -74,21 +63,15 @@ func TestExecInRlimit(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
container, err := newContainer(config)
|
container, err := newContainer(config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
stdinR, stdinW, err := os.Pipe()
|
stdinR, stdinW, err := os.Pipe()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
process := &libcontainer.Process{
|
process := &libcontainer.Process{
|
||||||
Args: []string{"cat"},
|
Args: []string{"cat"},
|
||||||
Env: standardEnvironment,
|
Env: standardEnvironment,
|
||||||
@ -97,9 +80,7 @@ func TestExecInRlimit(t *testing.T) {
|
|||||||
err = container.Start(process)
|
err = container.Start(process)
|
||||||
stdinR.Close()
|
stdinR.Close()
|
||||||
defer stdinW.Close()
|
defer stdinW.Close()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers := newStdBuffers()
|
buffers := newStdBuffers()
|
||||||
ps := &libcontainer.Process{
|
ps := &libcontainer.Process{
|
||||||
@ -110,12 +91,9 @@ func TestExecInRlimit(t *testing.T) {
|
|||||||
Stderr: buffers.Stderr,
|
Stderr: buffers.Stderr,
|
||||||
}
|
}
|
||||||
err = container.Start(ps)
|
err = container.Start(ps)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
_, err = ps.Wait()
|
||||||
}
|
ok(t, err)
|
||||||
if _, err := ps.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
stdinW.Close()
|
stdinW.Close()
|
||||||
if _, err := process.Wait(); err != nil {
|
if _, err := process.Wait(); err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
@ -131,22 +109,16 @@ func TestExecInError(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
rootfs, err := newRootfs()
|
rootfs, err := newRootfs()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer remove(rootfs)
|
defer remove(rootfs)
|
||||||
config := newTemplateConfig(rootfs)
|
config := newTemplateConfig(rootfs)
|
||||||
container, err := newContainer(config)
|
container, err := newContainer(config)
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
defer container.Destroy()
|
||||||
|
|
||||||
// Execute a first process in the container
|
// Execute a first process in the container
|
||||||
stdinR, stdinW, err := os.Pipe()
|
stdinR, stdinW, err := os.Pipe()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
process := &libcontainer.Process{
|
process := &libcontainer.Process{
|
||||||
Args: []string{"cat"},
|
Args: []string{"cat"},
|
||||||
Env: standardEnvironment,
|
Env: standardEnvironment,
|
||||||
@ -160,9 +132,7 @@ func TestExecInError(t *testing.T) {
|
|||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
ok(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unexistent := &libcontainer.Process{
|
unexistent := &libcontainer.Process{
|
||||||
Args: []string{"unexistent"},
|
Args: []string{"unexistent"},
|
||||||
@ -178,6 +148,121 @@ func TestExecInError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExecInTTY(t *testing.T) {
|
func TestExecInTTY(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
ok(t, err)
|
||||||
|
defer remove(rootfs)
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
container, err := newContainer(config)
|
||||||
|
ok(t, err)
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
// Execute a first process in the container
|
||||||
|
stdinR, stdinW, err := os.Pipe()
|
||||||
|
ok(t, err)
|
||||||
|
process := &libcontainer.Process{
|
||||||
|
Args: []string{"cat"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: stdinR,
|
||||||
|
}
|
||||||
|
err = container.Start(process)
|
||||||
|
stdinR.Close()
|
||||||
|
defer stdinW.Close()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
ps := &libcontainer.Process{
|
||||||
|
Args: []string{"ps"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
}
|
||||||
|
console, err := ps.NewConsole(0)
|
||||||
|
copy := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
io.Copy(&stdout, console)
|
||||||
|
close(copy)
|
||||||
|
}()
|
||||||
|
ok(t, err)
|
||||||
|
err = container.Start(ps)
|
||||||
|
ok(t, err)
|
||||||
|
select {
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("Waiting for copy timed out")
|
||||||
|
case <-copy:
|
||||||
|
}
|
||||||
|
_, err = ps.Wait()
|
||||||
|
ok(t, err)
|
||||||
|
stdinW.Close()
|
||||||
|
if _, err := process.Wait(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
out := stdout.String()
|
||||||
|
if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") {
|
||||||
|
t.Fatalf("unexpected running process, output %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecInEnvironment(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
ok(t, err)
|
||||||
|
defer remove(rootfs)
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
container, err := newContainer(config)
|
||||||
|
ok(t, err)
|
||||||
|
defer container.Destroy()
|
||||||
|
|
||||||
|
// Execute a first process in the container
|
||||||
|
stdinR, stdinW, err := os.Pipe()
|
||||||
|
ok(t, err)
|
||||||
|
process := &libcontainer.Process{
|
||||||
|
Args: []string{"cat"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: stdinR,
|
||||||
|
}
|
||||||
|
err = container.Start(process)
|
||||||
|
stdinR.Close()
|
||||||
|
defer stdinW.Close()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
buffers := newStdBuffers()
|
||||||
|
process2 := &libcontainer.Process{
|
||||||
|
Args: []string{"env"},
|
||||||
|
Env: []string{
|
||||||
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
"DEBUG=true",
|
||||||
|
"DEBUG=false",
|
||||||
|
"ENV=test",
|
||||||
|
},
|
||||||
|
Stdin: buffers.Stdin,
|
||||||
|
Stdout: buffers.Stdout,
|
||||||
|
Stderr: buffers.Stderr,
|
||||||
|
}
|
||||||
|
err = container.Start(process2)
|
||||||
|
ok(t, err)
|
||||||
|
if _, err := process2.Wait(); err != nil {
|
||||||
|
out := buffers.Stdout.String()
|
||||||
|
t.Fatal(err, out)
|
||||||
|
}
|
||||||
|
stdinW.Close()
|
||||||
|
if _, err := process.Wait(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
out := buffers.Stdout.String()
|
||||||
|
// check execin's process environment
|
||||||
|
if !strings.Contains(out, "DEBUG=false") ||
|
||||||
|
!strings.Contains(out, "ENV=test") ||
|
||||||
|
!strings.Contains(out, "HOME=/root") ||
|
||||||
|
!strings.Contains(out, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") ||
|
||||||
|
strings.Contains(out, "DEBUG=true") {
|
||||||
|
t.Fatalf("unexpected running process, output %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecinPassExtraFiles(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -211,106 +296,45 @@ func TestExecInTTY(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stdout bytes.Buffer
|
var stdout bytes.Buffer
|
||||||
ps := &libcontainer.Process{
|
pipeout1, pipein1, err := os.Pipe()
|
||||||
Args: []string{"ps"},
|
pipeout2, pipein2, err := os.Pipe()
|
||||||
Env: standardEnvironment,
|
inprocess := &libcontainer.Process{
|
||||||
|
Args: []string{"sh", "-c", "cd /proc/$$/fd; echo -n *; echo -n 1 >3; echo -n 2 >4"},
|
||||||
|
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||||
|
ExtraFiles: []*os.File{pipein1, pipein2},
|
||||||
|
Stdin: nil,
|
||||||
|
Stdout: &stdout,
|
||||||
}
|
}
|
||||||
console, err := ps.NewConsole(0)
|
err = container.Start(inprocess)
|
||||||
copy := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
io.Copy(&stdout, console)
|
|
||||||
close(copy)
|
|
||||||
}()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = container.Start(ps)
|
|
||||||
if err != nil {
|
waitProcess(inprocess, t)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-time.After(5 * time.Second):
|
|
||||||
t.Fatal("Waiting for copy timed out")
|
|
||||||
case <-copy:
|
|
||||||
}
|
|
||||||
if _, err := ps.Wait(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
stdinW.Close()
|
stdinW.Close()
|
||||||
if _, err := process.Wait(); err != nil {
|
waitProcess(process, t)
|
||||||
t.Log(err)
|
|
||||||
|
out := string(stdout.Bytes())
|
||||||
|
// fd 5 is the directory handle for /proc/$$/fd
|
||||||
|
if out != "0 1 2 3 4 5" {
|
||||||
|
t.Fatalf("expected to have the file descriptors '0 1 2 3 4 5' passed to exec, got '%s'", out)
|
||||||
}
|
}
|
||||||
out := stdout.String()
|
var buf = []byte{0}
|
||||||
if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") {
|
_, err = pipeout1.Read(buf)
|
||||||
t.Fatalf("unexpected running process, output %q", out)
|
if err != nil {
|
||||||
}
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
out1 := string(buf)
|
||||||
func TestExecInEnvironment(t *testing.T) {
|
if out1 != "1" {
|
||||||
if testing.Short() {
|
t.Fatalf("expected first pipe to receive '1', got '%s'", out1)
|
||||||
return
|
}
|
||||||
}
|
|
||||||
rootfs, err := newRootfs()
|
_, err = pipeout2.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer remove(rootfs)
|
out2 := string(buf)
|
||||||
config := newTemplateConfig(rootfs)
|
if out2 != "2" {
|
||||||
container, err := newContainer(config)
|
t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
|
||||||
|
|
||||||
// Execute a first process in the container
|
|
||||||
stdinR, stdinW, err := os.Pipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
process := &libcontainer.Process{
|
|
||||||
Args: []string{"cat"},
|
|
||||||
Env: standardEnvironment,
|
|
||||||
Stdin: stdinR,
|
|
||||||
}
|
|
||||||
err = container.Start(process)
|
|
||||||
stdinR.Close()
|
|
||||||
defer stdinW.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers := newStdBuffers()
|
|
||||||
process2 := &libcontainer.Process{
|
|
||||||
Args: []string{"env"},
|
|
||||||
Env: []string{
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
||||||
"DEBUG=true",
|
|
||||||
"DEBUG=false",
|
|
||||||
"ENV=test",
|
|
||||||
},
|
|
||||||
Stdin: buffers.Stdin,
|
|
||||||
Stdout: buffers.Stdout,
|
|
||||||
Stderr: buffers.Stderr,
|
|
||||||
}
|
|
||||||
err = container.Start(process2)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if _, err := process2.Wait(); err != nil {
|
|
||||||
out := buffers.Stdout.String()
|
|
||||||
t.Fatal(err, out)
|
|
||||||
}
|
|
||||||
stdinW.Close()
|
|
||||||
if _, err := process.Wait(); err != nil {
|
|
||||||
t.Log(err)
|
|
||||||
}
|
|
||||||
out := buffers.Stdout.String()
|
|
||||||
// check execin's process environment
|
|
||||||
if !strings.Contains(out, "DEBUG=false") ||
|
|
||||||
!strings.Contains(out, "ENV=test") ||
|
|
||||||
!strings.Contains(out, "HOME=/root") ||
|
|
||||||
!strings.Contains(out, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") ||
|
|
||||||
strings.Contains(out, "DEBUG=true") {
|
|
||||||
t.Fatalf("unexpected running process, output %q", out)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
Godeps/_workspace/src/github.com/docker/libcontainer/integration/init_test.go
generated
vendored
37
Godeps/_workspace/src/github.com/docker/libcontainer/integration/init_test.go
generated
vendored
@ -1,11 +1,13 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
|
"github.com/docker/libcontainer/cgroups/systemd"
|
||||||
_ "github.com/docker/libcontainer/nsenter"
|
_ "github.com/docker/libcontainer/nsenter"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +23,38 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to initialize for container: %s", err)
|
log.Fatalf("unable to initialize for container: %s", err)
|
||||||
}
|
}
|
||||||
if err := factory.StartInitialization(3); err != nil {
|
if err := factory.StartInitialization(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
factory libcontainer.Factory
|
||||||
|
systemdFactory libcontainer.Factory
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
ret int = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
|
||||||
|
factory, err = libcontainer.New(".", libcontainer.Cgroupfs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if systemd.UseSystemd() {
|
||||||
|
systemdFactory, err = libcontainer.New(".", libcontainer.SystemdCgroups)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m.Run()
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
24
Godeps/_workspace/src/github.com/docker/libcontainer/integration/utils_test.go
generated
vendored
24
Godeps/_workspace/src/github.com/docker/libcontainer/integration/utils_test.go
generated
vendored
@ -6,8 +6,11 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
@ -38,6 +41,14 @@ func (b *stdBuffers) String() string {
|
|||||||
return strings.Join(s, "|")
|
return strings.Join(s, "|")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ok fails the test if an err is not nil.
|
||||||
|
func ok(t testing.TB, err error) {
|
||||||
|
if err != nil {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
t.Fatalf("%s:%d: unexpected error: %s\n\n", filepath.Base(file), line, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// newRootfs creates a new tmp directory and copies the busybox root filesystem
|
// newRootfs creates a new tmp directory and copies the busybox root filesystem
|
||||||
func newRootfs() (string, error) {
|
func newRootfs() (string, error) {
|
||||||
dir, err := ioutil.TempDir("", "")
|
dir, err := ioutil.TempDir("", "")
|
||||||
@ -68,14 +79,13 @@ func copyBusybox(dest string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newContainer(config *configs.Config) (libcontainer.Container, error) {
|
func newContainer(config *configs.Config) (libcontainer.Container, error) {
|
||||||
factory, err := libcontainer.New(".",
|
f := factory
|
||||||
libcontainer.InitArgs(os.Args[0], "init", "--"),
|
|
||||||
libcontainer.Cgroupfs,
|
if config.Cgroups != nil && config.Cgroups.Slice == "system.slice" {
|
||||||
)
|
f = systemdFactory
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return factory.Create("testCT", config)
|
|
||||||
|
return f.Create("testCT", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// runContainer runs the container with the specific config and arguments
|
// runContainer runs the container with the specific config and arguments
|
||||||
|
14
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
14
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
@ -101,10 +101,22 @@ func SetFileCreateLabel(fileLabel string) error {
|
|||||||
// the MCS label should continue to be used. SELinux will use this field
|
// the MCS label should continue to be used. SELinux will use this field
|
||||||
// to make sure the content can not be shared by other containes.
|
// to make sure the content can not be shared by other containes.
|
||||||
func Relabel(path string, fileLabel string, relabel string) error {
|
func Relabel(path string, fileLabel string, relabel string) error {
|
||||||
|
exclude_path := []string{"/", "/usr", "/etc"}
|
||||||
if fileLabel == "" {
|
if fileLabel == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if relabel == "z" {
|
for _, p := range exclude_path {
|
||||||
|
if path == p {
|
||||||
|
return fmt.Errorf("Relabeling of %s is not allowed", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.ContainsAny(relabel, "zZ") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strings.Contains(relabel, "z") && strings.Contains(relabel, "Z") {
|
||||||
|
return fmt.Errorf("Bad SELinux option z and Z can not be used together")
|
||||||
|
}
|
||||||
|
if strings.Contains(relabel, "z") {
|
||||||
c := selinux.NewContext(fileLabel)
|
c := selinux.NewContext(fileLabel)
|
||||||
c["level"] = "s0"
|
c["level"] = "s0"
|
||||||
fileLabel = c.Get()
|
fileLabel = c.Get()
|
||||||
|
28
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux_test.go
generated
vendored
28
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux_test.go
generated
vendored
@ -87,3 +87,31 @@ func TestDuplicateLabel(t *testing.T) {
|
|||||||
t.Errorf("DisableSecOpt Failed level incorrect")
|
t.Errorf("DisableSecOpt Failed level incorrect")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestRelabel(t *testing.T) {
|
||||||
|
testdir := "/tmp/test"
|
||||||
|
label := "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2"
|
||||||
|
if err := Relabel(testdir, "", "z"); err != nil {
|
||||||
|
t.Fatal("Relabel with no label failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := Relabel(testdir, label, ""); err != nil {
|
||||||
|
t.Fatal("Relabel with no relabel field failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := Relabel(testdir, label, "z"); err != nil {
|
||||||
|
t.Fatal("Relabel shared failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := Relabel(testdir, label, "Z"); err != nil {
|
||||||
|
t.Fatal("Relabel unshared failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := Relabel(testdir, label, "zZ"); err == nil {
|
||||||
|
t.Fatal("Relabel with shared and unshared succeeded")
|
||||||
|
}
|
||||||
|
if err := Relabel("/etc", label, "zZ"); err == nil {
|
||||||
|
t.Fatal("Relabel /etc succeeded")
|
||||||
|
}
|
||||||
|
if err := Relabel("/", label, ""); err == nil {
|
||||||
|
t.Fatal("Relabel / succeeded")
|
||||||
|
}
|
||||||
|
if err := Relabel("/usr", label, "Z"); err == nil {
|
||||||
|
t.Fatal("Relabel /usr succeeded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
27
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/README.md
generated
vendored
27
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/README.md
generated
vendored
@ -1,6 +1,25 @@
|
|||||||
## nsenter
|
## nsenter
|
||||||
|
|
||||||
The `nsenter` package registers a special init constructor that is called before the Go runtime has
|
The `nsenter` package registers a special init constructor that is called before
|
||||||
a chance to boot. This provides us the ability to `setns` on existing namespaces and avoid the issues
|
the Go runtime has a chance to boot. This provides us the ability to `setns` on
|
||||||
that the Go runtime has with multiple threads. This constructor is only called if this package is
|
existing namespaces and avoid the issues that the Go runtime has with multiple
|
||||||
registered, imported, in your go application and the argv 0 is `nsenter`.
|
threads. This constructor will be called if this package is registered,
|
||||||
|
imported, in your go application.
|
||||||
|
|
||||||
|
The `nsenter` package will `import "C"` and it uses [cgo](https://golang.org/cmd/cgo/)
|
||||||
|
package. In cgo, if the import of "C" is immediately preceded by a comment, that comment,
|
||||||
|
called the preamble, is used as a header when compiling the C parts of the package.
|
||||||
|
So every time we import package `nsenter`, the C code function `nsexec()` would be
|
||||||
|
called. And package `nsenter` is now only imported in Docker execdriver, so every time
|
||||||
|
before we call `execdriver.Exec()`, that C code would run.
|
||||||
|
|
||||||
|
`nsexec()` will first check the environment variable `_LIBCONTAINER_INITPID`
|
||||||
|
which will give the process of the container that should be joined. Namespaces fd will
|
||||||
|
be found from `/proc/[pid]/ns` and set by `setns` syscall.
|
||||||
|
|
||||||
|
And then get the pipe number from `_LIBCONTAINER_INITPIPE`, error message could
|
||||||
|
be transfered through it. If tty is added, `_LIBCONTAINER_CONSOLE_PATH` will
|
||||||
|
have value and start a console for output.
|
||||||
|
|
||||||
|
Finally, `nsexec()` will clone a child process , exit the parent process and let
|
||||||
|
the Go runtime take over.
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsenter_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsenter_test.go
generated
vendored
@ -24,7 +24,7 @@ func TestNsenterAlivePid(t *testing.T) {
|
|||||||
Path: os.Args[0],
|
Path: os.Args[0],
|
||||||
Args: args,
|
Args: args,
|
||||||
ExtraFiles: []*os.File{w},
|
ExtraFiles: []*os.File{w},
|
||||||
Env: []string{fmt.Sprintf("_LIBCONTAINER_INITPID=%d", os.Getpid())},
|
Env: []string{fmt.Sprintf("_LIBCONTAINER_INITPID=%d", os.Getpid()), "_LIBCONTAINER_INITPIPE=3"},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
23
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsexec.c
generated
vendored
23
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsexec.c
generated
vendored
@ -66,7 +66,7 @@ void nsexec()
|
|||||||
const int num = sizeof(namespaces) / sizeof(char *);
|
const int num = sizeof(namespaces) / sizeof(char *);
|
||||||
jmp_buf env;
|
jmp_buf env;
|
||||||
char buf[PATH_MAX], *val;
|
char buf[PATH_MAX], *val;
|
||||||
int i, tfd, child, len, consolefd = -1;
|
int i, tfd, child, len, pipenum, consolefd = -1;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *console;
|
char *console;
|
||||||
|
|
||||||
@ -81,6 +81,19 @@ void nsexec()
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val = getenv("_LIBCONTAINER_INITPIPE");
|
||||||
|
if (val == NULL) {
|
||||||
|
pr_perror("Child pipe not found");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipenum = atoi(val);
|
||||||
|
snprintf(buf, sizeof(buf), "%d", pipenum);
|
||||||
|
if (strcmp(val, buf)) {
|
||||||
|
pr_perror("Unable to parse _LIBCONTAINER_INITPIPE");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
console = getenv("_LIBCONTAINER_CONSOLE_PATH");
|
console = getenv("_LIBCONTAINER_CONSOLE_PATH");
|
||||||
if (console != NULL) {
|
if (console != NULL) {
|
||||||
consolefd = open(console, O_RDWR);
|
consolefd = open(console, O_RDWR);
|
||||||
@ -124,6 +137,8 @@ void nsexec()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setjmp(env) == 1) {
|
if (setjmp(env) == 1) {
|
||||||
|
// Child
|
||||||
|
|
||||||
if (setsid() == -1) {
|
if (setsid() == -1) {
|
||||||
pr_perror("setsid failed");
|
pr_perror("setsid failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -149,7 +164,11 @@ void nsexec()
|
|||||||
// Finish executing, let the Go runtime take over.
|
// Finish executing, let the Go runtime take over.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Parent
|
||||||
|
|
||||||
|
// We must fork to actually enter the PID namespace, use CLONE_PARENT
|
||||||
|
// so the child can have the right parent, and we don't need to forward
|
||||||
|
// the child's exit code or resend its death signal.
|
||||||
child = clone_parent(&env);
|
child = clone_parent(&env);
|
||||||
if (child < 0) {
|
if (child < 0) {
|
||||||
pr_perror("Unable to fork");
|
pr_perror("Unable to fork");
|
||||||
@ -158,7 +177,7 @@ void nsexec()
|
|||||||
|
|
||||||
len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child);
|
len = snprintf(buf, sizeof(buf), "{ \"pid\" : %d }\n", child);
|
||||||
|
|
||||||
if (write(3, buf, len) != len) {
|
if (write(pipenum, buf, len) != len) {
|
||||||
pr_perror("Unable to send a child pid");
|
pr_perror("Unable to send a child pid");
|
||||||
kill(child, SIGKILL);
|
kill(child, SIGKILL);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
45
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/README.md
generated
vendored
45
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/README.md
generated
vendored
@ -65,3 +65,48 @@ You can identify if a process is running in a container by looking to see if
|
|||||||
|
|
||||||
You may also specify an alternate root directory from where the `container.json`
|
You may also specify an alternate root directory from where the `container.json`
|
||||||
file is read and where the `state.json` file will be saved.
|
file is read and where the `state.json` file will be saved.
|
||||||
|
|
||||||
|
### How to use?
|
||||||
|
|
||||||
|
Currently nsinit has 9 commands. Type `nsinit -h` to list all of them.
|
||||||
|
And for every alternative command, you can also use `--help` to get more
|
||||||
|
detailed help documents. For example, `nsinit config --help`.
|
||||||
|
|
||||||
|
`nsinit` cli application is implemented using [cli.go](https://github.com/codegangsta/cli).
|
||||||
|
Lots of details are handled in cli.go, so the implementation of `nsinit` itself
|
||||||
|
is very clean and clear.
|
||||||
|
|
||||||
|
* **config**
|
||||||
|
It will generate a standard configuration file for a container. By default, it
|
||||||
|
will generate as the template file in [config.go](https://github.com/docker/libcontainer/blob/master/nsinit/config.go#L192).
|
||||||
|
It will modify the template if you have specified some configuration by options.
|
||||||
|
* **exec**
|
||||||
|
Starts a container and execute a new command inside it. Besides common options, it
|
||||||
|
has some special options as below.
|
||||||
|
- `--tty,-t`: allocate a TTY to the container.
|
||||||
|
- `--config`: you can specify a configuration file. By default, it will use
|
||||||
|
template configuration.
|
||||||
|
- `--id`: specify the ID for a container. By default, the id is "nsinit".
|
||||||
|
- `--user,-u`: set the user, uid, and/or gid for the process. By default the
|
||||||
|
value is "root".
|
||||||
|
- `--cwd`: set the current working dir.
|
||||||
|
- `--env`: set environment variables for the process.
|
||||||
|
* **init**
|
||||||
|
It's an internal command that is called inside the container's namespaces to
|
||||||
|
initialize the namespace and exec the user's process. It should not be called
|
||||||
|
externally.
|
||||||
|
* **oom**
|
||||||
|
Display oom notifications for a container, you should specify container id.
|
||||||
|
* **pause**
|
||||||
|
Pause the container's processes, you should specify container id. It will use
|
||||||
|
cgroup freeze subsystem to help.
|
||||||
|
* **unpause**
|
||||||
|
Unpause the container's processes. Same with `pause`.
|
||||||
|
* **stats**
|
||||||
|
Display statistics for the container, it will mainly show cgroup and network
|
||||||
|
statistics.
|
||||||
|
* **state**
|
||||||
|
Get the container's current state. You can also read the state from `state.json`
|
||||||
|
in your container_id folder.
|
||||||
|
* **help, h**
|
||||||
|
Shows a list of commands or help for one command.
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/config.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/config.go
generated
vendored
@ -43,6 +43,7 @@ var createFlags = []cli.Flag{
|
|||||||
cli.StringFlag{Name: "veth-address", Usage: "veth ip address"},
|
cli.StringFlag{Name: "veth-address", Usage: "veth ip address"},
|
||||||
cli.StringFlag{Name: "veth-gateway", Usage: "veth gateway address"},
|
cli.StringFlag{Name: "veth-gateway", Usage: "veth gateway address"},
|
||||||
cli.IntFlag{Name: "veth-mtu", Usage: "veth mtu"},
|
cli.IntFlag{Name: "veth-mtu", Usage: "veth mtu"},
|
||||||
|
cli.BoolFlag{Name: "cgroup", Usage: "mount the cgroup data for the container"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var configCommand = cli.Command{
|
var configCommand = cli.Command{
|
||||||
@ -187,6 +188,12 @@ func modify(config *configs.Config, context *cli.Context) {
|
|||||||
}
|
}
|
||||||
config.Networks = append(config.Networks, network)
|
config.Networks = append(config.Networks, network)
|
||||||
}
|
}
|
||||||
|
if context.Bool("cgroup") {
|
||||||
|
config.Mounts = append(config.Mounts, &configs.Mount{
|
||||||
|
Destination: "/sys/fs/cgroup",
|
||||||
|
Device: "cgroup",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTemplate() *configs.Config {
|
func getTemplate() *configs.Config {
|
||||||
|
1
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/exec.go
generated
vendored
1
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/exec.go
generated
vendored
@ -23,6 +23,7 @@ var execCommand = cli.Command{
|
|||||||
Action: execAction,
|
Action: execAction,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
cli.BoolFlag{Name: "tty,t", Usage: "allocate a TTY to the container"},
|
cli.BoolFlag{Name: "tty,t", Usage: "allocate a TTY to the container"},
|
||||||
|
cli.BoolFlag{Name: "systemd", Usage: "Use systemd for managing cgroups, if available"},
|
||||||
cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"},
|
cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"},
|
||||||
cli.StringFlag{Name: "config", Value: "", Usage: "path to the configuration file"},
|
cli.StringFlag{Name: "config", Value: "", Usage: "path to the configuration file"},
|
||||||
cli.StringFlag{Name: "user,u", Value: "root", Usage: "set the user, uid, and/or gid for the process"},
|
cli.StringFlag{Name: "user,u", Value: "root", Usage: "set the user, uid, and/or gid for the process"},
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/init.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/init.go
generated
vendored
@ -20,7 +20,7 @@ var initCommand = cli.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
if err := factory.StartInitialization(3); err != nil {
|
if err := factory.StartInitialization(); err != nil {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
panic("This line should never been executed")
|
panic("This line should never been executed")
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/main.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/main.go
generated
vendored
@ -13,7 +13,7 @@ func main() {
|
|||||||
app.Version = "2"
|
app.Version = "2"
|
||||||
app.Author = "libcontainer maintainers"
|
app.Author = "libcontainer maintainers"
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
|
cli.StringFlag{Name: "root", Value: "/var/run/nsinit", Usage: "root directory for containers"},
|
||||||
cli.StringFlag{Name: "log-file", Value: "", Usage: "set the log file to output logs to"},
|
cli.StringFlag{Name: "log-file", Value: "", Usage: "set the log file to output logs to"},
|
||||||
cli.BoolFlag{Name: "debug", Usage: "enable debug output in the logs"},
|
cli.BoolFlag{Name: "debug", Usage: "enable debug output in the logs"},
|
||||||
}
|
}
|
||||||
|
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/oom.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/oom.go
generated
vendored
@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/pause.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/pause.go
generated
vendored
@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
12
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/utils.go
generated
vendored
12
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/utils.go
generated
vendored
@ -3,10 +3,12 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
|
"github.com/docker/libcontainer/cgroups/systemd"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +31,15 @@ func loadConfig(context *cli.Context) (*configs.Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
|
func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
|
||||||
return libcontainer.New(context.GlobalString("root"), libcontainer.Cgroupfs)
|
cgm := libcontainer.Cgroupfs
|
||||||
|
if context.Bool("systemd") {
|
||||||
|
if systemd.UseSystemd() {
|
||||||
|
cgm = libcontainer.SystemdCgroups
|
||||||
|
} else {
|
||||||
|
log.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return libcontainer.New(context.GlobalString("root"), cgm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainer(context *cli.Context) (libcontainer.Container, error) {
|
func getContainer(context *cli.Context) (libcontainer.Container, error) {
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/process.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/process.go
generated
vendored
@ -23,7 +23,7 @@ type Process struct {
|
|||||||
Env []string
|
Env []string
|
||||||
|
|
||||||
// User will set the uid and gid of the executing process running inside the container
|
// User will set the uid and gid of the executing process running inside the container
|
||||||
// local to the contaienr's user and group configuration.
|
// local to the container's user and group configuration.
|
||||||
User string
|
User string
|
||||||
|
|
||||||
// Cwd will change the processes current working directory inside the container's rootfs.
|
// Cwd will change the processes current working directory inside the container's rootfs.
|
||||||
@ -38,11 +38,14 @@ type Process struct {
|
|||||||
// Stderr is a pointer to a writer which receives the standard error stream.
|
// Stderr is a pointer to a writer which receives the standard error stream.
|
||||||
Stderr io.Writer
|
Stderr io.Writer
|
||||||
|
|
||||||
|
// ExtraFiles specifies additional open files to be inherited by the container
|
||||||
|
ExtraFiles []*os.File
|
||||||
|
|
||||||
// consolePath is the path to the console allocated to the container.
|
// consolePath is the path to the console allocated to the container.
|
||||||
consolePath string
|
consolePath string
|
||||||
|
|
||||||
// Capabilities specify the capabilities to keep when executing the process inside the container
|
// Capabilities specify the capabilities to keep when executing the process inside the container
|
||||||
// All capbilities not specified will be dropped from the processes capability mask
|
// All capabilities not specified will be dropped from the processes capability mask
|
||||||
Capabilities []string
|
Capabilities []string
|
||||||
|
|
||||||
ops processOperations
|
ops processOperations
|
||||||
|
3
Godeps/_workspace/src/github.com/docker/libcontainer/process_linux.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/process_linux.go
generated
vendored
@ -119,6 +119,9 @@ func (p *setnsProcess) execSetns() error {
|
|||||||
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
||||||
// avoid the process becomming a zombie.
|
// avoid the process becomming a zombie.
|
||||||
func (p *setnsProcess) terminate() error {
|
func (p *setnsProcess) terminate() error {
|
||||||
|
if p.cmd.Process == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
err := p.cmd.Process.Kill()
|
err := p.cmd.Process.Kill()
|
||||||
if _, werr := p.wait(); err == nil {
|
if _, werr := p.wait(); err == nil {
|
||||||
err = werr
|
err = werr
|
||||||
|
80
Godeps/_workspace/src/github.com/docker/libcontainer/rootfs_linux.go
generated
vendored
80
Godeps/_workspace/src/github.com/docker/libcontainer/rootfs_linux.go
generated
vendored
@ -6,11 +6,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
)
|
)
|
||||||
@ -24,9 +27,20 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) {
|
|||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
for _, m := range config.Mounts {
|
for _, m := range config.Mounts {
|
||||||
|
for _, precmd := range m.PremountCmds {
|
||||||
|
if err := mountCmd(precmd); err != nil {
|
||||||
|
return newSystemError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil {
|
if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, postcmd := range m.PostmountCmds {
|
||||||
|
if err := mountCmd(postcmd); err != nil {
|
||||||
|
return newSystemError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := createDevices(config); err != nil {
|
if err := createDevices(config); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
@ -62,6 +76,18 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mountCmd(cmd configs.Command) error {
|
||||||
|
|
||||||
|
command := exec.Command(cmd.Path, cmd.Args[:]...)
|
||||||
|
command.Env = cmd.Env
|
||||||
|
command.Dir = cmd.Dir
|
||||||
|
if out, err := command.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
||||||
var (
|
var (
|
||||||
dest = m.Destination
|
dest = m.Destination
|
||||||
@ -72,11 +98,19 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch m.Device {
|
switch m.Device {
|
||||||
case "proc", "mqueue", "sysfs":
|
case "proc", "sysfs":
|
||||||
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
|
return syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), "")
|
||||||
|
case "mqueue":
|
||||||
|
if err := os.MkdirAll(dest, 0755); err != nil && !os.IsExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags), ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return label.SetFileLabel(dest, mountLabel)
|
||||||
case "tmpfs":
|
case "tmpfs":
|
||||||
stat, err := os.Stat(dest)
|
stat, err := os.Stat(dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -126,6 +160,37 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "cgroup":
|
||||||
|
mounts, err := cgroups.GetCgroupMounts()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var binds []*configs.Mount
|
||||||
|
for _, mm := range mounts {
|
||||||
|
dir, err := mm.GetThisCgroupDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
binds = append(binds, &configs.Mount{
|
||||||
|
Device: "bind",
|
||||||
|
Source: filepath.Join(mm.Mountpoint, dir),
|
||||||
|
Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
|
||||||
|
Flags: syscall.MS_BIND | syscall.MS_REC | syscall.MS_RDONLY,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tmpfs := &configs.Mount{
|
||||||
|
Device: "tmpfs",
|
||||||
|
Destination: m.Destination,
|
||||||
|
Flags: syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV,
|
||||||
|
}
|
||||||
|
if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, b := range binds {
|
||||||
|
if err := mountToRootfs(b, rootfs, mountLabel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
||||||
}
|
}
|
||||||
@ -240,9 +305,9 @@ func mknodDevice(dest string, node *configs.Device) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func prepareRoot(config *configs.Config) error {
|
func prepareRoot(config *configs.Config) error {
|
||||||
flag := syscall.MS_PRIVATE | syscall.MS_REC
|
flag := syscall.MS_SLAVE | syscall.MS_REC
|
||||||
if config.NoPivotRoot {
|
if config.Privatefs {
|
||||||
flag = syscall.MS_SLAVE | syscall.MS_REC
|
flag = syscall.MS_PRIVATE | syscall.MS_REC
|
||||||
}
|
}
|
||||||
if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
|
if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -355,3 +420,10 @@ func maskFile(path string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
|
||||||
|
// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
|
||||||
|
func writeSystemProperty(key, value string) error {
|
||||||
|
keyPath := strings.Replace(key, ".", "/", -1)
|
||||||
|
return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
|
||||||
|
}
|
||||||
|
15
Godeps/_workspace/src/github.com/docker/libcontainer/standard_init_linux.go
generated
vendored
15
Godeps/_workspace/src/github.com/docker/libcontainer/standard_init_linux.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type linuxStandardInit struct {
|
type linuxStandardInit struct {
|
||||||
|
parentPid int
|
||||||
config *initConfig
|
config *initConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +64,13 @@ func (l *linuxStandardInit) Init() error {
|
|||||||
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key, value := range l.config.Config.SystemProperties {
|
||||||
|
if err := writeSystemProperty(key, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, path := range l.config.Config.ReadonlyPaths {
|
for _, path := range l.config.Config.ReadonlyPaths {
|
||||||
if err := remountReadonly(path); err != nil {
|
if err := remountReadonly(path); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -85,9 +93,10 @@ func (l *linuxStandardInit) Init() error {
|
|||||||
if err := pdeath.Restore(); err != nil {
|
if err := pdeath.Restore(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Signal self if parent is already dead. Does nothing if running in a new
|
// compare the parent from the inital start of the init process and make sure that it did not change.
|
||||||
// PID namespace, as Getppid will always return 0.
|
// if the parent changes that means it died and we were reparened to something else so we should
|
||||||
if syscall.Getppid() == 1 {
|
// just kill ourself and not cause problems for someone else.
|
||||||
|
if syscall.Getppid() != l.parentPid {
|
||||||
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
|
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
|
||||||
}
|
}
|
||||||
return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
|
return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
|
||||||
|
4
Godeps/_workspace/src/github.com/docker/libcontainer/system/setns_linux.go
generated
vendored
4
Godeps/_workspace/src/github.com/docker/libcontainer/system/setns_linux.go
generated
vendored
@ -12,8 +12,10 @@ import (
|
|||||||
// We are declaring the macro here because the SETNS syscall does not exist in th stdlib
|
// We are declaring the macro here because the SETNS syscall does not exist in th stdlib
|
||||||
var setNsMap = map[string]uintptr{
|
var setNsMap = map[string]uintptr{
|
||||||
"linux/386": 346,
|
"linux/386": 346,
|
||||||
|
"linux/arm64": 268,
|
||||||
"linux/amd64": 308,
|
"linux/amd64": 308,
|
||||||
"linux/arm": 374,
|
"linux/arm": 375,
|
||||||
|
"linux/ppc": 350,
|
||||||
"linux/ppc64": 350,
|
"linux/ppc64": 350,
|
||||||
"linux/ppc64le": 350,
|
"linux/ppc64le": 350,
|
||||||
"linux/s390x": 339,
|
"linux/s390x": 339,
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_64.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/system/syscall_linux_64.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// +build linux,amd64 linux,ppc64 linux,ppc64le linux,s390x
|
// +build linux,arm64 linux,amd64 linux,ppc linux,ppc64 linux,ppc64le linux,s390x
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
2
Godeps/_workspace/src/github.com/docker/libcontainer/update-vendor.sh
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/update-vendor.sh
generated
vendored
@ -43,7 +43,7 @@ clone() {
|
|||||||
clone git github.com/codegangsta/cli 1.1.0
|
clone git github.com/codegangsta/cli 1.1.0
|
||||||
clone git github.com/coreos/go-systemd v2
|
clone git github.com/coreos/go-systemd v2
|
||||||
clone git github.com/godbus/dbus v2
|
clone git github.com/godbus/dbus v2
|
||||||
clone git github.com/Sirupsen/logrus v0.6.6
|
clone git github.com/Sirupsen/logrus v0.7.3
|
||||||
clone git github.com/syndtr/gocapability 8e4cdcb
|
clone git github.com/syndtr/gocapability 8e4cdcb
|
||||||
|
|
||||||
# intentionally not vendoring Docker itself... that'd be a circle :)
|
# intentionally not vendoring Docker itself... that'd be a circle :)
|
||||||
|
7
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
formatter/text: Add configuration option for time format (#158)
|
@ -37,11 +37,13 @@ attached, the output is compatible with the
|
|||||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
@ -82,7 +84,7 @@ func init() {
|
|||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
// Output to stderr instead of stdout, could also be a file.
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
@ -106,6 +108,16 @@ func main() {
|
|||||||
"omg": true,
|
"omg": true,
|
||||||
"number": 100,
|
"number": 100,
|
||||||
}).Fatal("The ice breaks!")
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -164,43 +176,8 @@ You can add hooks for logging levels. For example to send errors to an exception
|
|||||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
multiple places simultaneously, e.g. syslog.
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
```go
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
`init`:
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.AddHook(new(AirbrakeHook))
|
|
||||||
}
|
|
||||||
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
|
|
||||||
// the fields for the entry. See the Fields section of the README.
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
err := airbrake.Notify(entry.Data["error"].(error))
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Info("Failed to send error to Airbrake")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// `Levels()` returns a slice of `Levels` the hook is fired for.
|
|
||||||
func (hook *AirbrakeHook) Levels() []log.Level {
|
|
||||||
return []log.Level{
|
|
||||||
log.ErrorLevel,
|
|
||||||
log.FatalLevel,
|
|
||||||
log.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@ -211,7 +188,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -222,28 +199,18 @@ func init() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go)
|
|
||||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
|
||||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/papertrail`](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go)
|
| Hook | Description |
|
||||||
Send errors to the Papertrail hosted logging service via UDP.
|
| ----- | ----------- |
|
||||||
|
| [Airbrake](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go) | Send errors to an exception tracking service compatible with the Airbrake API. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go)
|
| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
|
||||||
Send errors to remote syslog server.
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
Uses standard library `log/syslog` behind the scenes.
|
| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
Send errors to a channel in hipchat.
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
|
| [Graylog](https://github.com/gemnasium/logrus-hooks/tree/master/graylog) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
Send logs to Loggly (https://www.loggly.com/)
|
|
||||||
|
|
||||||
* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
|
|
||||||
Hook for Slack chat.
|
|
||||||
|
|
||||||
* [`github.com/wercker/journalhook`](https://github.com/wercker/journalhook).
|
|
||||||
Hook for logging to `systemd-journald`.
|
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
@ -321,6 +288,11 @@ The built-in logging formatters are:
|
|||||||
field to `true`. To force no colored output even if there is a TTY set the
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
`DisableColors` field to `true`
|
`DisableColors` field to `true`
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
* `logrus_logstash.LogstashFormatter`. Logs fields as Logstash Events (http://logstash.net).
|
||||||
|
|
||||||
|
```go
|
||||||
|
logrus.SetFormatter(&logrus_logstash.LogstashFormatter{Type: “application_name"})
|
||||||
|
```
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
|
@ -3,21 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
"github.com/tobi/airbrake-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logrus.New()
|
var log = logrus.New()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.Formatter = new(logrus.TextFormatter) // default
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
|
||||||
airbrake.ApiKey = "whatever"
|
|
||||||
airbrake.Environment = "production"
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"animal": "walrus",
|
"animal": "walrus",
|
||||||
"size": 10,
|
"size": 10,
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
//
|
//
|
||||||
|
56
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
56
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package logstash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Formatter generates json in logstash format.
|
||||||
|
// Logstash site: http://logstash.net/
|
||||||
|
type LogstashFormatter struct {
|
||||||
|
Type string // if not empty use for logstash type field.
|
||||||
|
|
||||||
|
// TimestampFormat sets the format used for timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
|
entry.Data["@version"] = 1
|
||||||
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = logrus.DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat)
|
||||||
|
|
||||||
|
// set message field
|
||||||
|
v, ok := entry.Data["message"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.message"] = v
|
||||||
|
}
|
||||||
|
entry.Data["message"] = entry.Message
|
||||||
|
|
||||||
|
// set level field
|
||||||
|
v, ok = entry.Data["level"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.level"] = v
|
||||||
|
}
|
||||||
|
entry.Data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
// set type field
|
||||||
|
if f.Type != "" {
|
||||||
|
v, ok = entry.Data["type"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.type"] = v
|
||||||
|
}
|
||||||
|
entry.Data["type"] = f.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
52
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
generated
vendored
Normal file
52
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package logstash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogstashFormatter(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
lf := LogstashFormatter{Type: "abc"}
|
||||||
|
|
||||||
|
fields := logrus.Fields{
|
||||||
|
"message": "def",
|
||||||
|
"level": "ijk",
|
||||||
|
"type": "lmn",
|
||||||
|
"one": 1,
|
||||||
|
"pi": 3.14,
|
||||||
|
"bool": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := logrus.WithFields(fields)
|
||||||
|
entry.Message = "msg"
|
||||||
|
entry.Level = logrus.InfoLevel
|
||||||
|
|
||||||
|
b, _ := lf.Format(entry)
|
||||||
|
|
||||||
|
var data map[string]interface{}
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(b))
|
||||||
|
dec.UseNumber()
|
||||||
|
dec.Decode(&data)
|
||||||
|
|
||||||
|
// base fields
|
||||||
|
assert.Equal(json.Number("1"), data["@version"])
|
||||||
|
assert.NotEmpty(data["@timestamp"])
|
||||||
|
assert.Equal("abc", data["type"])
|
||||||
|
assert.Equal("msg", data["message"])
|
||||||
|
assert.Equal("info", data["level"])
|
||||||
|
|
||||||
|
// substituted fields
|
||||||
|
assert.Equal("def", data["fields.message"])
|
||||||
|
assert.Equal("ijk", data["fields.level"])
|
||||||
|
assert.Equal("lmn", data["fields.type"])
|
||||||
|
|
||||||
|
// formats
|
||||||
|
assert.Equal(json.Number("1"), data["one"])
|
||||||
|
assert.Equal(json.Number("3.14"), data["pi"])
|
||||||
|
assert.Equal(true, data["bool"])
|
||||||
|
}
|
@ -1,51 +1,51 @@
|
|||||||
package logrus_airbrake
|
package airbrake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/tobi/airbrake-go"
|
"github.com/tobi/airbrake-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||||
// with the Airbrake API. You must set:
|
// with the Airbrake API.
|
||||||
// * airbrake.Endpoint
|
type airbrakeHook struct {
|
||||||
// * airbrake.ApiKey
|
APIKey string
|
||||||
// * airbrake.Environment
|
Endpoint string
|
||||||
//
|
Environment string
|
||||||
// Before using this hook, to send an error. Entries that trigger an Error,
|
}
|
||||||
// Fatal or Panic should now include an "error" field to send to Airbrake.
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
func NewHook(endpoint, apiKey, env string) *airbrakeHook {
|
||||||
if entry.Data["error"] == nil {
|
return &airbrakeHook{
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
APIKey: apiKey,
|
||||||
"source": "airbrake",
|
Endpoint: endpoint,
|
||||||
"endpoint": airbrake.Endpoint,
|
Environment: env,
|
||||||
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
|
||||||
|
airbrake.ApiKey = hook.APIKey
|
||||||
|
airbrake.Endpoint = hook.Endpoint
|
||||||
|
airbrake.Environment = hook.Environment
|
||||||
|
|
||||||
|
var notifyErr error
|
||||||
err, ok := entry.Data["error"].(error)
|
err, ok := entry.Data["error"].(error)
|
||||||
if !ok {
|
if ok {
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
notifyErr = err
|
||||||
"source": "airbrake",
|
} else {
|
||||||
"endpoint": airbrake.Endpoint,
|
notifyErr = errors.New(entry.Message)
|
||||||
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
airErr := airbrake.Notify(err)
|
airErr := airbrake.Notify(notifyErr)
|
||||||
if airErr != nil {
|
if airErr != nil {
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
"error": airErr,
|
|
||||||
}).Warn("Failed to send error to Airbrake")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
func (hook *airbrakeHook) Levels() []logrus.Level {
|
||||||
return []logrus.Level{
|
return []logrus.Level{
|
||||||
logrus.ErrorLevel,
|
logrus.ErrorLevel,
|
||||||
logrus.FatalLevel,
|
logrus.FatalLevel,
|
||||||
|
133
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go
generated
vendored
Normal file
133
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake_test.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package airbrake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type notice struct {
|
||||||
|
Error NoticeError `xml:"error"`
|
||||||
|
}
|
||||||
|
type NoticeError struct {
|
||||||
|
Class string `xml:"class"`
|
||||||
|
Message string `xml:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type customErr struct {
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *customErr) Error() string {
|
||||||
|
return e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
testAPIKey = "abcxyz"
|
||||||
|
testEnv = "development"
|
||||||
|
expectedClass = "*airbrake.customErr"
|
||||||
|
expectedMsg = "foo"
|
||||||
|
unintendedMsg = "Airbrake will not see this string"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
noticeError = make(chan NoticeError, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestLogEntryMessageReceived checks if invoking Logrus' log.Error
|
||||||
|
// method causes an XML payload containing the log entry message is received
|
||||||
|
// by a HTTP server emulating an Airbrake-compatible endpoint.
|
||||||
|
func TestLogEntryMessageReceived(t *testing.T) {
|
||||||
|
log := logrus.New()
|
||||||
|
ts := startAirbrakeServer(t)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
hook := NewHook(ts.URL, testAPIKey, "production")
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
log.Error(expectedMsg)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case received := <-noticeError:
|
||||||
|
if received.Message != expectedMsg {
|
||||||
|
t.Errorf("Unexpected message received: %s", received.Message)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("Timed out; no notice received by Airbrake API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLogEntryMessageReceived confirms that, when passing an error type using
|
||||||
|
// logrus.Fields, a HTTP server emulating an Airbrake endpoint receives the
|
||||||
|
// error message returned by the Error() method on the error interface
|
||||||
|
// rather than the logrus.Entry.Message string.
|
||||||
|
func TestLogEntryWithErrorReceived(t *testing.T) {
|
||||||
|
log := logrus.New()
|
||||||
|
ts := startAirbrakeServer(t)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
hook := NewHook(ts.URL, testAPIKey, "production")
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"error": &customErr{expectedMsg},
|
||||||
|
}).Error(unintendedMsg)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case received := <-noticeError:
|
||||||
|
if received.Message != expectedMsg {
|
||||||
|
t.Errorf("Unexpected message received: %s", received.Message)
|
||||||
|
}
|
||||||
|
if received.Class != expectedClass {
|
||||||
|
t.Errorf("Unexpected error class: %s", received.Class)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("Timed out; no notice received by Airbrake API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLogEntryWithNonErrorTypeNotReceived confirms that, when passing a
|
||||||
|
// non-error type using logrus.Fields, a HTTP server emulating an Airbrake
|
||||||
|
// endpoint receives the logrus.Entry.Message string.
|
||||||
|
//
|
||||||
|
// Only error types are supported when setting the 'error' field using
|
||||||
|
// logrus.WithFields().
|
||||||
|
func TestLogEntryWithNonErrorTypeNotReceived(t *testing.T) {
|
||||||
|
log := logrus.New()
|
||||||
|
ts := startAirbrakeServer(t)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
hook := NewHook(ts.URL, testAPIKey, "production")
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"error": expectedMsg,
|
||||||
|
}).Error(unintendedMsg)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case received := <-noticeError:
|
||||||
|
if received.Message != unintendedMsg {
|
||||||
|
t.Errorf("Unexpected message received: %s", received.Message)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("Timed out; no notice received by Airbrake API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startAirbrakeServer(t *testing.T) *httptest.Server {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var notice notice
|
||||||
|
if err := xml.NewDecoder(r.Body).Decode(¬ice); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
r.Body.Close()
|
||||||
|
|
||||||
|
noticeError <- notice.Error
|
||||||
|
}))
|
||||||
|
|
||||||
|
return ts
|
||||||
|
}
|
68
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package logrus_bugsnag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/bugsnag/bugsnag-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bugsnagHook struct{}
|
||||||
|
|
||||||
|
// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
|
||||||
|
// bugsnag.Configure. Bugsnag must be configured before the hook.
|
||||||
|
var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
|
||||||
|
|
||||||
|
// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
|
||||||
|
// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
|
||||||
|
// failed.
|
||||||
|
type ErrBugsnagSendFailed struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrBugsnagSendFailed) Error() string {
|
||||||
|
return "failed to send error to Bugsnag: " + e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBugsnagHook initializes a logrus hook which sends exceptions to an
|
||||||
|
// exception-tracking service compatible with the Bugsnag API. Before using
|
||||||
|
// this hook, you must call bugsnag.Configure(). The returned object should be
|
||||||
|
// registered with a log via `AddHook()`
|
||||||
|
//
|
||||||
|
// Entries that trigger an Error, Fatal or Panic should now include an "error"
|
||||||
|
// field to send to Bugsnag.
|
||||||
|
func NewBugsnagHook() (*bugsnagHook, error) {
|
||||||
|
if bugsnag.Config.APIKey == "" {
|
||||||
|
return nil, ErrBugsnagUnconfigured
|
||||||
|
}
|
||||||
|
return &bugsnagHook{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
|
||||||
|
// "error" field (or the Message if the error isn't present) and sends it off.
|
||||||
|
func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
|
||||||
|
var notifyErr error
|
||||||
|
err, ok := entry.Data["error"].(error)
|
||||||
|
if ok {
|
||||||
|
notifyErr = err
|
||||||
|
} else {
|
||||||
|
notifyErr = errors.New(entry.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
bugsnagErr := bugsnag.Notify(notifyErr)
|
||||||
|
if bugsnagErr != nil {
|
||||||
|
return ErrBugsnagSendFailed{bugsnagErr}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels enumerates the log levels on which the error should be forwarded to
|
||||||
|
// bugsnag: everything at or above the "Error" level.
|
||||||
|
func (hook *bugsnagHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
64
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go
generated
vendored
Normal file
64
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package logrus_bugsnag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/bugsnag/bugsnag-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type notice struct {
|
||||||
|
Events []struct {
|
||||||
|
Exceptions []struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"exceptions"`
|
||||||
|
} `json:"events"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoticeReceived(t *testing.T) {
|
||||||
|
msg := make(chan string, 1)
|
||||||
|
expectedMsg := "foo"
|
||||||
|
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var notice notice
|
||||||
|
data, _ := ioutil.ReadAll(r.Body)
|
||||||
|
if err := json.Unmarshal(data, ¬ice); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
_ = r.Body.Close()
|
||||||
|
|
||||||
|
msg <- notice.Events[0].Exceptions[0].Message
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
hook := &bugsnagHook{}
|
||||||
|
|
||||||
|
bugsnag.Configure(bugsnag.Configuration{
|
||||||
|
Endpoint: ts.URL,
|
||||||
|
ReleaseStage: "production",
|
||||||
|
APIKey: "12345678901234567890123456789012",
|
||||||
|
Synchronous: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
log := logrus.New()
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"error": errors.New(expectedMsg),
|
||||||
|
}).Error("Bugsnag will not see this string")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case received := <-msg:
|
||||||
|
if received != expectedMsg {
|
||||||
|
t.Errorf("Unexpected message received: %s", received)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("Timed out; no notice received by Bugsnag API")
|
||||||
|
}
|
||||||
|
}
|
@ -3,24 +3,32 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type JSONFormatter struct{}
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+3)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
// Otherwise errors are ignored by `encoding/json`
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
// https://github.com/Sirupsen/logrus/issues/137
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
if err, ok := v.(error); ok {
|
data[k] = v.Error()
|
||||||
data[k] = err.Error()
|
default:
|
||||||
} else {
|
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefixFieldClashes(data)
|
prefixFieldClashes(data)
|
||||||
data["time"] = entry.Time.Format(time.RFC3339)
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(f.TimestampFormat)
|
||||||
data["msg"] = entry.Message
|
data["msg"] = entry.Message
|
||||||
data["level"] = entry.Level.String()
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
@ -65,11 +65,15 @@ func (logger *Logger) WithFields(fields Fields) *Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
NewEntry(logger).Debugf(format, args...)
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
NewEntry(logger).Infof(format, args...)
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
@ -77,31 +81,45 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
NewEntry(logger).Errorf(format, args...)
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
NewEntry(logger).Fatalf(format, args...)
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
NewEntry(logger).Panicf(format, args...)
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
NewEntry(logger).Debug(args...)
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
NewEntry(logger).Info(args...)
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
@ -109,31 +127,45 @@ func (logger *Logger) Print(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warn(args...)
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warn(args...)
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
NewEntry(logger).Error(args...)
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
NewEntry(logger).Fatal(args...)
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
NewEntry(logger).Panic(args...)
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
NewEntry(logger).Debugln(args...)
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
NewEntry(logger).Infoln(args...)
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
@ -141,21 +173,31 @@ func (logger *Logger) Println(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warnln(args...)
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
NewEntry(logger).Warnln(args...)
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
NewEntry(logger).Errorln(args...)
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
NewEntry(logger).Fatalln(args...)
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
NewEntry(logger).Panicln(args...)
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
@ -3,7 +3,6 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -21,7 +20,6 @@ const (
|
|||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
noQuoteNeeded *regexp.Regexp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -48,6 +46,9 @@ type TextFormatter struct {
|
|||||||
// the time passed since beginning of execution.
|
// the time passed since beginning of execution.
|
||||||
FullTimestamp bool
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
// The fields are sorted by default for a consistent output. For applications
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
// that log extremely frequently and don't use the JSON formatter this may not
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
// be desired.
|
// be desired.
|
||||||
@ -70,11 +71,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
|
|
||||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
if isColored {
|
if isColored {
|
||||||
f.printColored(b, entry, keys)
|
f.printColored(b, entry, keys)
|
||||||
} else {
|
} else {
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
f.appendKeyValue(b, "time", entry.Time.Format(f.TimestampFormat))
|
||||||
}
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
@ -105,7 +109,7 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||||||
if !f.FullTimestamp {
|
if !f.FullTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(time.RFC3339), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(f.TimestampFormat), entry.Message)
|
||||||
}
|
}
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := entry.Data[k]
|
v := entry.Data[k]
|
||||||
|
@ -3,8 +3,8 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQuoting(t *testing.T) {
|
func TestQuoting(t *testing.T) {
|
||||||
@ -33,5 +33,29 @@ func TestQuoting(t *testing.T) {
|
|||||||
checkQuoting(true, errors.New("invalid argument"))
|
checkQuoting(true, errors.New("invalid argument"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimestampFormat(t *testing.T) {
|
||||||
|
checkTimeStr := func(format string) {
|
||||||
|
customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
|
||||||
|
customStr, _ := customFormatter.Format(WithField("test", "test"))
|
||||||
|
timeStart := bytes.Index(customStr, ([]byte)("time="))
|
||||||
|
timeEnd := bytes.Index(customStr, ([]byte)("level="))
|
||||||
|
timeStr := customStr[timeStart+5 : timeEnd-1]
|
||||||
|
if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' {
|
||||||
|
timeStr = timeStr[1 : len(timeStr)-1]
|
||||||
|
}
|
||||||
|
if format == "" {
|
||||||
|
format = time.RFC3339
|
||||||
|
}
|
||||||
|
_, e := time.Parse(format, (string)(timeStr))
|
||||||
|
if e != nil {
|
||||||
|
t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
|
||||||
|
checkTimeStr("Mon Jan _2 15:04:05 2006")
|
||||||
|
checkTimeStr("")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO add tests for sorting etc., this requires a parser for the text
|
// TODO add tests for sorting etc., this requires a parser for the text
|
||||||
// formatter output.
|
// formatter output.
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (logger *Logger) Writer() (*io.PipeWriter) {
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
go logger.writerScanner(reader)
|
go logger.writerScanner(reader)
|
||||||
|
3
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
3
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
@ -60,7 +60,8 @@ type Capabilities interface {
|
|||||||
Apply(kind CapType) error
|
Apply(kind CapType) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPid create new initialized Capabilities object for given pid.
|
// NewPid create new initialized Capabilities object for given pid when it
|
||||||
|
// is nonzero, or for the current pid if pid is 0
|
||||||
func NewPid(pid int) (Capabilities, error) {
|
func NewPid(pid int) (Capabilities, error) {
|
||||||
return newPid(pid)
|
return newPid(pid)
|
||||||
}
|
}
|
||||||
|
46
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
46
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
@ -24,12 +24,46 @@ const (
|
|||||||
linuxCapVer3 = 0x20080522
|
linuxCapVer3 = 0x20080522
|
||||||
)
|
)
|
||||||
|
|
||||||
var capVers uint32
|
var (
|
||||||
|
capVers uint32
|
||||||
|
capLastCap Cap
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var hdr capHeader
|
var hdr capHeader
|
||||||
capget(&hdr, nil)
|
capget(&hdr, nil)
|
||||||
capVers = hdr.version
|
capVers = hdr.version
|
||||||
|
|
||||||
|
if initLastCap() == nil {
|
||||||
|
CAP_LAST_CAP = capLastCap
|
||||||
|
if capLastCap > 31 {
|
||||||
|
capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1
|
||||||
|
} else {
|
||||||
|
capUpperMask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLastCap() error {
|
||||||
|
if capLastCap != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open("/proc/sys/kernel/cap_last_cap")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var b []byte = make([]byte, 11)
|
||||||
|
_, err = f.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Sscanf(string(b), "%d", &capLastCap)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
||||||
@ -351,7 +385,15 @@ func (c *capsV3) Load() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open(fmt.Sprintf("/proc/%d/status", c.hdr.pid))
|
var status_path string
|
||||||
|
|
||||||
|
if c.hdr.pid == 0 {
|
||||||
|
status_path = fmt.Sprintf("/proc/self/status")
|
||||||
|
} else {
|
||||||
|
status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(status_path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
89
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
89
Godeps/_workspace/src/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
@ -112,32 +112,33 @@ func (c Cap) String() string {
|
|||||||
return "wake_alarm"
|
return "wake_alarm"
|
||||||
case CAP_BLOCK_SUSPEND:
|
case CAP_BLOCK_SUSPEND:
|
||||||
return "block_suspend"
|
return "block_suspend"
|
||||||
|
case CAP_AUDIT_READ:
|
||||||
|
return "audit_read"
|
||||||
}
|
}
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POSIX-draft defined capabilities.
|
||||||
const (
|
const (
|
||||||
// POSIX-draft defined capabilities.
|
|
||||||
|
|
||||||
// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
|
// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
|
||||||
// overrides the restriction of changing file ownership and group
|
// overrides the restriction of changing file ownership and group
|
||||||
// ownership.
|
// ownership.
|
||||||
CAP_CHOWN Cap = 0
|
CAP_CHOWN = Cap(0)
|
||||||
|
|
||||||
// Override all DAC access, including ACL execute access if
|
// Override all DAC access, including ACL execute access if
|
||||||
// [_POSIX_ACL] is defined. Excluding DAC access covered by
|
// [_POSIX_ACL] is defined. Excluding DAC access covered by
|
||||||
// CAP_LINUX_IMMUTABLE.
|
// CAP_LINUX_IMMUTABLE.
|
||||||
CAP_DAC_OVERRIDE Cap = 1
|
CAP_DAC_OVERRIDE = Cap(1)
|
||||||
|
|
||||||
// Overrides all DAC restrictions regarding read and search on files
|
// Overrides all DAC restrictions regarding read and search on files
|
||||||
// and directories, including ACL restrictions if [_POSIX_ACL] is
|
// and directories, including ACL restrictions if [_POSIX_ACL] is
|
||||||
// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
|
// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
|
||||||
CAP_DAC_READ_SEARCH Cap = 2
|
CAP_DAC_READ_SEARCH = Cap(2)
|
||||||
|
|
||||||
// Overrides all restrictions about allowed operations on files, where
|
// Overrides all restrictions about allowed operations on files, where
|
||||||
// file owner ID must be equal to the user ID, except where CAP_FSETID
|
// file owner ID must be equal to the user ID, except where CAP_FSETID
|
||||||
// is applicable. It doesn't override MAC and DAC restrictions.
|
// is applicable. It doesn't override MAC and DAC restrictions.
|
||||||
CAP_FOWNER Cap = 3
|
CAP_FOWNER = Cap(3)
|
||||||
|
|
||||||
// Overrides the following restrictions that the effective user ID
|
// Overrides the following restrictions that the effective user ID
|
||||||
// shall match the file owner ID when setting the S_ISUID and S_ISGID
|
// shall match the file owner ID when setting the S_ISUID and S_ISGID
|
||||||
@ -145,21 +146,21 @@ const (
|
|||||||
// supplementary group IDs) shall match the file owner ID when setting
|
// supplementary group IDs) shall match the file owner ID when setting
|
||||||
// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
|
// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
|
||||||
// cleared on successful return from chown(2) (not implemented).
|
// cleared on successful return from chown(2) (not implemented).
|
||||||
CAP_FSETID Cap = 4
|
CAP_FSETID = Cap(4)
|
||||||
|
|
||||||
// Overrides the restriction that the real or effective user ID of a
|
// Overrides the restriction that the real or effective user ID of a
|
||||||
// process sending a signal must match the real or effective user ID
|
// process sending a signal must match the real or effective user ID
|
||||||
// of the process receiving the signal.
|
// of the process receiving the signal.
|
||||||
CAP_KILL Cap = 5
|
CAP_KILL = Cap(5)
|
||||||
|
|
||||||
// Allows setgid(2) manipulation
|
// Allows setgid(2) manipulation
|
||||||
// Allows setgroups(2)
|
// Allows setgroups(2)
|
||||||
// Allows forged gids on socket credentials passing.
|
// Allows forged gids on socket credentials passing.
|
||||||
CAP_SETGID Cap = 6
|
CAP_SETGID = Cap(6)
|
||||||
|
|
||||||
// Allows set*uid(2) manipulation (including fsuid).
|
// Allows set*uid(2) manipulation (including fsuid).
|
||||||
// Allows forged pids on socket credentials passing.
|
// Allows forged pids on socket credentials passing.
|
||||||
CAP_SETUID Cap = 7
|
CAP_SETUID = Cap(7)
|
||||||
|
|
||||||
// Linux-specific capabilities
|
// Linux-specific capabilities
|
||||||
|
|
||||||
@ -171,17 +172,17 @@ const (
|
|||||||
// to the current process' inheritable set
|
// to the current process' inheritable set
|
||||||
// Allow taking bits out of capability bounding set
|
// Allow taking bits out of capability bounding set
|
||||||
// Allow modification of the securebits for a process
|
// Allow modification of the securebits for a process
|
||||||
CAP_SETPCAP Cap = 8
|
CAP_SETPCAP = Cap(8)
|
||||||
|
|
||||||
// Allow modification of S_IMMUTABLE and S_APPEND file attributes
|
// Allow modification of S_IMMUTABLE and S_APPEND file attributes
|
||||||
CAP_LINUX_IMMUTABLE Cap = 9
|
CAP_LINUX_IMMUTABLE = Cap(9)
|
||||||
|
|
||||||
// Allows binding to TCP/UDP sockets below 1024
|
// Allows binding to TCP/UDP sockets below 1024
|
||||||
// Allows binding to ATM VCIs below 32
|
// Allows binding to ATM VCIs below 32
|
||||||
CAP_NET_BIND_SERVICE Cap = 10
|
CAP_NET_BIND_SERVICE = Cap(10)
|
||||||
|
|
||||||
// Allow broadcasting, listen to multicast
|
// Allow broadcasting, listen to multicast
|
||||||
CAP_NET_BROADCAST Cap = 11
|
CAP_NET_BROADCAST = Cap(11)
|
||||||
|
|
||||||
// Allow interface configuration
|
// Allow interface configuration
|
||||||
// Allow administration of IP firewall, masquerading and accounting
|
// Allow administration of IP firewall, masquerading and accounting
|
||||||
@ -196,36 +197,36 @@ const (
|
|||||||
// Allow multicasting
|
// Allow multicasting
|
||||||
// Allow read/write of device-specific registers
|
// Allow read/write of device-specific registers
|
||||||
// Allow activation of ATM control sockets
|
// Allow activation of ATM control sockets
|
||||||
CAP_NET_ADMIN Cap = 12
|
CAP_NET_ADMIN = Cap(12)
|
||||||
|
|
||||||
// Allow use of RAW sockets
|
// Allow use of RAW sockets
|
||||||
// Allow use of PACKET sockets
|
// Allow use of PACKET sockets
|
||||||
// Allow binding to any address for transparent proxying (also via NET_ADMIN)
|
// Allow binding to any address for transparent proxying (also via NET_ADMIN)
|
||||||
CAP_NET_RAW Cap = 13
|
CAP_NET_RAW = Cap(13)
|
||||||
|
|
||||||
// Allow locking of shared memory segments
|
// Allow locking of shared memory segments
|
||||||
// Allow mlock and mlockall (which doesn't really have anything to do
|
// Allow mlock and mlockall (which doesn't really have anything to do
|
||||||
// with IPC)
|
// with IPC)
|
||||||
CAP_IPC_LOCK Cap = 14
|
CAP_IPC_LOCK = Cap(14)
|
||||||
|
|
||||||
// Override IPC ownership checks
|
// Override IPC ownership checks
|
||||||
CAP_IPC_OWNER Cap = 15
|
CAP_IPC_OWNER = Cap(15)
|
||||||
|
|
||||||
// Insert and remove kernel modules - modify kernel without limit
|
// Insert and remove kernel modules - modify kernel without limit
|
||||||
CAP_SYS_MODULE Cap = 16
|
CAP_SYS_MODULE = Cap(16)
|
||||||
|
|
||||||
// Allow ioperm/iopl access
|
// Allow ioperm/iopl access
|
||||||
// Allow sending USB messages to any device via /proc/bus/usb
|
// Allow sending USB messages to any device via /proc/bus/usb
|
||||||
CAP_SYS_RAWIO Cap = 17
|
CAP_SYS_RAWIO = Cap(17)
|
||||||
|
|
||||||
// Allow use of chroot()
|
// Allow use of chroot()
|
||||||
CAP_SYS_CHROOT Cap = 18
|
CAP_SYS_CHROOT = Cap(18)
|
||||||
|
|
||||||
// Allow ptrace() of any process
|
// Allow ptrace() of any process
|
||||||
CAP_SYS_PTRACE Cap = 19
|
CAP_SYS_PTRACE = Cap(19)
|
||||||
|
|
||||||
// Allow configuration of process accounting
|
// Allow configuration of process accounting
|
||||||
CAP_SYS_PACCT Cap = 20
|
CAP_SYS_PACCT = Cap(20)
|
||||||
|
|
||||||
// Allow configuration of the secure attention key
|
// Allow configuration of the secure attention key
|
||||||
// Allow administration of the random device
|
// Allow administration of the random device
|
||||||
@ -263,10 +264,10 @@ const (
|
|||||||
// arbitrary SCSI commands
|
// arbitrary SCSI commands
|
||||||
// Allow setting encryption key on loopback filesystem
|
// Allow setting encryption key on loopback filesystem
|
||||||
// Allow setting zone reclaim policy
|
// Allow setting zone reclaim policy
|
||||||
CAP_SYS_ADMIN Cap = 21
|
CAP_SYS_ADMIN = Cap(21)
|
||||||
|
|
||||||
// Allow use of reboot()
|
// Allow use of reboot()
|
||||||
CAP_SYS_BOOT Cap = 22
|
CAP_SYS_BOOT = Cap(22)
|
||||||
|
|
||||||
// Allow raising priority and setting priority on other (different
|
// Allow raising priority and setting priority on other (different
|
||||||
// UID) processes
|
// UID) processes
|
||||||
@ -274,7 +275,7 @@ const (
|
|||||||
// processes and setting the scheduling algorithm used by another
|
// processes and setting the scheduling algorithm used by another
|
||||||
// process.
|
// process.
|
||||||
// Allow setting cpu affinity on other processes
|
// Allow setting cpu affinity on other processes
|
||||||
CAP_SYS_NICE Cap = 23
|
CAP_SYS_NICE = Cap(23)
|
||||||
|
|
||||||
// Override resource limits. Set resource limits.
|
// Override resource limits. Set resource limits.
|
||||||
// Override quota limits.
|
// Override quota limits.
|
||||||
@ -287,33 +288,33 @@ const (
|
|||||||
// Allow more than 64hz interrupts from the real-time clock
|
// Allow more than 64hz interrupts from the real-time clock
|
||||||
// Override max number of consoles on console allocation
|
// Override max number of consoles on console allocation
|
||||||
// Override max number of keymaps
|
// Override max number of keymaps
|
||||||
CAP_SYS_RESOURCE Cap = 24
|
CAP_SYS_RESOURCE = Cap(24)
|
||||||
|
|
||||||
// Allow manipulation of system clock
|
// Allow manipulation of system clock
|
||||||
// Allow irix_stime on mips
|
// Allow irix_stime on mips
|
||||||
// Allow setting the real-time clock
|
// Allow setting the real-time clock
|
||||||
CAP_SYS_TIME Cap = 25
|
CAP_SYS_TIME = Cap(25)
|
||||||
|
|
||||||
// Allow configuration of tty devices
|
// Allow configuration of tty devices
|
||||||
// Allow vhangup() of tty
|
// Allow vhangup() of tty
|
||||||
CAP_SYS_TTY_CONFIG Cap = 26
|
CAP_SYS_TTY_CONFIG = Cap(26)
|
||||||
|
|
||||||
// Allow the privileged aspects of mknod()
|
// Allow the privileged aspects of mknod()
|
||||||
CAP_MKNOD Cap = 27
|
CAP_MKNOD = Cap(27)
|
||||||
|
|
||||||
// Allow taking of leases on files
|
// Allow taking of leases on files
|
||||||
CAP_LEASE Cap = 28
|
CAP_LEASE = Cap(28)
|
||||||
|
|
||||||
CAP_AUDIT_WRITE Cap = 29
|
CAP_AUDIT_WRITE = Cap(29)
|
||||||
CAP_AUDIT_CONTROL Cap = 30
|
CAP_AUDIT_CONTROL = Cap(30)
|
||||||
CAP_SETFCAP Cap = 31
|
CAP_SETFCAP = Cap(31)
|
||||||
|
|
||||||
// Override MAC access.
|
// Override MAC access.
|
||||||
// The base kernel enforces no MAC policy.
|
// The base kernel enforces no MAC policy.
|
||||||
// An LSM may enforce a MAC policy, and if it does and it chooses
|
// An LSM may enforce a MAC policy, and if it does and it chooses
|
||||||
// to implement capability based overrides of that policy, this is
|
// to implement capability based overrides of that policy, this is
|
||||||
// the capability it should use to do so.
|
// the capability it should use to do so.
|
||||||
CAP_MAC_OVERRIDE Cap = 32
|
CAP_MAC_OVERRIDE = Cap(32)
|
||||||
|
|
||||||
// Allow MAC configuration or state changes.
|
// Allow MAC configuration or state changes.
|
||||||
// The base kernel requires no MAC configuration.
|
// The base kernel requires no MAC configuration.
|
||||||
@ -321,18 +322,24 @@ const (
|
|||||||
// to implement capability based checks on modifications to that
|
// to implement capability based checks on modifications to that
|
||||||
// policy or the data required to maintain it, this is the
|
// policy or the data required to maintain it, this is the
|
||||||
// capability it should use to do so.
|
// capability it should use to do so.
|
||||||
CAP_MAC_ADMIN Cap = 33
|
CAP_MAC_ADMIN = Cap(33)
|
||||||
|
|
||||||
// Allow configuring the kernel's syslog (printk behaviour)
|
// Allow configuring the kernel's syslog (printk behaviour)
|
||||||
CAP_SYSLOG Cap = 34
|
CAP_SYSLOG = Cap(34)
|
||||||
|
|
||||||
// Allow triggering something that will wake the system
|
// Allow triggering something that will wake the system
|
||||||
CAP_WAKE_ALARM Cap = 35
|
CAP_WAKE_ALARM = Cap(35)
|
||||||
|
|
||||||
// Allow preventing system suspends
|
// Allow preventing system suspends
|
||||||
CAP_BLOCK_SUSPEND Cap = 36
|
CAP_BLOCK_SUSPEND = Cap(36)
|
||||||
|
|
||||||
CAP_LAST_CAP = CAP_BLOCK_SUSPEND
|
// Allow reading audit messages from the kernel
|
||||||
|
CAP_AUDIT_READ = Cap(37)
|
||||||
)
|
)
|
||||||
|
|
||||||
const capUpperMask = (uint32(1) << (uint(CAP_LAST_CAP) - 31)) - 1
|
var (
|
||||||
|
// Highest valid capability of the running kernel.
|
||||||
|
CAP_LAST_CAP = Cap(63)
|
||||||
|
|
||||||
|
capUpperMask = ^uint32(0)
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user