diff --git a/.gitignore b/.gitignore index 4c16aaf..9c16d86 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ containerd-shim/containerd-shim bin/ ctr/ctr hack/benchmark +*.exe diff --git a/containerd/main.go b/containerd/main.go index 3584ade..c9ef921 100644 --- a/containerd/main.go +++ b/containerd/main.go @@ -1,25 +1,19 @@ package main import ( - "log" "net" "os" - "runtime" "sync" "time" "google.golang.org/grpc" "github.com/Sirupsen/logrus" - "github.com/cloudfoundry/gosigar" "github.com/codegangsta/cli" - "github.com/cyberdelia/go-metrics-graphite" "github.com/docker/containerd" "github.com/docker/containerd/api/grpc/server" "github.com/docker/containerd/api/grpc/types" - "github.com/docker/containerd/osutils" "github.com/docker/containerd/supervisor" - "github.com/rcrowley/go-metrics" ) const ( @@ -34,7 +28,7 @@ var daemonFlags = []cli.Flag{ }, cli.StringFlag{ Name: "state-dir", - Value: "/run/containerd", + Value: defaultStateDir, Usage: "runtime state directory", }, cli.DurationFlag{ @@ -44,43 +38,26 @@ var daemonFlags = []cli.Flag{ }, cli.StringFlag{ Name: "listen,l", - Value: "/run/containerd/containerd.sock", + Value: defaultGRPCEndpoint, Usage: "Address on which GRPC API will listen", }, - cli.BoolFlag{ - Name: "oom-notify", - Usage: "enable oom notifications for containers", - }, - cli.StringFlag{ - Name: "graphite-address", - Usage: "Address of graphite server", - }, } func main() { + appendPlatformFlags() app := cli.NewApp() app.Name = "containerd" app.Version = containerd.Version app.Usage = usage app.Flags = daemonFlags - app.Before = func(context *cli.Context) error { - if context.GlobalBool("debug") { - logrus.SetLevel(logrus.DebugLevel) - if err := debugMetrics(context.GlobalDuration("metrics-interval"), context.GlobalString("graphite-address")); err != nil { - return err - } - } - if err := checkLimits(); err != nil { - return err - } - return nil - } + setAppBefore(app) + app.Action = func(context *cli.Context) { if err := daemon( context.String("listen"), context.String("state-dir"), 10, - context.Bool("oom-notify"), + context.Bool("oom-notify"), // TODO Windows: Remove oom-notify ); err != nil { logrus.Fatal(err) } @@ -90,59 +67,6 @@ func main() { } } -func debugMetrics(interval time.Duration, graphiteAddr string) error { - for name, m := range supervisor.Metrics() { - if err := metrics.DefaultRegistry.Register(name, m); err != nil { - return err - } - } - processMetrics() - if graphiteAddr != "" { - addr, err := net.ResolveTCPAddr("tcp", graphiteAddr) - if err != nil { - return err - } - go graphite.Graphite(metrics.DefaultRegistry, 10e9, "metrics", addr) - } else { - l := log.New(os.Stdout, "[containerd] ", log.LstdFlags) - go metrics.Log(metrics.DefaultRegistry, interval, l) - } - return nil -} - -func processMetrics() { - var ( - g = metrics.NewGauge() - fg = metrics.NewGauge() - memg = metrics.NewGauge() - ) - metrics.DefaultRegistry.Register("goroutines", g) - metrics.DefaultRegistry.Register("fds", fg) - metrics.DefaultRegistry.Register("memory-used", memg) - collect := func() { - // update number of goroutines - g.Update(int64(runtime.NumGoroutine())) - // collect the number of open fds - fds, err := osutils.GetOpenFds(os.Getpid()) - if err != nil { - logrus.WithField("error", err).Error("containerd: get open fd count") - } - fg.Update(int64(fds)) - // get the memory used - m := sigar.ProcMem{} - if err := m.Get(os.Getpid()); err != nil { - logrus.WithField("error", err).Error("containerd: get pid memory information") - } - memg.Update(int64(m.Size)) - } - go func() { - collect() - for range time.Tick(30 * time.Second) { - collect() - } - }() -} - func daemon(address, stateDir string, concurrency int, oom bool) error { // setup a standard reaper so that we don't leave any zombies if we are still alive // this is just good practice because we are spawning new processes @@ -163,7 +87,7 @@ func daemon(address, stateDir string, concurrency int, oom bool) error { if err := os.RemoveAll(address); err != nil { return err } - l, err := net.Listen("unix", address) + l, err := net.Listen(defaultListenType, address) if err != nil { return err } diff --git a/containerd/main_linux.go b/containerd/main_linux.go index c6d0380..3d14396 100644 --- a/containerd/main_linux.go +++ b/containerd/main_linux.go @@ -1,14 +1,55 @@ package main import ( + "log" + "net" "os" "os/signal" + "runtime" "syscall" + "time" "github.com/Sirupsen/logrus" + "github.com/cloudfoundry/gosigar" + "github.com/codegangsta/cli" + "github.com/cyberdelia/go-metrics-graphite" "github.com/docker/containerd/osutils" + "github.com/docker/containerd/supervisor" + "github.com/rcrowley/go-metrics" ) +const ( + defaultStateDir = "/run/containerd" + defaultListenType = "unix" + defaultGRPCEndpoint = "/run/containerd/containerd.sock" +) + +func appendPlatformFlags() { + daemonFlags = append(daemonFlags, cli.BoolFlag{ + Name: "oom-notify", + Usage: "enable oom notifications for containers", + }) + daemonFlags = append(daemonFlags, cli.StringFlag{ + Name: "graphite-address", + Usage: "Address of graphite server", + }) +} + +func setAppBefore(app *cli.App) { + app.Before = func(context *cli.Context) error { + if context.GlobalBool("debug") { + logrus.SetLevel(logrus.DebugLevel) + if err := debugMetrics(context.GlobalDuration("metrics-interval"), context.GlobalString("graphite-address")); err != nil { + return err + } + } + if err := checkLimits(); err != nil { + return err + } + return nil + } +} + func checkLimits() error { var l syscall.Rlimit if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l); err != nil { @@ -37,3 +78,56 @@ func reapProcesses() { } } } + +func processMetrics() { + var ( + g = metrics.NewGauge() + fg = metrics.NewGauge() + memg = metrics.NewGauge() + ) + metrics.DefaultRegistry.Register("goroutines", g) + metrics.DefaultRegistry.Register("fds", fg) + metrics.DefaultRegistry.Register("memory-used", memg) + collect := func() { + // update number of goroutines + g.Update(int64(runtime.NumGoroutine())) + // collect the number of open fds + fds, err := osutils.GetOpenFds(os.Getpid()) + if err != nil { + logrus.WithField("error", err).Error("containerd: get open fd count") + } + fg.Update(int64(fds)) + // get the memory used + m := sigar.ProcMem{} + if err := m.Get(os.Getpid()); err != nil { + logrus.WithField("error", err).Error("containerd: get pid memory information") + } + memg.Update(int64(m.Size)) + } + go func() { + collect() + for range time.Tick(30 * time.Second) { + collect() + } + }() +} + +func debugMetrics(interval time.Duration, graphiteAddr string) error { + for name, m := range supervisor.Metrics() { + if err := metrics.DefaultRegistry.Register(name, m); err != nil { + return err + } + } + processMetrics() + if graphiteAddr != "" { + addr, err := net.ResolveTCPAddr("tcp", graphiteAddr) + if err != nil { + return err + } + go graphite.Graphite(metrics.DefaultRegistry, 10e9, "metrics", addr) + } else { + l := log.New(os.Stdout, "[containerd] ", log.LstdFlags) + go metrics.Log(metrics.DefaultRegistry, interval, l) + } + return nil +} diff --git a/containerd/main_windows.go b/containerd/main_windows.go index ba0fc59..06c5750 100644 --- a/containerd/main_windows.go +++ b/containerd/main_windows.go @@ -1,5 +1,21 @@ package main +import ( + "os" + + "github.com/codegangsta/cli" +) + +var defaultStateDir = os.Getenv("PROGRAMDATA") + `\docker\containerd` + +const ( + defaultListenType = "tcp" + defaultGRPCEndpoint = "localhost:2377" +) + +func appendPlatformFlags() { +} + // TODO Windows: May be able to factor out entirely func checkLimits() error { return nil @@ -8,3 +24,6 @@ func checkLimits() error { // No idea how to implement this on Windows. func reapProcesses() { } + +func setAppBefore(app *cli.App) { +} diff --git a/supervisor/machine.go b/supervisor/machine.go index 1dcada5..f6045a7 100644 --- a/supervisor/machine.go +++ b/supervisor/machine.go @@ -1,23 +1,6 @@ package supervisor -import "github.com/cloudfoundry/gosigar" - type Machine struct { Cpus int Memory int64 } - -func CollectMachineInformation() (Machine, error) { - m := Machine{} - cpu := sigar.CpuList{} - if err := cpu.Get(); err != nil { - return m, err - } - m.Cpus = len(cpu.List) - mem := sigar.Mem{} - if err := mem.Get(); err != nil { - return m, err - } - m.Memory = int64(mem.Total / 1024 / 1024) - return m, nil -} diff --git a/supervisor/machine_linux.go b/supervisor/machine_linux.go new file mode 100644 index 0000000..5cbec23 --- /dev/null +++ b/supervisor/machine_linux.go @@ -0,0 +1,18 @@ +package supervisor + +import "github.com/cloudfoundry/gosigar" + +func CollectMachineInformation() (Machine, error) { + m := Machine{} + cpu := sigar.CpuList{} + if err := cpu.Get(); err != nil { + return m, err + } + m.Cpus = len(cpu.List) + mem := sigar.Mem{} + if err := mem.Get(); err != nil { + return m, err + } + m.Memory = int64(mem.Total / 1024 / 1024) + return m, nil +} diff --git a/supervisor/machine_windows.go b/supervisor/machine_windows.go new file mode 100644 index 0000000..90d47c8 --- /dev/null +++ b/supervisor/machine_windows.go @@ -0,0 +1,5 @@ +package supervisor + +func CollectMachineInformation() (Machine, error) { + return Machine{}, nil +} diff --git a/supervisor/monitor_windows.go b/supervisor/monitor_windows.go index 74c8416..71db76e 100644 --- a/supervisor/monitor_windows.go +++ b/supervisor/monitor_windows.go @@ -11,7 +11,8 @@ import ( // Linux implementation. @crosbymichael - Help needed. func NewMonitor() (*Monitor, error) { - return nil, errors.New("NewMonitor not implemented on Windows") + // During Windows bring-up, don't error out other binary bombs immediately. + return &Monitor{}, nil } type Monitor struct {