Skip to content

Commit

Permalink
Merge pull request #289 from weaveworks/fix-host-on-darwin
Browse files Browse the repository at this point in the history
Fix host on darwin
  • Loading branch information
peterbourgon committed Jun 29, 2015
2 parents 56701b6 + 36212ce commit 6978549
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 82 deletions.
3 changes: 2 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ test:
- cd $SRCDIR; ./bin/lint .
- cd $SRCDIR; make client-test
- cd $SRCDIR; make static
- cd $SRCDIR; make
- cd $SRCDIR; rm -f app/app probe/probe; GOOS=darwin make
- cd $SRCDIR; rm -f app/app probe/probe; GOOS=linux make
- cd $SRCDIR; ./bin/test -slow
- cd $SRCDIR/experimental; make
post:
Expand Down
31 changes: 3 additions & 28 deletions probe/host/reporter.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package host

import (
"fmt"
"io/ioutil"
"net"
"runtime"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -34,7 +31,6 @@ const (
var (
InterfaceAddrs = net.InterfaceAddrs
Now = func() string { return time.Now().UTC().Format(time.RFC3339Nano) }
ReadFile = ioutil.ReadFile
)

type reporter struct {
Expand All @@ -51,27 +47,6 @@ func NewReporter(hostID, hostName string) tag.Reporter {
}
}

func getUptime() (time.Duration, error) {
var result time.Duration

buf, err := ReadFile(ProcUptime)
if err != nil {
return result, err
}

fields := strings.Fields(string(buf))
if len(fields) != 2 {
return result, fmt.Errorf("invalid format: %s", string(buf))
}

uptime, err := strconv.ParseFloat(fields[0], 64)
if err != nil {
return result, err
}

return time.Duration(uptime) * time.Second, nil
}

func (r *reporter) Report() (report.Report, error) {
var (
rep = report.MakeReport()
Expand All @@ -89,12 +64,12 @@ func (r *reporter) Report() (report.Report, error) {
}
}

uptime, err := getUptime()
uptime, err := GetUptime()
if err != nil {
return rep, err
}

kernel, err := getKernelVersion()
kernel, err := GetKernelVersion()
if err != nil {
return rep, err
}
Expand All @@ -104,7 +79,7 @@ func (r *reporter) Report() (report.Report, error) {
HostName: r.hostName,
LocalNetworks: strings.Join(localCIDRs, " "),
OS: runtime.GOOS,
Load: getLoad(),
Load: GetLoad(),
KernelVersion: kernel,
Uptime: uptime.String(),
}
Expand Down
67 changes: 23 additions & 44 deletions probe/host/reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,49 @@ import (
"net"
"reflect"
"runtime"
"syscall"
"testing"
"time"

"github.com/weaveworks/scope/probe/host"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
)

const (
procLoad = "0.59 0.36 0.29 1/200 12187"
procUptime = "1004143.23 1263220.30"
release = "release"
version = "version"

release = "release"
version = "version"
network = "192.168.0.0/16"
hostid = "hostid"
hostID = "hostid"
now = "now"
hostname = "hostname"
load = "0.59 0.36 0.29"
uptime = "278h55m43s"
kernel = "release version"
)

func string2c(s string) [65]int8 {
var result [65]int8
for i, c := range s {
result[i] = int8(c)
}
return result
}

func TestReporter(t *testing.T) {
oldInterfaceAddrs, oldNow, oldReadFile, oldUname := host.InterfaceAddrs, host.Now, host.ReadFile, host.Uname
var (
oldGetKernelVersion = host.GetKernelVersion
oldGetLoad = host.GetLoad
oldGetUptime = host.GetUptime
oldInterfaceAddrs = host.InterfaceAddrs
oldNow = host.Now
)
defer func() {
host.InterfaceAddrs, host.Now, host.ReadFile, host.Uname = oldInterfaceAddrs, oldNow, oldReadFile, oldUname
host.GetKernelVersion = oldGetKernelVersion
host.GetLoad = oldGetLoad
host.GetUptime = oldGetUptime
host.InterfaceAddrs = oldInterfaceAddrs
host.Now = oldNow
}()

host.InterfaceAddrs = func() ([]net.Addr, error) {
_, ipnet, _ := net.ParseCIDR(network)
return []net.Addr{ipnet}, nil
}

host.GetKernelVersion = func() (string, error) { return release + " " + version, nil }
host.GetLoad = func() string { return load }
host.GetUptime = func() (time.Duration, error) { return time.ParseDuration(uptime) }
host.Now = func() string { return now }
host.InterfaceAddrs = func() ([]net.Addr, error) { _, ipnet, _ := net.ParseCIDR(network); return []net.Addr{ipnet}, nil }

host.ReadFile = func(filename string) ([]byte, error) {
switch filename {
case host.ProcUptime:
return []byte(procUptime), nil
case host.ProcLoad:
return []byte(procLoad), nil
default:
panic(filename)
}
}

host.Uname = func(uts *syscall.Utsname) error {
uts.Release = string2c(release)
uts.Version = string2c(version)
return nil
}

r := host.NewReporter(hostid, hostname)
have, _ := r.Report()
want := report.MakeReport()
want.Host.NodeMetadatas[report.MakeHostNodeID(hostid)] = report.NodeMetadata{
want.Host.NodeMetadatas[report.MakeHostNodeID(hostID)] = report.NodeMetadata{
host.Timestamp: now,
host.HostName: hostname,
host.LocalNetworks: network,
Expand All @@ -77,7 +55,8 @@ func TestReporter(t *testing.T) {
host.Uptime: uptime,
host.KernelVersion: kernel,
}

r := host.NewReporter(hostID, hostname)
have, _ := r.Report()
if !reflect.DeepEqual(want, have) {
t.Errorf("%s", test.Diff(want, have))
}
Expand Down
49 changes: 45 additions & 4 deletions probe/host/system_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,31 @@ import (
"fmt"
"os/exec"
"regexp"
"strconv"
"time"
)

var loadRe = regexp.MustCompile(`load average\: ([0-9\.]+), ([0-9\.]+), ([0-9\.]+)`)
var (
unameRe = regexp.MustCompile(`Darwin Kernel Version ([0-9\.]+)\:`)
loadRe = regexp.MustCompile(`load averages: ([0-9\.]+) ([0-9\.]+) ([0-9\.]+)`)
uptimeRe = regexp.MustCompile(`up ([0-9]+) day[s]*,[ ]+([0-9]+)\:([0-9][0-9])`)
)

func getKernelVersion() (string, error) {
return "", nil
// GetKernelVersion returns the kernel version as reported by uname.
var GetKernelVersion = func() (string, error) {
out, err := exec.Command("uname", "-v").CombinedOutput()
if err != nil {
return "Darwin unknown", err
}
matches := unameRe.FindAllStringSubmatch(string(out), -1)
if matches == nil || len(matches) < 1 || len(matches[0]) < 1 {
return "Darwin unknown", nil
}
return fmt.Sprintf("Darwin %s", matches[0][1]), nil
}

func getLoad() string {
// GetLoad returns the current load averages in standard form.
var GetLoad = func() string {
out, err := exec.Command("w").CombinedOutput()
if err != nil {
return "unknown"
Expand All @@ -23,3 +39,28 @@ func getLoad() string {
}
return fmt.Sprintf("%s %s %s", matches[0][1], matches[0][2], matches[0][3])
}

// GetUptime returns the uptime of the host.
var GetUptime = func() (time.Duration, error) {
out, err := exec.Command("w").CombinedOutput()
if err != nil {
return 0, err
}
matches := uptimeRe.FindAllStringSubmatch(string(out), -1)
if matches == nil || len(matches) < 1 || len(matches[0]) < 4 {
return 0, err
}
d, err := strconv.Atoi(matches[0][1])
if err != nil {
return 0, err
}
h, err := strconv.Atoi(matches[0][2])
if err != nil {
return 0, err
}
m, err := strconv.Atoi(matches[0][3])
if err != nil {
return 0, err
}
return (time.Duration(d) * 24 * time.Hour) + (time.Duration(h) * time.Hour) + (time.Duration(m) * time.Minute), nil
}
34 changes: 29 additions & 5 deletions probe/host/system_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package host

import (
"fmt"
"io/ioutil"
"strconv"
"strings"
"syscall"
"time"
)

// Uname exported for testing
// Uname is swappable for mocking in tests.
var Uname = syscall.Uname

func charsToString(ca [65]int8) string {
Expand All @@ -22,16 +24,18 @@ func charsToString(ca [65]int8) string {
return string(s[0:lens])
}

func getKernelVersion() (string, error) {
// GetKernelVersion returns the kernel version as reported by uname.
var GetKernelVersion = func() (string, error) {
var utsname syscall.Utsname
if err := Uname(&utsname); err != nil {
return "", err
return "unknown", err
}
return fmt.Sprintf("%s %s", charsToString(utsname.Release), charsToString(utsname.Version)), nil
}

func getLoad() string {
buf, err := ReadFile(ProcLoad)
// GetLoad returns the current load averages in standard form.
var GetLoad = func() string {
buf, err := ioutil.ReadFile("/proc/loadavg")
if err != nil {
return "unknown"
}
Expand All @@ -53,3 +57,23 @@ func getLoad() string {
}
return fmt.Sprintf("%.2f %.2f %.2f", one, five, fifteen)
}

// GetUptime returns the uptime of the host.
var GetUptime = func() (time.Duration, error) {
buf, err := ioutil.ReadFile("/proc/uptime")
if err != nil {
return 0, err
}

fields := strings.Fields(string(buf))
if len(fields) != 2 {
return 0, fmt.Errorf("invalid format: %s", string(buf))
}

uptime, err := strconv.ParseFloat(fields[0], 64)
if err != nil {
return 0, err
}

return time.Duration(uptime) * time.Second, nil
}
40 changes: 40 additions & 0 deletions probe/host/system_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package host_test

import (
"fmt"
"syscall"
"testing"

"github.com/weaveworks/scope/probe/host"
)

func TestUname(t *testing.T) {
oldUname := host.Uname
defer func() { host.Uname = oldUname }()

const (
release = "rls"
version = "ver"
)
host.Uname = func(uts *syscall.Utsname) error {
uts.Release = string2c(release)
uts.Version = string2c(version)
return nil
}

have, err := host.GetKernelVersion()
if err != nil {
t.Fatal(err)
}
if want := fmt.Sprintf("%s %s", release, version); want != have {
t.Errorf("want %q, have %q", want, have)
}
}

func string2c(s string) [65]int8 {
var result [65]int8
for i, c := range s {
result[i] = int8(c)
}
return result
}
38 changes: 38 additions & 0 deletions probe/host/system_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package host_test

import (
"strings"
"testing"

"github.com/weaveworks/scope/probe/host"
)

func TestGetKernelVersion(t *testing.T) {
have, err := host.GetKernelVersion()
if err != nil {
t.Fatal(err)
}
if strings.Contains(have, "unknown") {
t.Fatal(have)
}
t.Log(have)
}

func TestGetLoad(t *testing.T) {
have := host.GetLoad()
if strings.Contains(have, "unknown") {
t.Fatal(have)
}
t.Log(have)
}

func TestGetUptime(t *testing.T) {
have, err := host.GetUptime()
if err != nil {
t.Fatal(err)
}
if have == 0 {
t.Fatal(have)
}
t.Log(have.String())
}

0 comments on commit 6978549

Please sign in to comment.