Merge branch 'master' into api
Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Conflicts: MAINTAINERS cgroups/cgroups.go cgroups/fs/apply_raw.go cgroups/fs/notify_linux.go cgroups/fs/notify_linux_test.go cgroups/systemd/apply_systemd.go config.go configs/config_test.go console/console.go integration/exec_test.go integration/init_test.go integration/template_test.go integration/utils_test.go linux_notify.go linux_notify_test.go mount/init.go mount/mount_config.go mount/pivotroot.go mount/ptmx.go namespaces/create.go namespaces/exec.go namespaces/execin.go namespaces/init.go namespaces/nsenter/nsenter.c namespaces/nsenter/nsenter.go namespaces/utils.go network/network.go network/types.go network/veth.go notify_linux.go notify_linux_test.go nsinit/exec.go nsinit/main.go nsinit/nsenter.go nsinit/oom.go sample_configs/host-pid.json sample_configs/userns.json security/capabilities/capabilities.go update-vendor.sh
This commit is contained in:
commit
f4cf808a3d
|
@ -3,4 +3,5 @@ Rohit Jnagal <jnagal@google.com> (@rjnagal)
|
||||||
Victor Marmol <vmarmol@google.com> (@vmarmol)
|
Victor Marmol <vmarmol@google.com> (@vmarmol)
|
||||||
Mrunal Patel <mpatel@redhat.com> (@mrunalp)
|
Mrunal Patel <mpatel@redhat.com> (@mrunalp)
|
||||||
Alexandr Morozov <lk4d4@docker.com> (@LK4D4)
|
Alexandr Morozov <lk4d4@docker.com> (@LK4D4)
|
||||||
|
Daniel, Dao Quang Minh <dqminh89@gmail.com> (@dqminh)
|
||||||
update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
update-vendor.sh: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -12,7 +12,6 @@ sh:
|
||||||
GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)
|
GO_PACKAGES = $(shell find . -not \( -wholename ./vendor -prune -o -wholename ./.git -prune \) -name '*.go' -print0 | xargs -0n1 dirname | sort -u)
|
||||||
|
|
||||||
direct-test:
|
direct-test:
|
||||||
go get github.com/golang/glog && \
|
|
||||||
go test $(TEST_TAGS) -cover -v $(GO_PACKAGES)
|
go test $(TEST_TAGS) -cover -v $(GO_PACKAGES)
|
||||||
|
|
||||||
direct-test-short:
|
direct-test-short:
|
||||||
|
|
|
@ -24,7 +24,6 @@ func ApplyProfile(name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cName := C.CString(name)
|
cName := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(cName))
|
defer C.free(unsafe.Pointer(cName))
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
|
@ -40,20 +40,31 @@ type Manager struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The absolute path to the root of the cgroup hierarchies.
|
// The absolute path to the root of the cgroup hierarchies.
|
||||||
|
var cgroupRootLock sync.Mutex
|
||||||
var cgroupRoot string
|
var cgroupRoot string
|
||||||
|
|
||||||
// TODO(vmarmol): Report error here, we'll probably need to wait for the new API.
|
// Gets the cgroupRoot.
|
||||||
func init() {
|
func getCgroupRoot() (string, error) {
|
||||||
|
cgroupRootLock.Lock()
|
||||||
|
defer cgroupRootLock.Unlock()
|
||||||
|
|
||||||
|
if cgroupRoot != "" {
|
||||||
|
return cgroupRoot, nil
|
||||||
|
}
|
||||||
|
|
||||||
// we can pick any subsystem to find the root
|
// we can pick any subsystem to find the root
|
||||||
cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
|
cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return "", err
|
||||||
}
|
}
|
||||||
cgroupRoot = filepath.Dir(cpuRoot)
|
root := filepath.Dir(cpuRoot)
|
||||||
|
|
||||||
if _, err := os.Stat(cgroupRoot); err != nil {
|
if _, err := os.Stat(root); err != nil {
|
||||||
return
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgroupRoot = root
|
||||||
|
return cgroupRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type data struct {
|
type data struct {
|
||||||
|
@ -172,8 +183,9 @@ func (m *Manager) GetPids() ([]int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCgroupData(c *configs.Cgroup, pid int) (*data, error) {
|
func getCgroupData(c *configs.Cgroup, pid int) (*data, error) {
|
||||||
if cgroupRoot == "" {
|
root, err := getCgroupRoot()
|
||||||
return nil, fmt.Errorf("failed to find the cgroup root")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cgroup := c.Name
|
cgroup := c.Name
|
||||||
|
@ -182,7 +194,7 @@ func getCgroupData(c *configs.Cgroup, pid int) (*data, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &data{
|
return &data{
|
||||||
root: cgroupRoot,
|
root: root,
|
||||||
cgroup: cgroup,
|
cgroup: cgroup,
|
||||||
c: c,
|
c: c,
|
||||||
pid: pid,
|
pid: pid,
|
||||||
|
|
|
@ -30,9 +30,10 @@ type subsystem interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
theConn *systemd.Conn
|
theConn *systemd.Conn
|
||||||
hasStartTransientUnit bool
|
hasStartTransientUnit bool
|
||||||
|
hasTransientDefaultDependencies bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func newProp(name string, units interface{}) systemd.Property {
|
func newProp(name string, units interface{}) systemd.Property {
|
||||||
|
@ -66,6 +67,18 @@ func UseSystemd() bool {
|
||||||
if dbusError, ok := err.(dbus.Error); ok {
|
if dbusError, ok := err.(dbus.Error); ok {
|
||||||
if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
|
if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
|
||||||
hasStartTransientUnit = false
|
hasStartTransientUnit = false
|
||||||
|
return hasStartTransientUnit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume StartTransientUnit on a scope allows DefaultDependencies
|
||||||
|
hasTransientDefaultDependencies = true
|
||||||
|
ddf := newProp("DefaultDependencies", false)
|
||||||
|
if _, err := theConn.StartTransientUnit("docker-systemd-test-default-dependencies.scope", "replace", ddf); err != nil {
|
||||||
|
if dbusError, ok := err.(dbus.Error); ok {
|
||||||
|
if dbusError.Name == "org.freedesktop.DBus.Error.PropertyReadOnly" {
|
||||||
|
hasTransientDefaultDependencies = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +121,11 @@ func (m *Manager) Apply(pid int) error {
|
||||||
newProp("CPUAccounting", true),
|
newProp("CPUAccounting", true),
|
||||||
newProp("BlockIOAccounting", true))
|
newProp("BlockIOAccounting", true))
|
||||||
|
|
||||||
|
if hasTransientDefaultDependencies {
|
||||||
|
properties = append(properties,
|
||||||
|
newProp("DefaultDependencies", false))
|
||||||
|
}
|
||||||
|
|
||||||
if c.Memory != 0 {
|
if c.Memory != 0 {
|
||||||
properties = append(properties,
|
properties = append(properties,
|
||||||
newProp("MemoryLimit", uint64(c.Memory)))
|
newProp("MemoryLimit", uint64(c.Memory)))
|
||||||
|
@ -128,14 +146,12 @@ func (m *Manager) Apply(pid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.AllowAllDevices {
|
if err := joinDevices(c, pid); err != nil {
|
||||||
if err := joinDevices(c, pid); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -1 disables memorySwap
|
// -1 disables memorySwap
|
||||||
if c.MemorySwap >= 0 && (c.Memory != 0 || c.MemorySwap > 0) {
|
if c.MemorySwap >= 0 && c.Memory != 0 {
|
||||||
if err := joinMemory(c, pid); err != nil {
|
if err := joinMemory(c, pid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -290,16 +306,16 @@ func joinDevices(c *configs.Cgroup, pid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := writeFile(path, "devices.deny", "a"); err != nil {
|
if !c.AllowAllDevices {
|
||||||
return err
|
if err := writeFile(path, "devices.deny", "a"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dev := range c.AllowedDevices {
|
for _, dev := range c.AllowedDevices {
|
||||||
if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
|
if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ func TestHostUIDNoUSERNS(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if uid != 0 {
|
if uid != 0 {
|
||||||
t.Fatal("expected uid 0 with no USERNS but received %d", uid)
|
t.Fatalf("expected uid 0 with no USERNS but received %d", uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ func TestHostUIDWithUSERNS(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if uid != 1000 {
|
if uid != 1000 {
|
||||||
t.Fatal("expected uid 1000 with no USERNS but received %d", uid)
|
t.Fatalf("expected uid 1000 with no USERNS but received %d", uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func TestHostGIDNoUSERNS(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if uid != 0 {
|
if uid != 0 {
|
||||||
t.Fatal("expected gid 0 with no USERNS but received %d", uid)
|
t.Fatalf("expected gid 0 with no USERNS but received %d", uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +215,6 @@ func TestHostGIDWithUSERNS(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if uid != 1000 {
|
if uid != 1000 {
|
||||||
t.Fatal("expected gid 1000 with no USERNS but received %d", uid)
|
t.Fatalf("expected gid 1000 with no USERNS but received %d", uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
% nsinit User Manual
|
||||||
|
% docker/libcontainer
|
||||||
|
% JAN 2015
|
||||||
|
|
||||||
|
NAME:
|
||||||
|
nsinit - A low-level utility for managing containers.
|
||||||
|
It is used to spawn new containers or join existing containers.
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
nsinit [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
|
VERSION:
|
||||||
|
0.1
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
config display the container configuration
|
||||||
|
exec execute a new command inside a container
|
||||||
|
init runs the init process inside the namespace
|
||||||
|
oom display oom notifications for a container
|
||||||
|
pause pause the container's processes
|
||||||
|
stats display statistics for the container
|
||||||
|
unpause unpause the container's processes
|
||||||
|
help, h shows a list of commands or help for one command
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
|
||||||
|
Get the <container_id> of an already running docker container.
|
||||||
|
`sudo docker ps` will return the list of all the running containers.
|
||||||
|
|
||||||
|
take the <container_id> (e.g. 4addb0b2d307) and go to its config directory
|
||||||
|
`/var/lib/docker/execdriver/native/4addb0b2d307` and here you can run the nsinit
|
||||||
|
command line utility.
|
||||||
|
|
||||||
|
e.g. `nsinit exec /bin/bash` will start a shell on the already running container.
|
||||||
|
|
||||||
|
# HISTORY
|
||||||
|
Jan 2015, Originally compiled by Shishir Mahajan (shishir dot mahajan at redhat dot com)
|
||||||
|
based on nsinit source material and internal work.
|
|
@ -0,0 +1,132 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecIn(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer remove(rootfs)
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
container, err := newContainer(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
|
buffers := newStdBuffers()
|
||||||
|
process := &libcontainer.Process{
|
||||||
|
Args: []string{"sleep", "10"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: buffers.Stdin,
|
||||||
|
Stdout: buffers.Stdout,
|
||||||
|
Stderr: buffers.Stderr,
|
||||||
|
}
|
||||||
|
pid1, err := container.Start(process)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
buffers = newStdBuffers()
|
||||||
|
psPid, err := container.Start(&libcontainer.Process{
|
||||||
|
Args: []string{"ps"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: buffers.Stdin,
|
||||||
|
Stdout: buffers.Stdout,
|
||||||
|
Stderr: buffers.Stderr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ps, err := os.FindProcess(psPid)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := ps.Wait(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p, err := os.FindProcess(pid1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := p.Signal(syscall.SIGKILL); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
if _, err := p.Wait(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
out := buffers.Stdout.String()
|
||||||
|
if !strings.Contains(out, "sleep 10") || !strings.Contains(out, "ps") {
|
||||||
|
t.Fatalf("unexpected running process, output %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecInRlimit(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rootfs, err := newRootfs()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer remove(rootfs)
|
||||||
|
config := newTemplateConfig(rootfs)
|
||||||
|
container, err := newContainer(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
|
buffers := newStdBuffers()
|
||||||
|
process := &libcontainer.Process{
|
||||||
|
Args: []string{"sleep", "10"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: buffers.Stdin,
|
||||||
|
Stdout: buffers.Stdout,
|
||||||
|
Stderr: buffers.Stderr,
|
||||||
|
}
|
||||||
|
pid1, err := container.Start(process)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
buffers = newStdBuffers()
|
||||||
|
psPid, err := container.Start(&libcontainer.Process{
|
||||||
|
Args: []string{"/bin/sh", "-c", "ulimit -n"},
|
||||||
|
Env: standardEnvironment,
|
||||||
|
Stdin: buffers.Stdin,
|
||||||
|
Stdout: buffers.Stdout,
|
||||||
|
Stderr: buffers.Stderr,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ps, err := os.FindProcess(psPid)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := ps.Wait(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p, err := os.FindProcess(pid1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := p.Signal(syscall.SIGKILL); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
if _, err := p.Wait(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
out := buffers.Stdout.String()
|
||||||
|
if limit := strings.TrimSpace(out); limit != "1024" {
|
||||||
|
t.Fatalf("expected rlimit to be 1024, got %s", limit)
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ 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)
|
||||||
}
|
}
|
||||||
factory.StartInitialization(3)
|
if err := factory.StartInitialization(3); err != nil {
|
||||||
os.Exit(1)
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,11 +67,27 @@ func copyBusybox(dest string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newContainer(config *configs.Config) (libcontainer.Container, error) {
|
||||||
|
factory, err := libcontainer.New(".",
|
||||||
|
libcontainer.InitArgs(os.Args[0], "init", "--"),
|
||||||
|
libcontainer.Cgroupfs,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return factory.Create("testCT", config)
|
||||||
|
}
|
||||||
|
|
||||||
// runContainer runs the container with the specific config and arguments
|
// runContainer runs the container with the specific config and arguments
|
||||||
//
|
//
|
||||||
// buffers are returned containing the STDOUT and STDERR output for the run
|
// buffers are returned containing the STDOUT and STDERR output for the run
|
||||||
// along with the exit code and any go error
|
// along with the exit code and any go error
|
||||||
func runContainer(config *configs.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) {
|
func runContainer(config *configs.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) {
|
||||||
|
container, err := newContainer(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
defer container.Destroy()
|
||||||
buffers = newStdBuffers()
|
buffers = newStdBuffers()
|
||||||
process := &libcontainer.Process{
|
process := &libcontainer.Process{
|
||||||
Args: args,
|
Args: args,
|
||||||
|
@ -81,32 +97,18 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe
|
||||||
Stderr: buffers.Stderr,
|
Stderr: buffers.Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
factory, err := libcontainer.New(".", libcontainer.InitArgs(os.Args[0], "init", "--"), libcontainer.Cgroupfs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := factory.Create("testCT", config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
defer container.Destroy()
|
|
||||||
|
|
||||||
pid, err := container.Start(process)
|
pid, err := container.Start(process)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := os.FindProcess(pid)
|
p, err := os.FindProcess(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ps, err := p.Wait()
|
ps, err := p.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
status := ps.Sys().(syscall.WaitStatus)
|
status := ps.Sys().(syscall.WaitStatus)
|
||||||
if status.Exited() {
|
if status.Exited() {
|
||||||
exitCode = status.ExitStatus()
|
exitCode = status.ExitStatus()
|
||||||
|
@ -115,6 +117,5 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe
|
||||||
} else {
|
} else {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type linuxContainer struct {
|
type linuxContainer struct {
|
||||||
|
@ -49,7 +49,6 @@ func (c *linuxContainer) State() (*State, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) Processes() ([]int, error) {
|
func (c *linuxContainer) Processes() ([]int, error) {
|
||||||
glog.Info("fetch container processes")
|
|
||||||
pids, err := c.cgroupManager.GetPids()
|
pids, err := c.cgroupManager.GetPids()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newSystemError(err)
|
return nil, newSystemError(err)
|
||||||
|
@ -58,7 +57,6 @@ func (c *linuxContainer) Processes() ([]int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linuxContainer) Stats() (*Stats, error) {
|
func (c *linuxContainer) Stats() (*Stats, error) {
|
||||||
glog.Info("fetch container stats")
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
stats = &Stats{}
|
stats = &Stats{}
|
||||||
|
@ -94,7 +92,7 @@ func (c *linuxContainer) Start(process *Process) (int, error) {
|
||||||
if err := parent.start(); err != nil {
|
if err := parent.start(); err != nil {
|
||||||
// terminate the process to ensure that it properly is reaped.
|
// terminate the process to ensure that it properly is reaped.
|
||||||
if err := parent.terminate(); err != nil {
|
if err := parent.terminate(); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
return -1, newSystemError(err)
|
return -1, newSystemError(err)
|
||||||
}
|
}
|
||||||
|
@ -207,7 +205,7 @@ func (c *linuxContainer) Destroy() error {
|
||||||
}
|
}
|
||||||
if !c.config.Namespaces.Contains(configs.NEWPID) {
|
if !c.config.Namespaces.Contains(configs.NEWPID) {
|
||||||
if err := killCgroupProcesses(c.cgroupManager); err != nil {
|
if err := killCgroupProcesses(c.cgroupManager); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = c.cgroupManager.Destroy()
|
err = c.cgroupManager.Destroy()
|
||||||
|
|
|
@ -9,13 +9,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
"github.com/docker/libcontainer/netlink"
|
"github.com/docker/libcontainer/netlink"
|
||||||
"github.com/docker/libcontainer/system"
|
"github.com/docker/libcontainer/system"
|
||||||
"github.com/docker/libcontainer/user"
|
"github.com/docker/libcontainer/user"
|
||||||
"github.com/docker/libcontainer/utils"
|
"github.com/docker/libcontainer/utils"
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type initType string
|
type initType string
|
||||||
|
@ -235,7 +235,7 @@ func setupRlimits(config *configs.Config) error {
|
||||||
func killCgroupProcesses(m cgroups.Manager) error {
|
func killCgroupProcesses(m cgroups.Manager) error {
|
||||||
var procs []*os.Process
|
var procs []*os.Process
|
||||||
if err := m.Freeze(configs.Frozen); err != nil {
|
if err := m.Freeze(configs.Frozen); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
pids, err := m.GetPids()
|
pids, err := m.GetPids()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -246,16 +246,16 @@ func killCgroupProcesses(m cgroups.Manager) error {
|
||||||
if p, err := os.FindProcess(pid); err == nil {
|
if p, err := os.FindProcess(pid); err == nil {
|
||||||
procs = append(procs, p)
|
procs = append(procs, p)
|
||||||
if err := p.Kill(); err != nil {
|
if err := p.Kill(); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := m.Freeze(configs.Thawed); err != nil {
|
if err := m.Freeze(configs.Thawed); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
for _, p := range procs {
|
for _, p := range procs {
|
||||||
if _, err := p.Wait(); err != nil {
|
if _, err := p.Wait(); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/system"
|
"github.com/docker/libcontainer/system"
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type parentProcess interface {
|
type parentProcess interface {
|
||||||
|
@ -82,7 +82,7 @@ func (p *setnsProcess) execSetns() (*os.Process, error) {
|
||||||
return nil, newSystemError(err)
|
return nil, newSystemError(err)
|
||||||
}
|
}
|
||||||
if !status.Success() {
|
if !status.Success() {
|
||||||
return nil, newSystemError(&exec.ExitError{status})
|
return nil, newSystemError(&exec.ExitError{ProcessState: status})
|
||||||
}
|
}
|
||||||
var pid *pid
|
var pid *pid
|
||||||
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil {
|
if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil {
|
||||||
|
@ -153,7 +153,7 @@ func (p *initProcess) start() error {
|
||||||
}
|
}
|
||||||
if err := parent.start(); err != nil {
|
if err := parent.start(); err != nil {
|
||||||
if err := parent.terminate(); err != nil {
|
if err := parent.terminate(); err != nil {
|
||||||
glog.Warning(err)
|
log.Warn(err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -23,6 +22,7 @@ const (
|
||||||
IFLA_VLAN_ID = 1
|
IFLA_VLAN_ID = 1
|
||||||
IFLA_NET_NS_FD = 28
|
IFLA_NET_NS_FD = 28
|
||||||
IFLA_ADDRESS = 1
|
IFLA_ADDRESS = 1
|
||||||
|
IFLA_BRPORT_MODE = 4
|
||||||
SIOC_BRADDBR = 0x89a0
|
SIOC_BRADDBR = 0x89a0
|
||||||
SIOC_BRDELBR = 0x89a1
|
SIOC_BRDELBR = 0x89a1
|
||||||
SIOC_BRADDIF = 0x89a2
|
SIOC_BRADDIF = 0x89a2
|
||||||
|
@ -1253,25 +1253,33 @@ func SetMacAddress(name, addr string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetHairpinMode(iface *net.Interface, enabled bool) error {
|
func SetHairpinMode(iface *net.Interface, enabled bool) error {
|
||||||
sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode")
|
s, err := getNetlinkSocket()
|
||||||
|
|
||||||
sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer sysFile.Close()
|
defer s.Close()
|
||||||
|
req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||||
|
|
||||||
var writeVal []byte
|
msg := newIfInfomsg(syscall.AF_BRIDGE)
|
||||||
|
msg.Type = syscall.RTM_SETLINK
|
||||||
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
|
msg.Index = int32(iface.Index)
|
||||||
|
msg.Change = DEFAULT_CHANGE
|
||||||
|
req.AddData(msg)
|
||||||
|
|
||||||
|
mode := []byte{0}
|
||||||
if enabled {
|
if enabled {
|
||||||
writeVal = []byte("1")
|
mode[0] = byte(1)
|
||||||
} else {
|
|
||||||
writeVal = []byte("0")
|
|
||||||
}
|
}
|
||||||
if _, err := sysFile.Write(writeVal); err != nil {
|
|
||||||
|
br := newRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
||||||
|
newRtAttrChild(br, IFLA_BRPORT_MODE, mode)
|
||||||
|
req.AddData(br)
|
||||||
|
if err := s.Send(req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return s.HandleAck(req.Seq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeName(iface *net.Interface, newName string) error {
|
func ChangeName(iface *net.Interface, newName string) error {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
"github.com/docker/libcontainer/utils"
|
"github.com/docker/libcontainer/utils"
|
||||||
|
@ -31,6 +32,7 @@ var execCommand = cli.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func execAction(context *cli.Context) {
|
func execAction(context *cli.Context) {
|
||||||
|
entry := log.WithField("parent", "nsinit")
|
||||||
factory, err := loadFactory(context)
|
factory, err := loadFactory(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
|
@ -42,9 +44,7 @@ func execAction(context *cli.Context) {
|
||||||
created := false
|
created := false
|
||||||
container, err := factory.Load(context.String("id"))
|
container, err := factory.Load(context.String("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if lerr, ok := err.(libcontainer.Error); !ok || lerr.Code() != libcontainer.ContainerNotExists {
|
entry.Debug("creating container")
|
||||||
fatal(err)
|
|
||||||
}
|
|
||||||
config, err := loadConfig(context)
|
config, err := loadConfig(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
@ -53,6 +53,7 @@ func execAction(context *cli.Context) {
|
||||||
if tty.console != nil {
|
if tty.console != nil {
|
||||||
config.Console = tty.console.Path()
|
config.Console = tty.console.Path()
|
||||||
}
|
}
|
||||||
|
|
||||||
created = true
|
created = true
|
||||||
if container, err = factory.Create(context.String("id"), config); err != nil {
|
if container, err = factory.Create(context.String("id"), config); err != nil {
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
@ -72,16 +73,25 @@ func execAction(context *cli.Context) {
|
||||||
pid, err := container.Start(process)
|
pid, err := container.Start(process)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
if created {
|
||||||
|
container.Destroy()
|
||||||
|
}
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
proc, err := os.FindProcess(pid)
|
proc, err := os.FindProcess(pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
if created {
|
||||||
|
container.Destroy()
|
||||||
|
}
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
status, err := proc.Wait()
|
status, err := proc.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
if created {
|
||||||
|
container.Destroy()
|
||||||
|
}
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
if created {
|
if created {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
_ "github.com/docker/libcontainer/nsenter"
|
_ "github.com/docker/libcontainer/nsenter"
|
||||||
|
@ -13,6 +13,7 @@ var initCommand = cli.Command{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
Usage: "runs the init process inside the namespace",
|
Usage: "runs the init process inside the namespace",
|
||||||
Action: func(context *cli.Context) {
|
Action: func(context *cli.Context) {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
runtime.GOMAXPROCS(1)
|
runtime.GOMAXPROCS(1)
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
factory, err := libcontainer.New("")
|
factory, err := libcontainer.New("")
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ 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: "nspid"},
|
|
||||||
cli.StringFlag{Name: "console"},
|
|
||||||
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
|
cli.StringFlag{Name: "root", Value: ".", Usage: "root directory for containers"},
|
||||||
|
cli.StringFlag{Name: "log-file", Value: "nsinit-debug.log", Usage: "set the log file to output logs to"},
|
||||||
|
cli.BoolFlag{Name: "debug", Usage: "enable debug output in the logs"},
|
||||||
}
|
}
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
configCommand,
|
configCommand,
|
||||||
|
@ -27,6 +27,19 @@ func main() {
|
||||||
unpauseCommand,
|
unpauseCommand,
|
||||||
stateCommand,
|
stateCommand,
|
||||||
}
|
}
|
||||||
|
app.Before = func(context *cli.Context) error {
|
||||||
|
if context.GlobalBool("debug") {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
}
|
||||||
|
if path := context.GlobalString("log-file"); path != "" {
|
||||||
|
f, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.SetOutput(f)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,194 +1,341 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/rootfs/jessie",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "",
|
||||||
},
|
"hostname": "nsinit",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"apparmor_profile": "docker-default",
|
},
|
||||||
"devices": [
|
{
|
||||||
{
|
"type": "NEWPID",
|
||||||
"permissions": "rwm",
|
"path": ""
|
||||||
"file_mode": 438,
|
},
|
||||||
"major": 1,
|
{
|
||||||
"minor": 3,
|
"type": "NEWNET",
|
||||||
"path": "/dev/null",
|
"path": ""
|
||||||
"type": 99
|
}
|
||||||
},
|
],
|
||||||
{
|
"capabilities": [
|
||||||
"permissions": "rwm",
|
"CHOWN",
|
||||||
"file_mode": 438,
|
"DAC_OVERRIDE",
|
||||||
"major": 1,
|
"FSETID",
|
||||||
"minor": 5,
|
"FOWNER",
|
||||||
"path": "/dev/zero",
|
"MKNOD",
|
||||||
"type": 99
|
"NET_RAW",
|
||||||
},
|
"SETGID",
|
||||||
{
|
"SETUID",
|
||||||
"permissions": "rwm",
|
"SETFCAP",
|
||||||
"file_mode": 438,
|
"SETPCAP",
|
||||||
"major": 1,
|
"NET_BIND_SERVICE",
|
||||||
"minor": 7,
|
"SYS_CHROOT",
|
||||||
"path": "/dev/full",
|
"KILL",
|
||||||
"type": 99
|
"AUDIT_WRITE"
|
||||||
},
|
],
|
||||||
{
|
"networks": [
|
||||||
"permissions": "rwm",
|
{
|
||||||
"file_mode": 438,
|
"type": "loopback",
|
||||||
"major": 5,
|
"name": "",
|
||||||
"path": "/dev/tty",
|
"bridge": "",
|
||||||
"type": 99
|
"mac_address": "",
|
||||||
},
|
"address": "127.0.0.1/0",
|
||||||
{
|
"gateway": "localhost",
|
||||||
"permissions": "rwm",
|
"ipv6_address": "",
|
||||||
"file_mode": 438,
|
"ipv6_gateway": "",
|
||||||
"major": 1,
|
"mtu": 0,
|
||||||
"minor": 9,
|
"txqueuelen": 0,
|
||||||
"path": "/dev/urandom",
|
"host_interface_name": ""
|
||||||
"type": 99
|
}
|
||||||
},
|
],
|
||||||
{
|
"routes": null,
|
||||||
"permissions": "rwm",
|
"cgroups": {
|
||||||
"file_mode": 438,
|
"name": "libcontainer",
|
||||||
"major": 1,
|
"parent": "nsinit",
|
||||||
"minor": 8,
|
"allow_all_devices": false,
|
||||||
"path": "/dev/random",
|
"allowed_devices": [
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": 99,
|
||||||
],
|
"path": "",
|
||||||
"environment": [
|
"major": -1,
|
||||||
"HOME=/",
|
"minor": -1,
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
"permissions": "m",
|
||||||
"HOSTNAME=koye",
|
"file_mode": 0,
|
||||||
"TERM=xterm"
|
"uid": 0,
|
||||||
],
|
"gid": 0
|
||||||
"hostname": "koye",
|
},
|
||||||
"namespaces": [
|
{
|
||||||
{"type":"NEWIPC"},
|
"type": 98,
|
||||||
{"type": "NEWNET"},
|
"path": "",
|
||||||
{"type": "NEWNS"},
|
"major": -1,
|
||||||
{"type": "NEWPID"},
|
"minor": -1,
|
||||||
{"type": "NEWUTS"}
|
"permissions": "m",
|
||||||
],
|
"file_mode": 0,
|
||||||
"networks": [
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"address": "127.0.0.1/0",
|
},
|
||||||
"gateway": "localhost",
|
{
|
||||||
"mtu": 1500,
|
"type": 99,
|
||||||
"type": "loopback"
|
"path": "/dev/console",
|
||||||
}
|
"major": 5,
|
||||||
],
|
"minor": 1,
|
||||||
"tty": true,
|
"permissions": "rwm",
|
||||||
"user": "daemon"
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty0",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty1",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 136,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 2,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 200,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "docker-default",
|
||||||
|
"process_label": "",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": null,
|
||||||
|
"gid_mappings": null,
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,200 +1,354 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/rootfs/jessie",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "",
|
||||||
},
|
"hostname": "koye",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"devices": [
|
},
|
||||||
|
{
|
||||||
|
"type": "NEWPID",
|
||||||
|
"path": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NEWNET",
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"capabilities": [
|
||||||
|
"CHOWN",
|
||||||
|
"DAC_OVERRIDE",
|
||||||
|
"FSETID",
|
||||||
|
"FOWNER",
|
||||||
|
"MKNOD",
|
||||||
|
"NET_RAW",
|
||||||
|
"SETGID",
|
||||||
|
"SETUID",
|
||||||
|
"SETFCAP",
|
||||||
|
"SETPCAP",
|
||||||
|
"NET_BIND_SERVICE",
|
||||||
|
"SYS_CHROOT",
|
||||||
|
"KILL",
|
||||||
|
"AUDIT_WRITE"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"type": "loopback",
|
||||||
|
"name": "",
|
||||||
|
"bridge": "",
|
||||||
|
"mac_address": "",
|
||||||
|
"address": "127.0.0.1/0",
|
||||||
|
"gateway": "localhost",
|
||||||
|
"ipv6_address": "",
|
||||||
|
"ipv6_gateway": "",
|
||||||
|
"mtu": 0,
|
||||||
|
"txqueuelen": 0,
|
||||||
|
"host_interface_name": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": "veth",
|
||||||
"file_mode": 438,
|
"name": "eth0",
|
||||||
"major": 1,
|
"bridge": "docker0",
|
||||||
"minor": 3,
|
"mac_address": "",
|
||||||
"path": "/dev/null",
|
"address": "172.17.0.101/16",
|
||||||
"type": 99
|
"gateway": "172.17.42.1",
|
||||||
},
|
"ipv6_address": "",
|
||||||
{
|
"ipv6_gateway": "",
|
||||||
"permissions": "rwm",
|
"mtu": 1500,
|
||||||
"file_mode": 438,
|
"txqueuelen": 0,
|
||||||
"major": 1,
|
"host_interface_name": "vethnsinit"
|
||||||
"minor": 5,
|
}
|
||||||
"path": "/dev/zero",
|
],
|
||||||
"type": 99
|
"routes": null,
|
||||||
},
|
"cgroups": {
|
||||||
{
|
"name": "libcontainer",
|
||||||
"permissions": "rwm",
|
"parent": "nsinit",
|
||||||
"file_mode": 438,
|
"allow_all_devices": false,
|
||||||
"major": 1,
|
"allowed_devices": [
|
||||||
"minor": 7,
|
{
|
||||||
"path": "/dev/full",
|
"type": 99,
|
||||||
"type": 99
|
"path": "",
|
||||||
},
|
"major": -1,
|
||||||
{
|
"minor": -1,
|
||||||
"permissions": "rwm",
|
"permissions": "m",
|
||||||
"file_mode": 438,
|
"file_mode": 0,
|
||||||
"major": 5,
|
"uid": 0,
|
||||||
"path": "/dev/tty",
|
"gid": 0
|
||||||
"type": 99
|
},
|
||||||
},
|
{
|
||||||
{
|
"type": 98,
|
||||||
"permissions": "rwm",
|
"path": "",
|
||||||
"file_mode": 438,
|
"major": -1,
|
||||||
"major": 1,
|
"minor": -1,
|
||||||
"minor": 9,
|
"permissions": "m",
|
||||||
"path": "/dev/urandom",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"file_mode": 438,
|
"type": 99,
|
||||||
"major": 1,
|
"path": "/dev/console",
|
||||||
"minor": 8,
|
"major": 5,
|
||||||
"path": "/dev/random",
|
"minor": 1,
|
||||||
"type": 99
|
"permissions": "rwm",
|
||||||
}
|
"file_mode": 0,
|
||||||
],
|
"uid": 0,
|
||||||
"environment": [
|
"gid": 0
|
||||||
"HOME=/",
|
},
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
{
|
||||||
"HOSTNAME=koye",
|
"type": 99,
|
||||||
"TERM=xterm"
|
"path": "/dev/tty0",
|
||||||
],
|
"major": 4,
|
||||||
"hostname": "koye",
|
"minor": 0,
|
||||||
"namespaces": [
|
"permissions": "rwm",
|
||||||
{"type": "NEWIPC"},
|
"file_mode": 0,
|
||||||
{"type": "NEWNET"},
|
"uid": 0,
|
||||||
{"type": "NEWNS"},
|
"gid": 0
|
||||||
{"type": "NEWPID"},
|
},
|
||||||
{"type": "NEWUTS"}
|
{
|
||||||
],
|
"type": 99,
|
||||||
"networks": [
|
"path": "/dev/tty1",
|
||||||
{
|
"major": 4,
|
||||||
"address": "127.0.0.1/0",
|
"minor": 1,
|
||||||
"gateway": "localhost",
|
"permissions": "rwm",
|
||||||
"mtu": 1500,
|
"file_mode": 0,
|
||||||
"type": "loopback"
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"address": "172.17.0.101/16",
|
{
|
||||||
"bridge": "docker0",
|
"type": 99,
|
||||||
"veth_prefix": "veth",
|
"path": "",
|
||||||
"gateway": "172.17.42.1",
|
"major": 136,
|
||||||
"mtu": 1500,
|
"minor": -1,
|
||||||
"type": "veth"
|
"permissions": "rwm",
|
||||||
}
|
"file_mode": 0,
|
||||||
],
|
"uid": 0,
|
||||||
"tty": true
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 2,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 200,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "",
|
||||||
|
"process_label": "",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": null,
|
||||||
|
"gid_mappings": null,
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,198 +1,337 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/rootfs/jessie",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "",
|
||||||
},
|
"hostname": "nsinit",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"devices": [
|
},
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 3,
|
|
||||||
"path": "/dev/null",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 5,
|
|
||||||
"path": "/dev/zero",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 7,
|
|
||||||
"path": "/dev/full",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 5,
|
|
||||||
"path": "/dev/tty",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 9,
|
|
||||||
"path": "/dev/urandom",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 8,
|
|
||||||
"path": "/dev/random",
|
|
||||||
"type": 99
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"mounts": [
|
|
||||||
{
|
|
||||||
"type": "tmpfs",
|
|
||||||
"destination": "/tmp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"environment": [
|
|
||||||
"HOME=/",
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
||||||
"HOSTNAME=koye",
|
|
||||||
"TERM=xterm"
|
|
||||||
],
|
|
||||||
"hostname": "koye",
|
|
||||||
"namespaces": [
|
|
||||||
{"type": "NEWIPC"},
|
|
||||||
{"type": "NEWNET"},
|
|
||||||
{"type": "NEWNS"},
|
|
||||||
{"type": "NEWUTS"}
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
{
|
{
|
||||||
"address": "127.0.0.1/0",
|
"type": "NEWNET",
|
||||||
"gateway": "localhost",
|
"path": ""
|
||||||
"mtu": 1500,
|
}
|
||||||
"type": "loopback"
|
],
|
||||||
}
|
"capabilities": [
|
||||||
],
|
"CHOWN",
|
||||||
"tty": true,
|
"DAC_OVERRIDE",
|
||||||
"user": "daemon"
|
"FSETID",
|
||||||
|
"FOWNER",
|
||||||
|
"MKNOD",
|
||||||
|
"NET_RAW",
|
||||||
|
"SETGID",
|
||||||
|
"SETUID",
|
||||||
|
"SETFCAP",
|
||||||
|
"SETPCAP",
|
||||||
|
"NET_BIND_SERVICE",
|
||||||
|
"SYS_CHROOT",
|
||||||
|
"KILL",
|
||||||
|
"AUDIT_WRITE"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"type": "loopback",
|
||||||
|
"name": "",
|
||||||
|
"bridge": "",
|
||||||
|
"mac_address": "",
|
||||||
|
"address": "127.0.0.1/0",
|
||||||
|
"gateway": "localhost",
|
||||||
|
"ipv6_address": "",
|
||||||
|
"ipv6_gateway": "",
|
||||||
|
"mtu": 0,
|
||||||
|
"txqueuelen": 0,
|
||||||
|
"host_interface_name": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": null,
|
||||||
|
"cgroups": {
|
||||||
|
"name": "libcontainer",
|
||||||
|
"parent": "nsinit",
|
||||||
|
"allow_all_devices": false,
|
||||||
|
"allowed_devices": [
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": -1,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "m",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 98,
|
||||||
|
"path": "",
|
||||||
|
"major": -1,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "m",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/console",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty0",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty1",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 136,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 2,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 200,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "",
|
||||||
|
"process_label": "",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": null,
|
||||||
|
"gid_mappings": null,
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,199 +1,341 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/home/michael/development/gocode/src/github.com/docker/libcontainer",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "",
|
||||||
},
|
"hostname": "nsinit",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"devices": [
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": "NEWPID",
|
||||||
"file_mode": 438,
|
"path": ""
|
||||||
"major": 1,
|
},
|
||||||
"minor": 3,
|
{
|
||||||
"path": "/dev/null",
|
"type": "NEWNET",
|
||||||
"type": 99
|
"path": ""
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"permissions": "rwm",
|
"capabilities": [
|
||||||
"file_mode": 438,
|
"CHOWN",
|
||||||
"major": 1,
|
"DAC_OVERRIDE",
|
||||||
"minor": 5,
|
"FSETID",
|
||||||
"path": "/dev/zero",
|
"FOWNER",
|
||||||
"type": 99
|
"MKNOD",
|
||||||
},
|
"NET_RAW",
|
||||||
{
|
"SETGID",
|
||||||
"permissions": "rwm",
|
"SETUID",
|
||||||
"file_mode": 438,
|
"SETFCAP",
|
||||||
"major": 1,
|
"SETPCAP",
|
||||||
"minor": 7,
|
"NET_BIND_SERVICE",
|
||||||
"path": "/dev/full",
|
"SYS_CHROOT",
|
||||||
"type": 99
|
"KILL",
|
||||||
},
|
"AUDIT_WRITE"
|
||||||
{
|
],
|
||||||
"permissions": "rwm",
|
"networks": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": "loopback",
|
||||||
"path": "/dev/tty",
|
"name": "",
|
||||||
"type": 99
|
"bridge": "",
|
||||||
},
|
"mac_address": "",
|
||||||
{
|
"address": "127.0.0.1/0",
|
||||||
"permissions": "rwm",
|
"gateway": "localhost",
|
||||||
"file_mode": 438,
|
"ipv6_address": "",
|
||||||
"major": 1,
|
"ipv6_gateway": "",
|
||||||
"minor": 9,
|
"mtu": 0,
|
||||||
"path": "/dev/urandom",
|
"txqueuelen": 0,
|
||||||
"type": 99
|
"host_interface_name": ""
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"permissions": "rwm",
|
"routes": null,
|
||||||
"file_mode": 438,
|
"cgroups": {
|
||||||
"major": 1,
|
"name": "libcontainer",
|
||||||
"minor": 8,
|
"parent": "nsinit",
|
||||||
"path": "/dev/random",
|
"allow_all_devices": false,
|
||||||
"type": 99
|
"allowed_devices": [
|
||||||
}
|
{
|
||||||
],
|
"type": 99,
|
||||||
"mounts": [
|
"path": "",
|
||||||
{
|
"major": -1,
|
||||||
"type": "tmpfs",
|
"minor": -1,
|
||||||
"destination": "/tmp"
|
"permissions": "m",
|
||||||
}
|
"file_mode": 0,
|
||||||
],
|
"uid": 0,
|
||||||
"environment": [
|
"gid": 0
|
||||||
"HOME=/",
|
},
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
{
|
||||||
"HOSTNAME=koye",
|
"type": 98,
|
||||||
"TERM=xterm"
|
"path": "",
|
||||||
],
|
"major": -1,
|
||||||
"hostname": "koye",
|
"minor": -1,
|
||||||
"namespaces": [
|
"permissions": "m",
|
||||||
{"type": "NEWIPC"},
|
"file_mode": 0,
|
||||||
{"type": "NEWNET"},
|
"uid": 0,
|
||||||
{"type": "NEWNS"},
|
"gid": 0
|
||||||
{"type": "NEWPID"},
|
},
|
||||||
{"type": "NEWUTS"}
|
{
|
||||||
],
|
"type": 99,
|
||||||
"networks": [
|
"path": "/dev/console",
|
||||||
{
|
"major": 5,
|
||||||
"address": "127.0.0.1/0",
|
"minor": 1,
|
||||||
"gateway": "localhost",
|
"permissions": "rwm",
|
||||||
"mtu": 1500,
|
"file_mode": 0,
|
||||||
"type": "loopback"
|
"uid": 0,
|
||||||
}
|
"gid": 0
|
||||||
],
|
},
|
||||||
"tty": true,
|
{
|
||||||
"user": "daemon"
|
"type": 99,
|
||||||
}
|
"path": "/dev/tty0",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty1",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 136,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 2,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 200,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "",
|
||||||
|
"process_label": "",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": null,
|
||||||
|
"gid_mappings": null,
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,207 +0,0 @@
|
||||||
{
|
|
||||||
"capabilities": [
|
|
||||||
"CHOWN",
|
|
||||||
"DAC_OVERRIDE",
|
|
||||||
"FOWNER",
|
|
||||||
"MKNOD",
|
|
||||||
"NET_RAW",
|
|
||||||
"SETGID",
|
|
||||||
"SETUID",
|
|
||||||
"SETFCAP",
|
|
||||||
"SETPCAP",
|
|
||||||
"NET_BIND_SERVICE",
|
|
||||||
"SYS_CHROOT",
|
|
||||||
"KILL"
|
|
||||||
],
|
|
||||||
"cgroups": {
|
|
||||||
"allowed_devices": [
|
|
||||||
{
|
|
||||||
"permissions": "m",
|
|
||||||
"major": -1,
|
|
||||||
"minor": -1,
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "m",
|
|
||||||
"major": -1,
|
|
||||||
"minor": -1,
|
|
||||||
"type": 98
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 5,
|
|
||||||
"minor": 1,
|
|
||||||
"path": "/dev/console",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 4,
|
|
||||||
"path": "/dev/tty0",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 4,
|
|
||||||
"minor": 1,
|
|
||||||
"path": "/dev/tty1",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 136,
|
|
||||||
"minor": -1,
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 5,
|
|
||||||
"minor": 2,
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"major": 10,
|
|
||||||
"minor": 200,
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 3,
|
|
||||||
"path": "/dev/null",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 5,
|
|
||||||
"path": "/dev/zero",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 7,
|
|
||||||
"path": "/dev/full",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 5,
|
|
||||||
"path": "/dev/tty",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 9,
|
|
||||||
"path": "/dev/urandom",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 8,
|
|
||||||
"path": "/dev/random",
|
|
||||||
"type": 99
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "docker-koye",
|
|
||||||
"parent": "docker"
|
|
||||||
},
|
|
||||||
"restrict_sys": true,
|
|
||||||
"devices": [
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 3,
|
|
||||||
"path": "/dev/null",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 5,
|
|
||||||
"path": "/dev/zero",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 7,
|
|
||||||
"path": "/dev/full",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 5,
|
|
||||||
"path": "/dev/tty",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 9,
|
|
||||||
"path": "/dev/urandom",
|
|
||||||
"type": 99
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"permissions": "rwm",
|
|
||||||
"file_mode": 438,
|
|
||||||
"major": 1,
|
|
||||||
"minor": 8,
|
|
||||||
"path": "/dev/random",
|
|
||||||
"type": 99
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"environment": [
|
|
||||||
"HOME=/",
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
||||||
"HOSTNAME=koye",
|
|
||||||
"TERM=xterm"
|
|
||||||
],
|
|
||||||
"hostname": "koye",
|
|
||||||
"namespaces": [
|
|
||||||
{"type": "NEWIPC"},
|
|
||||||
{"type": "NEWNET"},
|
|
||||||
{"type": "NEWNS"},
|
|
||||||
{"type": "NEWPID"},
|
|
||||||
{"type": "NEWUTS"}
|
|
||||||
],
|
|
||||||
"networks": [
|
|
||||||
{
|
|
||||||
"address": "127.0.0.1/0",
|
|
||||||
"gateway": "localhost",
|
|
||||||
"mtu": 1500,
|
|
||||||
"type": "loopback"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"address": "172.17.0.101/16",
|
|
||||||
"bridge": "docker0",
|
|
||||||
"veth_prefix": "veth",
|
|
||||||
"mtu": 1500,
|
|
||||||
"type": "veth"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"routes": [
|
|
||||||
{
|
|
||||||
"destination": "0.0.0.0/0",
|
|
||||||
"source": "172.17.0.101",
|
|
||||||
"gateway": "172.17.42.1",
|
|
||||||
"interface_name": "eth0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tty": true
|
|
||||||
}
|
|
|
@ -1,195 +1,341 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/rootfs/jessie",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475",
|
||||||
},
|
"hostname": "nsinit",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"process_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475",
|
},
|
||||||
"mount_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475",
|
{
|
||||||
"devices": [
|
"type": "NEWPID",
|
||||||
{
|
"path": ""
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNET",
|
||||||
"minor": 3,
|
"path": ""
|
||||||
"path": "/dev/null",
|
}
|
||||||
"type": 99
|
],
|
||||||
},
|
"capabilities": [
|
||||||
{
|
"CHOWN",
|
||||||
"permissions": "rwm",
|
"DAC_OVERRIDE",
|
||||||
"file_mode": 438,
|
"FSETID",
|
||||||
"major": 1,
|
"FOWNER",
|
||||||
"minor": 5,
|
"MKNOD",
|
||||||
"path": "/dev/zero",
|
"NET_RAW",
|
||||||
"type": 99
|
"SETGID",
|
||||||
},
|
"SETUID",
|
||||||
{
|
"SETFCAP",
|
||||||
"permissions": "rwm",
|
"SETPCAP",
|
||||||
"file_mode": 438,
|
"NET_BIND_SERVICE",
|
||||||
"major": 1,
|
"SYS_CHROOT",
|
||||||
"minor": 7,
|
"KILL",
|
||||||
"path": "/dev/full",
|
"AUDIT_WRITE"
|
||||||
"type": 99
|
],
|
||||||
},
|
"networks": [
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": "loopback",
|
||||||
"file_mode": 438,
|
"name": "",
|
||||||
"major": 5,
|
"bridge": "",
|
||||||
"path": "/dev/tty",
|
"mac_address": "",
|
||||||
"type": 99
|
"address": "127.0.0.1/0",
|
||||||
},
|
"gateway": "localhost",
|
||||||
{
|
"ipv6_address": "",
|
||||||
"permissions": "rwm",
|
"ipv6_gateway": "",
|
||||||
"file_mode": 438,
|
"mtu": 0,
|
||||||
"major": 1,
|
"txqueuelen": 0,
|
||||||
"minor": 9,
|
"host_interface_name": ""
|
||||||
"path": "/dev/urandom",
|
}
|
||||||
"type": 99
|
],
|
||||||
},
|
"routes": null,
|
||||||
{
|
"cgroups": {
|
||||||
"permissions": "rwm",
|
"name": "libcontainer",
|
||||||
"file_mode": 438,
|
"parent": "nsinit",
|
||||||
"major": 1,
|
"allow_all_devices": false,
|
||||||
"minor": 8,
|
"allowed_devices": [
|
||||||
"path": "/dev/random",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
}
|
"path": "",
|
||||||
],
|
"major": -1,
|
||||||
"environment": [
|
"minor": -1,
|
||||||
"HOME=/",
|
"permissions": "m",
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
"file_mode": 0,
|
||||||
"HOSTNAME=koye",
|
"uid": 0,
|
||||||
"TERM=xterm"
|
"gid": 0
|
||||||
],
|
},
|
||||||
"hostname": "koye",
|
{
|
||||||
"namespaces": [
|
"type": 98,
|
||||||
{"type": "NEWIPC"},
|
"path": "",
|
||||||
{"type": "NEWNET"},
|
"major": -1,
|
||||||
{"type": "NEWNS"},
|
"minor": -1,
|
||||||
{"type": "NEWPID"},
|
"permissions": "m",
|
||||||
{"type": "NEWUTS"}
|
"file_mode": 0,
|
||||||
],
|
"uid": 0,
|
||||||
"networks": [
|
"gid": 0
|
||||||
{
|
},
|
||||||
"address": "127.0.0.1/0",
|
{
|
||||||
"gateway": "localhost",
|
"type": 99,
|
||||||
"mtu": 1500,
|
"path": "/dev/console",
|
||||||
"type": "loopback"
|
"major": 5,
|
||||||
}
|
"minor": 1,
|
||||||
],
|
"permissions": "rwm",
|
||||||
"tty": true,
|
"file_mode": 0,
|
||||||
"user": "daemon"
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty0",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty1",
|
||||||
|
"major": 4,
|
||||||
|
"minor": 1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 136,
|
||||||
|
"minor": -1,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 2,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "",
|
||||||
|
"major": 10,
|
||||||
|
"minor": 200,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 0,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "",
|
||||||
|
"process_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": null,
|
||||||
|
"gid_mappings": null,
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,249 +1,377 @@
|
||||||
{
|
{
|
||||||
"capabilities": [
|
"no_pivot_root": false,
|
||||||
"CHOWN",
|
"parent_death_signal": 0,
|
||||||
"DAC_OVERRIDE",
|
"pivot_dir": "",
|
||||||
"FOWNER",
|
"rootfs": "/rootfs/jessie",
|
||||||
"MKNOD",
|
"readonlyfs": false,
|
||||||
"NET_RAW",
|
"mounts": [
|
||||||
"SETGID",
|
{
|
||||||
"SETUID",
|
"source": "shm",
|
||||||
"SETFCAP",
|
"destination": "/dev/shm",
|
||||||
"SETPCAP",
|
"device": "tmpfs",
|
||||||
"NET_BIND_SERVICE",
|
"flags": 14,
|
||||||
"SYS_CHROOT",
|
"data": "mode=1777,size=65536k",
|
||||||
"KILL"
|
"relabel": ""
|
||||||
],
|
},
|
||||||
"cgroups": {
|
{
|
||||||
"allowed_devices": [
|
"source": "mqueue",
|
||||||
{
|
"destination": "/dev/mqueue",
|
||||||
"permissions": "m",
|
"device": "mqueue",
|
||||||
"major": -1,
|
"flags": 14,
|
||||||
"minor": -1,
|
"data": "",
|
||||||
"type": 99
|
"relabel": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "m",
|
"source": "sysfs",
|
||||||
"major": -1,
|
"destination": "/sys",
|
||||||
"minor": -1,
|
"device": "sysfs",
|
||||||
"type": 98
|
"flags": 15,
|
||||||
},
|
"data": "",
|
||||||
{
|
"relabel": ""
|
||||||
"permissions": "rwm",
|
}
|
||||||
"major": 5,
|
],
|
||||||
"minor": 1,
|
"devices": [
|
||||||
"path": "/dev/console",
|
{
|
||||||
"type": 99
|
"type": 99,
|
||||||
},
|
"path": "/dev/fuse",
|
||||||
{
|
"major": 10,
|
||||||
"permissions": "rwm",
|
"minor": 229,
|
||||||
"major": 4,
|
"permissions": "rwm",
|
||||||
"path": "/dev/tty0",
|
"file_mode": 0,
|
||||||
"type": 99
|
"uid": 0,
|
||||||
},
|
"gid": 0
|
||||||
{
|
},
|
||||||
"permissions": "rwm",
|
{
|
||||||
"major": 4,
|
"type": 99,
|
||||||
"minor": 1,
|
"path": "/dev/null",
|
||||||
"path": "/dev/tty1",
|
"major": 1,
|
||||||
"type": 99
|
"minor": 3,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 438,
|
||||||
"permissions": "rwm",
|
"uid": 0,
|
||||||
"major": 136,
|
"gid": 0
|
||||||
"minor": -1,
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/zero",
|
||||||
"permissions": "rwm",
|
"major": 1,
|
||||||
"major": 5,
|
"minor": 5,
|
||||||
"minor": 2,
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"major": 10,
|
{
|
||||||
"minor": 200,
|
"type": 99,
|
||||||
"type": 99
|
"path": "/dev/full",
|
||||||
},
|
"major": 1,
|
||||||
{
|
"minor": 7,
|
||||||
"permissions": "rwm",
|
"permissions": "rwm",
|
||||||
"file_mode": 438,
|
"file_mode": 438,
|
||||||
"major": 1,
|
"uid": 0,
|
||||||
"minor": 3,
|
"gid": 0
|
||||||
"path": "/dev/null",
|
},
|
||||||
"type": 99
|
{
|
||||||
},
|
"type": 99,
|
||||||
{
|
"path": "/dev/tty",
|
||||||
"permissions": "rwm",
|
"major": 5,
|
||||||
"file_mode": 438,
|
"minor": 0,
|
||||||
"major": 1,
|
"permissions": "rwm",
|
||||||
"minor": 5,
|
"file_mode": 438,
|
||||||
"path": "/dev/zero",
|
"uid": 0,
|
||||||
"type": 99
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": 99,
|
||||||
"file_mode": 438,
|
"path": "/dev/urandom",
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 7,
|
"minor": 9,
|
||||||
"path": "/dev/full",
|
"permissions": "rwm",
|
||||||
"type": 99
|
"file_mode": 438,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"permissions": "rwm",
|
},
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 5,
|
"type": 99,
|
||||||
"path": "/dev/tty",
|
"path": "/dev/random",
|
||||||
"type": 99
|
"major": 1,
|
||||||
},
|
"minor": 8,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"permissions": "rwm",
|
"file_mode": 438,
|
||||||
"file_mode": 438,
|
"uid": 0,
|
||||||
"major": 1,
|
"gid": 0
|
||||||
"minor": 9,
|
}
|
||||||
"path": "/dev/urandom",
|
],
|
||||||
"type": 99
|
"mount_label": "",
|
||||||
},
|
"hostname": "nsinit",
|
||||||
{
|
"console": "",
|
||||||
"permissions": "rwm",
|
"namespaces": [
|
||||||
"file_mode": 438,
|
{
|
||||||
"major": 1,
|
"type": "NEWNS",
|
||||||
"minor": 8,
|
"path": ""
|
||||||
"path": "/dev/random",
|
},
|
||||||
"type": 99
|
{
|
||||||
}
|
"type": "NEWUTS",
|
||||||
],
|
"path": ""
|
||||||
"name": "docker-koye",
|
},
|
||||||
"parent": "docker"
|
{
|
||||||
},
|
"type": "NEWIPC",
|
||||||
"restrict_sys": true,
|
"path": ""
|
||||||
"devices": [
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": "NEWPID",
|
||||||
"file_mode": 438,
|
"path": ""
|
||||||
"major": 1,
|
},
|
||||||
"minor": 3,
|
{
|
||||||
"path": "/dev/null",
|
"type": "NEWNET",
|
||||||
"type": 99
|
"path": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"permissions": "rwm",
|
"type": "NEWUSER",
|
||||||
"file_mode": 438,
|
"path": ""
|
||||||
"major": 1,
|
}
|
||||||
"minor": 5,
|
],
|
||||||
"path": "/dev/zero",
|
"capabilities": [
|
||||||
"type": 99
|
"CHOWN",
|
||||||
},
|
"DAC_OVERRIDE",
|
||||||
{
|
"FSETID",
|
||||||
"permissions": "rwm",
|
"FOWNER",
|
||||||
"file_mode": 438,
|
"MKNOD",
|
||||||
"major": 1,
|
"NET_RAW",
|
||||||
"minor": 7,
|
"SETGID",
|
||||||
"path": "/dev/full",
|
"SETUID",
|
||||||
"type": 99
|
"SETFCAP",
|
||||||
},
|
"SETPCAP",
|
||||||
{
|
"NET_BIND_SERVICE",
|
||||||
"permissions": "rwm",
|
"SYS_CHROOT",
|
||||||
"file_mode": 438,
|
"KILL",
|
||||||
"major": 5,
|
"AUDIT_WRITE"
|
||||||
"path": "/dev/tty",
|
],
|
||||||
"type": 99
|
"networks": [
|
||||||
},
|
{
|
||||||
{
|
"type": "loopback",
|
||||||
"permissions": "rwm",
|
"name": "",
|
||||||
"file_mode": 438,
|
"bridge": "",
|
||||||
"major": 1,
|
"mac_address": "",
|
||||||
"minor": 9,
|
"address": "127.0.0.1/0",
|
||||||
"path": "/dev/urandom",
|
"gateway": "localhost",
|
||||||
"type": 99
|
"ipv6_address": "",
|
||||||
},
|
"ipv6_gateway": "",
|
||||||
{
|
"mtu": 0,
|
||||||
"permissions": "rwm",
|
"txqueuelen": 0,
|
||||||
"file_mode": 438,
|
"host_interface_name": ""
|
||||||
"major": 1,
|
}
|
||||||
"minor": 8,
|
],
|
||||||
"path": "/dev/random",
|
"routes": null,
|
||||||
"type": 99
|
"cgroups": {
|
||||||
}
|
"name": "libcontainer",
|
||||||
],
|
"parent": "nsinit",
|
||||||
"mounts": [
|
"allow_all_devices": false,
|
||||||
{
|
"allowed_devices": [
|
||||||
"type": "tmpfs",
|
{
|
||||||
"destination": "/tmp"
|
"type": 99,
|
||||||
}
|
"path": "",
|
||||||
],
|
"major": -1,
|
||||||
"environment": [
|
"minor": -1,
|
||||||
"HOME=/",
|
"permissions": "m",
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
"file_mode": 0,
|
||||||
"HOSTNAME=koye",
|
"uid": 0,
|
||||||
"TERM=xterm"
|
"gid": 0
|
||||||
],
|
},
|
||||||
"hostname": "koye",
|
{
|
||||||
"namespaces": [
|
"type": 98,
|
||||||
{"type": "NEWIPC"},
|
"path": "",
|
||||||
{"type": "NEWNET"},
|
"major": -1,
|
||||||
{"type": "NEWNS"},
|
"minor": -1,
|
||||||
{"type": "NEWPID"},
|
"permissions": "m",
|
||||||
{"type": "NEWUTS"},
|
"file_mode": 0,
|
||||||
{"type": "NEWUSER"}
|
"uid": 0,
|
||||||
],
|
"gid": 0
|
||||||
"networks": [
|
},
|
||||||
{
|
{
|
||||||
"address": "127.0.0.1/0",
|
"type": 99,
|
||||||
"gateway": "localhost",
|
"path": "/dev/console",
|
||||||
"mtu": 1500,
|
"major": 5,
|
||||||
"type": "loopback"
|
"minor": 1,
|
||||||
},
|
"permissions": "rwm",
|
||||||
{
|
"file_mode": 0,
|
||||||
"address": "172.17.0.9/16",
|
"uid": 0,
|
||||||
"gateway": "172.17.42.1",
|
"gid": 0
|
||||||
"bridge": "docker0",
|
},
|
||||||
"veth_prefix": "veth",
|
{
|
||||||
"mtu": 1500,
|
"type": 99,
|
||||||
"type": "veth"
|
"path": "/dev/tty0",
|
||||||
}
|
"major": 4,
|
||||||
],
|
"minor": 0,
|
||||||
"tty": true,
|
"permissions": "rwm",
|
||||||
"user": "root",
|
"file_mode": 0,
|
||||||
"uid_mappings": [
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"container_id": 0,
|
},
|
||||||
"host_id": 1000,
|
{
|
||||||
"size": 1
|
"type": 99,
|
||||||
},
|
"path": "/dev/tty1",
|
||||||
{
|
"major": 4,
|
||||||
"container_id": 1,
|
"minor": 1,
|
||||||
"host_id": 1,
|
"permissions": "rwm",
|
||||||
"size": 999
|
"file_mode": 0,
|
||||||
},
|
"uid": 0,
|
||||||
{
|
"gid": 0
|
||||||
"container_id": 1001,
|
},
|
||||||
"host_id": 1001,
|
{
|
||||||
"size": 9000
|
"type": 99,
|
||||||
}
|
"path": "",
|
||||||
],
|
"major": 136,
|
||||||
"gid_mappings": [
|
"minor": -1,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"container_id": 0,
|
"file_mode": 0,
|
||||||
"host_id": 1000,
|
"uid": 0,
|
||||||
"size": 1
|
"gid": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"container_id": 1,
|
"type": 99,
|
||||||
"host_id": 1,
|
"path": "",
|
||||||
"size": 999
|
"major": 5,
|
||||||
},
|
"minor": 2,
|
||||||
{
|
"permissions": "rwm",
|
||||||
"container_id": 1001,
|
"file_mode": 0,
|
||||||
"host_id": 1001,
|
"uid": 0,
|
||||||
"size": 9000
|
"gid": 0
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"rlimits": [
|
"type": 99,
|
||||||
{
|
"path": "",
|
||||||
"type": 7,
|
"major": 10,
|
||||||
"hard": 999,
|
"minor": 200,
|
||||||
"soft": 999
|
"permissions": "rwm",
|
||||||
}
|
"file_mode": 0,
|
||||||
]
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/null",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 3,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/zero",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 5,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/full",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 7,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/tty",
|
||||||
|
"major": 5,
|
||||||
|
"minor": 0,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/urandom",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 9,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 99,
|
||||||
|
"path": "/dev/random",
|
||||||
|
"major": 1,
|
||||||
|
"minor": 8,
|
||||||
|
"permissions": "rwm",
|
||||||
|
"file_mode": 438,
|
||||||
|
"uid": 0,
|
||||||
|
"gid": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memory": 0,
|
||||||
|
"memory_reservation": 0,
|
||||||
|
"memory_swap": 0,
|
||||||
|
"cpu_shares": 0,
|
||||||
|
"cpu_quota": 0,
|
||||||
|
"cpu_period": 0,
|
||||||
|
"cpuset_cpus": "",
|
||||||
|
"cpuset_mems": "",
|
||||||
|
"blkio_weight": 0,
|
||||||
|
"freezer": "",
|
||||||
|
"slice": ""
|
||||||
|
},
|
||||||
|
"apparmor_profile": "",
|
||||||
|
"process_label": "",
|
||||||
|
"rlimits": [
|
||||||
|
{
|
||||||
|
"type": 7,
|
||||||
|
"hard": 1024,
|
||||||
|
"soft": 1024
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additional_groups": null,
|
||||||
|
"uid_mappings": [
|
||||||
|
{
|
||||||
|
"container_id": 0,
|
||||||
|
"host_id": 1000,
|
||||||
|
"size": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_id": 1,
|
||||||
|
"host_id": 1,
|
||||||
|
"size": 999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_id": 1001,
|
||||||
|
"host_id": 1001,
|
||||||
|
"size": 2147482647
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gid_mappings": [
|
||||||
|
{
|
||||||
|
"container_id": 0,
|
||||||
|
"host_id": 1000,
|
||||||
|
"size": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_id": 1,
|
||||||
|
"host_id": 1,
|
||||||
|
"size": 999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"container_id": 1001,
|
||||||
|
"host_id": 1001,
|
||||||
|
"size": 2147482647
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mask_paths": [
|
||||||
|
"/proc/kcore"
|
||||||
|
],
|
||||||
|
"readonly_paths": [
|
||||||
|
"/proc/sys",
|
||||||
|
"/proc/sysrq-trigger",
|
||||||
|
"/proc/irq",
|
||||||
|
"/proc/bus"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ clone() {
|
||||||
# the following lines are in sorted order, FYI
|
# the following lines are in sorted order, FYI
|
||||||
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 v1
|
clone git github.com/godbus/dbus v2
|
||||||
clone git github.com/syndtr/gocapability 3c85049eae
|
clone git github.com/Sirupsen/logrus v0.6.0
|
||||||
clone git github.com/golang/glog 44145f04b68c
|
clone git github.com/syndtr/gocapability 1cf3ac4dc4
|
||||||
|
|
||||||
# intentionally not vendoring Docker itself... that'd be a circle :)
|
# intentionally not vendoring Docker itself... that'd be a circle :)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
logrus
|
|
@ -0,0 +1,9 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- tip
|
||||||
|
install:
|
||||||
|
- go get github.com/stretchr/testify
|
||||||
|
- go get github.com/stvp/go-udp-testing
|
||||||
|
- go get github.com/tobi/airbrake-go
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,342 @@
|
||||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)
|
||||||
|
|
||||||
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
yet stable (pre 1.0), the core API is unlikely change much but please version
|
||||||
|
control your Logrus to make sure you aren't fetching latest `master` on every
|
||||||
|
build.**
|
||||||
|
|
||||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
|
plain text):
|
||||||
|
|
||||||
|
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||||
|
|
||||||
|
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
||||||
|
or Splunk:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
||||||
|
attached, the output is compatible with the
|
||||||
|
[l2met](http://r.32k.io/l2met-introduction) format:
|
||||||
|
|
||||||
|
```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="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
||||||
|
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
||||||
|
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
||||||
|
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||||
|
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||||
|
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||||
|
want:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
||||||
|
|
||||||
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
// Only log the warning severity or above.
|
||||||
|
log.SetLevel(log.WarnLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced usage such as logging to multiple locations from the same
|
||||||
|
application, you can also create an instance of the `logrus` Logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a new instance of the logger. You can have any number of instances.
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// The API for setting attributes is a little different than the package level
|
||||||
|
// exported logger. See Godoc.
|
||||||
|
log.Out = os.Stderr
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
Logrus encourages careful, structured logging though logging fields instead of
|
||||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||||
|
to send event %s to topic %s with key %d")`, you should log the much more
|
||||||
|
discoverable:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"event": event,
|
||||||
|
"topic": topic,
|
||||||
|
"key": key,
|
||||||
|
}).Fatal("Failed to send event")
|
||||||
|
```
|
||||||
|
|
||||||
|
We've found this API forces you to think about logging in a way that produces
|
||||||
|
much more useful logging messages. We've been in countless situations where just
|
||||||
|
a single added field to a log statement that was already there would've saved us
|
||||||
|
hours. The `WithFields` call is optional.
|
||||||
|
|
||||||
|
In general, with Logrus using any of the `printf`-family functions should be
|
||||||
|
seen as a hint you should add a field, however, you can still use the
|
||||||
|
`printf`-family functions with Logrus.
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
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
|
||||||
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
||||||
|
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
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
||||||
|
log.AddHook(logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* [`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)
|
||||||
|
Send errors to the Papertrail hosted logging service via UDP.
|
||||||
|
|
||||||
|
* [`github.com/Sirupsen/logrus/hooks/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.
|
||||||
|
|
||||||
|
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
||||||
|
Send errors to a channel in hipchat.
|
||||||
|
|
||||||
|
#### Level logging
|
||||||
|
|
||||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.Debug("Useful debugging information.")
|
||||||
|
log.Info("Something noteworthy happened!")
|
||||||
|
log.Warn("You should probably take a look at this.")
|
||||||
|
log.Error("Something failed but I'm not quitting.")
|
||||||
|
// Calls os.Exit(1) after logging
|
||||||
|
log.Fatal("Bye.")
|
||||||
|
// Calls panic() after logging
|
||||||
|
log.Panic("I'm bailing.")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set the logging level on a `Logger`, then it will only log entries with
|
||||||
|
that severity or anything above it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||||
|
environment if your application has that.
|
||||||
|
|
||||||
|
#### Entries
|
||||||
|
|
||||||
|
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||||
|
automatically added to all logging events:
|
||||||
|
|
||||||
|
1. `time`. The timestamp when the entry was created.
|
||||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||||
|
the `AddFields` call. E.g. `Failed to send event.`
|
||||||
|
3. `level`. The logging level. E.g. `info`.
|
||||||
|
|
||||||
|
#### Environments
|
||||||
|
|
||||||
|
Logrus has no notion of environment.
|
||||||
|
|
||||||
|
If you wish for hooks and formatters to only be used in specific environments,
|
||||||
|
you should handle that yourself. For example, if your application has a global
|
||||||
|
variable `Environment`, which is a string representation of the environment you
|
||||||
|
could do:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// do something here to set environment depending on an environment variable
|
||||||
|
// or command-line flag
|
||||||
|
if Environment == "production" {
|
||||||
|
log.SetFormatter(logrus.JSONFormatter)
|
||||||
|
} else {
|
||||||
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
|
log.SetFormatter(logrus.TextFormatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration is how `logrus` was intended to be used, but JSON in
|
||||||
|
production is mostly only useful if you do log aggregation with tools like
|
||||||
|
Splunk or Logstash.
|
||||||
|
|
||||||
|
#### Formatters
|
||||||
|
|
||||||
|
The built-in logging formatters are:
|
||||||
|
|
||||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||||
|
without colors.
|
||||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||||
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
|
`DisableColors` field to `true`
|
||||||
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
|
||||||
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||||
|
default ones (see Entries section above):
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyJSONFormatter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
|
// source of the official loggers.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rotation
|
||||||
|
|
||||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
external program (like `logrotated(8)`) that can compress and delete old log
|
||||||
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
|
||||||
|
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
|
@ -0,0 +1,248 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||||
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||||
|
// passed around as much as you wish to avoid field duplication.
|
||||||
|
type Entry struct {
|
||||||
|
Logger *Logger
|
||||||
|
|
||||||
|
// Contains all the fields set by the user.
|
||||||
|
Data Fields
|
||||||
|
|
||||||
|
// Time at which the log entry was created
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Level Level
|
||||||
|
|
||||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntry(logger *Logger) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Logger: logger,
|
||||||
|
// Default is three fields, give a little extra room
|
||||||
|
Data: make(Fields, 5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||||
|
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
return bytes.NewBuffer(serialized), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the string representation from the reader and ultimately the
|
||||||
|
// formatter.
|
||||||
|
func (entry *Entry) String() (string, error) {
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a single field to the Entry.
|
||||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
return entry.WithFields(Fields{key: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a map of fields to the Entry.
|
||||||
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
|
data := Fields{}
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range fields {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) log(level Level, msg string) {
|
||||||
|
entry.Time = time.Now()
|
||||||
|
entry.Level = level
|
||||||
|
entry.Message = msg
|
||||||
|
|
||||||
|
if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
|
||||||
|
_, err = io.Copy(entry.Logger.Out, reader)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
|
// directly here.
|
||||||
|
if level <= PanicLevel {
|
||||||
|
panic(reader.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Print(args ...interface{}) {
|
||||||
|
entry.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Info(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Println family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infoln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
|
entry.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
|
entry.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||||
|
// string allocation, we do the simplest thing.
|
||||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||||
|
msg := fmt.Sprintln(args...)
|
||||||
|
return msg[:len(msg)-1]
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.JSONFormatter)
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
"github.com/tobi/airbrake-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
||||||
|
airbrake.ApiKey = "whatever"
|
||||||
|
airbrake.Environment = "production"
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// std is the name of the standard logger in stdlib `log`
|
||||||
|
std = New()
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetOutput sets the standard logger output.
|
||||||
|
func SetOutput(out io.Writer) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the standard logger formatter.
|
||||||
|
func SetFormatter(formatter Formatter) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the standard logger level.
|
||||||
|
func SetLevel(level Level) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Level = level
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
|
func AddHook(hook Hook) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithField(key string, value interface{}) *Entry {
|
||||||
|
return std.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||||
|
// once for each field.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithFields(fields Fields) *Entry {
|
||||||
|
return std.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
|
func Debug(args ...interface{}) {
|
||||||
|
std.Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print logs a message at level Info on the standard logger.
|
||||||
|
func Print(args ...interface{}) {
|
||||||
|
std.Print(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at level Info on the standard logger.
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
std.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||||
|
func Warn(args ...interface{}) {
|
||||||
|
std.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||||
|
func Warning(args ...interface{}) {
|
||||||
|
std.Warning(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at level Error on the standard logger.
|
||||||
|
func Error(args ...interface{}) {
|
||||||
|
std.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||||
|
func Panic(args ...interface{}) {
|
||||||
|
std.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatal(args ...interface{}) {
|
||||||
|
std.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
std.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf logs a message at level Info on the standard logger.
|
||||||
|
func Printf(format string, args ...interface{}) {
|
||||||
|
std.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a message at level Info on the standard logger.
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
std.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
std.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||||
|
func Warningf(format string, args ...interface{}) {
|
||||||
|
std.Warningf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
std.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||||
|
func Panicf(format string, args ...interface{}) {
|
||||||
|
std.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
std.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
|
func Debugln(args ...interface{}) {
|
||||||
|
std.Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println logs a message at level Info on the standard logger.
|
||||||
|
func Println(args ...interface{}) {
|
||||||
|
std.Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||||
|
func Infoln(args ...interface{}) {
|
||||||
|
std.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||||
|
func Warnln(args ...interface{}) {
|
||||||
|
std.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||||
|
func Warningln(args ...interface{}) {
|
||||||
|
std.Warningln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||||
|
func Errorln(args ...interface{}) {
|
||||||
|
std.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||||
|
func Panicln(args ...interface{}) {
|
||||||
|
std.Panicln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalln logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalln(args ...interface{}) {
|
||||||
|
std.Fatalln(args...)
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
//
|
||||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||||
|
//
|
||||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||||
|
// logged to `logger.Out`.
|
||||||
|
type Formatter interface {
|
||||||
|
Format(*Entry) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||||
|
// dumping it. If this code wasn't there doing:
|
||||||
|
//
|
||||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
|
//
|
||||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||||
|
// it'll logged as:
|
||||||
|
//
|
||||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||||
|
//
|
||||||
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
|
// avoid code duplication between the two default formatters.
|
||||||
|
func prefixFieldClashes(entry *Entry) {
|
||||||
|
_, ok := entry.Data["time"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.time"] = entry.Data["time"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = entry.Data["msg"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.msg"] = entry.Data["msg"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = entry.Data["level"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.level"] = entry.Data["level"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// smallFields is a small size data set for benchmarking
|
||||||
|
var smallFields = Fields{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "qux",
|
||||||
|
"one": "two",
|
||||||
|
"three": "four",
|
||||||
|
}
|
||||||
|
|
||||||
|
// largeFields is a large size data set for benchmarking
|
||||||
|
var largeFields = Fields{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "qux",
|
||||||
|
"one": "two",
|
||||||
|
"three": "four",
|
||||||
|
"five": "six",
|
||||||
|
"seven": "eight",
|
||||||
|
"nine": "ten",
|
||||||
|
"eleven": "twelve",
|
||||||
|
"thirteen": "fourteen",
|
||||||
|
"fifteen": "sixteen",
|
||||||
|
"seventeen": "eighteen",
|
||||||
|
"nineteen": "twenty",
|
||||||
|
"a": "b",
|
||||||
|
"c": "d",
|
||||||
|
"e": "f",
|
||||||
|
"g": "h",
|
||||||
|
"i": "j",
|
||||||
|
"k": "l",
|
||||||
|
"m": "n",
|
||||||
|
"o": "p",
|
||||||
|
"q": "r",
|
||||||
|
"s": "t",
|
||||||
|
"u": "v",
|
||||||
|
"w": "x",
|
||||||
|
"y": "z",
|
||||||
|
"this": "will",
|
||||||
|
"make": "thirty",
|
||||||
|
"entries": "yeah",
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||||
|
entry := &Entry{
|
||||||
|
Time: time.Time{},
|
||||||
|
Level: InfoLevel,
|
||||||
|
Message: "message",
|
||||||
|
Data: fields,
|
||||||
|
}
|
||||||
|
var d []byte
|
||||||
|
var err error
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
d, err = formatter.Format(entry)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.SetBytes(int64(len(d)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestHook struct {
|
||||||
|
Fired bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *TestHook) Fire(entry *Entry) error {
|
||||||
|
hook.Fired = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *TestHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
DebugLevel,
|
||||||
|
InfoLevel,
|
||||||
|
WarnLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
FatalLevel,
|
||||||
|
PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookFires(t *testing.T) {
|
||||||
|
hook := new(TestHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
assert.Equal(t, hook.Fired, false)
|
||||||
|
|
||||||
|
log.Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyHook struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||||
|
entry.Data["wow"] = "whale"
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ModifyHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
DebugLevel,
|
||||||
|
InfoLevel,
|
||||||
|
WarnLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
FatalLevel,
|
||||||
|
PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookCanModifyEntry(t *testing.T) {
|
||||||
|
hook := new(ModifyHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.WithField("wow", "elephant").Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["wow"], "whale")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanFireMultipleHooks(t *testing.T) {
|
||||||
|
hook1 := new(ModifyHook)
|
||||||
|
hook2 := new(TestHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook1)
|
||||||
|
log.Hooks.Add(hook2)
|
||||||
|
|
||||||
|
log.WithField("wow", "elephant").Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["wow"], "whale")
|
||||||
|
assert.Equal(t, hook2.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorHook struct {
|
||||||
|
Fired bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ErrorHook) Fire(entry *Entry) error {
|
||||||
|
hook.Fired = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ErrorHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
ErrorLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
||||||
|
hook := new(ErrorHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorHookShouldFireOnError(t *testing.T) {
|
||||||
|
hook := new(ErrorHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.Error("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||||
|
type Hook interface {
|
||||||
|
Levels() []Level
|
||||||
|
Fire(*Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal type for storing the hooks on a logger instance.
|
||||||
|
type levelHooks map[Level][]Hook
|
||||||
|
|
||||||
|
// Add a hook to an instance of logger. This is called with
|
||||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
|
func (hooks levelHooks) Add(hook Hook) {
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
hooks[level] = append(hooks[level], hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
|
// appropriate hooks for a log entry.
|
||||||
|
func (hooks levelHooks) Fire(level Level, entry *Entry) error {
|
||||||
|
for _, hook := range hooks[level] {
|
||||||
|
if err := hook.Fire(entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package logrus_airbrake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/tobi/airbrake-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||||
|
// with the Airbrake API. You must set:
|
||||||
|
// * airbrake.Endpoint
|
||||||
|
// * airbrake.ApiKey
|
||||||
|
// * airbrake.Environment (only sends exceptions when set to "production")
|
||||||
|
//
|
||||||
|
// 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 {
|
||||||
|
if entry.Data["error"] == nil {
|
||||||
|
entry.Logger.WithFields(logrus.Fields{
|
||||||
|
"source": "airbrake",
|
||||||
|
"endpoint": airbrake.Endpoint,
|
||||||
|
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err, ok := entry.Data["error"].(error)
|
||||||
|
if !ok {
|
||||||
|
entry.Logger.WithFields(logrus.Fields{
|
||||||
|
"source": "airbrake",
|
||||||
|
"endpoint": airbrake.Endpoint,
|
||||||
|
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
airErr := airbrake.Notify(err)
|
||||||
|
if airErr != nil {
|
||||||
|
entry.Logger.WithFields(logrus.Fields{
|
||||||
|
"source": "airbrake",
|
||||||
|
"endpoint": airbrake.Endpoint,
|
||||||
|
"error": airErr,
|
||||||
|
}).Warn("Failed to send error to Airbrake")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||||
|
|
||||||
|
[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
|
||||||
|
|
||||||
|
In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
|
||||||
|
|
||||||
|
For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/papertrail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,54 @@
|
||||||
|
package logrus_papertrail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
format = "Jan 2 15:04:05"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
|
||||||
|
type PapertrailHook struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
AppName string
|
||||||
|
UDPConn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPapertrailHook creates a hook to be added to an instance of logger.
|
||||||
|
func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
|
||||||
|
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
|
||||||
|
return &PapertrailHook{host, port, appName, conn}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire is called when a log event is fired.
|
||||||
|
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||||
|
date := time.Now().Format(format)
|
||||||
|
payload := fmt.Sprintf("<22> %s %s: [%s] %s", date, hook.AppName, entry.Data["level"], entry.Message)
|
||||||
|
|
||||||
|
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels returns the available logging levels.
|
||||||
|
func (hook *PapertrailHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.WarnLevel,
|
||||||
|
logrus.InfoLevel,
|
||||||
|
logrus.DebugLevel,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package logrus_papertrail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/stvp/go-udp-testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWritingToUDP(t *testing.T) {
|
||||||
|
port := 16661
|
||||||
|
udp.SetAddr(fmt.Sprintf(":%d", port))
|
||||||
|
|
||||||
|
hook, err := NewPapertrailHook("localhost", port, "test")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unable to connect to local UDP server.")
|
||||||
|
}
|
||||||
|
|
||||||
|
log := logrus.New()
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
udp.ShouldReceive(t, "foo", func() {
|
||||||
|
log.Info("foo")
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,59 @@
|
||||||
|
package logrus_syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"log/syslog"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyslogHook to send logs via syslog.
|
||||||
|
type SyslogHook struct {
|
||||||
|
Writer *syslog.Writer
|
||||||
|
SyslogNetwork string
|
||||||
|
SyslogRaddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a hook to be added to an instance of logger. This is called with
|
||||||
|
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||||
|
// `if err == nil { log.Hooks.Add(hook) }`
|
||||||
|
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||||
|
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||||
|
return &SyslogHook{w, network, raddr}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||||
|
line, err := entry.String()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch entry.Data["level"] {
|
||||||
|
case "panic":
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case "fatal":
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case "error":
|
||||||
|
return hook.Writer.Err(line)
|
||||||
|
case "warn":
|
||||||
|
return hook.Writer.Warning(line)
|
||||||
|
case "info":
|
||||||
|
return hook.Writer.Info(line)
|
||||||
|
case "debug":
|
||||||
|
return hook.Writer.Debug(line)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.WarnLevel,
|
||||||
|
logrus.InfoLevel,
|
||||||
|
logrus.DebugLevel,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package logrus_syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"log/syslog"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocalhostAddAndPrint(t *testing.T) {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unable to connect to local syslog.")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
if len(log.Hooks[level]) != 1 {
|
||||||
|
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Congratulations!")
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONFormatter struct{}
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
prefixFieldClashes(entry)
|
||||||
|
entry.Data["time"] = entry.Time.Format(time.RFC3339)
|
||||||
|
entry.Data["msg"] = entry.Message
|
||||||
|
entry.Data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
|
// file, or leave it default which is `os.Stdout`. You can also set this to
|
||||||
|
// something more adventorous, such as logging to Kafka.
|
||||||
|
Out io.Writer
|
||||||
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
|
Hooks levelHooks
|
||||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
|
// formatters for examples.
|
||||||
|
Formatter Formatter
|
||||||
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
|
// logged. `logrus.Debug` is useful in
|
||||||
|
Level Level
|
||||||
|
// Used to sync writing to the log.
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||||
|
// instantiate your own:
|
||||||
|
//
|
||||||
|
// var log = &Logger{
|
||||||
|
// Out: os.Stderr,
|
||||||
|
// Formatter: new(JSONFormatter),
|
||||||
|
// Hooks: make(levelHooks),
|
||||||
|
// Level: logrus.Debug,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// It's recommended to make this a global instance called `log`.
|
||||||
|
func New() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
Out: os.Stdout,
|
||||||
|
Formatter: new(TextFormatter),
|
||||||
|
Hooks: make(levelHooks),
|
||||||
|
Level: InfoLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||||
|
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||||
|
// Ff you want multiple fields, use `WithFields`.
|
||||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
|
return NewEntry(logger).WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||||
|
// each `Field`.
|
||||||
|
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
|
return NewEntry(logger).WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
NewEntry(logger).Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Level type
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
|
func (level Level) String() string {
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
return "debug"
|
||||||
|
case InfoLevel:
|
||||||
|
return "info"
|
||||||
|
case WarnLevel:
|
||||||
|
return "warning"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "error"
|
||||||
|
case FatalLevel:
|
||||||
|
return "fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "panic"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
|
switch lvl {
|
||||||
|
case "panic":
|
||||||
|
return PanicLevel, nil
|
||||||
|
case "fatal":
|
||||||
|
return FatalLevel, nil
|
||||||
|
case "error":
|
||||||
|
return ErrorLevel, nil
|
||||||
|
case "warn", "warning":
|
||||||
|
return WarnLevel, nil
|
||||||
|
case "info":
|
||||||
|
return InfoLevel, nil
|
||||||
|
case "debug":
|
||||||
|
return DebugLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var l Level
|
||||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the different logging levels. You can set the logging level to log
|
||||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
|
const (
|
||||||
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
|
// message passed to Debug, Info, ...
|
||||||
|
PanicLevel Level = iota
|
||||||
|
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||||
|
// logging level is set to Panic.
|
||||||
|
FatalLevel
|
||||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||||
|
ErrorLevel
|
||||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||||
|
WarnLevel
|
||||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||||
|
// application.
|
||||||
|
InfoLevel
|
||||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
|
var _ StdLogger = &log.Logger{}
|
||||||
|
|
||||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
// interface, this is the closest we get, unfortunately.
|
||||||
|
type StdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
}
|
|
@ -0,0 +1,247 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
log(logger)
|
||||||
|
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assertions(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = &TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
log(logger)
|
||||||
|
|
||||||
|
fields := make(map[string]string)
|
||||||
|
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||||
|
if !strings.Contains(kv, "=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kvArr := strings.Split(kv, "=")
|
||||||
|
key := strings.TrimSpace(kvArr[0])
|
||||||
|
val, err := strconv.Unquote(kvArr[1])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
fields[key] = val
|
||||||
|
}
|
||||||
|
assertions(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrint(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test")
|
||||||
|
assert.Equal(t, fields["level"], "info")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfo(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test")
|
||||||
|
assert.Equal(t, fields["level"], "info")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWarn(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Warn("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test")
|
||||||
|
assert.Equal(t, fields["level"], "warning")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln("test", "test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln("test", 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln(10, 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "10 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln(10, 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "10 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Info("test", 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Info("test", "test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "testtest")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
localLog := logger.WithFields(Fields{
|
||||||
|
"key1": "value1",
|
||||||
|
})
|
||||||
|
|
||||||
|
localLog.WithField("key2", "value2").Info("test")
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "value2", fields["key2"])
|
||||||
|
assert.Equal(t, "value1", fields["key1"])
|
||||||
|
|
||||||
|
buffer = bytes.Buffer{}
|
||||||
|
fields = Fields{}
|
||||||
|
localLog.Info("test")
|
||||||
|
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
_, ok := fields["key2"]
|
||||||
|
assert.Equal(t, false, ok)
|
||||||
|
assert.Equal(t, "value1", fields["key1"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.WithField("msg", "hello").Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.WithField("msg", "hello").Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test")
|
||||||
|
assert.Equal(t, fields["fields.msg"], "hello")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.WithField("time", "hello").Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["fields.time"], "hello")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.WithField("level", 1).Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["level"], "info")
|
||||||
|
assert.Equal(t, fields["fields.level"], 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||||
|
LogAndAssertText(t, func(log *Logger) {
|
||||||
|
ll := log.WithField("herp", "derp")
|
||||||
|
ll.Info("hello")
|
||||||
|
ll.Info("bye")
|
||||||
|
}, func(fields map[string]string) {
|
||||||
|
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||||
|
if _, ok := fields[fieldName]; ok {
|
||||||
|
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertLevelToString(t *testing.T) {
|
||||||
|
assert.Equal(t, "debug", DebugLevel.String())
|
||||||
|
assert.Equal(t, "info", InfoLevel.String())
|
||||||
|
assert.Equal(t, "warning", WarnLevel.String())
|
||||||
|
assert.Equal(t, "error", ErrorLevel.String())
|
||||||
|
assert.Equal(t, "fatal", FatalLevel.String())
|
||||||
|
assert.Equal(t, "panic", PanicLevel.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseLevel(t *testing.T) {
|
||||||
|
l, err := ParseLevel("panic")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, PanicLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("fatal")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, FatalLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("error")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, ErrorLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("warn")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("warning")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("info")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, InfoLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("debug")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, DebugLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("invalid")
|
||||||
|
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
||||||
|
*/
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios struct {
|
||||||
|
Iflag uint32
|
||||||
|
Oflag uint32
|
||||||
|
Cflag uint32
|
||||||
|
Lflag uint32
|
||||||
|
Cc [20]uint8
|
||||||
|
Ispeed uint32
|
||||||
|
Ospeed uint32
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TCGETS
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build linux,!appengine darwin freebsd
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stdout
|
||||||
|
var termios Termios
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
|
return err == 0
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stdout
|
||||||
|
var st uint32
|
||||||
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
|
return r != 0 && e == 0
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseTimestamp time.Time
|
||||||
|
isTerminal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseTimestamp = time.Now()
|
||||||
|
isTerminal = IsTerminal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func miniTS() int {
|
||||||
|
return int(time.Since(baseTimestamp) / time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextFormatter struct {
|
||||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
|
ForceColors bool
|
||||||
|
DisableColors bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
|
||||||
|
var keys []string
|
||||||
|
for k := range entry.Data {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
|
prefixFieldClashes(entry)
|
||||||
|
|
||||||
|
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
if isColored {
|
||||||
|
printColored(b, entry, keys)
|
||||||
|
} else {
|
||||||
|
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
||||||
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
|
for _, key := range keys {
|
||||||
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
||||||
|
var levelColor int
|
||||||
|
switch entry.Level {
|
||||||
|
case WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
|
for _, k := range keys {
|
||||||
|
v := entry.Data[k]
|
||||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
||||||
|
switch value.(type) {
|
||||||
|
case string, error:
|
||||||
|
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(b, "%v=%v ", key, value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
# How to Contribute
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
- Fork the repository on GitHub
|
||||||
|
- Read the [README](README.markdown) for build and test instructions
|
||||||
|
- Play with the project, submit bugs, submit patches!
|
||||||
|
|
||||||
|
## Contribution Flow
|
||||||
|
|
||||||
|
This is a rough outline of what a contributor's workflow looks like:
|
||||||
|
|
||||||
|
- Create a topic branch from where you want to base your work (usually master).
|
||||||
|
- Make commits of logical units.
|
||||||
|
- Make sure your commit messages are in the proper format (see below).
|
||||||
|
- Push your changes to a topic branch in your fork of the repository.
|
||||||
|
- Make sure the tests pass, and add any new tests as appropriate.
|
||||||
|
- Submit a pull request to the original repository.
|
||||||
|
|
||||||
|
Thanks for your contributions!
|
||||||
|
|
||||||
|
### Format of the Commit Message
|
||||||
|
|
||||||
|
We follow a rough convention for commit messages that is designed to answer two
|
||||||
|
questions: what changed and why. The subject line should feature the what and
|
||||||
|
the body of the commit should describe the why.
|
||||||
|
|
||||||
|
```
|
||||||
|
scripts: add the test-cluster command
|
||||||
|
|
||||||
|
this uses tmux to setup a test cluster that you can easily kill and
|
||||||
|
start for debugging.
|
||||||
|
|
||||||
|
Fixes #38
|
||||||
|
```
|
||||||
|
|
||||||
|
The format can be described more formally as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
<subsystem>: <what changed>
|
||||||
|
<BLANK LINE>
|
||||||
|
<why this change was made>
|
||||||
|
<BLANK LINE>
|
||||||
|
<footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
The first line is the subject and should be no longer than 70 characters, the
|
||||||
|
second line is always blank, and other lines should be wrapped at 80 characters.
|
||||||
|
This allows the message to be easier to read on GitHub as well as in various
|
||||||
|
git tools.
|
|
@ -0,0 +1,2 @@
|
||||||
|
Brandon Philips <brandon@ifup.org> (@philips)
|
||||||
|
Brian Waldon <brian@waldon.cc> (@bcwaldon)
|
|
@ -175,6 +175,13 @@ func (conn *Conn) BusObject() *Object {
|
||||||
// not be called on shared connections.
|
// not be called on shared connections.
|
||||||
func (conn *Conn) Close() error {
|
func (conn *Conn) Close() error {
|
||||||
conn.outLck.Lock()
|
conn.outLck.Lock()
|
||||||
|
if conn.closed {
|
||||||
|
// inWorker calls Close on read error, the read error may
|
||||||
|
// be caused by another caller calling Close to shutdown the
|
||||||
|
// dbus connection, a double-close scenario we prevent here.
|
||||||
|
conn.outLck.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
close(conn.out)
|
close(conn.out)
|
||||||
conn.closed = true
|
conn.closed = true
|
||||||
conn.outLck.Unlock()
|
conn.outLck.Unlock()
|
||||||
|
@ -317,11 +324,7 @@ func (conn *Conn) inWorker() {
|
||||||
}
|
}
|
||||||
conn.signalsLck.Lock()
|
conn.signalsLck.Lock()
|
||||||
for _, ch := range conn.signals {
|
for _, ch := range conn.signals {
|
||||||
// don't block trying to send a signal
|
ch <- signal
|
||||||
select {
|
|
||||||
case ch <- signal:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
conn.signalsLck.Unlock()
|
conn.signalsLck.Unlock()
|
||||||
case TypeMethodCall:
|
case TypeMethodCall:
|
||||||
|
@ -508,6 +511,10 @@ type Error struct {
|
||||||
Body []interface{}
|
Body []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewError(name string, body []interface{}) *Error {
|
||||||
|
return &Error{name, body}
|
||||||
|
}
|
||||||
|
|
||||||
func (e Error) Error() string {
|
func (e Error) Error() string {
|
||||||
if len(e.Body) >= 1 {
|
if len(e.Body) >= 1 {
|
||||||
s, ok := e.Body[0].(string)
|
s, ok := e.Body[0].(string)
|
||||||
|
@ -546,13 +553,14 @@ type transport interface {
|
||||||
SendMessage(*Message) error
|
SendMessage(*Message) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
transports map[string]func(string) (transport, error) = make(map[string]func(string) (transport, error))
|
||||||
|
)
|
||||||
|
|
||||||
func getTransport(address string) (transport, error) {
|
func getTransport(address string) (transport, error) {
|
||||||
var err error
|
var err error
|
||||||
var t transport
|
var t transport
|
||||||
|
|
||||||
m := map[string]func(string) (transport, error){
|
|
||||||
"unix": newUnixTransport,
|
|
||||||
}
|
|
||||||
addresses := strings.Split(address, ";")
|
addresses := strings.Split(address, ";")
|
||||||
for _, v := range addresses {
|
for _, v := range addresses {
|
||||||
i := strings.IndexRune(v, ':')
|
i := strings.IndexRune(v, ':')
|
||||||
|
@ -560,7 +568,7 @@ func getTransport(address string) (transport, error) {
|
||||||
err = errors.New("dbus: invalid bus address (no transport)")
|
err = errors.New("dbus: invalid bus address (no transport)")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f := m[v[:i]]
|
f := transports[v[:i]]
|
||||||
if f == nil {
|
if f == nil {
|
||||||
err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
|
err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ var IntrospectData = Interface{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XML document type declaration of the introspection format version 1.0
|
||||||
|
const IntrospectDeclarationString = `
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
`
|
||||||
|
|
||||||
// The introspection data for the org.freedesktop.DBus.Introspectable interface,
|
// The introspection data for the org.freedesktop.DBus.Introspectable interface,
|
||||||
// as a string.
|
// as a string.
|
||||||
const IntrospectDataString = `
|
const IntrospectDataString = `
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"github.com/godbus/dbus"
|
"github.com/godbus/dbus"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Introspectable implements org.freedesktop.Introspectable.
|
// Introspectable implements org.freedesktop.Introspectable.
|
||||||
|
@ -31,7 +32,7 @@ func NewIntrospectable(n *Node) Introspectable {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return Introspectable(b)
|
return Introspectable(strings.TrimSpace(IntrospectDeclarationString) + string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Introspect implements org.freedesktop.Introspectable.Introspect.
|
// Introspect implements org.freedesktop.Introspectable.Introspect.
|
||||||
|
@ -50,7 +51,7 @@ func Methods(v interface{}) []Method {
|
||||||
}
|
}
|
||||||
mt := t.Method(i).Type
|
mt := t.Method(i).Type
|
||||||
if mt.NumOut() == 0 ||
|
if mt.NumOut() == 0 ||
|
||||||
mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{"", nil}) {
|
mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{}) {
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,19 +22,19 @@ const (
|
||||||
|
|
||||||
// ErrIfaceNotFound is the error returned to peers who try to access properties
|
// ErrIfaceNotFound is the error returned to peers who try to access properties
|
||||||
// on interfaces that aren't found.
|
// on interfaces that aren't found.
|
||||||
var ErrIfaceNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil}
|
var ErrIfaceNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil)
|
||||||
|
|
||||||
// ErrPropNotFound is the error returned to peers trying to access properties
|
// ErrPropNotFound is the error returned to peers trying to access properties
|
||||||
// that aren't found.
|
// that aren't found.
|
||||||
var ErrPropNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil}
|
var ErrPropNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil)
|
||||||
|
|
||||||
// ErrReadOnly is the error returned to peers trying to set a read-only
|
// ErrReadOnly is the error returned to peers trying to set a read-only
|
||||||
// property.
|
// property.
|
||||||
var ErrReadOnly = &dbus.Error{"org.freedesktop.DBus.Properties.Error.ReadOnly", nil}
|
var ErrReadOnly = dbus.NewError("org.freedesktop.DBus.Properties.Error.ReadOnly", nil)
|
||||||
|
|
||||||
// ErrInvalidArg is returned to peers if the type of the property that is being
|
// ErrInvalidArg is returned to peers if the type of the property that is being
|
||||||
// changed and the argument don't match.
|
// changed and the argument don't match.
|
||||||
var ErrInvalidArg = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InvalidArg", nil}
|
var ErrInvalidArg = dbus.NewError("org.freedesktop.DBus.Properties.Error.InvalidArg", nil)
|
||||||
|
|
||||||
// The introspection data for the org.freedesktop.DBus.Properties interface.
|
// The introspection data for the org.freedesktop.DBus.Properties interface.
|
||||||
var IntrospectData = introspect.Interface{
|
var IntrospectData = introspect.Interface{
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//+build !windows
|
||||||
|
|
||||||
package dbus
|
package dbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -58,6 +60,10 @@ func newUnixTransport(keys string) (transport, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
transports["unix"] = newUnixTransport
|
||||||
|
}
|
||||||
|
|
||||||
func (t *unixTransport) EnableUnixFDs() {
|
func (t *unixTransport) EnableUnixFDs() {
|
||||||
t.hasUnixFDs = true
|
t.hasUnixFDs = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
// The UnixCredentials system call is currently only implemented on Linux
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
|
||||||
|
// https://golang.org/s/go1.4-syscall
|
||||||
|
// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
|
||||||
|
|
||||||
|
// Local implementation of the UnixCredentials system call for DragonFly BSD
|
||||||
|
|
||||||
|
package dbus
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <sys/ucred.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/ztypes_linux_amd64.go
|
||||||
|
// http://golang.org/src/pkg/syscall/ztypes_dragonfly_amd64.go
|
||||||
|
type Ucred struct {
|
||||||
|
Pid int32
|
||||||
|
Uid uint32
|
||||||
|
Gid uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/types_linux.go
|
||||||
|
// http://golang.org/src/pkg/syscall/types_dragonfly.go
|
||||||
|
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/ucred.h
|
||||||
|
const (
|
||||||
|
SizeofUcred = C.sizeof_struct_ucred
|
||||||
|
)
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
|
||||||
|
func cmsgAlignOf(salen int) int {
|
||||||
|
// From http://golang.org/src/pkg/syscall/sockcmsg_unix.go
|
||||||
|
//salign := sizeofPtr
|
||||||
|
// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
|
||||||
|
// still require 32-bit aligned access to network subsystem.
|
||||||
|
//if darwin64Bit || dragonfly64Bit {
|
||||||
|
// salign = 4
|
||||||
|
//}
|
||||||
|
salign := 4
|
||||||
|
return (salen + salign - 1) & ^(salign - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_unix.go
|
||||||
|
func cmsgData(h *syscall.Cmsghdr) unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(syscall.SizeofCmsghdr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
|
||||||
|
// UnixCredentials encodes credentials into a socket control message
|
||||||
|
// for sending to another process. This can be used for
|
||||||
|
// authentication.
|
||||||
|
func UnixCredentials(ucred *Ucred) []byte {
|
||||||
|
b := make([]byte, syscall.CmsgSpace(SizeofUcred))
|
||||||
|
h := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
|
||||||
|
h.Level = syscall.SOL_SOCKET
|
||||||
|
h.Type = syscall.SCM_CREDS
|
||||||
|
h.SetLen(syscall.CmsgLen(SizeofUcred))
|
||||||
|
*((*Ucred)(cmsgData(h))) = *ucred
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
|
||||||
|
// ParseUnixCredentials decodes a socket control message that contains
|
||||||
|
// credentials in a Ucred structure. To receive such a message, the
|
||||||
|
// SO_PASSCRED option must be enabled on the socket.
|
||||||
|
func ParseUnixCredentials(m *syscall.SocketControlMessage) (*Ucred, error) {
|
||||||
|
if m.Header.Level != syscall.SOL_SOCKET {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
if m.Header.Type != syscall.SCM_CREDS {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
|
||||||
|
return &ucred, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *unixTransport) SendNullByte() error {
|
||||||
|
ucred := &Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
|
||||||
|
b := UnixCredentials(ucred)
|
||||||
|
_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if oobn != len(b) {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
// +build !darwin
|
// The UnixCredentials system call is currently only implemented on Linux
|
||||||
|
// http://golang.org/src/pkg/syscall/sockcmsg_linux.go
|
||||||
|
// https://golang.org/s/go1.4-syscall
|
||||||
|
// http://code.google.com/p/go/source/browse/unix/sockcmsg_linux.go?repo=sys
|
||||||
|
|
||||||
package dbus
|
package dbus
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -89,18 +90,27 @@ func (v Variant) format() (string, bool) {
|
||||||
return "{}", false
|
return "{}", false
|
||||||
}
|
}
|
||||||
unamb := true
|
unamb := true
|
||||||
buf := bytes.NewBuffer([]byte("{"))
|
var buf bytes.Buffer
|
||||||
|
kvs := make([]string, rv.Len())
|
||||||
for i, k := range rv.MapKeys() {
|
for i, k := range rv.MapKeys() {
|
||||||
s, b := MakeVariant(k.Interface()).format()
|
s, b := MakeVariant(k.Interface()).format()
|
||||||
unamb = unamb && b
|
unamb = unamb && b
|
||||||
|
buf.Reset()
|
||||||
buf.WriteString(s)
|
buf.WriteString(s)
|
||||||
buf.WriteString(": ")
|
buf.WriteString(": ")
|
||||||
s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
|
s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
|
||||||
unamb = unamb && b
|
unamb = unamb && b
|
||||||
buf.WriteString(s)
|
buf.WriteString(s)
|
||||||
if i != rv.Len()-1 {
|
kvs[i] = buf.String()
|
||||||
|
}
|
||||||
|
buf.Reset()
|
||||||
|
buf.WriteByte('{')
|
||||||
|
sort.Strings(kvs)
|
||||||
|
for i, kv := range kvs {
|
||||||
|
if i > 0 {
|
||||||
buf.WriteString(", ")
|
buf.WriteString(", ")
|
||||||
}
|
}
|
||||||
|
buf.WriteString(kv)
|
||||||
}
|
}
|
||||||
buf.WriteByte('}')
|
buf.WriteByte('}')
|
||||||
return buf.String(), unamb
|
return buf.String(), unamb
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and
|
|
||||||
distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
|
||||||
owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
|
||||||
that control, are controlled by, or are under common control with that entity.
|
|
||||||
For the purposes of this definition, "control" means (i) the power, direct or
|
|
||||||
indirect, to cause the direction or management of such entity, whether by
|
|
||||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
|
||||||
permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications, including
|
|
||||||
but not limited to software source code, documentation source, and configuration
|
|
||||||
files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or
|
|
||||||
translation of a Source form, including but not limited to compiled object code,
|
|
||||||
generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
|
||||||
available under the License, as indicated by a copyright notice that is included
|
|
||||||
in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
|
||||||
is based on (or derived from) the Work and for which the editorial revisions,
|
|
||||||
annotations, elaborations, or other modifications represent, as a whole, an
|
|
||||||
original work of authorship. For the purposes of this License, Derivative Works
|
|
||||||
shall not include works that remain separable from, or merely link (or bind by
|
|
||||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including the original version
|
|
||||||
of the Work and any modifications or additions to that Work or Derivative Works
|
|
||||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
|
||||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
|
||||||
on behalf of the copyright owner. For the purposes of this definition,
|
|
||||||
"submitted" means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems, and
|
|
||||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
|
||||||
the purpose of discussing and improving the Work, but excluding communication
|
|
||||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
|
||||||
owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
|
||||||
of whom a Contribution has been received by Licensor and subsequently
|
|
||||||
incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
|
||||||
Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License.
|
|
||||||
|
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby
|
|
||||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
|
||||||
irrevocable (except as stated in this section) patent license to make, have
|
|
||||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
|
||||||
such license applies only to those patent claims licensable by such Contributor
|
|
||||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
|
||||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
|
||||||
submitted. If You institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
|
||||||
Contribution incorporated within the Work constitutes direct or contributory
|
|
||||||
patent infringement, then any patent licenses granted to You under this License
|
|
||||||
for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution.
|
|
||||||
|
|
||||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
|
||||||
in any medium, with or without modifications, and in Source or Object form,
|
|
||||||
provided that You meet the following conditions:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of
|
|
||||||
this License; and
|
|
||||||
You must cause any modified files to carry prominent notices stating that You
|
|
||||||
changed the files; and
|
|
||||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
|
||||||
all copyright, patent, trademark, and attribution notices from the Source form
|
|
||||||
of the Work, excluding those notices that do not pertain to any part of the
|
|
||||||
Derivative Works; and
|
|
||||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
|
||||||
Derivative Works that You distribute must include a readable copy of the
|
|
||||||
attribution notices contained within such NOTICE file, excluding those notices
|
|
||||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
|
||||||
following places: within a NOTICE text file distributed as part of the
|
|
||||||
Derivative Works; within the Source form or documentation, if provided along
|
|
||||||
with the Derivative Works; or, within a display generated by the Derivative
|
|
||||||
Works, if and wherever such third-party notices normally appear. The contents of
|
|
||||||
the NOTICE file are for informational purposes only and do not modify the
|
|
||||||
License. You may add Your own attribution notices within Derivative Works that
|
|
||||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
|
||||||
provided that such additional attribution notices cannot be construed as
|
|
||||||
modifying the License.
|
|
||||||
You may add Your own copyright statement to Your modifications and may provide
|
|
||||||
additional or different license terms and conditions for use, reproduction, or
|
|
||||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
|
||||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
|
||||||
with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions.
|
|
||||||
|
|
||||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
|
||||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
|
||||||
conditions of this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
|
||||||
any separate license agreement you may have executed with Licensor regarding
|
|
||||||
such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks.
|
|
||||||
|
|
||||||
This License does not grant permission to use the trade names, trademarks,
|
|
||||||
service marks, or product names of the Licensor, except as required for
|
|
||||||
reasonable and customary use in describing the origin of the Work and
|
|
||||||
reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
|
||||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
|
||||||
including, without limitation, any warranties or conditions of TITLE,
|
|
||||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
|
||||||
solely responsible for determining the appropriateness of using or
|
|
||||||
redistributing the Work and assume any risks associated with Your exercise of
|
|
||||||
permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability.
|
|
||||||
|
|
||||||
In no event and under no legal theory, whether in tort (including negligence),
|
|
||||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
|
||||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special, incidental,
|
|
||||||
or consequential damages of any character arising as a result of this License or
|
|
||||||
out of the use or inability to use the Work (including but not limited to
|
|
||||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
|
||||||
any and all other commercial damages or losses), even if such Contributor has
|
|
||||||
been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability.
|
|
||||||
|
|
||||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
|
||||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
|
||||||
other liability obligations and/or rights consistent with this License. However,
|
|
||||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
|
||||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
|
||||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason of your
|
|
||||||
accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following boilerplate
|
|
||||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
|
||||||
identifying information. (Don't include the brackets!) The text should be
|
|
||||||
enclosed in the appropriate comment syntax for the file format. We also
|
|
||||||
recommend that a file or class name and description of purpose be included on
|
|
||||||
the same "printed page" as the copyright notice for easier identification within
|
|
||||||
third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,44 +0,0 @@
|
||||||
glog
|
|
||||||
====
|
|
||||||
|
|
||||||
Leveled execution logs for Go.
|
|
||||||
|
|
||||||
This is an efficient pure Go implementation of leveled logs in the
|
|
||||||
manner of the open source C++ package
|
|
||||||
http://code.google.com/p/google-glog
|
|
||||||
|
|
||||||
By binding methods to booleans it is possible to use the log package
|
|
||||||
without paying the expense of evaluating the arguments to the log.
|
|
||||||
Through the -vmodule flag, the package also provides fine-grained
|
|
||||||
control over logging at the file level.
|
|
||||||
|
|
||||||
The comment from glog.go introduces the ideas:
|
|
||||||
|
|
||||||
Package glog implements logging analogous to the Google-internal
|
|
||||||
C++ INFO/ERROR/V setup. It provides functions Info, Warning,
|
|
||||||
Error, Fatal, plus formatting variants such as Infof. It
|
|
||||||
also provides V-style logging controlled by the -v and
|
|
||||||
-vmodule=file=2 flags.
|
|
||||||
|
|
||||||
Basic examples:
|
|
||||||
|
|
||||||
glog.Info("Prepare to repel boarders")
|
|
||||||
|
|
||||||
glog.Fatalf("Initialization failed: %s", err)
|
|
||||||
|
|
||||||
See the documentation for the V function for an explanation
|
|
||||||
of these examples:
|
|
||||||
|
|
||||||
if glog.V(2) {
|
|
||||||
glog.Info("Starting transaction...")
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(2).Infoln("Processed", nItems, "elements")
|
|
||||||
|
|
||||||
|
|
||||||
The repository contains an open source version of the log package
|
|
||||||
used inside Google. The master copy of the source lives inside
|
|
||||||
Google, not here. The code in this repo is for export only and is not itself
|
|
||||||
under development. Feature requests will be ignored.
|
|
||||||
|
|
||||||
Send bug reports to golang-nuts@googlegroups.com.
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,124 +0,0 @@
|
||||||
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
|
||||||
//
|
|
||||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// File I/O for logs.
|
|
||||||
|
|
||||||
package glog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MaxSize is the maximum size of a log file in bytes.
|
|
||||||
var MaxSize uint64 = 1024 * 1024 * 1800
|
|
||||||
|
|
||||||
// logDirs lists the candidate directories for new log files.
|
|
||||||
var logDirs []string
|
|
||||||
|
|
||||||
// If non-empty, overrides the choice of directory in which to write logs.
|
|
||||||
// See createLogDirs for the full list of possible destinations.
|
|
||||||
var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
|
|
||||||
|
|
||||||
func createLogDirs() {
|
|
||||||
if *logDir != "" {
|
|
||||||
logDirs = append(logDirs, *logDir)
|
|
||||||
}
|
|
||||||
logDirs = append(logDirs, os.TempDir())
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
pid = os.Getpid()
|
|
||||||
program = filepath.Base(os.Args[0])
|
|
||||||
host = "unknownhost"
|
|
||||||
userName = "unknownuser"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
h, err := os.Hostname()
|
|
||||||
if err == nil {
|
|
||||||
host = shortHostname(h)
|
|
||||||
}
|
|
||||||
|
|
||||||
current, err := user.Current()
|
|
||||||
if err == nil {
|
|
||||||
userName = current.Username
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitize userName since it may contain filepath separators on Windows.
|
|
||||||
userName = strings.Replace(userName, `\`, "_", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shortHostname returns its argument, truncating at the first period.
|
|
||||||
// For instance, given "www.google.com" it returns "www".
|
|
||||||
func shortHostname(hostname string) string {
|
|
||||||
if i := strings.Index(hostname, "."); i >= 0 {
|
|
||||||
return hostname[:i]
|
|
||||||
}
|
|
||||||
return hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
// logName returns a new log file name containing tag, with start time t, and
|
|
||||||
// the name for the symlink for tag.
|
|
||||||
func logName(tag string, t time.Time) (name, link string) {
|
|
||||||
name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
|
|
||||||
program,
|
|
||||||
host,
|
|
||||||
userName,
|
|
||||||
tag,
|
|
||||||
t.Year(),
|
|
||||||
t.Month(),
|
|
||||||
t.Day(),
|
|
||||||
t.Hour(),
|
|
||||||
t.Minute(),
|
|
||||||
t.Second(),
|
|
||||||
pid)
|
|
||||||
return name, program + "." + tag
|
|
||||||
}
|
|
||||||
|
|
||||||
var onceLogDirs sync.Once
|
|
||||||
|
|
||||||
// create creates a new log file and returns the file and its filename, which
|
|
||||||
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
|
||||||
// successfully, create also attempts to update the symlink for that tag, ignoring
|
|
||||||
// errors.
|
|
||||||
func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
|
||||||
onceLogDirs.Do(createLogDirs)
|
|
||||||
if len(logDirs) == 0 {
|
|
||||||
return nil, "", errors.New("log: no log dirs")
|
|
||||||
}
|
|
||||||
name, link := logName(tag, t)
|
|
||||||
var lastErr error
|
|
||||||
for _, dir := range logDirs {
|
|
||||||
fname := filepath.Join(dir, name)
|
|
||||||
f, err := os.Create(fname)
|
|
||||||
if err == nil {
|
|
||||||
symlink := filepath.Join(dir, link)
|
|
||||||
os.Remove(symlink) // ignore err
|
|
||||||
os.Symlink(name, symlink) // ignore err
|
|
||||||
return f, fname, nil
|
|
||||||
}
|
|
||||||
lastErr = err
|
|
||||||
}
|
|
||||||
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
|
||||||
}
|
|
|
@ -1,415 +0,0 @@
|
||||||
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
|
||||||
//
|
|
||||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package glog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
stdLog "log"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Test that shortHostname works as advertised.
|
|
||||||
func TestShortHostname(t *testing.T) {
|
|
||||||
for hostname, expect := range map[string]string{
|
|
||||||
"": "",
|
|
||||||
"host": "host",
|
|
||||||
"host.google.com": "host",
|
|
||||||
} {
|
|
||||||
if got := shortHostname(hostname); expect != got {
|
|
||||||
t.Errorf("shortHostname(%q): expected %q, got %q", hostname, expect, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// flushBuffer wraps a bytes.Buffer to satisfy flushSyncWriter.
|
|
||||||
type flushBuffer struct {
|
|
||||||
bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flushBuffer) Flush() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flushBuffer) Sync() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// swap sets the log writers and returns the old array.
|
|
||||||
func (l *loggingT) swap(writers [numSeverity]flushSyncWriter) (old [numSeverity]flushSyncWriter) {
|
|
||||||
l.mu.Lock()
|
|
||||||
defer l.mu.Unlock()
|
|
||||||
old = l.file
|
|
||||||
for i, w := range writers {
|
|
||||||
logging.file[i] = w
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// newBuffers sets the log writers to all new byte buffers and returns the old array.
|
|
||||||
func (l *loggingT) newBuffers() [numSeverity]flushSyncWriter {
|
|
||||||
return l.swap([numSeverity]flushSyncWriter{new(flushBuffer), new(flushBuffer), new(flushBuffer), new(flushBuffer)})
|
|
||||||
}
|
|
||||||
|
|
||||||
// contents returns the specified log value as a string.
|
|
||||||
func contents(s severity) string {
|
|
||||||
return logging.file[s].(*flushBuffer).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// contains reports whether the string is contained in the log.
|
|
||||||
func contains(s severity, str string, t *testing.T) bool {
|
|
||||||
return strings.Contains(contents(s), str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setFlags configures the logging flags how the test expects them.
|
|
||||||
func setFlags() {
|
|
||||||
logging.toStderr = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that Info works as advertised.
|
|
||||||
func TestInfo(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
Info("test")
|
|
||||||
if !contains(infoLog, "I", t) {
|
|
||||||
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
|
||||||
}
|
|
||||||
if !contains(infoLog, "test", t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfoDepth(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
|
|
||||||
f := func() { InfoDepth(1, "depth-test1") }
|
|
||||||
|
|
||||||
// The next three lines must stay together
|
|
||||||
_, _, wantLine, _ := runtime.Caller(0)
|
|
||||||
InfoDepth(0, "depth-test0")
|
|
||||||
f()
|
|
||||||
|
|
||||||
msgs := strings.Split(strings.TrimSuffix(contents(infoLog), "\n"), "\n")
|
|
||||||
if len(msgs) != 2 {
|
|
||||||
t.Fatalf("Got %d lines, expected 2", len(msgs))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, m := range msgs {
|
|
||||||
if !strings.HasPrefix(m, "I") {
|
|
||||||
t.Errorf("InfoDepth[%d] has wrong character: %q", i, m)
|
|
||||||
}
|
|
||||||
w := fmt.Sprintf("depth-test%d", i)
|
|
||||||
if !strings.Contains(m, w) {
|
|
||||||
t.Errorf("InfoDepth[%d] missing %q: %q", i, w, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pull out the line number (between : and ])
|
|
||||||
msg := m[strings.LastIndex(m, ":")+1:]
|
|
||||||
x := strings.Index(msg, "]")
|
|
||||||
if x < 0 {
|
|
||||||
t.Errorf("InfoDepth[%d]: missing ']': %q", i, m)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
line, err := strconv.Atoi(msg[:x])
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("InfoDepth[%d]: bad line number: %q", i, m)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wantLine++
|
|
||||||
if wantLine != line {
|
|
||||||
t.Errorf("InfoDepth[%d]: got line %d, want %d", i, line, wantLine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
CopyStandardLogTo("INFO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that CopyStandardLogTo panics on bad input.
|
|
||||||
func TestCopyStandardLogToPanic(t *testing.T) {
|
|
||||||
defer func() {
|
|
||||||
if s, ok := recover().(string); !ok || !strings.Contains(s, "LOG") {
|
|
||||||
t.Errorf(`CopyStandardLogTo("LOG") should have panicked: %v`, s)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
CopyStandardLogTo("LOG")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that using the standard log package logs to INFO.
|
|
||||||
func TestStandardLog(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
stdLog.Print("test")
|
|
||||||
if !contains(infoLog, "I", t) {
|
|
||||||
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
|
||||||
}
|
|
||||||
if !contains(infoLog, "test", t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that the header has the correct format.
|
|
||||||
func TestHeader(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
defer func(previous func() time.Time) { timeNow = previous }(timeNow)
|
|
||||||
timeNow = func() time.Time {
|
|
||||||
return time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.Local)
|
|
||||||
}
|
|
||||||
pid = 1234
|
|
||||||
Info("test")
|
|
||||||
var line int
|
|
||||||
format := "I0102 15:04:05.067890 1234 glog_test.go:%d] test\n"
|
|
||||||
n, err := fmt.Sscanf(contents(infoLog), format, &line)
|
|
||||||
if n != 1 || err != nil {
|
|
||||||
t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog))
|
|
||||||
}
|
|
||||||
// Scanf treats multiple spaces as equivalent to a single space,
|
|
||||||
// so check for correct space-padding also.
|
|
||||||
want := fmt.Sprintf(format, line)
|
|
||||||
if contents(infoLog) != want {
|
|
||||||
t.Errorf("log format error: got:\n\t%q\nwant:\t%q", contents(infoLog), want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that an Error log goes to Warning and Info.
|
|
||||||
// Even in the Info log, the source character will be E, so the data should
|
|
||||||
// all be identical.
|
|
||||||
func TestError(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
Error("test")
|
|
||||||
if !contains(errorLog, "E", t) {
|
|
||||||
t.Errorf("Error has wrong character: %q", contents(errorLog))
|
|
||||||
}
|
|
||||||
if !contains(errorLog, "test", t) {
|
|
||||||
t.Error("Error failed")
|
|
||||||
}
|
|
||||||
str := contents(errorLog)
|
|
||||||
if !contains(warningLog, str, t) {
|
|
||||||
t.Error("Warning failed")
|
|
||||||
}
|
|
||||||
if !contains(infoLog, str, t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a Warning log goes to Info.
|
|
||||||
// Even in the Info log, the source character will be W, so the data should
|
|
||||||
// all be identical.
|
|
||||||
func TestWarning(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
Warning("test")
|
|
||||||
if !contains(warningLog, "W", t) {
|
|
||||||
t.Errorf("Warning has wrong character: %q", contents(warningLog))
|
|
||||||
}
|
|
||||||
if !contains(warningLog, "test", t) {
|
|
||||||
t.Error("Warning failed")
|
|
||||||
}
|
|
||||||
str := contents(warningLog)
|
|
||||||
if !contains(infoLog, str, t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a V log goes to Info.
|
|
||||||
func TestV(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
logging.verbosity.Set("2")
|
|
||||||
defer logging.verbosity.Set("0")
|
|
||||||
V(2).Info("test")
|
|
||||||
if !contains(infoLog, "I", t) {
|
|
||||||
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
|
||||||
}
|
|
||||||
if !contains(infoLog, "test", t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a vmodule enables a log in this file.
|
|
||||||
func TestVmoduleOn(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
logging.vmodule.Set("glog_test=2")
|
|
||||||
defer logging.vmodule.Set("")
|
|
||||||
if !V(1) {
|
|
||||||
t.Error("V not enabled for 1")
|
|
||||||
}
|
|
||||||
if !V(2) {
|
|
||||||
t.Error("V not enabled for 2")
|
|
||||||
}
|
|
||||||
if V(3) {
|
|
||||||
t.Error("V enabled for 3")
|
|
||||||
}
|
|
||||||
V(2).Info("test")
|
|
||||||
if !contains(infoLog, "I", t) {
|
|
||||||
t.Errorf("Info has wrong character: %q", contents(infoLog))
|
|
||||||
}
|
|
||||||
if !contains(infoLog, "test", t) {
|
|
||||||
t.Error("Info failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a vmodule of another file does not enable a log in this file.
|
|
||||||
func TestVmoduleOff(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
logging.vmodule.Set("notthisfile=2")
|
|
||||||
defer logging.vmodule.Set("")
|
|
||||||
for i := 1; i <= 3; i++ {
|
|
||||||
if V(Level(i)) {
|
|
||||||
t.Errorf("V enabled for %d", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
V(2).Info("test")
|
|
||||||
if contents(infoLog) != "" {
|
|
||||||
t.Error("V logged incorrectly")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// vGlobs are patterns that match/don't match this file at V=2.
|
|
||||||
var vGlobs = map[string]bool{
|
|
||||||
// Easy to test the numeric match here.
|
|
||||||
"glog_test=1": false, // If -vmodule sets V to 1, V(2) will fail.
|
|
||||||
"glog_test=2": true,
|
|
||||||
"glog_test=3": true, // If -vmodule sets V to 1, V(3) will succeed.
|
|
||||||
// These all use 2 and check the patterns. All are true.
|
|
||||||
"*=2": true,
|
|
||||||
"?l*=2": true,
|
|
||||||
"????_*=2": true,
|
|
||||||
"??[mno]?_*t=2": true,
|
|
||||||
// These all use 2 and check the patterns. All are false.
|
|
||||||
"*x=2": false,
|
|
||||||
"m*=2": false,
|
|
||||||
"??_*=2": false,
|
|
||||||
"?[abc]?_*t=2": false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that vmodule globbing works as advertised.
|
|
||||||
func testVmoduleGlob(pat string, match bool, t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
defer logging.vmodule.Set("")
|
|
||||||
logging.vmodule.Set(pat)
|
|
||||||
if V(2) != Verbose(match) {
|
|
||||||
t.Errorf("incorrect match for %q: got %t expected %t", pat, V(2), match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a vmodule globbing works as advertised.
|
|
||||||
func TestVmoduleGlob(t *testing.T) {
|
|
||||||
for glob, match := range vGlobs {
|
|
||||||
testVmoduleGlob(glob, match, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRollover(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
var err error
|
|
||||||
defer func(previous func(error)) { logExitFunc = previous }(logExitFunc)
|
|
||||||
logExitFunc = func(e error) {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
defer func(previous uint64) { MaxSize = previous }(MaxSize)
|
|
||||||
MaxSize = 512
|
|
||||||
|
|
||||||
Info("x") // Be sure we have a file.
|
|
||||||
info, ok := logging.file[infoLog].(*syncBuffer)
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("info wasn't created")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("info has initial error: %v", err)
|
|
||||||
}
|
|
||||||
fname0 := info.file.Name()
|
|
||||||
Info(strings.Repeat("x", int(MaxSize))) // force a rollover
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("info has error after big write: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the next log file gets a file name with a different
|
|
||||||
// time stamp.
|
|
||||||
//
|
|
||||||
// TODO: determine whether we need to support subsecond log
|
|
||||||
// rotation. C++ does not appear to handle this case (nor does it
|
|
||||||
// handle Daylight Savings Time properly).
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
Info("x") // create a new file
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error after rotation: %v", err)
|
|
||||||
}
|
|
||||||
fname1 := info.file.Name()
|
|
||||||
if fname0 == fname1 {
|
|
||||||
t.Errorf("info.f.Name did not change: %v", fname0)
|
|
||||||
}
|
|
||||||
if info.nbytes >= MaxSize {
|
|
||||||
t.Errorf("file size was not reset: %d", info.nbytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLogBacktraceAt(t *testing.T) {
|
|
||||||
setFlags()
|
|
||||||
defer logging.swap(logging.newBuffers())
|
|
||||||
// The peculiar style of this code simplifies line counting and maintenance of the
|
|
||||||
// tracing block below.
|
|
||||||
var infoLine string
|
|
||||||
setTraceLocation := func(file string, line int, ok bool, delta int) {
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("could not get file:line")
|
|
||||||
}
|
|
||||||
_, file = filepath.Split(file)
|
|
||||||
infoLine = fmt.Sprintf("%s:%d", file, line+delta)
|
|
||||||
err := logging.traceLocation.Set(infoLine)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("error setting log_backtrace_at: ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Start of tracing block. These lines know about each other's relative position.
|
|
||||||
_, file, line, ok := runtime.Caller(0)
|
|
||||||
setTraceLocation(file, line, ok, +2) // Two lines between Caller and Info calls.
|
|
||||||
Info("we want a stack trace here")
|
|
||||||
}
|
|
||||||
numAppearances := strings.Count(contents(infoLog), infoLine)
|
|
||||||
if numAppearances < 2 {
|
|
||||||
// Need 2 appearances, one in the log header and one in the trace:
|
|
||||||
// log_test.go:281: I0511 16:36:06.952398 02238 log_test.go:280] we want a stack trace here
|
|
||||||
// ...
|
|
||||||
// github.com/glog/glog_test.go:280 (0x41ba91)
|
|
||||||
// ...
|
|
||||||
// We could be more precise but that would require knowing the details
|
|
||||||
// of the traceback format, which may not be dependable.
|
|
||||||
t.Fatal("got no trace back; log is ", contents(infoLog))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkHeader(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
buf, _, _ := logging.header(infoLog, 0)
|
|
||||||
logging.putBuffer(buf)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,7 +351,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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue