diff --git a/MAINTAINERS b/MAINTAINERS index 52351317..cea3500f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3,4 +3,5 @@ Rohit Jnagal (@rjnagal) Victor Marmol (@vmarmol) Mrunal Patel (@mrunalp) Alexandr Morozov (@LK4D4) +Daniel, Dao Quang Minh (@dqminh) update-vendor.sh: Tianon Gravi (@tianon) diff --git a/Makefile b/Makefile index c7cec0b9..e1567ab5 100644 --- a/Makefile +++ b/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) direct-test: - go get github.com/golang/glog && \ go test $(TEST_TAGS) -cover -v $(GO_PACKAGES) direct-test-short: diff --git a/apparmor/apparmor.go b/apparmor/apparmor.go index fb1574df..3be3294d 100644 --- a/apparmor/apparmor.go +++ b/apparmor/apparmor.go @@ -24,7 +24,6 @@ func ApplyProfile(name string) error { if name == "" { return nil } - cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) diff --git a/cgroups/fs/apply_raw.go b/cgroups/fs/apply_raw.go index a56b59a1..ba09bfb7 100644 --- a/cgroups/fs/apply_raw.go +++ b/cgroups/fs/apply_raw.go @@ -1,11 +1,11 @@ package fs import ( - "fmt" "io/ioutil" "os" "path/filepath" "strconv" + "sync" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/configs" @@ -40,20 +40,31 @@ type Manager struct { } // The absolute path to the root of the cgroup hierarchies. +var cgroupRootLock sync.Mutex var cgroupRoot string -// TODO(vmarmol): Report error here, we'll probably need to wait for the new API. -func init() { +// Gets the cgroupRoot. +func getCgroupRoot() (string, error) { + cgroupRootLock.Lock() + defer cgroupRootLock.Unlock() + + if cgroupRoot != "" { + return cgroupRoot, nil + } + // we can pick any subsystem to find the root cpuRoot, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { - return + return "", err } - cgroupRoot = filepath.Dir(cpuRoot) + root := filepath.Dir(cpuRoot) - if _, err := os.Stat(cgroupRoot); err != nil { - return + if _, err := os.Stat(root); err != nil { + return "", err } + + cgroupRoot = root + return cgroupRoot, nil } type data struct { @@ -172,8 +183,9 @@ func (m *Manager) GetPids() ([]int, error) { } func getCgroupData(c *configs.Cgroup, pid int) (*data, error) { - if cgroupRoot == "" { - return nil, fmt.Errorf("failed to find the cgroup root") + root, err := getCgroupRoot() + if err != nil { + return nil, err } cgroup := c.Name @@ -182,7 +194,7 @@ func getCgroupData(c *configs.Cgroup, pid int) (*data, error) { } return &data{ - root: cgroupRoot, + root: root, cgroup: cgroup, c: c, pid: pid, diff --git a/cgroups/systemd/apply_systemd.go b/cgroups/systemd/apply_systemd.go index f46067b4..194884bc 100644 --- a/cgroups/systemd/apply_systemd.go +++ b/cgroups/systemd/apply_systemd.go @@ -30,9 +30,10 @@ type subsystem interface { } var ( - connLock sync.Mutex - theConn *systemd.Conn - hasStartTransientUnit bool + connLock sync.Mutex + theConn *systemd.Conn + hasStartTransientUnit bool + hasTransientDefaultDependencies bool ) func newProp(name string, units interface{}) systemd.Property { @@ -66,6 +67,18 @@ func UseSystemd() bool { if dbusError, ok := err.(dbus.Error); ok { if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" { 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("BlockIOAccounting", true)) + if hasTransientDefaultDependencies { + properties = append(properties, + newProp("DefaultDependencies", false)) + } + if c.Memory != 0 { properties = append(properties, newProp("MemoryLimit", uint64(c.Memory))) @@ -128,14 +146,12 @@ func (m *Manager) Apply(pid int) error { return err } - if !c.AllowAllDevices { - if err := joinDevices(c, pid); err != nil { - return err - } + if err := joinDevices(c, pid); err != nil { + return err } // -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 { return err } @@ -290,16 +306,16 @@ func joinDevices(c *configs.Cgroup, pid int) error { return err } - if err := writeFile(path, "devices.deny", "a"); err != nil { - return err + if !c.AllowAllDevices { + if err := writeFile(path, "devices.deny", "a"); err != nil { + return err + } } - for _, dev := range c.AllowedDevices { if err := writeFile(path, "devices.allow", dev.CgroupString()); err != nil { return err } } - return nil } diff --git a/configs/config_test.go b/configs/config_test.go index a34d1b09..2fc0513f 100644 --- a/configs/config_test.go +++ b/configs/config_test.go @@ -162,7 +162,7 @@ func TestHostUIDNoUSERNS(t *testing.T) { t.Fatal(err) } 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) } 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) } 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) } 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) } } diff --git a/docs/man/nsinit.1.md b/docs/man/nsinit.1.md new file mode 100644 index 00000000..898dba23 --- /dev/null +++ b/docs/man/nsinit.1.md @@ -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 of an already running docker container. +`sudo docker ps` will return the list of all the running containers. + +take the (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. diff --git a/integration/execin_test.go b/integration/execin_test.go new file mode 100644 index 00000000..3f015d34 --- /dev/null +++ b/integration/execin_test.go @@ -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) + } +} diff --git a/integration/init_test.go b/integration/init_test.go index c2abe3b7..f11834de 100644 --- a/integration/init_test.go +++ b/integration/init_test.go @@ -21,6 +21,7 @@ func init() { if err != nil { log.Fatalf("unable to initialize for container: %s", err) } - factory.StartInitialization(3) - os.Exit(1) + if err := factory.StartInitialization(3); err != nil { + log.Fatal(err) + } } diff --git a/integration/utils_test.go b/integration/utils_test.go index cd82859b..d31bd480 100644 --- a/integration/utils_test.go +++ b/integration/utils_test.go @@ -67,11 +67,27 @@ func copyBusybox(dest string) error { 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 // // buffers are returned containing the STDOUT and STDERR output for the run // along with the exit code and any go 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() process := &libcontainer.Process{ Args: args, @@ -81,32 +97,18 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe 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) if err != nil { return nil, -1, err } - p, err := os.FindProcess(pid) if err != nil { return nil, -1, err } - ps, err := p.Wait() if err != nil { return nil, -1, err } - status := ps.Sys().(syscall.WaitStatus) if status.Exited() { exitCode = status.ExitStatus() @@ -115,6 +117,5 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe } else { return nil, -1, err } - return } diff --git a/linux_container.go b/linux_container.go index 7ab13a72..01e34769 100644 --- a/linux_container.go +++ b/linux_container.go @@ -11,9 +11,9 @@ import ( "sync" "syscall" + log "github.com/Sirupsen/logrus" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/configs" - "github.com/golang/glog" ) type linuxContainer struct { @@ -49,7 +49,6 @@ func (c *linuxContainer) State() (*State, error) { } func (c *linuxContainer) Processes() ([]int, error) { - glog.Info("fetch container processes") pids, err := c.cgroupManager.GetPids() if err != nil { return nil, newSystemError(err) @@ -58,7 +57,6 @@ func (c *linuxContainer) Processes() ([]int, error) { } func (c *linuxContainer) Stats() (*Stats, error) { - glog.Info("fetch container stats") var ( err error stats = &Stats{} @@ -94,7 +92,7 @@ func (c *linuxContainer) Start(process *Process) (int, error) { if err := parent.start(); err != nil { // terminate the process to ensure that it properly is reaped. if err := parent.terminate(); err != nil { - glog.Warning(err) + log.Warn(err) } return -1, newSystemError(err) } @@ -207,7 +205,7 @@ func (c *linuxContainer) Destroy() error { } if !c.config.Namespaces.Contains(configs.NEWPID) { if err := killCgroupProcesses(c.cgroupManager); err != nil { - glog.Warning(err) + log.Warn(err) } } err = c.cgroupManager.Destroy() diff --git a/linux_init.go b/linux_init.go index 0fbda641..4755edb0 100644 --- a/linux_init.go +++ b/linux_init.go @@ -9,13 +9,13 @@ import ( "strings" "syscall" + log "github.com/Sirupsen/logrus" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/netlink" "github.com/docker/libcontainer/system" "github.com/docker/libcontainer/user" "github.com/docker/libcontainer/utils" - "github.com/golang/glog" ) type initType string @@ -235,7 +235,7 @@ func setupRlimits(config *configs.Config) error { func killCgroupProcesses(m cgroups.Manager) error { var procs []*os.Process if err := m.Freeze(configs.Frozen); err != nil { - glog.Warning(err) + log.Warn(err) } pids, err := m.GetPids() if err != nil { @@ -246,16 +246,16 @@ func killCgroupProcesses(m cgroups.Manager) error { if p, err := os.FindProcess(pid); err == nil { procs = append(procs, p) if err := p.Kill(); err != nil { - glog.Warning(err) + log.Warn(err) } } } if err := m.Freeze(configs.Thawed); err != nil { - glog.Warning(err) + log.Warn(err) } for _, p := range procs { if _, err := p.Wait(); err != nil { - glog.Warning(err) + log.Warn(err) } } return nil diff --git a/linux_process.go b/linux_process.go index ceef3c70..83addf24 100644 --- a/linux_process.go +++ b/linux_process.go @@ -10,9 +10,9 @@ import ( "os/exec" "syscall" + log "github.com/Sirupsen/logrus" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/system" - "github.com/golang/glog" ) type parentProcess interface { @@ -82,7 +82,7 @@ func (p *setnsProcess) execSetns() (*os.Process, error) { return nil, newSystemError(err) } if !status.Success() { - return nil, newSystemError(&exec.ExitError{status}) + return nil, newSystemError(&exec.ExitError{ProcessState: status}) } var pid *pid 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.terminate(); err != nil { - glog.Warning(err) + log.Warn(err) } return err } diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 3cc3cc94..3ecb81fb 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -7,7 +7,6 @@ import ( "math/rand" "net" "os" - "path/filepath" "sync/atomic" "syscall" "unsafe" @@ -23,6 +22,7 @@ const ( IFLA_VLAN_ID = 1 IFLA_NET_NS_FD = 28 IFLA_ADDRESS = 1 + IFLA_BRPORT_MODE = 4 SIOC_BRADDBR = 0x89a0 SIOC_BRDELBR = 0x89a1 SIOC_BRADDIF = 0x89a2 @@ -1253,25 +1253,33 @@ func SetMacAddress(name, addr string) error { } func SetHairpinMode(iface *net.Interface, enabled bool) error { - sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode") - - sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0) + s, err := getNetlinkSocket() if err != nil { 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 { - writeVal = []byte("1") - } else { - writeVal = []byte("0") + mode[0] = byte(1) } - 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 nil + return s.HandleAck(req.Seq) } func ChangeName(iface *net.Interface, newName string) error { diff --git a/nsinit/exec.go b/nsinit/exec.go index 5c6b830f..b499d66e 100644 --- a/nsinit/exec.go +++ b/nsinit/exec.go @@ -5,6 +5,7 @@ import ( "os/signal" "syscall" + log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/libcontainer" "github.com/docker/libcontainer/utils" @@ -31,6 +32,7 @@ var execCommand = cli.Command{ } func execAction(context *cli.Context) { + entry := log.WithField("parent", "nsinit") factory, err := loadFactory(context) if err != nil { fatal(err) @@ -42,9 +44,7 @@ func execAction(context *cli.Context) { created := false container, err := factory.Load(context.String("id")) if err != nil { - if lerr, ok := err.(libcontainer.Error); !ok || lerr.Code() != libcontainer.ContainerNotExists { - fatal(err) - } + entry.Debug("creating container") config, err := loadConfig(context) if err != nil { tty.Close() @@ -53,6 +53,7 @@ func execAction(context *cli.Context) { if tty.console != nil { config.Console = tty.console.Path() } + created = true if container, err = factory.Create(context.String("id"), config); err != nil { tty.Close() @@ -72,16 +73,25 @@ func execAction(context *cli.Context) { pid, err := container.Start(process) if err != nil { tty.Close() + if created { + container.Destroy() + } fatal(err) } proc, err := os.FindProcess(pid) if err != nil { tty.Close() + if created { + container.Destroy() + } fatal(err) } status, err := proc.Wait() if err != nil { tty.Close() + if created { + container.Destroy() + } fatal(err) } if created { diff --git a/nsinit/init.go b/nsinit/init.go index 4d9a8e63..96957824 100644 --- a/nsinit/init.go +++ b/nsinit/init.go @@ -1,9 +1,9 @@ package main import ( - "log" "runtime" + log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/libcontainer" _ "github.com/docker/libcontainer/nsenter" @@ -13,6 +13,7 @@ var initCommand = cli.Command{ Name: "init", Usage: "runs the init process inside the namespace", Action: func(context *cli.Context) { + log.SetLevel(log.DebugLevel) runtime.GOMAXPROCS(1) runtime.LockOSThread() factory, err := libcontainer.New("") diff --git a/nsinit/main.go b/nsinit/main.go index 28e315be..f8ccd62e 100644 --- a/nsinit/main.go +++ b/nsinit/main.go @@ -1,9 +1,9 @@ package main import ( - "log" "os" + log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" ) @@ -13,9 +13,9 @@ func main() { app.Version = "2" app.Author = "libcontainer maintainers" 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: "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{ configCommand, @@ -27,6 +27,19 @@ func main() { unpauseCommand, 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 { log.Fatal(err) } diff --git a/sample_configs/apparmor.json b/sample_configs/apparmor.json index bc423f50..b8860bbb 100644 --- a/sample_configs/apparmor.json +++ b/sample_configs/apparmor.json @@ -1,194 +1,341 @@ { - "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, - "apparmor_profile": "docker-default", - "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" - } - ], - "tty": true, - "user": "daemon" + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/rootfs/jessie", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "", + "hostname": "nsinit", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, + { + "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": "" + } + ], + "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": "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" + ] } diff --git a/sample_configs/attach_to_bridge.json b/sample_configs/attach_to_bridge.json index eb788691..a2b8738b 100644 --- a/sample_configs/attach_to_bridge.json +++ b/sample_configs/attach_to_bridge.json @@ -1,200 +1,354 @@ { - "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": [ + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/rootfs/jessie", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "", + "hostname": "koye", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, + { + "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", - "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", - "gateway": "172.17.42.1", - "mtu": 1500, - "type": "veth" - } - ], - "tty": true + "type": "veth", + "name": "eth0", + "bridge": "docker0", + "mac_address": "", + "address": "172.17.0.101/16", + "gateway": "172.17.42.1", + "ipv6_address": "", + "ipv6_gateway": "", + "mtu": 1500, + "txqueuelen": 0, + "host_interface_name": "vethnsinit" + } + ], + "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" + ] } diff --git a/sample_configs/host-pid.json b/sample_configs/host-pid.json index 5ef8f78c..b5eb89bc 100644 --- a/sample_configs/host-pid.json +++ b/sample_configs/host-pid.json @@ -1,198 +1,337 @@ { - "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 - } - ], - "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": [ + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/rootfs/jessie", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "", + "hostname": "nsinit", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, { - "address": "127.0.0.1/0", - "gateway": "localhost", - "mtu": 1500, - "type": "loopback" - } - ], - "tty": true, - "user": "daemon" + "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": "" + } + ], + "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" + ] } diff --git a/sample_configs/minimal.json b/sample_configs/minimal.json index d6ee044c..b936ebdf 100644 --- a/sample_configs/minimal.json +++ b/sample_configs/minimal.json @@ -1,199 +1,341 @@ { - "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 - } - ], - "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": "NEWPID"}, - {"type": "NEWUTS"} - ], - "networks": [ - { - "address": "127.0.0.1/0", - "gateway": "localhost", - "mtu": 1500, - "type": "loopback" - } - ], - "tty": true, - "user": "daemon" -} + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/home/michael/development/gocode/src/github.com/docker/libcontainer", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "", + "hostname": "nsinit", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, + { + "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": "" + } + ], + "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" + ] +} \ No newline at end of file diff --git a/sample_configs/route_source_address_selection.json b/sample_configs/route_source_address_selection.json deleted file mode 100644 index 2ade6d00..00000000 --- a/sample_configs/route_source_address_selection.json +++ /dev/null @@ -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 -} diff --git a/sample_configs/selinux.json b/sample_configs/selinux.json index 4d6971a4..033d3be1 100644 --- a/sample_configs/selinux.json +++ b/sample_configs/selinux.json @@ -1,195 +1,341 @@ { - "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, - "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": [ - { - "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" - } - ], - "tty": true, - "user": "daemon" + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/rootfs/jessie", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "system_u:system_r:svirt_lxc_net_t:s0:c164,c475", + "hostname": "nsinit", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, + { + "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": "" + } + ], + "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": "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" + ] } diff --git a/sample_configs/userns.json b/sample_configs/userns.json index ad10b249..0b0644fb 100644 --- a/sample_configs/userns.json +++ b/sample_configs/userns.json @@ -1,249 +1,377 @@ { - "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 - } - ], - "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": "NEWPID"}, - {"type": "NEWUTS"}, - {"type": "NEWUSER"} - ], - "networks": [ - { - "address": "127.0.0.1/0", - "gateway": "localhost", - "mtu": 1500, - "type": "loopback" - }, - { - "address": "172.17.0.9/16", - "gateway": "172.17.42.1", - "bridge": "docker0", - "veth_prefix": "veth", - "mtu": 1500, - "type": "veth" - } - ], - "tty": true, - "user": "root", - "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": 9000 - } - ], - "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": 9000 - } - ], - "rlimits": [ - { - "type": 7, - "hard": 999, - "soft": 999 - } - ] + "no_pivot_root": false, + "parent_death_signal": 0, + "pivot_dir": "", + "rootfs": "/rootfs/jessie", + "readonlyfs": false, + "mounts": [ + { + "source": "shm", + "destination": "/dev/shm", + "device": "tmpfs", + "flags": 14, + "data": "mode=1777,size=65536k", + "relabel": "" + }, + { + "source": "mqueue", + "destination": "/dev/mqueue", + "device": "mqueue", + "flags": 14, + "data": "", + "relabel": "" + }, + { + "source": "sysfs", + "destination": "/sys", + "device": "sysfs", + "flags": 15, + "data": "", + "relabel": "" + } + ], + "devices": [ + { + "type": 99, + "path": "/dev/fuse", + "major": 10, + "minor": 229, + "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 + } + ], + "mount_label": "", + "hostname": "nsinit", + "console": "", + "namespaces": [ + { + "type": "NEWNS", + "path": "" + }, + { + "type": "NEWUTS", + "path": "" + }, + { + "type": "NEWIPC", + "path": "" + }, + { + "type": "NEWPID", + "path": "" + }, + { + "type": "NEWNET", + "path": "" + }, + { + "type": "NEWUSER", + "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": "" + } + ], + "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": [ + { + "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" + ] } diff --git a/update-vendor.sh b/update-vendor.sh index b3849330..ab201d6f 100755 --- a/update-vendor.sh +++ b/update-vendor.sh @@ -42,8 +42,8 @@ clone() { # the following lines are in sorted order, FYI clone git github.com/codegangsta/cli 1.1.0 clone git github.com/coreos/go-systemd v2 -clone git github.com/godbus/dbus v1 -clone git github.com/syndtr/gocapability 3c85049eae -clone git github.com/golang/glog 44145f04b68c +clone git github.com/godbus/dbus v2 +clone git github.com/Sirupsen/logrus v0.6.0 +clone git github.com/syndtr/gocapability 1cf3ac4dc4 # intentionally not vendoring Docker itself... that'd be a circle :) diff --git a/vendor/src/github.com/Sirupsen/logrus/.gitignore b/vendor/src/github.com/Sirupsen/logrus/.gitignore new file mode 100644 index 00000000..66be63a0 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/.gitignore @@ -0,0 +1 @@ +logrus diff --git a/vendor/src/github.com/Sirupsen/logrus/.travis.yml b/vendor/src/github.com/Sirupsen/logrus/.travis.yml new file mode 100644 index 00000000..d5a559f8 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/.travis.yml @@ -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 diff --git a/vendor/src/github.com/Sirupsen/logrus/LICENSE b/vendor/src/github.com/Sirupsen/logrus/LICENSE new file mode 100644 index 00000000..f090cb42 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/LICENSE @@ -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. diff --git a/vendor/src/github.com/Sirupsen/logrus/README.md b/vendor/src/github.com/Sirupsen/logrus/README.md new file mode 100644 index 00000000..01769c72 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/README.md @@ -0,0 +1,342 @@ +# Logrus :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 diff --git a/vendor/src/github.com/Sirupsen/logrus/entry.go b/vendor/src/github.com/Sirupsen/logrus/entry.go new file mode 100644 index 00000000..a77c4b0e --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/entry.go @@ -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] +} diff --git a/vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go b/vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go new file mode 100644 index 00000000..35945509 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go @@ -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!") +} diff --git a/vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go b/vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go new file mode 100644 index 00000000..42e7a4c9 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go @@ -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!") +} diff --git a/vendor/src/github.com/Sirupsen/logrus/exported.go b/vendor/src/github.com/Sirupsen/logrus/exported.go new file mode 100644 index 00000000..0e2d59f1 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/exported.go @@ -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...) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/formatter.go b/vendor/src/github.com/Sirupsen/logrus/formatter.go new file mode 100644 index 00000000..74c49a0e --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/formatter.go @@ -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"] + } +} diff --git a/vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go b/vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go new file mode 100644 index 00000000..77989da6 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go @@ -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))) + } +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hook_test.go b/vendor/src/github.com/Sirupsen/logrus/hook_test.go new file mode 100644 index 00000000..13f34cb6 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hook_test.go @@ -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) + }) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks.go b/vendor/src/github.com/Sirupsen/logrus/hooks.go new file mode 100644 index 00000000..0da2b365 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks.go @@ -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 +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go b/vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go new file mode 100644 index 00000000..880d21ec --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go @@ -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, + } +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md new file mode 100644 index 00000000..ae61e922 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md @@ -0,0 +1,28 @@ +# Papertrail Hook for Logrus :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) + } +} +``` diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go new file mode 100644 index 00000000..48e2feae --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go @@ -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, + } +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go new file mode 100644 index 00000000..96318d00 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go @@ -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") + }) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md new file mode 100644 index 00000000..cd706bc1 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md @@ -0,0 +1,20 @@ +# Syslog Hooks for Logrus :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) + } +} +``` \ No newline at end of file diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go new file mode 100644 index 00000000..2a18ce61 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go @@ -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, + } +} diff --git a/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go new file mode 100644 index 00000000..42762dc1 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go @@ -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!") +} diff --git a/vendor/src/github.com/Sirupsen/logrus/json_formatter.go b/vendor/src/github.com/Sirupsen/logrus/json_formatter.go new file mode 100644 index 00000000..9d11b642 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/json_formatter.go @@ -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 +} diff --git a/vendor/src/github.com/Sirupsen/logrus/logger.go b/vendor/src/github.com/Sirupsen/logrus/logger.go new file mode 100644 index 00000000..7374fe36 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/logger.go @@ -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...) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/logrus.go b/vendor/src/github.com/Sirupsen/logrus/logrus.go new file mode 100644 index 00000000..43ee12e9 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/logrus.go @@ -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{}) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/logrus_test.go b/vendor/src/github.com/Sirupsen/logrus/logrus_test.go new file mode 100644 index 00000000..15157d17 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/logrus_test.go @@ -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()) +} diff --git a/vendor/src/github.com/Sirupsen/logrus/terminal_darwin.go b/vendor/src/github.com/Sirupsen/logrus/terminal_darwin.go new file mode 100644 index 00000000..8fe02a4a --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/terminal_darwin.go @@ -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 diff --git a/vendor/src/github.com/Sirupsen/logrus/terminal_freebsd.go b/vendor/src/github.com/Sirupsen/logrus/terminal_freebsd.go new file mode 100644 index 00000000..0428ee5d --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/terminal_freebsd.go @@ -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 +} diff --git a/vendor/src/github.com/Sirupsen/logrus/terminal_linux.go b/vendor/src/github.com/Sirupsen/logrus/terminal_linux.go new file mode 100644 index 00000000..a2c0b40d --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/terminal_linux.go @@ -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 diff --git a/vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go b/vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go new file mode 100644 index 00000000..276447bd --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go @@ -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 +} diff --git a/vendor/src/github.com/Sirupsen/logrus/terminal_windows.go b/vendor/src/github.com/Sirupsen/logrus/terminal_windows.go new file mode 100644 index 00000000..2e09f6f7 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/terminal_windows.go @@ -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 +} diff --git a/vendor/src/github.com/Sirupsen/logrus/text_formatter.go b/vendor/src/github.com/Sirupsen/logrus/text_formatter.go new file mode 100644 index 00000000..fc0a4082 --- /dev/null +++ b/vendor/src/github.com/Sirupsen/logrus/text_formatter.go @@ -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) + } +} diff --git a/vendor/src/github.com/godbus/dbus/CONTRIBUTING.md b/vendor/src/github.com/godbus/dbus/CONTRIBUTING.md new file mode 100644 index 00000000..c88f9b2b --- /dev/null +++ b/vendor/src/github.com/godbus/dbus/CONTRIBUTING.md @@ -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: + +``` +: + + + +