Merge pull request #15612 from jimmidyson/cadvisor-kubelet
Auto commit by PR queue bot
This commit is contained in:
76
Godeps/Godeps.json
generated
76
Godeps/Godeps.json
generated
@@ -216,8 +216,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/libcontainer",
|
"ImportPath": "github.com/docker/libcontainer",
|
||||||
"Comment": "v1.4.0-446-gae812bd",
|
"Comment": "v1.4.0-501-ga1fe3f1",
|
||||||
"Rev": "ae812bdca78084dc322037225d170e1883521d87"
|
"Rev": "a1fe3f1c7ad2e8eebe6d59e573f04d2b10961cf6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/spdystream",
|
"ImportPath": "github.com/docker/spdystream",
|
||||||
@@ -281,93 +281,93 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/api",
|
"ImportPath": "github.com/google/cadvisor/api",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/cache/memory",
|
"ImportPath": "github.com/google/cadvisor/cache/memory",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/collector",
|
"ImportPath": "github.com/google/cadvisor/collector",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/container",
|
"ImportPath": "github.com/google/cadvisor/container",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/events",
|
"ImportPath": "github.com/google/cadvisor/events",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/fs",
|
"ImportPath": "github.com/google/cadvisor/fs",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/healthz",
|
"ImportPath": "github.com/google/cadvisor/healthz",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/http",
|
"ImportPath": "github.com/google/cadvisor/http",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/info/v1",
|
"ImportPath": "github.com/google/cadvisor/info/v1",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/info/v2",
|
"ImportPath": "github.com/google/cadvisor/info/v2",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/manager",
|
"ImportPath": "github.com/google/cadvisor/manager",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/metrics",
|
"ImportPath": "github.com/google/cadvisor/metrics",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/pages",
|
"ImportPath": "github.com/google/cadvisor/pages",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/storage",
|
"ImportPath": "github.com/google/cadvisor/storage",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/summary",
|
"ImportPath": "github.com/google/cadvisor/summary",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/utils",
|
"ImportPath": "github.com/google/cadvisor/utils",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/validate",
|
"ImportPath": "github.com/google/cadvisor/validate",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/cadvisor/version",
|
"ImportPath": "github.com/google/cadvisor/version",
|
||||||
"Comment": "0.16.0.2",
|
"Comment": "0.19.0",
|
||||||
"Rev": "cefada41b87c35294533638733c563a349b95f05"
|
"Rev": "0d6015c74114de9503d68c3c91efceee4dc41bd2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/google/gofuzz",
|
"ImportPath": "github.com/google/gofuzz",
|
||||||
|
|||||||
6
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/apparmor.go
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/apparmor/apparmor.go
generated
vendored
@@ -14,8 +14,10 @@ import (
|
|||||||
|
|
||||||
func IsEnabled() bool {
|
func IsEnabled() bool {
|
||||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
|
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" {
|
||||||
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
if _, err = os.Stat("/sbin/apparmor_parser"); err == nil {
|
||||||
return err == nil && len(buf) > 1 && buf[0] == 'Y'
|
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
||||||
|
return err == nil && len(buf) > 1 && buf[0] == 'Y'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
49
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
49
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go
generated
vendored
@@ -1,6 +1,8 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -19,6 +21,7 @@ var (
|
|||||||
"cpuset": &CpusetGroup{},
|
"cpuset": &CpusetGroup{},
|
||||||
"cpuacct": &CpuacctGroup{},
|
"cpuacct": &CpuacctGroup{},
|
||||||
"blkio": &BlkioGroup{},
|
"blkio": &BlkioGroup{},
|
||||||
|
"hugetlb": &HugetlbGroup{},
|
||||||
"perf_event": &PerfEventGroup{},
|
"perf_event": &PerfEventGroup{},
|
||||||
"freezer": &FreezerGroup{},
|
"freezer": &FreezerGroup{},
|
||||||
}
|
}
|
||||||
@@ -75,10 +78,13 @@ type data struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Apply(pid int) error {
|
func (m *Manager) Apply(pid int) error {
|
||||||
|
|
||||||
if m.Cgroups == nil {
|
if m.Cgroups == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var c = m.Cgroups
|
||||||
|
|
||||||
d, err := getCgroupData(m.Cgroups, pid)
|
d, err := getCgroupData(m.Cgroups, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -108,6 +114,12 @@ func (m *Manager) Apply(pid int) error {
|
|||||||
}
|
}
|
||||||
m.Paths = paths
|
m.Paths = paths
|
||||||
|
|
||||||
|
if paths["cpu"] != "" {
|
||||||
|
if err := CheckCpushares(paths["cpu"], c.CpuShares); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,19 +131,6 @@ func (m *Manager) GetPaths() map[string]string {
|
|||||||
return m.Paths
|
return m.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symmetrical public function to update device based cgroups. Also available
|
|
||||||
// in the systemd implementation.
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
d, err := getCgroupData(c, pid)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
devices := subsystems["devices"]
|
|
||||||
|
|
||||||
return devices.Apply(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
||||||
stats := cgroups.NewStats()
|
stats := cgroups.NewStats()
|
||||||
for name, path := range m.Paths {
|
for name, path := range m.Paths {
|
||||||
@@ -280,3 +279,27 @@ func removePath(p string, err error) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckCpushares(path string, c int64) error {
|
||||||
|
var cpuShares int64
|
||||||
|
|
||||||
|
fd, err := os.Open(filepath.Join(path, "cpu.shares"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
_, err = fmt.Fscanf(fd, "%d", &cpuShares)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c != 0 {
|
||||||
|
if c > cpuShares {
|
||||||
|
return fmt.Errorf("The maximum allowed cpu-shares is %d", cpuShares)
|
||||||
|
} else if c < cpuShares {
|
||||||
|
return fmt.Errorf("The minimum allowed cpu-shares is %d", cpuShares)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
20
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/blkio.go
generated
vendored
@@ -40,6 +40,26 @@ func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cgroup.BlkioThrottleReadBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_bps_device", cgroup.BlkioThrottleReadBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleWriteBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_bps_device", cgroup.BlkioThrottleWriteBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleReadIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_iops_device", cgroup.BlkioThrottleReadIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cgroup.BlkioThrottleWriteIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_iops_device", cgroup.BlkioThrottleWriteIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
11
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices.go
generated
vendored
11
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/devices.go
generated
vendored
@@ -32,6 +32,17 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeFile(path, "devices.allow", "a"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dev := range cgroup.DeniedDevices {
|
||||||
|
if err := writeFile(path, "devices.deny", dev.CgroupString()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
29
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
Normal file
29
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/libcontainer/cgroups"
|
||||||
|
"github.com/docker/libcontainer/configs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HugetlbGroup struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Apply(d *data) error {
|
||||||
|
// we just want to join this group even though we don't set anything
|
||||||
|
if _, err := d.join("hugetlb"); err != nil && !cgroups.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) Remove(d *data) error {
|
||||||
|
return removePath(d.path("hugetlb"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -46,10 +46,6 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
|
|||||||
return fmt.Errorf("Systemd not supported")
|
return fmt.Errorf("Systemd not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
return fmt.Errorf("Systemd not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
|
func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
|
||||||
return fmt.Errorf("Systemd not supported")
|
return fmt.Errorf("Systemd not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
54
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go
generated
vendored
54
Godeps/_workspace/src/github.com/docker/libcontainer/cgroups/systemd/apply_systemd.go
generated
vendored
@@ -38,6 +38,7 @@ var subsystems = map[string]subsystem{
|
|||||||
"cpuset": &fs.CpusetGroup{},
|
"cpuset": &fs.CpusetGroup{},
|
||||||
"cpuacct": &fs.CpuacctGroup{},
|
"cpuacct": &fs.CpuacctGroup{},
|
||||||
"blkio": &fs.BlkioGroup{},
|
"blkio": &fs.BlkioGroup{},
|
||||||
|
"hugetlb": &fs.HugetlbGroup{},
|
||||||
"perf_event": &fs.PerfEventGroup{},
|
"perf_event": &fs.PerfEventGroup{},
|
||||||
"freezer": &fs.FreezerGroup{},
|
"freezer": &fs.FreezerGroup{},
|
||||||
}
|
}
|
||||||
@@ -235,9 +236,14 @@ func (m *Manager) Apply(pid int) error {
|
|||||||
}
|
}
|
||||||
paths[sysname] = subsystemPath
|
paths[sysname] = subsystemPath
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Paths = paths
|
m.Paths = paths
|
||||||
|
|
||||||
|
if paths["cpu"] != "" {
|
||||||
|
if err := fs.CheckCpushares(paths["cpu"], c.CpuShares); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +363,17 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Set(container *configs.Config) error {
|
func (m *Manager) Set(container *configs.Config) error {
|
||||||
panic("not implemented")
|
for name, path := range m.Paths {
|
||||||
|
sys, ok := subsystems[name]
|
||||||
|
if !ok || !cgroups.PathExists(path) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := sys.Set(path, container.Cgroups); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnitName(c *configs.Cgroup) string {
|
func getUnitName(c *configs.Cgroup) string {
|
||||||
@@ -369,7 +385,7 @@ func getUnitName(c *configs.Cgroup) string {
|
|||||||
// * Support for wildcards to allow /dev/pts support
|
// * Support for wildcards to allow /dev/pts support
|
||||||
//
|
//
|
||||||
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
|
// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
|
||||||
// in wide use. When both these are availalable we will be able to switch, but need to keep the old
|
// in wide use. When both these are available we will be able to switch, but need to keep the old
|
||||||
// implementation for backwards compat.
|
// implementation for backwards compat.
|
||||||
//
|
//
|
||||||
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
|
// Note: we can't use systemd to set up the initial limits, and then change the cgroup
|
||||||
@@ -382,17 +398,7 @@ func joinDevices(c *configs.Cgroup, pid int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
devices := subsystems["devices"]
|
devices := subsystems["devices"]
|
||||||
if err := devices.Set(path, c); err != nil {
|
return devices.Set(path, c)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symmetrical public function to update device based cgroups. Also available
|
|
||||||
// in the fs implementation.
|
|
||||||
func ApplyDevices(c *configs.Cgroup, pid int) error {
|
|
||||||
return joinDevices(c, pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinMemory(c *configs.Cgroup, pid int) error {
|
func joinMemory(c *configs.Cgroup, pid int) error {
|
||||||
@@ -438,6 +444,26 @@ func joinBlkio(c *configs.Cgroup, pid int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.BlkioThrottleReadBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_bps_device", c.BlkioThrottleReadBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleWriteBpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_bps_device", c.BlkioThrottleWriteBpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleReadIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.read_iops_device", c.BlkioThrottleReadIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.BlkioThrottleWriteIOpsDevice != "" {
|
||||||
|
if err := writeFile(path, "blkio.throttle.write_iops_device", c.BlkioThrottleWriteIOpsDevice); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
14
Godeps/_workspace/src/github.com/docker/libcontainer/configs/cgroup.go
generated
vendored
14
Godeps/_workspace/src/github.com/docker/libcontainer/configs/cgroup.go
generated
vendored
@@ -19,6 +19,8 @@ type Cgroup struct {
|
|||||||
|
|
||||||
AllowedDevices []*Device `json:"allowed_devices"`
|
AllowedDevices []*Device `json:"allowed_devices"`
|
||||||
|
|
||||||
|
DeniedDevices []*Device `json:"denied_devices"`
|
||||||
|
|
||||||
// Memory limit (in bytes)
|
// Memory limit (in bytes)
|
||||||
Memory int64 `json:"memory"`
|
Memory int64 `json:"memory"`
|
||||||
|
|
||||||
@@ -43,6 +45,18 @@ type Cgroup struct {
|
|||||||
// MEM to use
|
// MEM to use
|
||||||
CpusetMems string `json:"cpuset_mems"`
|
CpusetMems string `json:"cpuset_mems"`
|
||||||
|
|
||||||
|
// IO read rate limit per cgroup per device, bytes per second.
|
||||||
|
BlkioThrottleReadBpsDevice string `json:"blkio_throttle_read_bps_device"`
|
||||||
|
|
||||||
|
// IO write rate limit per cgroup per divice, bytes per second.
|
||||||
|
BlkioThrottleWriteBpsDevice string `json:"blkio_throttle_write_bps_device"`
|
||||||
|
|
||||||
|
// IO read rate limit per cgroup per device, IO per second.
|
||||||
|
BlkioThrottleReadIOpsDevice string `json:"blkio_throttle_read_iops_device"`
|
||||||
|
|
||||||
|
// IO write rate limit per cgroup per device, IO per second.
|
||||||
|
BlkioThrottleWriteIOpsDevice string `json:"blkio_throttle_write_iops_device"`
|
||||||
|
|
||||||
// Specifies per cgroup weight, range is from 10 to 1000.
|
// Specifies per cgroup weight, range is from 10 to 1000.
|
||||||
BlkioWeight int64 `json:"blkio_weight"`
|
BlkioWeight int64 `json:"blkio_weight"`
|
||||||
|
|
||||||
|
|||||||
7
Godeps/_workspace/src/github.com/docker/libcontainer/configs/config.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/configs/config.go
generated
vendored
@@ -37,6 +37,9 @@ type Config struct {
|
|||||||
// bind mounts are writtable.
|
// bind mounts are writtable.
|
||||||
Readonlyfs bool `json:"readonlyfs"`
|
Readonlyfs bool `json:"readonlyfs"`
|
||||||
|
|
||||||
|
// Privatefs will mount the container's rootfs as private where mount points from the parent will not propogate
|
||||||
|
Privatefs bool `json:"privatefs"`
|
||||||
|
|
||||||
// Mounts specify additional source and destination paths that will be mounted inside the container's
|
// Mounts specify additional source and destination paths that will be mounted inside the container's
|
||||||
// rootfs and mount namespace if specified
|
// rootfs and mount namespace if specified
|
||||||
Mounts []*Mount `json:"mounts"`
|
Mounts []*Mount `json:"mounts"`
|
||||||
@@ -96,6 +99,10 @@ type Config struct {
|
|||||||
// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
|
// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
|
||||||
// so that these files prevent any writes.
|
// so that these files prevent any writes.
|
||||||
ReadonlyPaths []string `json:"readonly_paths"`
|
ReadonlyPaths []string `json:"readonly_paths"`
|
||||||
|
|
||||||
|
// SystemProperties is a map of properties and their values. It is the equivalent of using
|
||||||
|
// sysctl -w my.property.name value in Linux.
|
||||||
|
SystemProperties map[string]string `json:"system_properties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the root uid for the process on host which could be non-zero
|
// Gets the root uid for the process on host which could be non-zero
|
||||||
|
|||||||
13
Godeps/_workspace/src/github.com/docker/libcontainer/configs/mount.go
generated
vendored
13
Godeps/_workspace/src/github.com/docker/libcontainer/configs/mount.go
generated
vendored
@@ -18,4 +18,17 @@ type Mount struct {
|
|||||||
|
|
||||||
// Relabel source if set, "z" indicates shared, "Z" indicates unshared.
|
// Relabel source if set, "z" indicates shared, "Z" indicates unshared.
|
||||||
Relabel string `json:"relabel"`
|
Relabel string `json:"relabel"`
|
||||||
|
|
||||||
|
// Optional Command to be run before Source is mounted.
|
||||||
|
PremountCmds []Command `json:"premount_cmds"`
|
||||||
|
|
||||||
|
// Optional Command to be run after Source is mounted.
|
||||||
|
PostmountCmds []Command `json:"postmount_cmds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Args []string `json:"args"`
|
||||||
|
Env []string `json:"env"`
|
||||||
|
Dir string `json:"dir"`
|
||||||
}
|
}
|
||||||
|
|||||||
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces.go
generated
vendored
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces.go
generated
vendored
@@ -1,9 +1,6 @@
|
|||||||
package configs
|
package configs
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NamespaceType string
|
type NamespaceType string
|
||||||
|
|
||||||
@@ -34,10 +31,6 @@ type Namespace struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Namespace) Syscall() int {
|
|
||||||
return namespaceInfo[n.Type]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Namespace) GetPath(pid int) string {
|
func (n *Namespace) GetPath(pid int) string {
|
||||||
if n.Path != "" {
|
if n.Path != "" {
|
||||||
return n.Path
|
return n.Path
|
||||||
@@ -96,25 +89,3 @@ func (n *Namespaces) index(t NamespaceType) int {
|
|||||||
func (n *Namespaces) Contains(t NamespaceType) bool {
|
func (n *Namespaces) Contains(t NamespaceType) bool {
|
||||||
return n.index(t) != -1
|
return n.index(t) != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespaceInfo = map[NamespaceType]int{
|
|
||||||
NEWNET: syscall.CLONE_NEWNET,
|
|
||||||
NEWNS: syscall.CLONE_NEWNS,
|
|
||||||
NEWUSER: syscall.CLONE_NEWUSER,
|
|
||||||
NEWIPC: syscall.CLONE_NEWIPC,
|
|
||||||
NEWUTS: syscall.CLONE_NEWUTS,
|
|
||||||
NEWPID: syscall.CLONE_NEWPID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloneFlags parses the container's Namespaces options to set the correct
|
|
||||||
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
|
||||||
func (n *Namespaces) CloneFlags() uintptr {
|
|
||||||
var flag int
|
|
||||||
for _, v := range *n {
|
|
||||||
if v.Path != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
flag |= namespaceInfo[v.Type]
|
|
||||||
}
|
|
||||||
return uintptr(flag)
|
|
||||||
}
|
|
||||||
|
|||||||
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall.go
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package configs
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func (n *Namespace) Syscall() int {
|
||||||
|
return namespaceInfo[n.Type]
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespaceInfo = map[NamespaceType]int{
|
||||||
|
NEWNET: syscall.CLONE_NEWNET,
|
||||||
|
NEWNS: syscall.CLONE_NEWNS,
|
||||||
|
NEWUSER: syscall.CLONE_NEWUSER,
|
||||||
|
NEWIPC: syscall.CLONE_NEWIPC,
|
||||||
|
NEWUTS: syscall.CLONE_NEWUTS,
|
||||||
|
NEWPID: syscall.CLONE_NEWPID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneFlags parses the container's Namespaces options to set the correct
|
||||||
|
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
||||||
|
func (n *Namespaces) CloneFlags() uintptr {
|
||||||
|
var flag int
|
||||||
|
for _, v := range *n {
|
||||||
|
if v.Path != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
flag |= namespaceInfo[v.Type]
|
||||||
|
}
|
||||||
|
return uintptr(flag)
|
||||||
|
}
|
||||||
15
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall_unsupported.go
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/docker/libcontainer/configs/namespaces_syscall_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package configs
|
||||||
|
|
||||||
|
func (n *Namespace) Syscall() int {
|
||||||
|
panic("No namespace syscall support")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloneFlags parses the container's Namespaces options to set the correct
|
||||||
|
// flags on clone, unshare. This functions returns flags only for new namespaces.
|
||||||
|
func (n *Namespaces) CloneFlags() uintptr {
|
||||||
|
panic("No namespace syscall support")
|
||||||
|
return uintptr(0)
|
||||||
|
}
|
||||||
4
Godeps/_workspace/src/github.com/docker/libcontainer/configs/network.go
generated
vendored
4
Godeps/_workspace/src/github.com/docker/libcontainer/configs/network.go
generated
vendored
@@ -2,7 +2,7 @@ package configs
|
|||||||
|
|
||||||
// Network defines configuration for a container's networking stack
|
// Network defines configuration for a container's networking stack
|
||||||
//
|
//
|
||||||
// The network configuration can be omited from a container causing the
|
// The network configuration can be omitted from a container causing the
|
||||||
// container to be setup with the host's networking stack
|
// container to be setup with the host's networking stack
|
||||||
type Network struct {
|
type Network struct {
|
||||||
// Type sets the networks type, commonly veth and loopback
|
// Type sets the networks type, commonly veth and loopback
|
||||||
@@ -53,7 +53,7 @@ type Network struct {
|
|||||||
// Routes can be specified to create entries in the route table as the container is started
|
// Routes can be specified to create entries in the route table as the container is started
|
||||||
//
|
//
|
||||||
// All of destination, source, and gateway should be either IPv4 or IPv6.
|
// All of destination, source, and gateway should be either IPv4 or IPv6.
|
||||||
// One of the three options must be present, and ommitted entries will use their
|
// One of the three options must be present, and omitted entries will use their
|
||||||
// IP family default for the route table. For IPv4 for example, setting the
|
// IP family default for the route table. For IPv4 for example, setting the
|
||||||
// gateway to 1.2.3.4 and the interface to eth0 will set up a standard
|
// gateway to 1.2.3.4 and the interface to eth0 will set up a standard
|
||||||
// destination of 0.0.0.0(or *) when viewed in the route table.
|
// destination of 0.0.0.0(or *) when viewed in the route table.
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/docker/libcontainer/console_linux.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/console_linux.go
generated
vendored
@@ -38,7 +38,7 @@ func newConsole(uid, gid int) (Console, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newConsoleFromPath is an internal fucntion returning an initialzied console for use inside
|
// newConsoleFromPath is an internal function returning an initialized console for use inside
|
||||||
// a container's MNT namespace.
|
// a container's MNT namespace.
|
||||||
func newConsoleFromPath(slavePath string) *linuxConsole {
|
func newConsoleFromPath(slavePath string) *linuxConsole {
|
||||||
return &linuxConsole{
|
return &linuxConsole{
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/docker/libcontainer/container.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/container.go
generated
vendored
@@ -67,7 +67,7 @@ type Container interface {
|
|||||||
// State returns the current container's state information.
|
// State returns the current container's state information.
|
||||||
//
|
//
|
||||||
// errors:
|
// errors:
|
||||||
// Systemerror - System erroor.
|
// Systemerror - System error.
|
||||||
State() (*State, error)
|
State() (*State, error)
|
||||||
|
|
||||||
// Returns the current config of the container.
|
// Returns the current config of the container.
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/devices/devices.go
generated
vendored
@@ -21,7 +21,7 @@ var (
|
|||||||
ioutilReadDir = ioutil.ReadDir
|
ioutilReadDir = ioutil.ReadDir
|
||||||
)
|
)
|
||||||
|
|
||||||
// Given the path to a device and it's cgroup_permissions(which cannot be easilly queried) look up the information about a linux device and return that information as a Device struct.
|
// Given the path to a device and it's cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
|
||||||
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
||||||
fileInfo, err := osLstat(path)
|
fileInfo, err := osLstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/docker/libcontainer/factory.go
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/factory.go
generated
vendored
@@ -32,7 +32,7 @@ type Factory interface {
|
|||||||
// System error
|
// System error
|
||||||
Load(id string) (Container, error)
|
Load(id string) (Container, error)
|
||||||
|
|
||||||
// StartInitialization is an internal API to libcontainer used during the rexec of the
|
// StartInitialization is an internal API to libcontainer used during the reexec of the
|
||||||
// container.
|
// container.
|
||||||
//
|
//
|
||||||
// Errors:
|
// Errors:
|
||||||
|
|||||||
6
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/label/label_selinux.go
generated
vendored
@@ -101,9 +101,15 @@ func SetFileCreateLabel(fileLabel string) error {
|
|||||||
// the MCS label should continue to be used. SELinux will use this field
|
// the MCS label should continue to be used. SELinux will use this field
|
||||||
// to make sure the content can not be shared by other containes.
|
// to make sure the content can not be shared by other containes.
|
||||||
func Relabel(path string, fileLabel string, relabel string) error {
|
func Relabel(path string, fileLabel string, relabel string) error {
|
||||||
|
exclude_path := []string{"/", "/usr", "/etc"}
|
||||||
if fileLabel == "" {
|
if fileLabel == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
for _, p := range exclude_path {
|
||||||
|
if path == p {
|
||||||
|
return fmt.Errorf("Relabeling of %s is not allowed", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
if !strings.ContainsAny(relabel, "zZ") {
|
if !strings.ContainsAny(relabel, "zZ") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
27
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/README.md
generated
vendored
27
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/README.md
generated
vendored
@@ -1,6 +1,25 @@
|
|||||||
## nsenter
|
## nsenter
|
||||||
|
|
||||||
The `nsenter` package registers a special init constructor that is called before the Go runtime has
|
The `nsenter` package registers a special init constructor that is called before
|
||||||
a chance to boot. This provides us the ability to `setns` on existing namespaces and avoid the issues
|
the Go runtime has a chance to boot. This provides us the ability to `setns` on
|
||||||
that the Go runtime has with multiple threads. This constructor is only called if this package is
|
existing namespaces and avoid the issues that the Go runtime has with multiple
|
||||||
registered, imported, in your go application and the argv 0 is `nsenter`.
|
threads. This constructor will be called if this package is registered,
|
||||||
|
imported, in your go application.
|
||||||
|
|
||||||
|
The `nsenter` package will `import "C"` and it uses [cgo](https://golang.org/cmd/cgo/)
|
||||||
|
package. In cgo, if the import of "C" is immediately preceded by a comment, that comment,
|
||||||
|
called the preamble, is used as a header when compiling the C parts of the package.
|
||||||
|
So every time we import package `nsenter`, the C code function `nsexec()` would be
|
||||||
|
called. And package `nsenter` is now only imported in Docker execdriver, so every time
|
||||||
|
before we call `execdriver.Exec()`, that C code would run.
|
||||||
|
|
||||||
|
`nsexec()` will first check the environment variable `_LIBCONTAINER_INITPID`
|
||||||
|
which will give the process of the container that should be joined. Namespaces fd will
|
||||||
|
be found from `/proc/[pid]/ns` and set by `setns` syscall.
|
||||||
|
|
||||||
|
And then get the pipe number from `_LIBCONTAINER_INITPIPE`, error message could
|
||||||
|
be transfered through it. If tty is added, `_LIBCONTAINER_CONSOLE_PATH` will
|
||||||
|
have value and start a console for output.
|
||||||
|
|
||||||
|
Finally, `nsexec()` will clone a child process , exit the parent process and let
|
||||||
|
the Go runtime take over.
|
||||||
|
|||||||
6
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsexec.c
generated
vendored
6
Godeps/_workspace/src/github.com/docker/libcontainer/nsenter/nsexec.c
generated
vendored
@@ -137,6 +137,8 @@ void nsexec()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setjmp(env) == 1) {
|
if (setjmp(env) == 1) {
|
||||||
|
// Child
|
||||||
|
|
||||||
if (setsid() == -1) {
|
if (setsid() == -1) {
|
||||||
pr_perror("setsid failed");
|
pr_perror("setsid failed");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -162,7 +164,11 @@ void nsexec()
|
|||||||
// Finish executing, let the Go runtime take over.
|
// Finish executing, let the Go runtime take over.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Parent
|
||||||
|
|
||||||
|
// We must fork to actually enter the PID namespace, use CLONE_PARENT
|
||||||
|
// so the child can have the right parent, and we don't need to forward
|
||||||
|
// the child's exit code or resend its death signal.
|
||||||
child = clone_parent(&env);
|
child = clone_parent(&env);
|
||||||
if (child < 0) {
|
if (child < 0) {
|
||||||
pr_perror("Unable to fork");
|
pr_perror("Unable to fork");
|
||||||
|
|||||||
7
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/config.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/config.go
generated
vendored
@@ -43,6 +43,7 @@ var createFlags = []cli.Flag{
|
|||||||
cli.StringFlag{Name: "veth-address", Usage: "veth ip address"},
|
cli.StringFlag{Name: "veth-address", Usage: "veth ip address"},
|
||||||
cli.StringFlag{Name: "veth-gateway", Usage: "veth gateway address"},
|
cli.StringFlag{Name: "veth-gateway", Usage: "veth gateway address"},
|
||||||
cli.IntFlag{Name: "veth-mtu", Usage: "veth mtu"},
|
cli.IntFlag{Name: "veth-mtu", Usage: "veth mtu"},
|
||||||
|
cli.BoolFlag{Name: "cgroup", Usage: "mount the cgroup data for the container"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var configCommand = cli.Command{
|
var configCommand = cli.Command{
|
||||||
@@ -187,6 +188,12 @@ func modify(config *configs.Config, context *cli.Context) {
|
|||||||
}
|
}
|
||||||
config.Networks = append(config.Networks, network)
|
config.Networks = append(config.Networks, network)
|
||||||
}
|
}
|
||||||
|
if context.Bool("cgroup") {
|
||||||
|
config.Mounts = append(config.Mounts, &configs.Mount{
|
||||||
|
Destination: "/sys/fs/cgroup",
|
||||||
|
Device: "cgroup",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTemplate() *configs.Config {
|
func getTemplate() *configs.Config {
|
||||||
|
|||||||
1
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/exec.go
generated
vendored
1
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/exec.go
generated
vendored
@@ -23,6 +23,7 @@ var execCommand = cli.Command{
|
|||||||
Action: execAction,
|
Action: execAction,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
cli.BoolFlag{Name: "tty,t", Usage: "allocate a TTY to the container"},
|
cli.BoolFlag{Name: "tty,t", Usage: "allocate a TTY to the container"},
|
||||||
|
cli.BoolFlag{Name: "systemd", Usage: "Use systemd for managing cgroups, if available"},
|
||||||
cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"},
|
cli.StringFlag{Name: "id", Value: "nsinit", Usage: "specify the ID for a container"},
|
||||||
cli.StringFlag{Name: "config", Value: "", Usage: "path to the configuration file"},
|
cli.StringFlag{Name: "config", Value: "", Usage: "path to the configuration file"},
|
||||||
cli.StringFlag{Name: "user,u", Value: "root", Usage: "set the user, uid, and/or gid for the process"},
|
cli.StringFlag{Name: "user,u", Value: "root", Usage: "set the user, uid, and/or gid for the process"},
|
||||||
|
|||||||
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/oom.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/oom.go
generated
vendored
@@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/pause.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/pause.go
generated
vendored
@@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
12
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/utils.go
generated
vendored
12
Godeps/_workspace/src/github.com/docker/libcontainer/nsinit/utils.go
generated
vendored
@@ -3,10 +3,12 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/docker/libcontainer"
|
"github.com/docker/libcontainer"
|
||||||
|
"github.com/docker/libcontainer/cgroups/systemd"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +31,15 @@ func loadConfig(context *cli.Context) (*configs.Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
|
func loadFactory(context *cli.Context) (libcontainer.Factory, error) {
|
||||||
return libcontainer.New(context.GlobalString("root"), libcontainer.Cgroupfs)
|
cgm := libcontainer.Cgroupfs
|
||||||
|
if context.Bool("systemd") {
|
||||||
|
if systemd.UseSystemd() {
|
||||||
|
cgm = libcontainer.SystemdCgroups
|
||||||
|
} else {
|
||||||
|
log.Warn("systemd cgroup flag passed, but systemd support for managing cgroups is not available.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return libcontainer.New(context.GlobalString("root"), cgm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainer(context *cli.Context) (libcontainer.Container, error) {
|
func getContainer(context *cli.Context) (libcontainer.Container, error) {
|
||||||
|
|||||||
4
Godeps/_workspace/src/github.com/docker/libcontainer/process.go
generated
vendored
4
Godeps/_workspace/src/github.com/docker/libcontainer/process.go
generated
vendored
@@ -23,7 +23,7 @@ type Process struct {
|
|||||||
Env []string
|
Env []string
|
||||||
|
|
||||||
// User will set the uid and gid of the executing process running inside the container
|
// User will set the uid and gid of the executing process running inside the container
|
||||||
// local to the contaienr's user and group configuration.
|
// local to the container's user and group configuration.
|
||||||
User string
|
User string
|
||||||
|
|
||||||
// Cwd will change the processes current working directory inside the container's rootfs.
|
// Cwd will change the processes current working directory inside the container's rootfs.
|
||||||
@@ -45,7 +45,7 @@ type Process struct {
|
|||||||
consolePath string
|
consolePath string
|
||||||
|
|
||||||
// Capabilities specify the capabilities to keep when executing the process inside the container
|
// Capabilities specify the capabilities to keep when executing the process inside the container
|
||||||
// All capbilities not specified will be dropped from the processes capability mask
|
// All capabilities not specified will be dropped from the processes capability mask
|
||||||
Capabilities []string
|
Capabilities []string
|
||||||
|
|
||||||
ops processOperations
|
ops processOperations
|
||||||
|
|||||||
3
Godeps/_workspace/src/github.com/docker/libcontainer/process_linux.go
generated
vendored
3
Godeps/_workspace/src/github.com/docker/libcontainer/process_linux.go
generated
vendored
@@ -119,6 +119,9 @@ func (p *setnsProcess) execSetns() error {
|
|||||||
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
||||||
// avoid the process becomming a zombie.
|
// avoid the process becomming a zombie.
|
||||||
func (p *setnsProcess) terminate() error {
|
func (p *setnsProcess) terminate() error {
|
||||||
|
if p.cmd.Process == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
err := p.cmd.Process.Kill()
|
err := p.cmd.Process.Kill()
|
||||||
if _, werr := p.wait(); err == nil {
|
if _, werr := p.wait(); err == nil {
|
||||||
err = werr
|
err = werr
|
||||||
|
|||||||
70
Godeps/_workspace/src/github.com/docker/libcontainer/rootfs_linux.go
generated
vendored
70
Godeps/_workspace/src/github.com/docker/libcontainer/rootfs_linux.go
generated
vendored
@@ -6,11 +6,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/libcontainer/cgroups"
|
||||||
"github.com/docker/libcontainer/configs"
|
"github.com/docker/libcontainer/configs"
|
||||||
"github.com/docker/libcontainer/label"
|
"github.com/docker/libcontainer/label"
|
||||||
)
|
)
|
||||||
@@ -24,9 +27,20 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) {
|
|||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
for _, m := range config.Mounts {
|
for _, m := range config.Mounts {
|
||||||
|
for _, precmd := range m.PremountCmds {
|
||||||
|
if err := mountCmd(precmd); err != nil {
|
||||||
|
return newSystemError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil {
|
if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, postcmd := range m.PostmountCmds {
|
||||||
|
if err := mountCmd(postcmd); err != nil {
|
||||||
|
return newSystemError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := createDevices(config); err != nil {
|
if err := createDevices(config); err != nil {
|
||||||
return newSystemError(err)
|
return newSystemError(err)
|
||||||
@@ -62,6 +76,18 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mountCmd(cmd configs.Command) error {
|
||||||
|
|
||||||
|
command := exec.Command(cmd.Path, cmd.Args[:]...)
|
||||||
|
command.Env = cmd.Env
|
||||||
|
command.Dir = cmd.Dir
|
||||||
|
if out, err := command.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
||||||
var (
|
var (
|
||||||
dest = m.Destination
|
dest = m.Destination
|
||||||
@@ -134,6 +160,37 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "cgroup":
|
||||||
|
mounts, err := cgroups.GetCgroupMounts()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var binds []*configs.Mount
|
||||||
|
for _, mm := range mounts {
|
||||||
|
dir, err := mm.GetThisCgroupDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
binds = append(binds, &configs.Mount{
|
||||||
|
Device: "bind",
|
||||||
|
Source: filepath.Join(mm.Mountpoint, dir),
|
||||||
|
Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
|
||||||
|
Flags: syscall.MS_BIND | syscall.MS_REC | syscall.MS_RDONLY,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tmpfs := &configs.Mount{
|
||||||
|
Device: "tmpfs",
|
||||||
|
Destination: m.Destination,
|
||||||
|
Flags: syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV,
|
||||||
|
}
|
||||||
|
if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, b := range binds {
|
||||||
|
if err := mountToRootfs(b, rootfs, mountLabel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
return fmt.Errorf("unknown mount device %q to %q", m.Device, m.Destination)
|
||||||
}
|
}
|
||||||
@@ -248,9 +305,9 @@ func mknodDevice(dest string, node *configs.Device) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func prepareRoot(config *configs.Config) error {
|
func prepareRoot(config *configs.Config) error {
|
||||||
flag := syscall.MS_PRIVATE | syscall.MS_REC
|
flag := syscall.MS_SLAVE | syscall.MS_REC
|
||||||
if config.NoPivotRoot {
|
if config.Privatefs {
|
||||||
flag = syscall.MS_SLAVE | syscall.MS_REC
|
flag = syscall.MS_PRIVATE | syscall.MS_REC
|
||||||
}
|
}
|
||||||
if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
|
if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -363,3 +420,10 @@ func maskFile(path string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
|
||||||
|
// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
|
||||||
|
func writeSystemProperty(key, value string) error {
|
||||||
|
keyPath := strings.Replace(key, ".", "/", -1)
|
||||||
|
return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
|
||||||
|
}
|
||||||
|
|||||||
7
Godeps/_workspace/src/github.com/docker/libcontainer/standard_init_linux.go
generated
vendored
7
Godeps/_workspace/src/github.com/docker/libcontainer/standard_init_linux.go
generated
vendored
@@ -64,6 +64,13 @@ func (l *linuxStandardInit) Init() error {
|
|||||||
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key, value := range l.config.Config.SystemProperties {
|
||||||
|
if err := writeSystemProperty(key, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, path := range l.config.Config.ReadonlyPaths {
|
for _, path := range l.config.Config.ReadonlyPaths {
|
||||||
if err := remountReadonly(path); err != nil {
|
if err := remountReadonly(path); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/docker/libcontainer/update-vendor.sh
generated
vendored
2
Godeps/_workspace/src/github.com/docker/libcontainer/update-vendor.sh
generated
vendored
@@ -43,7 +43,7 @@ clone() {
|
|||||||
clone git github.com/codegangsta/cli 1.1.0
|
clone git github.com/codegangsta/cli 1.1.0
|
||||||
clone git github.com/coreos/go-systemd v2
|
clone git github.com/coreos/go-systemd v2
|
||||||
clone git github.com/godbus/dbus v2
|
clone git github.com/godbus/dbus v2
|
||||||
clone git github.com/Sirupsen/logrus v0.6.6
|
clone git github.com/Sirupsen/logrus v0.7.3
|
||||||
clone git github.com/syndtr/gocapability 8e4cdcb
|
clone git github.com/syndtr/gocapability 8e4cdcb
|
||||||
|
|
||||||
# intentionally not vendoring Docker itself... that'd be a circle :)
|
# intentionally not vendoring Docker itself... that'd be a circle :)
|
||||||
|
|||||||
7
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
formatter/text: Add configuration option for time format (#158)
|
||||||
@@ -37,11 +37,13 @@ attached, the output is compatible with the
|
|||||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
@@ -82,7 +84,7 @@ func init() {
|
|||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
// Output to stderr instead of stdout, could also be a file.
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
@@ -106,6 +108,16 @@ func main() {
|
|||||||
"omg": true,
|
"omg": true,
|
||||||
"number": 100,
|
"number": 100,
|
||||||
}).Fatal("The ice breaks!")
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -164,43 +176,8 @@ You can add hooks for logging levels. For example to send errors to an exception
|
|||||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
multiple places simultaneously, e.g. syslog.
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
```go
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
`init`:
|
||||||
import (
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
log.AddHook(new(AirbrakeHook))
|
|
||||||
}
|
|
||||||
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
|
|
||||||
// the fields for the entry. See the Fields section of the README.
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
|
||||||
err := airbrake.Notify(entry.Data["error"].(error))
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
}).Info("Failed to send error to Airbrake")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// `Levels()` returns a slice of `Levels` the hook is fired for.
|
|
||||||
func (hook *AirbrakeHook) Levels() []log.Level {
|
|
||||||
return []log.Level{
|
|
||||||
log.ErrorLevel,
|
|
||||||
log.FatalLevel,
|
|
||||||
log.PanicLevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
@@ -211,7 +188,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -222,28 +199,18 @@ func init() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go)
|
|
||||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
|
||||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
|
||||||
|
|
||||||
* [`github.com/Sirupsen/logrus/hooks/papertrail`](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go)
|
| Hook | Description |
|
||||||
Send errors to the Papertrail hosted logging service via UDP.
|
| ----- | ----------- |
|
||||||
|
| [Airbrake](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go) | Send errors to an exception tracking service compatible with the Airbrake API. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go)
|
| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
|
||||||
Send errors to remote syslog server.
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
Uses standard library `log/syslog` behind the scenes.
|
| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
Send errors to a channel in hipchat.
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
|
| [Graylog](https://github.com/gemnasium/logrus-hooks/tree/master/graylog) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
Send logs to Loggly (https://www.loggly.com/)
|
|
||||||
|
|
||||||
* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
|
|
||||||
Hook for Slack chat.
|
|
||||||
|
|
||||||
* [`github.com/wercker/journalhook`](https://github.com/wercker/journalhook).
|
|
||||||
Hook for logging to `systemd-journald`.
|
|
||||||
|
|
||||||
#### Level logging
|
#### Level logging
|
||||||
|
|
||||||
@@ -321,6 +288,11 @@ The built-in logging formatters are:
|
|||||||
field to `true`. To force no colored output even if there is a TTY set the
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
`DisableColors` field to `true`
|
`DisableColors` field to `true`
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
* `logrus_logstash.LogstashFormatter`. Logs fields as Logstash Events (http://logstash.net).
|
||||||
|
|
||||||
|
```go
|
||||||
|
logrus.SetFormatter(&logrus_logstash.LogstashFormatter{Type: “application_name"})
|
||||||
|
```
|
||||||
|
|
||||||
Third party logging formatters:
|
Third party logging formatters:
|
||||||
|
|
||||||
|
|||||||
@@ -3,21 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
"github.com/tobi/airbrake-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logrus.New()
|
var log = logrus.New()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.Formatter = new(logrus.TextFormatter) // default
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
|
||||||
airbrake.ApiKey = "whatever"
|
|
||||||
airbrake.Environment = "production"
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
log.WithFields(logrus.Fields{
|
||||||
"animal": "walrus",
|
"animal": "walrus",
|
||||||
"size": 10,
|
"size": 10,
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
//
|
//
|
||||||
|
|||||||
56
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
56
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package logstash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Formatter generates json in logstash format.
|
||||||
|
// Logstash site: http://logstash.net/
|
||||||
|
type LogstashFormatter struct {
|
||||||
|
Type string // if not empty use for logstash type field.
|
||||||
|
|
||||||
|
// TimestampFormat sets the format used for timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
|
entry.Data["@version"] = 1
|
||||||
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = logrus.DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat)
|
||||||
|
|
||||||
|
// set message field
|
||||||
|
v, ok := entry.Data["message"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.message"] = v
|
||||||
|
}
|
||||||
|
entry.Data["message"] = entry.Message
|
||||||
|
|
||||||
|
// set level field
|
||||||
|
v, ok = entry.Data["level"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.level"] = v
|
||||||
|
}
|
||||||
|
entry.Data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
// set type field
|
||||||
|
if f.Type != "" {
|
||||||
|
v, ok = entry.Data["type"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.type"] = v
|
||||||
|
}
|
||||||
|
entry.Data["type"] = f.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
||||||
@@ -1,51 +1,51 @@
|
|||||||
package logrus_airbrake
|
package airbrake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/tobi/airbrake-go"
|
"github.com/tobi/airbrake-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||||
// with the Airbrake API. You must set:
|
// with the Airbrake API.
|
||||||
// * airbrake.Endpoint
|
type airbrakeHook struct {
|
||||||
// * airbrake.ApiKey
|
APIKey string
|
||||||
// * airbrake.Environment
|
Endpoint string
|
||||||
//
|
Environment string
|
||||||
// Before using this hook, to send an error. Entries that trigger an Error,
|
}
|
||||||
// Fatal or Panic should now include an "error" field to send to Airbrake.
|
|
||||||
type AirbrakeHook struct{}
|
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
func NewHook(endpoint, apiKey, env string) *airbrakeHook {
|
||||||
if entry.Data["error"] == nil {
|
return &airbrakeHook{
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
APIKey: apiKey,
|
||||||
"source": "airbrake",
|
Endpoint: endpoint,
|
||||||
"endpoint": airbrake.Endpoint,
|
Environment: env,
|
||||||
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
|
||||||
|
airbrake.ApiKey = hook.APIKey
|
||||||
|
airbrake.Endpoint = hook.Endpoint
|
||||||
|
airbrake.Environment = hook.Environment
|
||||||
|
|
||||||
|
var notifyErr error
|
||||||
err, ok := entry.Data["error"].(error)
|
err, ok := entry.Data["error"].(error)
|
||||||
if !ok {
|
if ok {
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
notifyErr = err
|
||||||
"source": "airbrake",
|
} else {
|
||||||
"endpoint": airbrake.Endpoint,
|
notifyErr = errors.New(entry.Message)
|
||||||
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
airErr := airbrake.Notify(err)
|
airErr := airbrake.Notify(notifyErr)
|
||||||
if airErr != nil {
|
if airErr != nil {
|
||||||
entry.Logger.WithFields(logrus.Fields{
|
return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
|
||||||
"source": "airbrake",
|
|
||||||
"endpoint": airbrake.Endpoint,
|
|
||||||
"error": airErr,
|
|
||||||
}).Warn("Failed to send error to Airbrake")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
func (hook *airbrakeHook) Levels() []logrus.Level {
|
||||||
return []logrus.Level{
|
return []logrus.Level{
|
||||||
logrus.ErrorLevel,
|
logrus.ErrorLevel,
|
||||||
logrus.FatalLevel,
|
logrus.FatalLevel,
|
||||||
|
|||||||
68
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/docker/libcontainer/vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package logrus_bugsnag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/bugsnag/bugsnag-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bugsnagHook struct{}
|
||||||
|
|
||||||
|
// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
|
||||||
|
// bugsnag.Configure. Bugsnag must be configured before the hook.
|
||||||
|
var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
|
||||||
|
|
||||||
|
// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
|
||||||
|
// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
|
||||||
|
// failed.
|
||||||
|
type ErrBugsnagSendFailed struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrBugsnagSendFailed) Error() string {
|
||||||
|
return "failed to send error to Bugsnag: " + e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBugsnagHook initializes a logrus hook which sends exceptions to an
|
||||||
|
// exception-tracking service compatible with the Bugsnag API. Before using
|
||||||
|
// this hook, you must call bugsnag.Configure(). The returned object should be
|
||||||
|
// registered with a log via `AddHook()`
|
||||||
|
//
|
||||||
|
// Entries that trigger an Error, Fatal or Panic should now include an "error"
|
||||||
|
// field to send to Bugsnag.
|
||||||
|
func NewBugsnagHook() (*bugsnagHook, error) {
|
||||||
|
if bugsnag.Config.APIKey == "" {
|
||||||
|
return nil, ErrBugsnagUnconfigured
|
||||||
|
}
|
||||||
|
return &bugsnagHook{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
|
||||||
|
// "error" field (or the Message if the error isn't present) and sends it off.
|
||||||
|
func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
|
||||||
|
var notifyErr error
|
||||||
|
err, ok := entry.Data["error"].(error)
|
||||||
|
if ok {
|
||||||
|
notifyErr = err
|
||||||
|
} else {
|
||||||
|
notifyErr = errors.New(entry.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
bugsnagErr := bugsnag.Notify(notifyErr)
|
||||||
|
if bugsnagErr != nil {
|
||||||
|
return ErrBugsnagSendFailed{bugsnagErr}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels enumerates the log levels on which the error should be forwarded to
|
||||||
|
// bugsnag: everything at or above the "Error" level.
|
||||||
|
func (hook *bugsnagHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,24 +3,32 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type JSONFormatter struct{}
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
data := make(Fields, len(entry.Data)+3)
|
data := make(Fields, len(entry.Data)+3)
|
||||||
for k, v := range entry.Data {
|
for k, v := range entry.Data {
|
||||||
// Otherwise errors are ignored by `encoding/json`
|
switch v := v.(type) {
|
||||||
// https://github.com/Sirupsen/logrus/issues/137
|
case error:
|
||||||
if err, ok := v.(error); ok {
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
data[k] = err.Error()
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
} else {
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefixFieldClashes(data)
|
prefixFieldClashes(data)
|
||||||
data["time"] = entry.Time.Format(time.RFC3339)
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(f.TimestampFormat)
|
||||||
data["msg"] = entry.Message
|
data["msg"] = entry.Message
|
||||||
data["level"] = entry.Level.String()
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
|||||||
@@ -65,11 +65,15 @@ func (logger *Logger) WithFields(fields Fields) *Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Debugf(format, args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Infof(format, args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
@@ -77,31 +81,45 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Warnf(format, args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Errorf(format, args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Fatalf(format, args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
NewEntry(logger).Panicf(format, args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
NewEntry(logger).Debug(args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
NewEntry(logger).Info(args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
@@ -109,31 +127,45 @@ func (logger *Logger) Print(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
NewEntry(logger).Warn(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
NewEntry(logger).Warn(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
NewEntry(logger).Error(args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
NewEntry(logger).Fatal(args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
NewEntry(logger).Panic(args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
NewEntry(logger).Debugln(args...)
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
NewEntry(logger).Infoln(args...)
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
@@ -141,21 +173,31 @@ func (logger *Logger) Println(args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
NewEntry(logger).Warnln(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
NewEntry(logger).Warnln(args...)
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
NewEntry(logger).Errorln(args...)
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
NewEntry(logger).Fatalln(args...)
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
NewEntry(logger).Panicln(args...)
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package logrus
|
package logrus
|
||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package logrus
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -21,7 +20,6 @@ const (
|
|||||||
var (
|
var (
|
||||||
baseTimestamp time.Time
|
baseTimestamp time.Time
|
||||||
isTerminal bool
|
isTerminal bool
|
||||||
noQuoteNeeded *regexp.Regexp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -48,6 +46,9 @@ type TextFormatter struct {
|
|||||||
// the time passed since beginning of execution.
|
// the time passed since beginning of execution.
|
||||||
FullTimestamp bool
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
// The fields are sorted by default for a consistent output. For applications
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
// that log extremely frequently and don't use the JSON formatter this may not
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
// be desired.
|
// be desired.
|
||||||
@@ -70,11 +71,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||||||
|
|
||||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
if isColored {
|
if isColored {
|
||||||
f.printColored(b, entry, keys)
|
f.printColored(b, entry, keys)
|
||||||
} else {
|
} else {
|
||||||
if !f.DisableTimestamp {
|
if !f.DisableTimestamp {
|
||||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
f.appendKeyValue(b, "time", entry.Time.Format(f.TimestampFormat))
|
||||||
}
|
}
|
||||||
f.appendKeyValue(b, "level", entry.Level.String())
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
f.appendKeyValue(b, "msg", entry.Message)
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
@@ -105,7 +109,7 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
|||||||
if !f.FullTimestamp {
|
if !f.FullTimestamp {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(time.RFC3339), entry.Message)
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(f.TimestampFormat), entry.Message)
|
||||||
}
|
}
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := entry.Data[k]
|
v := entry.Data[k]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (logger *Logger) Writer() (*io.PipeWriter) {
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
go logger.writerScanner(reader)
|
go logger.writerScanner(reader)
|
||||||
|
|||||||
23
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
23
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/factory.go
generated
vendored
@@ -42,6 +42,10 @@ var DockerNamespace = "docker"
|
|||||||
var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path to the Docker state root directory (default: /var/lib/docker)")
|
var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path to the Docker state root directory (default: /var/lib/docker)")
|
||||||
var dockerRunDir = flag.String("docker_run", "/var/run/docker", "Absolute path to the Docker run directory (default: /var/run/docker)")
|
var dockerRunDir = flag.String("docker_run", "/var/run/docker", "Absolute path to the Docker run directory (default: /var/run/docker)")
|
||||||
|
|
||||||
|
// Regexp that identifies docker cgroups, containers started with
|
||||||
|
// --cgroup-parent have another prefix than 'docker'
|
||||||
|
var dockerCgroupRegexp = regexp.MustCompile(`.+-([a-z0-9]{64})\.scope$`)
|
||||||
|
|
||||||
// TODO(vmarmol): Export run dir too for newer Dockers.
|
// TODO(vmarmol): Export run dir too for newer Dockers.
|
||||||
// Directory holding Docker container state information.
|
// Directory holding Docker container state information.
|
||||||
func DockerStateDir() string {
|
func DockerStateDir() string {
|
||||||
@@ -119,27 +123,30 @@ func ContainerNameToDockerId(name string) string {
|
|||||||
|
|
||||||
// Turn systemd cgroup name into Docker ID.
|
// Turn systemd cgroup name into Docker ID.
|
||||||
if UseSystemd() {
|
if UseSystemd() {
|
||||||
id = strings.TrimPrefix(id, "docker-")
|
if matches := dockerCgroupRegexp.FindStringSubmatch(id); matches != nil {
|
||||||
id = strings.TrimSuffix(id, ".scope")
|
id = matches[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a full container name for the specified Docker ID.
|
func isContainerName(name string) bool {
|
||||||
func FullContainerName(dockerId string) string {
|
|
||||||
// Add the full container name.
|
|
||||||
if UseSystemd() {
|
if UseSystemd() {
|
||||||
return path.Join("/system.slice", fmt.Sprintf("docker-%s.scope", dockerId))
|
return dockerCgroupRegexp.MatchString(path.Base(name))
|
||||||
} else {
|
|
||||||
return path.Join("/docker", dockerId)
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Docker handles all containers under /docker
|
// Docker handles all containers under /docker
|
||||||
func (self *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
func (self *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
|
||||||
// docker factory accepts all containers it can handle.
|
// docker factory accepts all containers it can handle.
|
||||||
canAccept := true
|
canAccept := true
|
||||||
|
|
||||||
|
if !isContainerName(name) {
|
||||||
|
return false, canAccept, fmt.Errorf("invalid container name")
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the container is known to docker and it is active.
|
// Check if the container is known to docker and it is active.
|
||||||
id := ContainerNameToDockerId(name)
|
id := ContainerNameToDockerId(name)
|
||||||
|
|
||||||
|
|||||||
109
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/fsHandler.go
generated
vendored
Normal file
109
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/fsHandler.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Handler for Docker containers.
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/google/cadvisor/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fsHandler interface {
|
||||||
|
start()
|
||||||
|
usage() uint64
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
type realFsHandler struct {
|
||||||
|
sync.RWMutex
|
||||||
|
lastUpdate time.Time
|
||||||
|
usageBytes uint64
|
||||||
|
period time.Duration
|
||||||
|
storageDirs []string
|
||||||
|
fsInfo fs.FsInfo
|
||||||
|
// Tells the container to stop.
|
||||||
|
stopChan chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
const longDu = time.Second
|
||||||
|
|
||||||
|
var _ fsHandler = &realFsHandler{}
|
||||||
|
|
||||||
|
func newFsHandler(period time.Duration, storageDirs []string, fsInfo fs.FsInfo) fsHandler {
|
||||||
|
return &realFsHandler{
|
||||||
|
lastUpdate: time.Time{},
|
||||||
|
usageBytes: 0,
|
||||||
|
period: period,
|
||||||
|
storageDirs: storageDirs,
|
||||||
|
fsInfo: fsInfo,
|
||||||
|
stopChan: make(chan struct{}, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) needsUpdate() bool {
|
||||||
|
return time.Now().After(fh.lastUpdate.Add(fh.period))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) update() error {
|
||||||
|
var usage uint64
|
||||||
|
for _, dir := range fh.storageDirs {
|
||||||
|
// TODO(Vishh): Add support for external mounts.
|
||||||
|
dirUsage, err := fh.fsInfo.GetDirUsage(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
usage += dirUsage
|
||||||
|
}
|
||||||
|
fh.Lock()
|
||||||
|
defer fh.Unlock()
|
||||||
|
fh.lastUpdate = time.Now()
|
||||||
|
fh.usageBytes = usage
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) trackUsage() {
|
||||||
|
for {
|
||||||
|
start := time.Now()
|
||||||
|
if _, ok := <-fh.stopChan; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := fh.update(); err != nil {
|
||||||
|
glog.V(2).Infof("failed to collect filesystem stats - %v", err)
|
||||||
|
}
|
||||||
|
duration := time.Since(start)
|
||||||
|
if duration > longDu {
|
||||||
|
glog.V(3).Infof("`du` on following dirs took %v: %v", duration, fh.storageDirs)
|
||||||
|
}
|
||||||
|
next := start.Add(fh.period)
|
||||||
|
time.Sleep(next.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) start() {
|
||||||
|
go fh.trackUsage()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) stop() {
|
||||||
|
close(fh.stopChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *realFsHandler) usage() uint64 {
|
||||||
|
fh.RLock()
|
||||||
|
defer fh.RUnlock()
|
||||||
|
return fh.usageBytes
|
||||||
|
}
|
||||||
57
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
57
Godeps/_workspace/src/github.com/google/cadvisor/container/docker/handler.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/docker/libcontainer/cgroups"
|
"github.com/docker/libcontainer/cgroups"
|
||||||
cgroup_fs "github.com/docker/libcontainer/cgroups/fs"
|
cgroup_fs "github.com/docker/libcontainer/cgroups/fs"
|
||||||
libcontainerConfigs "github.com/docker/libcontainer/configs"
|
libcontainerConfigs "github.com/docker/libcontainer/configs"
|
||||||
"github.com/fsouza/go-dockerclient"
|
docker "github.com/fsouza/go-dockerclient"
|
||||||
"github.com/google/cadvisor/container"
|
"github.com/google/cadvisor/container"
|
||||||
containerLibcontainer "github.com/google/cadvisor/container/libcontainer"
|
containerLibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||||
"github.com/google/cadvisor/fs"
|
"github.com/google/cadvisor/fs"
|
||||||
@@ -83,6 +83,9 @@ type dockerContainerHandler struct {
|
|||||||
|
|
||||||
// The network mode of the container
|
// The network mode of the container
|
||||||
networkMode string
|
networkMode string
|
||||||
|
|
||||||
|
// Filesystem handler.
|
||||||
|
fsHandler fsHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDockerContainerHandler(
|
func newDockerContainerHandler(
|
||||||
@@ -114,6 +117,9 @@ func newDockerContainerHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id := ContainerNameToDockerId(name)
|
id := ContainerNameToDockerId(name)
|
||||||
|
|
||||||
|
storageDirs := []string{path.Join(*dockerRootDir, pathToAufsDir, id)}
|
||||||
|
|
||||||
handler := &dockerContainerHandler{
|
handler := &dockerContainerHandler{
|
||||||
id: id,
|
id: id,
|
||||||
client: client,
|
client: client,
|
||||||
@@ -124,8 +130,13 @@ func newDockerContainerHandler(
|
|||||||
usesAufsDriver: usesAufsDriver,
|
usesAufsDriver: usesAufsDriver,
|
||||||
fsInfo: fsInfo,
|
fsInfo: fsInfo,
|
||||||
rootFs: rootFs,
|
rootFs: rootFs,
|
||||||
|
storageDirs: storageDirs,
|
||||||
|
fsHandler: newFsHandler(time.Minute, storageDirs, fsInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
if usesAufsDriver {
|
||||||
|
handler.fsHandler.start()
|
||||||
}
|
}
|
||||||
handler.storageDirs = append(handler.storageDirs, path.Join(*dockerRootDir, pathToAufsDir, id))
|
|
||||||
|
|
||||||
// We assume that if Inspect fails then the container is not known to docker.
|
// We assume that if Inspect fails then the container is not known to docker.
|
||||||
ctnr, err := client.InspectContainer(id)
|
ctnr, err := client.InspectContainer(id)
|
||||||
@@ -136,8 +147,7 @@ func newDockerContainerHandler(
|
|||||||
handler.pid = ctnr.State.Pid
|
handler.pid = ctnr.State.Pid
|
||||||
|
|
||||||
// Add the name and bare ID as aliases of the container.
|
// Add the name and bare ID as aliases of the container.
|
||||||
handler.aliases = append(handler.aliases, strings.TrimPrefix(ctnr.Name, "/"))
|
handler.aliases = append(handler.aliases, strings.TrimPrefix(ctnr.Name, "/"), id)
|
||||||
handler.aliases = append(handler.aliases, id)
|
|
||||||
handler.labels = ctnr.Config.Labels
|
handler.labels = ctnr.Config.Labels
|
||||||
handler.image = ctnr.Config.Image
|
handler.image = ctnr.Config.Image
|
||||||
handler.networkMode = ctnr.HostConfig.NetworkMode
|
handler.networkMode = ctnr.HostConfig.NetworkMode
|
||||||
@@ -256,16 +266,7 @@ func (self *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error
|
|||||||
|
|
||||||
fsStat := info.FsStats{Device: deviceInfo.Device, Limit: limit}
|
fsStat := info.FsStats{Device: deviceInfo.Device, Limit: limit}
|
||||||
|
|
||||||
var usage uint64 = 0
|
fsStat.Usage = self.fsHandler.usage()
|
||||||
for _, dir := range self.storageDirs {
|
|
||||||
// TODO(Vishh): Add support for external mounts.
|
|
||||||
dirUsage, err := self.fsInfo.GetDirUsage(dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
usage += dirUsage
|
|
||||||
}
|
|
||||||
fsStat.Usage = usage
|
|
||||||
stats.Filesystem = append(stats.Filesystem, fsStat)
|
stats.Filesystem = append(stats.Filesystem, fsStat)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -295,32 +296,8 @@ func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||||
if self.name != "/docker" {
|
// No-op for Docker driver.
|
||||||
return []info.ContainerReference{}, nil
|
return []info.ContainerReference{}, nil
|
||||||
}
|
|
||||||
opt := docker.ListContainersOptions{
|
|
||||||
All: true,
|
|
||||||
}
|
|
||||||
containers, err := self.client.ListContainers(opt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := make([]info.ContainerReference, 0, len(containers)+1)
|
|
||||||
for _, c := range containers {
|
|
||||||
if !strings.HasPrefix(c.Status, "Up ") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ref := info.ContainerReference{
|
|
||||||
Name: FullContainerName(c.ID),
|
|
||||||
Aliases: append(c.Names, c.ID),
|
|
||||||
Namespace: DockerNamespace,
|
|
||||||
}
|
|
||||||
ret = append(ret, ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *dockerContainerHandler) GetCgroupPath(resource string) (string, error) {
|
func (self *dockerContainerHandler) GetCgroupPath(resource string) (string, error) {
|
||||||
|
|||||||
87
Godeps/_workspace/src/github.com/google/cadvisor/container/libcontainer/helpers.go
generated
vendored
87
Godeps/_workspace/src/github.com/google/cadvisor/container/libcontainer/helpers.go
generated
vendored
@@ -97,6 +97,20 @@ func GetStats(cgroupManager cgroups.Manager, rootFs string, pid int) (*info.Cont
|
|||||||
} else {
|
} else {
|
||||||
stats.Network.Interfaces = append(stats.Network.Interfaces, netStats...)
|
stats.Network.Interfaces = append(stats.Network.Interfaces, netStats...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t, err := tcpStatsFromProc(rootFs, pid, "net/tcp")
|
||||||
|
if err != nil {
|
||||||
|
glog.V(2).Infof("Unable to get tcp stats from pid %d: %v", pid, err)
|
||||||
|
} else {
|
||||||
|
stats.Network.Tcp = t
|
||||||
|
}
|
||||||
|
|
||||||
|
t6, err := tcpStatsFromProc(rootFs, pid, "net/tcp6")
|
||||||
|
if err != nil {
|
||||||
|
glog.V(2).Infof("Unable to get tcp6 stats from pid %d: %v", pid, err)
|
||||||
|
} else {
|
||||||
|
stats.Network.Tcp6 = t6
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For backwards compatibility.
|
// For backwards compatibility.
|
||||||
@@ -173,6 +187,78 @@ func scanInterfaceStats(netStatsFile string) ([]info.InterfaceStats, error) {
|
|||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error) {
|
||||||
|
tcpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file)
|
||||||
|
|
||||||
|
tcpStats, err := scanTcpStats(tcpStatsFile)
|
||||||
|
if err != nil {
|
||||||
|
return tcpStats, fmt.Errorf("couldn't read tcp stats: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tcpStats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
|
||||||
|
|
||||||
|
var stats info.TcpStat
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(tcpStatsFile)
|
||||||
|
if err != nil {
|
||||||
|
return stats, fmt.Errorf("failure opening %s: %v", tcpStatsFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpStatLineRE, _ := regexp.Compile("[0-9:].*")
|
||||||
|
|
||||||
|
tcpStateMap := map[string]uint64{
|
||||||
|
"01": 0, //ESTABLISHED
|
||||||
|
"02": 0, //SYN_SENT
|
||||||
|
"03": 0, //SYN_RECV
|
||||||
|
"04": 0, //FIN_WAIT1
|
||||||
|
"05": 0, //FIN_WAIT2
|
||||||
|
"06": 0, //TIME_WAIT
|
||||||
|
"07": 0, //CLOSE
|
||||||
|
"08": 0, //CLOSE_WAIT
|
||||||
|
"09": 0, //LAST_ACK
|
||||||
|
"0A": 0, //LISTEN
|
||||||
|
"0B": 0, //CLOSING
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := strings.NewReader(string(data))
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
|
||||||
|
line := scanner.Text()
|
||||||
|
//skip header
|
||||||
|
matched := tcpStatLineRE.MatchString(line)
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
state := strings.Fields(line)
|
||||||
|
//#file header tcp state is the 4 filed:
|
||||||
|
//sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
||||||
|
tcpStateMap[state[3]]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stats = info.TcpStat{
|
||||||
|
Established: tcpStateMap["01"],
|
||||||
|
SynSent: tcpStateMap["02"],
|
||||||
|
SynRecv: tcpStateMap["03"],
|
||||||
|
FinWait1: tcpStateMap["04"],
|
||||||
|
FinWait2: tcpStateMap["05"],
|
||||||
|
TimeWait: tcpStateMap["06"],
|
||||||
|
Close: tcpStateMap["07"],
|
||||||
|
CloseWait: tcpStateMap["08"],
|
||||||
|
LastAck: tcpStateMap["09"],
|
||||||
|
Listen: tcpStateMap["0A"],
|
||||||
|
Closing: tcpStateMap["0B"],
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
|
func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
|
||||||
pids, err := cgroupManager.GetPids()
|
pids, err := cgroupManager.GetPids()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -262,6 +348,7 @@ func toContainerStats1(s *cgroups.Stats, ret *info.ContainerStats) {
|
|||||||
|
|
||||||
func toContainerStats2(s *cgroups.Stats, ret *info.ContainerStats) {
|
func toContainerStats2(s *cgroups.Stats, ret *info.ContainerStats) {
|
||||||
ret.Memory.Usage = s.MemoryStats.Usage
|
ret.Memory.Usage = s.MemoryStats.Usage
|
||||||
|
ret.Memory.Failcnt = s.MemoryStats.Failcnt
|
||||||
if v, ok := s.MemoryStats.Stats["pgfault"]; ok {
|
if v, ok := s.MemoryStats.Stats["pgfault"]; ok {
|
||||||
ret.Memory.ContainerData.Pgfault = v
|
ret.Memory.ContainerData.Pgfault = v
|
||||||
ret.Memory.HierarchicalData.Pgfault = v
|
ret.Memory.HierarchicalData.Pgfault = v
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/fs/fs.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/fs/fs.go
generated
vendored
@@ -282,7 +282,7 @@ func (self *RealFsInfo) GetDirFsDevice(dir string) (*DeviceInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *RealFsInfo) GetDirUsage(dir string) (uint64, error) {
|
func (self *RealFsInfo) GetDirUsage(dir string) (uint64, error) {
|
||||||
out, err := exec.Command("du", "-s", dir).CombinedOutput()
|
out, err := exec.Command("nice", "-n", "19", "du", "-s", dir).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("du command failed on %s with output %s - %s", dir, out, err)
|
return 0, fmt.Errorf("du command failed on %s with output %s - %s", dir, out, err)
|
||||||
}
|
}
|
||||||
|
|||||||
12
Godeps/_workspace/src/github.com/google/cadvisor/http/handlers.go
generated
vendored
12
Godeps/_workspace/src/github.com/google/cadvisor/http/handlers.go
generated
vendored
@@ -31,7 +31,7 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterHandlers(mux httpMux.Mux, containerManager manager.Manager, httpAuthFile, httpAuthRealm, httpDigestFile, httpDigestRealm, prometheusEndpoint string) error {
|
func RegisterHandlers(mux httpMux.Mux, containerManager manager.Manager, httpAuthFile, httpAuthRealm, httpDigestFile, httpDigestRealm string) error {
|
||||||
// Basic health handler.
|
// Basic health handler.
|
||||||
if err := healthz.RegisterHandler(mux); err != nil {
|
if err := healthz.RegisterHandler(mux); err != nil {
|
||||||
return fmt.Errorf("failed to register healthz handler: %s", err)
|
return fmt.Errorf("failed to register healthz handler: %s", err)
|
||||||
@@ -85,13 +85,15 @@ func RegisterHandlers(mux httpMux.Mux, containerManager manager.Manager, httpAut
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collector := metrics.NewPrometheusCollector(containerManager)
|
|
||||||
prometheus.MustRegister(collector)
|
|
||||||
http.Handle(prometheusEndpoint, prometheus.Handler())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RegisterPrometheusHandler(mux httpMux.Mux, containerManager manager.Manager, prometheusEndpoint string, containerNameToLabelsFunc metrics.ContainerNameToLabelsFunc) {
|
||||||
|
collector := metrics.NewPrometheusCollector(containerManager, containerNameToLabelsFunc)
|
||||||
|
prometheus.MustRegister(collector)
|
||||||
|
mux.Handle(prometheusEndpoint, prometheus.Handler())
|
||||||
|
}
|
||||||
|
|
||||||
func staticHandlerNoAuth(w http.ResponseWriter, r *http.Request) {
|
func staticHandlerNoAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
err := static.HandleRequest(w, r.URL)
|
err := static.HandleRequest(w, r.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
31
Godeps/_workspace/src/github.com/google/cadvisor/info/v1/container.go
generated
vendored
31
Godeps/_workspace/src/github.com/google/cadvisor/info/v1/container.go
generated
vendored
@@ -312,6 +312,8 @@ type MemoryStats struct {
|
|||||||
// Units: Bytes.
|
// Units: Bytes.
|
||||||
WorkingSet uint64 `json:"working_set"`
|
WorkingSet uint64 `json:"working_set"`
|
||||||
|
|
||||||
|
Failcnt uint64 `json:"failcnt"`
|
||||||
|
|
||||||
ContainerData MemoryStatsMemoryData `json:"container_data,omitempty"`
|
ContainerData MemoryStatsMemoryData `json:"container_data,omitempty"`
|
||||||
HierarchicalData MemoryStatsMemoryData `json:"hierarchical_data,omitempty"`
|
HierarchicalData MemoryStatsMemoryData `json:"hierarchical_data,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -345,6 +347,35 @@ type InterfaceStats struct {
|
|||||||
type NetworkStats struct {
|
type NetworkStats struct {
|
||||||
InterfaceStats `json:",inline"`
|
InterfaceStats `json:",inline"`
|
||||||
Interfaces []InterfaceStats `json:"interfaces,omitempty"`
|
Interfaces []InterfaceStats `json:"interfaces,omitempty"`
|
||||||
|
// TCP connection stats (Established, Listen...)
|
||||||
|
Tcp TcpStat `json:"tcp"`
|
||||||
|
// TCP6 connection stats (Established, Listen...)
|
||||||
|
Tcp6 TcpStat `json:"tcp6"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TcpStat struct {
|
||||||
|
//Count of TCP connections in state "Established"
|
||||||
|
Established uint64
|
||||||
|
//Count of TCP connections in state "Syn_Sent"
|
||||||
|
SynSent uint64
|
||||||
|
//Count of TCP connections in state "Syn_Recv"
|
||||||
|
SynRecv uint64
|
||||||
|
//Count of TCP connections in state "Fin_Wait1"
|
||||||
|
FinWait1 uint64
|
||||||
|
//Count of TCP connections in state "Fin_Wait2"
|
||||||
|
FinWait2 uint64
|
||||||
|
//Count of TCP connections in state "Time_Wait
|
||||||
|
TimeWait uint64
|
||||||
|
//Count of TCP connections in state "Close"
|
||||||
|
Close uint64
|
||||||
|
//Count of TCP connections in state "Close_Wait"
|
||||||
|
CloseWait uint64
|
||||||
|
//Count of TCP connections in state "Listen_Ack"
|
||||||
|
LastAck uint64
|
||||||
|
//Count of TCP connections in state "Listen"
|
||||||
|
Listen uint64
|
||||||
|
//Count of TCP connections in state "Closing"
|
||||||
|
Closing uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type FsStats struct {
|
type FsStats struct {
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/info/v1/machine.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/info/v1/machine.go
generated
vendored
@@ -179,6 +179,8 @@ type VersionInfo struct {
|
|||||||
|
|
||||||
// cAdvisor version.
|
// cAdvisor version.
|
||||||
CadvisorVersion string `json:"cadvisor_version"`
|
CadvisorVersion string `json:"cadvisor_version"`
|
||||||
|
// cAdvisor git revision.
|
||||||
|
CadvisorRevision string `json:"cadvisor_revision"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MachineInfoFactory interface {
|
type MachineInfoFactory interface {
|
||||||
|
|||||||
18
Godeps/_workspace/src/github.com/google/cadvisor/info/v2/container.go
generated
vendored
18
Godeps/_workspace/src/github.com/google/cadvisor/info/v2/container.go
generated
vendored
@@ -206,9 +206,27 @@ type ProcessInfo struct {
|
|||||||
Cmd string `json:"cmd"`
|
Cmd string `json:"cmd"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TcpStat struct {
|
||||||
|
Established uint64
|
||||||
|
SynSent uint64
|
||||||
|
SynRecv uint64
|
||||||
|
FinWait1 uint64
|
||||||
|
FinWait2 uint64
|
||||||
|
TimeWait uint64
|
||||||
|
Close uint64
|
||||||
|
CloseWait uint64
|
||||||
|
LastAck uint64
|
||||||
|
Listen uint64
|
||||||
|
Closing uint64
|
||||||
|
}
|
||||||
|
|
||||||
type NetworkStats struct {
|
type NetworkStats struct {
|
||||||
// Network stats by interface.
|
// Network stats by interface.
|
||||||
Interfaces []v1.InterfaceStats `json:"interfaces,omitempty"`
|
Interfaces []v1.InterfaceStats `json:"interfaces,omitempty"`
|
||||||
|
// TCP connection stats (Established, Listen...)
|
||||||
|
Tcp TcpStat `json:"tcp"`
|
||||||
|
// TCP6 connection stats (Established, Listen...)
|
||||||
|
Tcp6 TcpStat `json:"tcp6"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantaneous CPU stats
|
// Instantaneous CPU stats
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/manager/container.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/manager/container.go
generated
vendored
@@ -42,7 +42,7 @@ import (
|
|||||||
// Housekeeping interval.
|
// Housekeeping interval.
|
||||||
var HousekeepingInterval = flag.Duration("housekeeping_interval", 1*time.Second, "Interval between container housekeepings")
|
var HousekeepingInterval = flag.Duration("housekeeping_interval", 1*time.Second, "Interval between container housekeepings")
|
||||||
|
|
||||||
var cgroupPathRegExp = regexp.MustCompile(".*devices:(.*?)[,;$].*")
|
var cgroupPathRegExp = regexp.MustCompile(".*devices.*:(.*?)[,;$].*")
|
||||||
|
|
||||||
// Decay value used for load average smoothing. Interval length of 10 seconds is used.
|
// Decay value used for load average smoothing. Interval length of 10 seconds is used.
|
||||||
var loadDecay = math.Exp(float64(-1 * (*HousekeepingInterval).Seconds() / 10))
|
var loadDecay = math.Exp(float64(-1 * (*HousekeepingInterval).Seconds() / 10))
|
||||||
|
|||||||
3
Godeps/_workspace/src/github.com/google/cadvisor/manager/machine.go
generated
vendored
3
Godeps/_workspace/src/github.com/google/cadvisor/manager/machine.go
generated
vendored
@@ -122,7 +122,8 @@ func getVersionInfo() (*info.VersionInfo, error) {
|
|||||||
KernelVersion: kernel_version,
|
KernelVersion: kernel_version,
|
||||||
ContainerOsVersion: container_os,
|
ContainerOsVersion: container_os,
|
||||||
DockerVersion: docker_version,
|
DockerVersion: docker_version,
|
||||||
CadvisorVersion: version.VERSION,
|
CadvisorVersion: version.Info["version"],
|
||||||
|
CadvisorRevision: version.Info["revision"],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
119
Godeps/_workspace/src/github.com/google/cadvisor/metrics/prometheus.go
generated
vendored
119
Godeps/_workspace/src/github.com/google/cadvisor/metrics/prometheus.go
generated
vendored
@@ -24,9 +24,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// This will usually be manager.Manager, but can be swapped out for testing.
|
// This will usually be manager.Manager, but can be swapped out for testing.
|
||||||
type subcontainersInfoProvider interface {
|
type infoProvider interface {
|
||||||
// Get information about all subcontainers of the specified container (includes self).
|
// Get information about all subcontainers of the specified container (includes self).
|
||||||
SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error)
|
SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error)
|
||||||
|
// Get information about the version.
|
||||||
|
GetVersionInfo() (*info.VersionInfo, error)
|
||||||
|
// Get information about the machine.
|
||||||
|
GetMachineInfo() (*info.MachineInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// metricValue describes a single metric value for a given set of label values
|
// metricValue describes a single metric value for a given set of label values
|
||||||
@@ -60,21 +64,25 @@ type containerMetric struct {
|
|||||||
getValues func(s *info.ContainerStats) metricValues
|
getValues func(s *info.ContainerStats) metricValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *containerMetric) desc() *prometheus.Desc {
|
func (cm *containerMetric) desc(baseLabels []string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(cm.name, cm.help, append([]string{"name", "id", "image"}, cm.extraLabels...), nil)
|
return prometheus.NewDesc(cm.name, cm.help, append(baseLabels, cm.extraLabels...), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContainerNameToLabelsFunc func(containerName string) map[string]string
|
||||||
|
|
||||||
// PrometheusCollector implements prometheus.Collector.
|
// PrometheusCollector implements prometheus.Collector.
|
||||||
type PrometheusCollector struct {
|
type PrometheusCollector struct {
|
||||||
infoProvider subcontainersInfoProvider
|
infoProvider infoProvider
|
||||||
errors prometheus.Gauge
|
errors prometheus.Gauge
|
||||||
containerMetrics []containerMetric
|
containerMetrics []containerMetric
|
||||||
|
containerNameToLabels ContainerNameToLabelsFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrometheusCollector returns a new PrometheusCollector.
|
// NewPrometheusCollector returns a new PrometheusCollector.
|
||||||
func NewPrometheusCollector(infoProvider subcontainersInfoProvider) *PrometheusCollector {
|
func NewPrometheusCollector(infoProvider infoProvider, f ContainerNameToLabelsFunc) *PrometheusCollector {
|
||||||
c := &PrometheusCollector{
|
c := &PrometheusCollector{
|
||||||
infoProvider: infoProvider,
|
infoProvider: infoProvider,
|
||||||
|
containerNameToLabels: f,
|
||||||
errors: prometheus.NewGauge(prometheus.GaugeOpts{
|
errors: prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "container",
|
Namespace: "container",
|
||||||
Name: "scrape_error",
|
Name: "scrape_error",
|
||||||
@@ -117,6 +125,13 @@ func NewPrometheusCollector(infoProvider subcontainersInfoProvider) *PrometheusC
|
|||||||
}
|
}
|
||||||
return values
|
return values
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
name: "container_memory_failcnt",
|
||||||
|
help: "Number of memory usage hits limits",
|
||||||
|
valueType: prometheus.CounterValue,
|
||||||
|
getValues: func(s *info.ContainerStats) metricValues {
|
||||||
|
return metricValues{{value: float64(s.Memory.Failcnt)}}
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: "container_memory_usage_bytes",
|
name: "container_memory_usage_bytes",
|
||||||
help: "Current memory usage in bytes.",
|
help: "Current memory usage in bytes.",
|
||||||
@@ -441,18 +456,34 @@ func NewPrometheusCollector(infoProvider subcontainersInfoProvider) *PrometheusC
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
versionInfoDesc = prometheus.NewDesc("cadvisor_version_info", "A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.", []string{"kernelVersion", "osVersion", "dockerVersion", "cadvisorVersion", "cadvisorRevision"}, nil)
|
||||||
|
machineInfoCoresDesc = prometheus.NewDesc("machine_cpu_cores", "Number of CPU cores on the machine.", nil, nil)
|
||||||
|
machineInfoMemoryDesc = prometheus.NewDesc("machine_memory_bytes", "Amount of memory installed on the machine.", nil, nil)
|
||||||
|
)
|
||||||
|
|
||||||
// Describe describes all the metrics ever exported by cadvisor. It
|
// Describe describes all the metrics ever exported by cadvisor. It
|
||||||
// implements prometheus.PrometheusCollector.
|
// implements prometheus.PrometheusCollector.
|
||||||
func (c *PrometheusCollector) Describe(ch chan<- *prometheus.Desc) {
|
func (c *PrometheusCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||||
c.errors.Describe(ch)
|
c.errors.Describe(ch)
|
||||||
for _, cm := range c.containerMetrics {
|
for _, cm := range c.containerMetrics {
|
||||||
ch <- cm.desc()
|
ch <- cm.desc([]string{})
|
||||||
}
|
}
|
||||||
|
ch <- versionInfoDesc
|
||||||
|
ch <- machineInfoCoresDesc
|
||||||
|
ch <- machineInfoMemoryDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect fetches the stats from all containers and delivers them as
|
// Collect fetches the stats from all containers and delivers them as
|
||||||
// Prometheus metrics. It implements prometheus.PrometheusCollector.
|
// Prometheus metrics. It implements prometheus.PrometheusCollector.
|
||||||
func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric) {
|
func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
c.collectMachineInfo(ch)
|
||||||
|
c.collectVersionInfo(ch)
|
||||||
|
c.collectContainersInfo(ch)
|
||||||
|
c.errors.Collect(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PrometheusCollector) collectContainersInfo(ch chan<- prometheus.Metric) {
|
||||||
containers, err := c.infoProvider.SubcontainersInfo("/", &info.ContainerInfoRequest{NumStats: 1})
|
containers, err := c.infoProvider.SubcontainersInfo("/", &info.ContainerInfoRequest{NumStats: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.errors.Set(1)
|
c.errors.Set(1)
|
||||||
@@ -460,20 +491,82 @@ func (c *PrometheusCollector) Collect(ch chan<- prometheus.Metric) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
|
baseLabels := []string{"id"}
|
||||||
id := container.Name
|
id := container.Name
|
||||||
name := id
|
name := id
|
||||||
if len(container.Aliases) > 0 {
|
if len(container.Aliases) > 0 {
|
||||||
name = container.Aliases[0]
|
name = container.Aliases[0]
|
||||||
|
baseLabels = append(baseLabels, "name")
|
||||||
}
|
}
|
||||||
image := container.Spec.Image
|
image := container.Spec.Image
|
||||||
stats := container.Stats[0]
|
if len(image) > 0 {
|
||||||
|
baseLabels = append(baseLabels, "image")
|
||||||
|
}
|
||||||
|
baseLabelValues := []string{id, name, image}[:len(baseLabels)]
|
||||||
|
|
||||||
|
if c.containerNameToLabels != nil {
|
||||||
|
newLabels := c.containerNameToLabels(name)
|
||||||
|
for k, v := range newLabels {
|
||||||
|
baseLabels = append(baseLabels, k)
|
||||||
|
baseLabelValues = append(baseLabelValues, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container spec
|
||||||
|
desc := prometheus.NewDesc("container_start_time_seconds", "Start time of the container since unix epoch in seconds.", baseLabels, nil)
|
||||||
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(container.Spec.CreationTime.Unix()), baseLabelValues...)
|
||||||
|
|
||||||
|
if container.Spec.HasCpu {
|
||||||
|
desc := prometheus.NewDesc("container_spec_cpu_shares", "CPU share of the container.", baseLabels, nil)
|
||||||
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(container.Spec.Cpu.Limit), baseLabelValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.Spec.HasMemory {
|
||||||
|
desc := prometheus.NewDesc("container_spec_memory_limit_bytes", "Memory limit for the container.", baseLabels, nil)
|
||||||
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(container.Spec.Memory.Limit), baseLabelValues...)
|
||||||
|
desc = prometheus.NewDesc("container_spec_memory_swap_limit_bytes", "Memory swap limit for the container.", baseLabels, nil)
|
||||||
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, specMemoryValue(container.Spec.Memory.SwapLimit), baseLabelValues...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now for the actual metrics
|
||||||
|
stats := container.Stats[0]
|
||||||
for _, cm := range c.containerMetrics {
|
for _, cm := range c.containerMetrics {
|
||||||
desc := cm.desc()
|
desc := cm.desc(baseLabels)
|
||||||
for _, metricValue := range cm.getValues(stats) {
|
for _, metricValue := range cm.getValues(stats) {
|
||||||
ch <- prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append([]string{name, id, image}, metricValue.labels...)...)
|
ch <- prometheus.MustNewConstMetric(desc, cm.valueType, float64(metricValue.value), append(baseLabelValues, metricValue.labels...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.errors.Collect(ch)
|
}
|
||||||
|
|
||||||
|
func (c *PrometheusCollector) collectVersionInfo(ch chan<- prometheus.Metric) {
|
||||||
|
versionInfo, err := c.infoProvider.GetVersionInfo()
|
||||||
|
if err != nil {
|
||||||
|
c.errors.Set(1)
|
||||||
|
glog.Warningf("Couldn't get version info: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(versionInfoDesc, prometheus.GaugeValue, 1, []string{versionInfo.KernelVersion, versionInfo.ContainerOsVersion, versionInfo.DockerVersion, versionInfo.CadvisorVersion, versionInfo.CadvisorRevision}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PrometheusCollector) collectMachineInfo(ch chan<- prometheus.Metric) {
|
||||||
|
machineInfo, err := c.infoProvider.GetMachineInfo()
|
||||||
|
if err != nil {
|
||||||
|
c.errors.Set(1)
|
||||||
|
glog.Warningf("Couldn't get machine info: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(machineInfoCoresDesc, prometheus.GaugeValue, float64(machineInfo.NumCores))
|
||||||
|
ch <- prometheus.MustNewConstMetric(machineInfoMemoryDesc, prometheus.GaugeValue, float64(machineInfo.MemoryCapacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size after which we consider memory to be "unlimited". This is not
|
||||||
|
// MaxInt64 due to rounding by the kernel.
|
||||||
|
const maxMemorySize = uint64(1 << 62)
|
||||||
|
|
||||||
|
func specMemoryValue(v uint64) float64 {
|
||||||
|
if v > maxMemorySize {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float64(v)
|
||||||
}
|
}
|
||||||
|
|||||||
18
Godeps/_workspace/src/github.com/google/cadvisor/pages/docker.go
generated
vendored
18
Godeps/_workspace/src/github.com/google/cadvisor/pages/docker.go
generated
vendored
@@ -53,11 +53,11 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// The container name is the path after the handler
|
// The container name is the path after the handler
|
||||||
containerName := u.Path[len(DockerPage):]
|
containerName := u.Path[len(DockerPage)-1:]
|
||||||
rootDir := getRootDir(u.Path)
|
rootDir := getRootDir(containerName)
|
||||||
|
|
||||||
var data *pageData
|
var data *pageData
|
||||||
if containerName == "" {
|
if containerName == "/" {
|
||||||
// Get the containers.
|
// Get the containers.
|
||||||
reqParams := info.ContainerInfoRequest{
|
reqParams := info.ContainerInfoRequest{
|
||||||
NumStats: 0,
|
NumStats: 0,
|
||||||
@@ -70,7 +70,7 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
for _, cont := range conts {
|
for _, cont := range conts {
|
||||||
subcontainers = append(subcontainers, link{
|
subcontainers = append(subcontainers, link{
|
||||||
Text: getContainerDisplayName(cont.ContainerReference),
|
Text: getContainerDisplayName(cont.ContainerReference),
|
||||||
Link: path.Join("/docker", docker.ContainerNameToDockerId(cont.ContainerReference.Name)),
|
Link: path.Join(rootDir, DockerPage, docker.ContainerNameToDockerId(cont.ContainerReference.Name)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
ParentContainers: []link{
|
ParentContainers: []link{
|
||||||
{
|
{
|
||||||
Text: dockerContainersText,
|
Text: dockerContainersText,
|
||||||
Link: DockerPage,
|
Link: path.Join(rootDir, DockerPage),
|
||||||
}},
|
}},
|
||||||
Subcontainers: subcontainers,
|
Subcontainers: subcontainers,
|
||||||
Root: rootDir,
|
Root: rootDir,
|
||||||
@@ -106,7 +106,7 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
reqParams := info.ContainerInfoRequest{
|
reqParams := info.ContainerInfoRequest{
|
||||||
NumStats: 60,
|
NumStats: 60,
|
||||||
}
|
}
|
||||||
cont, err := m.DockerContainer(containerName, &reqParams)
|
cont, err := m.DockerContainer(containerName[1:], &reqParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
|
return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
|
||||||
}
|
}
|
||||||
@@ -115,12 +115,12 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
// Make a list of the parent containers and their links
|
// Make a list of the parent containers and their links
|
||||||
var parentContainers []link
|
var parentContainers []link
|
||||||
parentContainers = append(parentContainers, link{
|
parentContainers = append(parentContainers, link{
|
||||||
Text: "Docker containers",
|
Text: "Docker Containers",
|
||||||
Link: DockerPage,
|
Link: path.Join(rootDir, DockerPage),
|
||||||
})
|
})
|
||||||
parentContainers = append(parentContainers, link{
|
parentContainers = append(parentContainers, link{
|
||||||
Text: displayName,
|
Text: displayName,
|
||||||
Link: path.Join(DockerPage, docker.ContainerNameToDockerId(cont.Name)),
|
Link: path.Join(rootDir, DockerPage, docker.ContainerNameToDockerId(cont.Name)),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get the MachineInfo
|
// Get the MachineInfo
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/storage/bigquery/bigquery.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/storage/bigquery/bigquery.go
generated
vendored
@@ -15,10 +15,10 @@
|
|||||||
package bigquery
|
package bigquery
|
||||||
|
|
||||||
import (
|
import (
|
||||||
bigquery "code.google.com/p/google-api-go-client/bigquery/v2"
|
|
||||||
info "github.com/google/cadvisor/info/v1"
|
info "github.com/google/cadvisor/info/v1"
|
||||||
"github.com/google/cadvisor/storage"
|
"github.com/google/cadvisor/storage"
|
||||||
"github.com/google/cadvisor/storage/bigquery/client"
|
"github.com/google/cadvisor/storage/bigquery/client"
|
||||||
|
bigquery "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bigqueryStorage struct {
|
type bigqueryStorage struct {
|
||||||
|
|||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/storage/bigquery/client/client.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/storage/bigquery/client/client.go
generated
vendored
@@ -20,9 +20,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
bigquery "code.google.com/p/google-api-go-client/bigquery/v2"
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/jwt"
|
"golang.org/x/oauth2/jwt"
|
||||||
|
bigquery "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
127
Godeps/_workspace/src/github.com/google/cadvisor/storage/elasticsearch/elasticsearch.go
generated
vendored
Normal file
127
Godeps/_workspace/src/github.com/google/cadvisor/storage/elasticsearch/elasticsearch.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package elasticsearch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
info "github.com/google/cadvisor/info/v1"
|
||||||
|
storage "github.com/google/cadvisor/storage"
|
||||||
|
"gopkg.in/olivere/elastic.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type elasticStorage struct {
|
||||||
|
client *elastic.Client
|
||||||
|
machineName string
|
||||||
|
indexName string
|
||||||
|
typeName string
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type detailSpec struct {
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
MachineName string `json:"machine_name,omitempty"`
|
||||||
|
ContainerName string `json:"container_Name,omitempty"`
|
||||||
|
ContainerStats *info.ContainerStats `json:"container_stats,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *elasticStorage) containerStatsAndDefaultValues(
|
||||||
|
ref info.ContainerReference, stats *info.ContainerStats) *detailSpec {
|
||||||
|
timestamp := stats.Timestamp.UnixNano() / 1E3
|
||||||
|
var containerName string
|
||||||
|
if len(ref.Aliases) > 0 {
|
||||||
|
containerName = ref.Aliases[0]
|
||||||
|
} else {
|
||||||
|
containerName = ref.Name
|
||||||
|
}
|
||||||
|
detail := &detailSpec{
|
||||||
|
Timestamp: timestamp,
|
||||||
|
MachineName: self.machineName,
|
||||||
|
ContainerName: containerName,
|
||||||
|
ContainerStats: stats,
|
||||||
|
}
|
||||||
|
return detail
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *elasticStorage) AddStats(ref info.ContainerReference, stats *info.ContainerStats) error {
|
||||||
|
if stats == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func() {
|
||||||
|
// AddStats will be invoked simultaneously from multiple threads and only one of them will perform a write.
|
||||||
|
self.lock.Lock()
|
||||||
|
defer self.lock.Unlock()
|
||||||
|
// Add some default params based on ContainerStats
|
||||||
|
detail := self.containerStatsAndDefaultValues(ref, stats)
|
||||||
|
// Index a cadvisor (using JSON serialization)
|
||||||
|
_, err := self.client.Index().
|
||||||
|
Index(self.indexName).
|
||||||
|
Type(self.typeName).
|
||||||
|
BodyJson(detail).
|
||||||
|
Do()
|
||||||
|
if err != nil {
|
||||||
|
// Handle error
|
||||||
|
panic(fmt.Errorf("failed to write stats to ElasticSearch- %s", err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *elasticStorage) Close() error {
|
||||||
|
self.client = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// machineName: A unique identifier to identify the host that current cAdvisor
|
||||||
|
// instance is running on.
|
||||||
|
// ElasticHost: The host which runs ElasticSearch.
|
||||||
|
func New(machineName,
|
||||||
|
indexName,
|
||||||
|
typeName,
|
||||||
|
elasticHost string,
|
||||||
|
enableSniffer bool,
|
||||||
|
) (storage.StorageDriver, error) {
|
||||||
|
// Obtain a client and connect to the default Elasticsearch installation
|
||||||
|
// on 127.0.0.1:9200. Of course you can configure your client to connect
|
||||||
|
// to other hosts and configure it in various other ways.
|
||||||
|
client, err := elastic.NewClient(
|
||||||
|
elastic.SetHealthcheck(true),
|
||||||
|
elastic.SetSniff(enableSniffer),
|
||||||
|
elastic.SetHealthcheckInterval(30*time.Second),
|
||||||
|
elastic.SetURL(elasticHost),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// Handle error
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping the Elasticsearch server to get e.g. the version number
|
||||||
|
info, code, err := client.Ping().URL(elasticHost).Do()
|
||||||
|
if err != nil {
|
||||||
|
// Handle error
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Elasticsearch returned with code %d and version %s", code, info.Version.Number)
|
||||||
|
|
||||||
|
ret := &elasticStorage{
|
||||||
|
client: client,
|
||||||
|
machineName: machineName,
|
||||||
|
indexName: indexName,
|
||||||
|
typeName: typeName,
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
2
Godeps/_workspace/src/github.com/google/cadvisor/utils/oomparser/oomparser.go
generated
vendored
2
Godeps/_workspace/src/github.com/google/cadvisor/utils/oomparser/oomparser.go
generated
vendored
@@ -164,7 +164,7 @@ func (self *OomParser) StreamOoms(outStream chan *OomInstance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func callJournalctl() (io.ReadCloser, error) {
|
func callJournalctl() (io.ReadCloser, error) {
|
||||||
cmd := exec.Command("journalctl", "-f")
|
cmd := exec.Command("journalctl", "-k", "-f")
|
||||||
readcloser, err := cmd.StdoutPipe()
|
readcloser, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
1
Godeps/_workspace/src/github.com/google/cadvisor/version/VERSION
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/google/cadvisor/version/VERSION
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0.18.0
|
||||||
21
Godeps/_workspace/src/github.com/google/cadvisor/version/version.go
generated
vendored
21
Godeps/_workspace/src/github.com/google/cadvisor/version/version.go
generated
vendored
@@ -14,5 +14,22 @@
|
|||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
// Version of cAdvisor.
|
// Build information. Populated at build-time.
|
||||||
const VERSION = "0.16.0"
|
var (
|
||||||
|
Version string
|
||||||
|
Revision string
|
||||||
|
Branch string
|
||||||
|
BuildUser string
|
||||||
|
BuildDate string
|
||||||
|
GoVersion string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Info provides the iterable version information.
|
||||||
|
var Info = map[string]string{
|
||||||
|
"version": Version,
|
||||||
|
"revision": Revision,
|
||||||
|
"branch": Branch,
|
||||||
|
"buildUser": BuildUser,
|
||||||
|
"buildDate": BuildDate,
|
||||||
|
"goVersion": GoVersion,
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package cadvisor
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@@ -79,11 +80,24 @@ func (cc *cadvisorClient) exportHTTP(port uint) error {
|
|||||||
// Register the handlers regardless as this registers the prometheus
|
// Register the handlers regardless as this registers the prometheus
|
||||||
// collector properly.
|
// collector properly.
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
err := cadvisorHttp.RegisterHandlers(mux, cc, "", "", "", "", "/metrics")
|
err := cadvisorHttp.RegisterHandlers(mux, cc, "", "", "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`^k8s_(?P<kubernetes_container_name>[^_\.]+)[^_]+_(?P<kubernetes_pod_name>[^_]+)_(?P<kubernetes_namespace>[^_]+)`)
|
||||||
|
reCaptureNames := re.SubexpNames()
|
||||||
|
cadvisorHttp.RegisterPrometheusHandler(mux, cc, "/metrics", func(name string) map[string]string {
|
||||||
|
extraLabels := map[string]string{}
|
||||||
|
matches := re.FindStringSubmatch(name)
|
||||||
|
for i, match := range matches {
|
||||||
|
if len(reCaptureNames[i]) > 0 {
|
||||||
|
extraLabels[re.SubexpNames()[i]] = match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extraLabels
|
||||||
|
})
|
||||||
|
|
||||||
// Only start the http server if port > 0
|
// Only start the http server if port > 0
|
||||||
if port > 0 {
|
if port > 0 {
|
||||||
serv := &http.Server{
|
serv := &http.Server{
|
||||||
|
|||||||
Reference in New Issue
Block a user