diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 6c9a3c4513a..f3ad84e2c06 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -36,6 +36,7 @@ https://github.com/elastic/beats/compare/v6.0.0-alpha1...master[Check the HEAD d *Metricbeat* - Fix a debug statement that said a module wrapper had stopped when it hadn't. {pull}4264[4264] +- Use MemAvailable value from /proc/meminfo on Linux 3.14. {pull}4316[4316] *Packetbeat* diff --git a/vendor/github.com/elastic/gosigar/CHANGELOG.md b/vendor/github.com/elastic/gosigar/CHANGELOG.md index 548b1ceee4a..8c7d2f71931 100644 --- a/vendor/github.com/elastic/gosigar/CHANGELOG.md +++ b/vendor/github.com/elastic/gosigar/CHANGELOG.md @@ -2,9 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [0.3.0] ### Added +- Read `MemAvailable` value for kernel 3.14+ ### Changed diff --git a/vendor/github.com/elastic/gosigar/codecov.yml b/vendor/github.com/elastic/gosigar/codecov.yml new file mode 100644 index 00000000000..76ade0fdb0e --- /dev/null +++ b/vendor/github.com/elastic/gosigar/codecov.yml @@ -0,0 +1,21 @@ +# Enable coverage report message for diff on commit +coverage: + status: + project: off + patch: + default: + # basic + target: auto + threshold: null + base: auto + # advanced + branches: null + if_no_uploads: error + if_not_found: success + if_ci_failed: error + only_pulls: false + flags: null + paths: null + +# Disable comments on Pull Requests +comment: false diff --git a/vendor/github.com/elastic/gosigar/sigar_darwin_test.go b/vendor/github.com/elastic/gosigar/sigar_darwin_test.go new file mode 100644 index 00000000000..8650491f0e1 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sigar_darwin_test.go @@ -0,0 +1,76 @@ +package gosigar_test + +import ( + "bufio" + "bytes" + "fmt" + "os/exec" + "os/user" + "strconv" + "strings" + "testing" + + sigar "github.com/elastic/gosigar" + "github.com/stretchr/testify/assert" +) + +var procinfo map[string]string + +func setUp(t testing.TB) { + out, err := exec.Command("/bin/ps", "-p1", "-c", "-opid,comm,stat,ppid,pgid,tty,pri,ni").Output() + if err != nil { + t.Fatal(err) + } + rdr := bufio.NewReader(bytes.NewReader(out)) + _, err = rdr.ReadString('\n') // skip header + if err != nil { + t.Fatal(err) + } + data, err := rdr.ReadString('\n') + if err != nil { + t.Fatal(err) + } + procinfo = make(map[string]string, 8) + fields := strings.Fields(data) + procinfo["pid"] = fields[0] + procinfo["name"] = fields[1] + procinfo["stat"] = fields[2] + procinfo["ppid"] = fields[3] + procinfo["pgid"] = fields[4] + procinfo["tty"] = fields[5] + procinfo["prio"] = fields[6] + procinfo["nice"] = fields[7] + +} + +func tearDown(t testing.TB) { +} + +/* ProcState.Get() call task_info, which on Mac OS X requires root + or a signed executable. Skip the test if not running as root + to accommodate automated tests, but let users test locally using + `sudo -E go test` +*/ + +func TestDarwinProcState(t *testing.T) { + setUp(t) + defer tearDown(t) + + state := sigar.ProcState{} + usr, err := user.Current() + if err == nil && usr.Username == "root" { + if assert.NoError(t, state.Get(1)) { + + ppid, _ := strconv.Atoi(procinfo["ppid"]) + pgid, _ := strconv.Atoi(procinfo["pgid"]) + + assert.Equal(t, procinfo["name"], state.Name) + assert.Equal(t, ppid, state.Ppid) + assert.Equal(t, pgid, state.Pgid) + assert.Equal(t, 1, state.Pgid) + assert.Equal(t, 0, state.Ppid) + } + } else { + fmt.Println("Skipping ProcState test; run as root to test") + } +} diff --git a/vendor/github.com/elastic/gosigar/sigar_linux_common.go b/vendor/github.com/elastic/gosigar/sigar_linux_common.go index 7753a7e7904..3f490bf9712 100644 --- a/vendor/github.com/elastic/gosigar/sigar_linux_common.go +++ b/vendor/github.com/elastic/gosigar/sigar_linux_common.go @@ -53,35 +53,38 @@ func (self *LoadAverage) Get() error { } func (self *Mem) Get() error { - var buffers, cached uint64 - table := map[string]*uint64{ - "MemTotal": &self.Total, - "MemFree": &self.Free, - "Buffers": &buffers, - "Cached": &cached, - } - if err := parseMeminfo(table); err != nil { + table, err := parseMeminfo() + if err != nil { return err } - self.Used = self.Total - self.Free - kern := buffers + cached - self.ActualFree = self.Free + kern - self.ActualUsed = self.Used - kern + self.Total, _ = table["MemTotal"] + self.Free, _ = table["MemFree"] + buffers, _ := table["Buffers"] + cached, _ := table["Cached"] + + if available, ok := table["MemAvailable"]; ok { + // MemAvailable is in /proc/meminfo (kernel 3.14+) + self.ActualFree = available + } else { + self.ActualFree = self.Free + buffers + cached + } + + self.Used = self.Total - self.ActualFree + self.ActualUsed = self.Total - self.ActualFree return nil } func (self *Swap) Get() error { - table := map[string]*uint64{ - "SwapTotal": &self.Total, - "SwapFree": &self.Free, - } - if err := parseMeminfo(table); err != nil { + table, err := parseMeminfo() + if err != nil { return err } + self.Total, _ = table["SwapTotal"] + self.Free, _ = table["SwapFree"] self.Used = self.Total - self.Free return nil @@ -353,20 +356,26 @@ func (self *ProcExe) Get(pid int) error { return nil } -func parseMeminfo(table map[string]*uint64) error { - return readFile(Procd+"/meminfo", func(line string) bool { +func parseMeminfo() (map[string]uint64, error) { + table := map[string]uint64{} + + err := readFile(Procd+"/meminfo", func(line string) bool { fields := strings.Split(line, ":") - if ptr := table[fields[0]]; ptr != nil { - num := strings.TrimLeft(fields[1], " ") - val, err := strtoull(strings.Fields(num)[0]) - if err == nil { - *ptr = val * 1024 - } + if len(fields) != 2 { + return true // skip on errors + } + + num := strings.TrimLeft(fields[1], " ") + val, err := strtoull(strings.Fields(num)[0]) + if err != nil { + return true // skip on errors } + table[fields[0]] = val * 1024 //in bytes return true }) + return table, err } func readFile(file string, handler func(string) bool) error { diff --git a/vendor/github.com/elastic/gosigar/sigar_linux_test.go b/vendor/github.com/elastic/gosigar/sigar_linux_test.go new file mode 100644 index 00000000000..06990d875ba --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sigar_linux_test.go @@ -0,0 +1,594 @@ +package gosigar_test + +import ( + "fmt" + "io/ioutil" + "math/rand" + "os" + "path/filepath" + "strconv" + "testing" + "time" + + sigar "github.com/elastic/gosigar" + "github.com/stretchr/testify/assert" +) + +var procd string + +func setUp(t testing.TB) { + var err error + procd, err = ioutil.TempDir("", "sigarTests") + if err != nil { + t.Fatal(err) + } + sigar.Procd = procd +} + +func tearDown(t testing.TB) { + sigar.Procd = "/proc" + err := os.RemoveAll(procd) + if err != nil { + t.Fatal(err) + } +} + +func TestLinuxProcState(t *testing.T) { + setUp(t) + defer tearDown(t) + + var procNames = []string{ + "cron", + "a very long process name", + } + + for _, n := range procNames { + func() { + pid := rand.Int() + pidDir := filepath.Join(procd, strconv.Itoa(pid)) + err := os.Mkdir(pidDir, 0755) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(pidDir) + pidStatFile := filepath.Join(pidDir, "stat") + writePidStats(pid, n, pidStatFile) + if err != nil { + t.Fatal(err) + } + + pidStatusFile := filepath.Join(pidDir, "status") + uid := 123456789 + writePidStatus(n, pid, uid, pidStatusFile) + if err != nil { + t.Fatal(err) + } + + state := sigar.ProcState{} + if assert.NoError(t, state.Get(pid)) { + assert.Equal(t, n, state.Name) + assert.Equal(t, 2, state.Pgid) + assert.Equal(t, strconv.Itoa(uid), state.Username) + } + }() + } +} + +func TestLinuxCPU(t *testing.T) { + setUp(t) + defer tearDown(t) + + tests := []struct { + stat string + user uint64 + }{ + {"cpu 25 1 2 3 4 5 6 7", 25}, + // Ignore empty lines + {"cpu ", 0}, + } + + statFile := procd + "/stat" + for _, test := range tests { + func() { + statContents := []byte(test.stat) + err := ioutil.WriteFile(statFile, statContents, 0644) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(statFile) + + cpu := sigar.Cpu{} + if assert.NoError(t, cpu.Get()) { + assert.Equal(t, uint64(test.user), cpu.User, "cpu.User") + } + }() + } +} + +func TestLinuxCollectCpuStats(t *testing.T) { + setUp(t) + defer tearDown(t) + + statFile := procd + "/stat" + statContents := []byte("cpu 25 1 2 3 4 5 6 7") + err := ioutil.WriteFile(statFile, statContents, 0644) + if err != nil { + t.Fatal(err) + } + + concreteSigar := &sigar.ConcreteSigar{} + cpuUsages, stop := concreteSigar.CollectCpuStats(500 * time.Millisecond) + + assert.Equal(t, sigar.Cpu{ + User: uint64(25), + Nice: uint64(1), + Sys: uint64(2), + Idle: uint64(3), + Wait: uint64(4), + Irq: uint64(5), + SoftIrq: uint64(6), + Stolen: uint64(7), + }, <-cpuUsages) + + statContents = []byte("cpu 30 3 7 10 25 55 36 65") + err = ioutil.WriteFile(statFile, statContents, 0644) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, sigar.Cpu{ + User: uint64(5), + Nice: uint64(2), + Sys: uint64(5), + Idle: uint64(7), + Wait: uint64(21), + Irq: uint64(50), + SoftIrq: uint64(30), + Stolen: uint64(58), + }, <-cpuUsages) + + stop <- struct{}{} +} + +func TestLinuxMemAndSwap(t *testing.T) { + setUp(t) + defer tearDown(t) + + meminfoContents := ` +MemTotal: 374256 kB +MemFree: 274460 kB +Buffers: 9764 kB +Cached: 38648 kB +SwapCached: 0 kB +Active: 33772 kB +Inactive: 31184 kB +Active(anon): 16572 kB +Inactive(anon): 552 kB +Active(file): 17200 kB +Inactive(file): 30632 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 786428 kB +SwapFree: 786428 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 16564 kB +Mapped: 6612 kB +Shmem: 584 kB +Slab: 19092 kB +SReclaimable: 9128 kB +SUnreclaim: 9964 kB +KernelStack: 672 kB +PageTables: 1864 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 973556 kB +Committed_AS: 55880 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 21428 kB +VmallocChunk: 34359713596 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 59328 kB +DirectMap2M: 333824 kB +` + + meminfoFile := procd + "/meminfo" + err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) + if err != nil { + t.Fatal(err) + } + + mem := sigar.Mem{} + if assert.NoError(t, mem.Get()) { + assert.Equal(t, uint64(374256*1024), mem.Total) + assert.Equal(t, uint64(274460*1024), mem.Free) + } + + swap := sigar.Swap{} + if assert.NoError(t, swap.Get()) { + assert.Equal(t, uint64(786428*1024), swap.Total) + assert.Equal(t, uint64(786428*1024), swap.Free) + } +} + +func TestLinuxMemAndSwapKernel_3_14(t *testing.T) { + setUp(t) + defer tearDown(t) + + meminfoContents := ` +MemTotal: 500184 kB +MemFree: 31360 kB +MemAvailable: 414168 kB +Buffers: 28740 kB +Cached: 325408 kB +SwapCached: 264 kB +Active: 195476 kB +Inactive: 198612 kB +Active(anon): 14920 kB +Inactive(anon): 27268 kB +Active(file): 180556 kB +Inactive(file): 171344 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 524284 kB +SwapFree: 520352 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 39772 kB +Mapped: 24132 kB +Shmem: 2236 kB +Slab: 57988 kB +SReclaimable: 43524 kB +SUnreclaim: 14464 kB +KernelStack: 2464 kB +PageTables: 3096 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 774376 kB +Committed_AS: 490916 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 0 kB +VmallocChunk: 0 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 63424 kB +DirectMap2M: 460800 kB +` + + meminfoFile := procd + "/meminfo" + err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) + if err != nil { + t.Fatal(err) + } + + mem := sigar.Mem{} + if assert.NoError(t, mem.Get()) { + assert.Equal(t, uint64(500184*1024), mem.Total) + assert.Equal(t, uint64(31360*1024), mem.Free) + assert.Equal(t, uint64(414168*1024), mem.ActualFree) + } + + swap := sigar.Swap{} + if assert.NoError(t, swap.Get()) { + assert.Equal(t, uint64(524284*1024), swap.Total) + assert.Equal(t, uint64(520352*1024), swap.Free) + } +} + +func TestLinuxMemAndSwapMissingMemTotal(t *testing.T) { + setUp(t) + defer tearDown(t) + + meminfoContents := ` +MemFree: 31360 kB +MemAvailable: 414168 kB +Buffers: 28740 kB +Cached: 325408 kB +SwapCached: 264 kB +Active: 195476 kB +Inactive: 198612 kB +Active(anon): 14920 kB +Inactive(anon): 27268 kB +Active(file): 180556 kB +Inactive(file): 171344 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 524284 kB +SwapFree: 520352 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 39772 kB +Mapped: 24132 kB +Shmem: 2236 kB +Slab: 57988 kB +SReclaimable: 43524 kB +SUnreclaim: 14464 kB +KernelStack: 2464 kB +PageTables: 3096 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 774376 kB +Committed_AS: 490916 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 0 kB +VmallocChunk: 0 kB +HardwareCorrupted: 0 kB +AnonHugePages: 0 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 63424 kB +DirectMap2M: 460800 kB +` + + meminfoFile := procd + "/meminfo" + err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) + if err != nil { + t.Fatal(err) + } + + mem := sigar.Mem{} + if assert.NoError(t, mem.Get()) { + assert.Equal(t, uint64(0), mem.Total) + assert.Equal(t, uint64(31360*1024), mem.Free) + assert.Equal(t, uint64(414168*1024), mem.ActualFree) + } + + swap := sigar.Swap{} + if assert.NoError(t, swap.Get()) { + assert.Equal(t, uint64(524284*1024), swap.Total) + assert.Equal(t, uint64(520352*1024), swap.Free) + } +} + +func TestLinuxMemAndSwapKernel_3_14_memavailable_zero(t *testing.T) { + setUp(t) + defer tearDown(t) + + meminfoContents := ` +MemTotal: 148535680 kB +MemFree: 417356 kB +MemAvailable: 0 kB +Buffers: 1728 kB +Cached: 129928 kB +SwapCached: 8208 kB +Active: 141088676 kB +Inactive: 5568132 kB +Active(anon): 141076780 kB +Inactive(anon): 5556936 kB +Active(file): 11896 kB +Inactive(file): 11196 kB +Unevictable: 3648 kB +Mlocked: 3648 kB +SwapTotal: 4882428 kB +SwapFree: 0 kB +Dirty: 808 kB +Writeback: 220 kB +AnonPages: 146521272 kB +Mapped: 41384 kB +Shmem: 105864 kB +Slab: 522648 kB +SReclaimable: 233508 kB +SUnreclaim: 289140 kB +KernelStack: 85024 kB +PageTables: 368760 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 79150268 kB +Committed_AS: 272491684 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 0 kB +VmallocChunk: 0 kB +HardwareCorrupted: 0 kB +AnonHugePages: 78061568 kB +ShmemHugePages: 0 kB +ShmemPmdMapped: 0 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 124388 kB +DirectMap2M: 5105664 kB +DirectMap1G: 147849216 kB +` + + meminfoFile := procd + "/meminfo" + err := ioutil.WriteFile(meminfoFile, []byte(meminfoContents), 0444) + if err != nil { + t.Fatal(err) + } + + mem := sigar.Mem{} + if assert.NoError(t, mem.Get()) { + assert.Equal(t, uint64(148535680*1024), mem.Total) + assert.Equal(t, uint64(417356*1024), mem.Free) + assert.Equal(t, uint64(0), mem.ActualFree) + } + + swap := sigar.Swap{} + if assert.NoError(t, swap.Get()) { + assert.Equal(t, uint64(4882428*1024), swap.Total) + assert.Equal(t, uint64(0), swap.Free) + } + +} + +func TestFDUsage(t *testing.T) { + setUp(t) + defer tearDown(t) + + // There is no Uint63 until 2.0 + open := uint64(rand.Uint32()) + unused := uint64(rand.Uint32()) + max := uint64(rand.Uint32()) + fileNRContents := fmt.Sprintf("%d %d %d", open, unused, max) + + fileNRPath := procd + "/sys/fs" + os.MkdirAll(fileNRPath, 0755) + fileNRFile := fileNRPath + "/file-nr" + err := ioutil.WriteFile(fileNRFile, []byte(fileNRContents), 0444) + if err != nil { + t.Fatal(err) + } + + fd := sigar.FDUsage{} + if assert.NoError(t, fd.Get()) { + assert.Equal(t, open, fd.Open) + assert.Equal(t, unused, fd.Unused) + assert.Equal(t, max, fd.Max) + } +} + +func TestProcFDUsage(t *testing.T) { + setUp(t) + defer tearDown(t) + + pid := rand.Intn(32768) + pidDir := fmt.Sprintf("%s/%d", procd, pid) + err := os.Mkdir(pidDir, 0755) + if err != nil { + t.Fatal(err) + } + soft := uint64(rand.Uint32()) + // subtract to prevent the posibility of overflow + if soft != 0 { + soft -= 1 + } + // max sure hard is always bigger than soft + hard := soft + uint64(rand.Uint32()) + + limitsContents := `Limit Soft Limit Hard Limit Units +Max cpu time unlimited unlimited seconds +Max file size unlimited unlimited bytes +Max data size unlimited unlimited bytes +Max stack size 8388608 unlimited bytes +Max core file size 0 unlimited bytes +Max resident set unlimited unlimited bytes +Max processes 29875 29875 processes +Max open files %d %d files +Max locked memory 65536 65536 bytes +Max address space unlimited unlimited bytes +Max file locks unlimited unlimited locks +Max pending signals 29875 29875 signals +Max msgqueue size 819200 819200 bytes +Max nice priority 0 0 +Max realtime priority 0 0 +Max realtime timeout unlimited unlimited us +` + + limitsContents = fmt.Sprintf(limitsContents, soft, hard) + + limitsFile := pidDir + "/limits" + err = ioutil.WriteFile(limitsFile, []byte(limitsContents), 0444) + if err != nil { + t.Fatal(err) + } + open := rand.Intn(32768) + if err = writeFDs(pid, open); err != nil { + t.Fatal(err) + } + + procFD := sigar.ProcFDUsage{} + if assert.NoError(t, procFD.Get(pid)) { + assert.Equal(t, uint64(open), procFD.Open) + assert.Equal(t, soft, procFD.SoftLimit) + assert.Equal(t, hard, procFD.HardLimit) + } +} + +func writeFDs(pid int, count int) error { + fdDir := fmt.Sprintf("%s/%d/fd", procd, pid) + err := os.Mkdir(fdDir, 0755) + if err != nil { + return err + } + + for i := 0; i < count; i++ { + fdPath := fmt.Sprintf("%s/%d", fdDir, i) + f, err := os.Create(fdPath) + if err != nil { + return err + } + f.Close() + } + return nil +} + +func writePidStats(pid int, procName string, path string) error { + stats := "S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 " + + "20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 " + + "35 36 37 38 39" + + statContents := []byte(fmt.Sprintf("%d (%s) %s", pid, procName, stats)) + return ioutil.WriteFile(path, statContents, 0644) +} + +func writePidStatus(name string, pid int, uid int, pidStatusFile string) error { + status := ` +Name: %s +State: R (running) +Tgid: 5452 +Pid: %d +PPid: 743 +TracerPid: 0 +Uid: %d %d %d %d +Gid: 100 100 100 100 +FDSize: 256 +Groups: 100 14 16 +VmPeak: 5004 kB +VmSize: 5004 kB +VmLck: 0 kB +VmHWM: 476 kB +VmRSS: 476 kB +RssAnon: 352 kB +RssFile: 120 kB +RssShmem: 4 kB +VmData: 156 kB +VmStk: 88 kB +VmExe: 68 kB +VmLib: 1412 kB +VmPTE: 20 kb +VmSwap: 0 kB +HugetlbPages: 0 kB +Threads: 1 +SigQ: 0/28578 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000000000 +SigIgn: 0000000000000000 +SigCgt: 0000000000000000 +CapInh: 00000000fffffeff +CapPrm: 0000000000000000 +CapEff: 0000000000000000 +CapBnd: ffffffffffffffff +Seccomp: 0 +voluntary_ctxt_switches: 0 +nonvoluntary_ctxt_switches: 1` + + statusContents := []byte(fmt.Sprintf(status, name, pid, uid)) + return ioutil.WriteFile(pidStatusFile, statusContents, 0644) +} diff --git a/vendor/github.com/elastic/gosigar/sys/linux/inetdiag_test.go b/vendor/github.com/elastic/gosigar/sys/linux/inetdiag_test.go new file mode 100644 index 00000000000..d4ff64b5e7a --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/linux/inetdiag_test.go @@ -0,0 +1,79 @@ +// +build linux + +package linux + +import ( + "bytes" + "encoding/hex" + "io/ioutil" + "syscall" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestParseInetDiagMsgs reads netlink messages stored in a file (these can be +// captured with ss -diag ). +func TestParseInetDiagMsgs(t *testing.T) { + data, err := ioutil.ReadFile("testdata/inet-dump-rhel6-2.6.32-504.3.3.el6.x86_64.bin") + if err != nil { + t.Fatal(err) + } + + t.Log("Netlink data length: ", len(data)) + netlinkMsgs, err := syscall.ParseNetlinkMessage(data) + if err != nil { + t.Fatal(err) + } + + t.Logf("Parsed %d netlink messages", len(netlinkMsgs)) + done := false + for _, m := range netlinkMsgs { + if m.Header.Type == syscall.NLMSG_DONE { + done = true + break + } + + inetDiagMsg, err := ParseInetDiagMsg(m.Data) + if err != nil { + t.Fatal("parse error", err) + } + + if inetDiagMsg.DstPort() == 0 { + assert.EqualValues(t, TCP_LISTEN, inetDiagMsg.State) + } else { + assert.EqualValues(t, TCP_ESTABLISHED, inetDiagMsg.State) + } + } + + assert.True(t, done, "missing NLMSG_DONE message") +} + +// TestNetlinkInetDiag sends a inet_diag_req to the kernel, checks for errors, +// and inspects the responses based on some invariant rules. +func TestNetlinkInetDiag(t *testing.T) { + req := NewInetDiagReq() + req.Header.Seq = 12345 + + dump := new(bytes.Buffer) + msgs, err := NetlinkInetDiagWithBuf(req, nil, dump) + if err != nil { + t.Fatal(err) + } + + t.Logf("Received %d messages decoded from %d bytes", len(msgs), dump.Len()) + for _, m := range msgs { + if m.Family != uint8(AF_INET) && m.Family != uint8(AF_INET6) { + t.Errorf("invalid Family (%v)", m.Family) + } + + if m.DstPort() == 0 { + assert.True(t, m.DstIP().IsUnspecified(), "dport is 0, dst ip should be unspecified") + assert.EqualValues(t, m.State, TCP_LISTEN) + } + } + + if t.Failed() { + t.Log("Raw newlink response:\n", hex.Dump(dump.Bytes())) + } +} diff --git a/vendor/github.com/elastic/gosigar/sys/linux/netlink.go b/vendor/github.com/elastic/gosigar/sys/linux/netlink.go index 3c50f456971..f8747781581 100644 --- a/vendor/github.com/elastic/gosigar/sys/linux/netlink.go +++ b/vendor/github.com/elastic/gosigar/sys/linux/netlink.go @@ -1,3 +1,5 @@ +// +build linux + package linux import ( @@ -5,6 +7,8 @@ import ( "errors" ) +// Netlink Error Code Handling + // ParseNetlinkError parses the errno from the data section of a // syscall.NetlinkMessage. If netlinkData is less than 4 bytes an error // describing the problem will be returned. diff --git a/vendor/github.com/elastic/gosigar/sys/linux/netlink_test.go b/vendor/github.com/elastic/gosigar/sys/linux/netlink_test.go new file mode 100644 index 00000000000..7d7ce7d2a8c --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/linux/netlink_test.go @@ -0,0 +1,21 @@ +// +build linux + +package linux + +import ( + "bytes" + "encoding/binary" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseNetlinkErrorDataTooShort(t *testing.T) { + assert.Error(t, ParseNetlinkError(nil), "too short") +} + +func TestParseNetlinkErrorErrno(t *testing.T) { + buf := new(bytes.Buffer) + binary.Write(buf, binary.LittleEndian, -1*int32(NLE_MSG_TOOSHORT)) + assert.Equal(t, ParseNetlinkError(buf.Bytes()), NLE_MSG_TOOSHORT) +} diff --git a/vendor/github.com/elastic/gosigar/sys/windows/privileges_test.go b/vendor/github.com/elastic/gosigar/sys/windows/privileges_test.go new file mode 100644 index 00000000000..0bce86da6a3 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/privileges_test.go @@ -0,0 +1,82 @@ +// +build windows + +package windows + +import ( + "syscall" + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/sys/windows" +) + +func TestGetDebugInfo(t *testing.T) { + debug, err := GetDebugInfo() + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", debug) +} + +func TestGetTokenPrivileges(t *testing.T) { + h, err := windows.GetCurrentProcess() + if err != nil { + t.Fatal("GetCurrentProcess", err) + } + + var token syscall.Token + err = syscall.OpenProcessToken(syscall.Handle(h), syscall.TOKEN_QUERY, &token) + if err != nil { + t.Fatal("OpenProcessToken", err) + } + + privs, err := GetTokenPrivileges(token) + if err != nil { + t.Fatal("GetTokenPrivileges", err) + } + + for _, priv := range privs { + t.Log(priv) + } +} + +func TestEnableTokenPrivileges(t *testing.T) { + h, err := windows.GetCurrentProcess() + if err != nil { + t.Fatal("GetCurrentProcess", err) + } + + var token syscall.Token + err = syscall.OpenProcessToken(syscall.Handle(h), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, &token) + if err != nil { + t.Fatal("OpenProcessToken", err) + } + + privs, err := GetTokenPrivileges(token) + if err != nil { + t.Fatal("GetTokenPrivileges", err) + } + + priv, found := privs[SeDebugPrivilege] + if found { + t.Logf("Token has privilege: %v", priv) + } else { + t.Logf("Token is missing privilege %v", SeDebugPrivilege) + } + + err = EnableTokenPrivileges(token, SeDebugPrivilege) + if err != nil { + t.Fatal("EnableTokenPrivileges", err) + } + + privs, err = GetTokenPrivileges(token) + if err != nil { + t.Fatal("GetTokenPrivileges", err) + } + + priv, found = privs[SeDebugPrivilege] + if found && assert.True(t, priv.Enabled, "%v is not enabled. %v", SeDebugPrivilege, priv) { + t.Logf("%v is enabled.", SeDebugPrivilege) + } +} diff --git a/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows_test.go b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows_test.go new file mode 100644 index 00000000000..96e4022b7dc --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows_test.go @@ -0,0 +1,183 @@ +package windows + +import ( + "os" + "runtime" + "syscall" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestGetProcessImageFileName(t *testing.T) { + h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) + if err != nil { + t.Fatal(err) + } + + filename, err := GetProcessImageFileName(h) + if err != nil { + t.Fatal(err) + } + + t.Logf("GetProcessImageFileName: %v", filename) +} + +func TestGetProcessMemoryInfo(t *testing.T) { + h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) + if err != nil { + t.Fatal(err) + } + + counters, err := GetProcessMemoryInfo(h) + if err != nil { + t.Fatal(err) + } + + t.Logf("GetProcessMemoryInfo: ProcessMemoryCountersEx=%+v", counters) +} + +func TestGetLogicalDriveStrings(t *testing.T) { + drives, err := GetLogicalDriveStrings() + if err != nil { + t.Fatal(err) + } + + t.Logf("GetLogicalDriveStrings: %v", drives) +} + +func TestGetDriveType(t *testing.T) { + drives, err := GetLogicalDriveStrings() + if err != nil { + t.Fatal(err) + } + + for _, drive := range drives { + dt, err := GetDriveType(drive) + if err != nil { + t.Fatal(err) + } + + t.Logf("GetDriveType: drive=%v, type=%v", drive, dt) + } +} + +func TestGetSystemTimes(t *testing.T) { + idle, kernel, user, err := GetSystemTimes() + if err != nil { + t.Fatal(err) + } + + t.Logf("GetSystemTimes: idle=%v, kernel=%v, user=%v", idle, kernel, user) +} + +func TestGlobalMemoryStatusEx(t *testing.T) { + mem, err := GlobalMemoryStatusEx() + if err != nil { + t.Fatal(err) + } + + t.Logf("GlobalMemoryStatusEx: %+v", mem) +} + +func TestEnumProcesses(t *testing.T) { + pids, err := EnumProcesses() + if err != nil { + t.Fatal(err) + } + + t.Logf("EnumProcesses: %v", pids) +} + +func TestGetDiskFreeSpaceEx(t *testing.T) { + drives, err := GetLogicalDriveStrings() + if err != nil { + t.Fatal(err) + } + + for _, drive := range drives { + dt, err := GetDriveType(drive) + if err != nil { + t.Fatal(err) + } + + // Ignore CDROM drives. They return an error if the drive is emtpy. + if dt != DRIVE_CDROM { + free, total, totalFree, err := GetDiskFreeSpaceEx(drive) + if err != nil { + t.Fatal(err) + } + t.Logf("GetDiskFreeSpaceEx: %v, %v, %v", free, total, totalFree) + } + } +} + +func TestGetWindowsVersion(t *testing.T) { + ver := GetWindowsVersion() + assert.True(t, ver.Major >= 5) + t.Logf("GetWindowsVersion: %+v", ver) +} + +func TestCreateToolhelp32Snapshot(t *testing.T) { + handle, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + if err != nil { + t.Fatal(err) + } + defer syscall.CloseHandle(syscall.Handle(handle)) + + // Iterate over the snapshots until our PID is found. + pid := uint32(syscall.Getpid()) + for { + process, err := Process32Next(handle) + if errors.Cause(err) == syscall.ERROR_NO_MORE_FILES { + break + } + if err != nil { + t.Fatal(err) + } + + t.Logf("CreateToolhelp32Snapshot: ProcessEntry32=%v", process) + + if process.ProcessID == pid { + assert.EqualValues(t, syscall.Getppid(), process.ParentProcessID) + return + } + } + + assert.Fail(t, "Snapshot not found for PID=%v", pid) +} + +func TestNtQuerySystemProcessorPerformanceInformation(t *testing.T) { + cpus, err := NtQuerySystemProcessorPerformanceInformation() + if err != nil { + t.Fatal(err) + } + + assert.Len(t, cpus, runtime.NumCPU()) + + for i, cpu := range cpus { + assert.NotZero(t, cpu.IdleTime) + assert.NotZero(t, cpu.KernelTime) + assert.NotZero(t, cpu.UserTime) + + t.Logf("CPU=%v SystemProcessorPerformanceInformation=%v", i, cpu) + } +} + +func TestNtQueryProcessBasicInformation(t *testing.T) { + h, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(syscall.Getpid())) + if err != nil { + t.Fatal(err) + } + + info, err := NtQueryProcessBasicInformation(h) + if err != nil { + t.Fatal(err) + } + + assert.EqualValues(t, os.Getpid(), info.UniqueProcessID) + assert.EqualValues(t, os.Getppid(), info.InheritedFromUniqueProcessID) + + t.Logf("NtQueryProcessBasicInformation: %+v", info) +} diff --git a/vendor/vendor.json b/vendor/vendor.json index a9714d5a780..9424cb3255e 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -154,28 +154,36 @@ "revisionTime": "2017-02-07T06:38:51Z" }, { - "checksumSHA1": "Ylm1LLWfMHrInIZKDNv87ifR2EQ=", + "checksumSHA1": "0Yo0jEfGWE40M4U9Z7JNxd/RA/w=", "path": "github.com/elastic/gosigar", - "revision": "4c790f73760ca6dccd61882b263e03a5f23fbb77", - "revisionTime": "2017-02-28T14:16:55Z" + "revision": "026c67add059f36c9679ddc16fe57ebae37fb8d6", + "revisionTime": "2017-05-15T15:13:16Z", + "version": "v0.3.0", + "versionExact": "v0.3.0" }, { "checksumSHA1": "jE0nhsyuGyQ7vWoyBRPEU63mQ4g=", "path": "github.com/elastic/gosigar/cgroup", - "revision": "4c790f73760ca6dccd61882b263e03a5f23fbb77", - "revisionTime": "2017-02-28T14:16:55Z" + "revision": "026c67add059f36c9679ddc16fe57ebae37fb8d6", + "revisionTime": "2017-05-15T15:13:16Z", + "version": "v0.3.0", + "versionExact": "v0.3.0" }, { - "checksumSHA1": "naNuxf2j2CBb+5u73viadrKjD+c=", + "checksumSHA1": "vfoRHmXWguwll8nBV4DzE8jv2wA=", "path": "github.com/elastic/gosigar/sys/linux", - "revision": "4c790f73760ca6dccd61882b263e03a5f23fbb77", - "revisionTime": "2017-02-28T14:16:55Z" + "revision": "026c67add059f36c9679ddc16fe57ebae37fb8d6", + "revisionTime": "2017-05-15T15:13:16Z", + "version": "v0.3.0", + "versionExact": "v0.3.0" }, { - "checksumSHA1": "qDsgp2kAeI9nhj565HUScaUyjU4=", + "checksumSHA1": "g1QbhJfmuVvEfcg/yvd2PURU2F0=", "path": "github.com/elastic/gosigar/sys/windows", - "revision": "4c790f73760ca6dccd61882b263e03a5f23fbb77", - "revisionTime": "2017-02-28T14:16:55Z" + "revision": "026c67add059f36c9679ddc16fe57ebae37fb8d6", + "revisionTime": "2017-05-15T15:13:16Z", + "version": "v0.3.0", + "versionExact": "v0.3.0" }, { "checksumSHA1": "P0CvGmmAM8uYPSE2ix4th/L9c/8=",