Use 'common' library

This commit is contained in:
Jonathan Lange
2016-12-07 11:22:38 +00:00
parent 6344358c6b
commit e8085b01b6
63 changed files with 49 additions and 1192 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ import (
"github.com/ugorji/go/codec"
"golang.org/x/net/context"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -6,8 +6,8 @@ import (
"golang.org/x/net/context"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/app"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/reflect"
+1 -1
View File
@@ -17,8 +17,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
"github.com/weaveworks/common/instrument"
"github.com/weaveworks/scope/app"
"github.com/weaveworks/scope/common/instrument"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -13,8 +13,8 @@ import (
"github.com/gorilla/websocket"
"golang.org/x/net/context"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/app"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/common/xfer"
)
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
"github.com/weaveworks/scope/common/instrument"
"github.com/weaveworks/common/instrument"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
"github.com/weaveworks/scope/common/instrument"
"github.com/weaveworks/common/instrument"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -15,8 +15,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
"github.com/weaveworks/common/instrument"
"github.com/weaveworks/scope/app"
"github.com/weaveworks/scope/common/instrument"
"github.com/weaveworks/scope/common/xfer"
)
+1 -1
View File
@@ -9,7 +9,7 @@ import (
log "github.com/Sirupsen/logrus"
"golang.org/x/net/context"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/common/xfer"
)
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"github.com/gorilla/websocket"
"golang.org/x/net/context"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/common/xfer"
"github.com/weaveworks/scope/probe/appclient"
"github.com/weaveworks/scope/probe/controls"
+1 -1
View File
@@ -7,7 +7,7 @@ import (
fsouza "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/scope/common/backoff"
"github.com/weaveworks/common/backoff"
)
// Default values for weave app integration
-96
View File
@@ -1,96 +0,0 @@
package backoff
import (
"time"
log "github.com/Sirupsen/logrus"
)
type backoff struct {
f func() (bool, error)
quit, done chan struct{}
msg string
initialBackoff, maxBackoff time.Duration
}
// Interface does f in a loop, sleeping for initialBackoff between
// each iterations. If it hits an error, it exponentially backs
// off to maxBackoff. Backoff will log when it backs off, but
// will stop logging when it reaches maxBackoff. It will also
// log on first success.
type Interface interface {
Start()
Stop()
SetInitialBackoff(time.Duration)
SetMaxBackoff(time.Duration)
}
// New makes a new Interface
func New(f func() (bool, error), msg string) Interface {
return &backoff{
f: f,
quit: make(chan struct{}),
done: make(chan struct{}),
msg: msg,
initialBackoff: 10 * time.Second,
maxBackoff: 60 * time.Second,
}
}
func (b *backoff) SetInitialBackoff(d time.Duration) {
b.initialBackoff = d
}
func (b *backoff) SetMaxBackoff(d time.Duration) {
b.maxBackoff = d
}
// Stop the backoff, and waits for it to stop.
func (b *backoff) Stop() {
close(b.quit)
<-b.done
}
// Start the backoff. Can only be called once.
func (b *backoff) Start() {
defer close(b.done)
backoff := b.initialBackoff
shouldLog := true
for {
done, err := b.f()
if done {
return
}
if err != nil {
backoff *= 2
if backoff > b.maxBackoff {
backoff = b.maxBackoff
}
} else if backoff > b.initialBackoff {
backoff = b.initialBackoff
shouldLog = true
}
if shouldLog {
if err != nil {
log.Warnf("Error %s, backing off %s: %s",
b.msg, backoff, err)
} else {
log.Infof("Success %s", b.msg)
}
}
if backoff >= b.maxBackoff || err == nil {
shouldLog = false
}
select {
case <-time.After(backoff):
case <-b.quit:
return
}
}
}
-30
View File
@@ -1,30 +0,0 @@
package exec
import (
"io"
"os/exec"
)
// Cmd is a hook for mocking
type Cmd interface {
StdoutPipe() (io.ReadCloser, error)
StderrPipe() (io.ReadCloser, error)
Start() error
Wait() error
Kill() error
Output() ([]byte, error)
Run() error
}
// Command is a hook for mocking
var Command = func(name string, args ...string) Cmd {
return &realCmd{exec.Command(name, args...)}
}
type realCmd struct {
*exec.Cmd
}
func (c *realCmd) Kill() error {
return c.Cmd.Process.Kill()
}
-94
View File
@@ -1,94 +0,0 @@
package fs
import (
"io"
"io/ioutil"
"os"
"syscall"
)
// Interface is the filesystem interface type.
type Interface interface {
ReadDir(string) ([]os.FileInfo, error)
ReadDirNames(string) ([]string, error)
ReadFile(string) ([]byte, error)
Lstat(string, *syscall.Stat_t) error
Stat(string, *syscall.Stat_t) error
Open(string) (io.ReadWriteCloser, error)
}
type realFS struct{}
// FS is the way you should access the filesystem.
var fs Interface = realFS{}
func (realFS) ReadDir(path string) ([]os.FileInfo, error) {
return ioutil.ReadDir(path)
}
func (realFS) ReadDirNames(path string) ([]string, error) {
fh, err := os.Open(path)
if err != nil {
return nil, err
}
defer fh.Close()
return fh.Readdirnames(-1)
}
func (realFS) ReadFile(path string) ([]byte, error) {
return ioutil.ReadFile(path)
}
func (realFS) Lstat(path string, stat *syscall.Stat_t) error {
return syscall.Lstat(path, stat)
}
func (realFS) Stat(path string, stat *syscall.Stat_t) error {
return syscall.Stat(path, stat)
}
func (realFS) Open(path string) (io.ReadWriteCloser, error) {
return os.Open(path)
}
// trampolines here to allow users to do fs.ReadDir etc
// ReadDir see ioutil.ReadDir
func ReadDir(path string) ([]os.FileInfo, error) {
return fs.ReadDir(path)
}
// ReadDirNames see os.File.ReadDirNames
func ReadDirNames(path string) ([]string, error) {
return fs.ReadDirNames(path)
}
// ReadFile see ioutil.ReadFile
func ReadFile(path string) ([]byte, error) {
return fs.ReadFile(path)
}
// Lstat see syscall.Lstat
func Lstat(path string, stat *syscall.Stat_t) error {
return fs.Lstat(path, stat)
}
// Stat see syscall.Stat
func Stat(path string, stat *syscall.Stat_t) error {
return fs.Stat(path, stat)
}
// Open see os.Open
func Open(path string) (io.ReadWriteCloser, error) {
return fs.Open(path)
}
// Mock is used to switch out the filesystem for a mock.
func Mock(mock Interface) {
fs = mock
}
// Restore puts back the real filesystem.
func Restore() {
fs = realFS{}
}
-53
View File
@@ -1,53 +0,0 @@
package instrument
import (
"time"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/net/context"
)
// ErrorCode converts an error in to an http-style error-code.
func ErrorCode(err error) string {
if err == nil {
return "200"
}
return "500"
}
// TimeRequestHistogram runs 'f' and records how long it took in the given Prometheus
// histogram metric. If 'f' returns successfully, record a "200". Otherwise, record
// "500". It will also emit an OpenTracing span if you have a global tracer configured.
//
// If you want more complicated logic for translating errors into statuses,
// use 'TimeRequestStatus'.
func TimeRequestHistogram(ctx context.Context, method string, metric *prometheus.HistogramVec, f func(context.Context) error) error {
return TimeRequestHistogramStatus(ctx, method, metric, ErrorCode, f)
}
// TimeRequestHistogramStatus runs 'f' and records how long it took in the given
// Prometheus histogram metric. It will also emit an OpenTracing span if you have
// a global tracer configured.
//
// toStatusCode is a function that translates errors returned by 'f' into
// HTTP-like status codes.
func TimeRequestHistogramStatus(ctx context.Context, method string, metric *prometheus.HistogramVec, toStatusCode func(error) string, f func(context.Context) error) error {
if toStatusCode == nil {
toStatusCode = ErrorCode
}
sp, newCtx := opentracing.StartSpanFromContext(ctx, method)
ext.SpanKindRPCClient.Set(sp)
startTime := time.Now()
err := f(newCtx)
if err != nil {
ext.Error.Set(sp, true)
}
sp.Finish()
metric.WithLabelValues(method, toStatusCode(err)).Observe(time.Now().Sub(startTime).Seconds())
return err
}
-94
View File
@@ -1,94 +0,0 @@
package middleware
import (
"bufio"
"fmt"
"net"
"net/http"
)
func copyHeaders(src, dest http.Header) {
for k, v := range src {
dest[k] = v
}
}
// ErrorHandler lets you call an alternate http handler upon a certain response code.
// Note it will assume a 200 if the wrapped handler does not write anything
type ErrorHandler struct {
Code int
Handler http.Handler
}
// Wrap implements Middleware
func (e ErrorHandler) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
i := newErrorInterceptor(w, e.Code)
next.ServeHTTP(i, r)
if !i.gotCode {
i.WriteHeader(http.StatusOK)
}
if i.intercepted {
e.Handler.ServeHTTP(w, r)
}
})
}
// errorInterceptor wraps an underlying ResponseWriter and buffers all header changes, until it knows the return code.
// It then passes everything through, unless the code matches the target code, in which case it will discard everything.
type errorInterceptor struct {
originalWriter http.ResponseWriter
targetCode int
headers http.Header
gotCode bool
intercepted bool
}
func newErrorInterceptor(w http.ResponseWriter, code int) *errorInterceptor {
i := errorInterceptor{originalWriter: w, targetCode: code}
i.headers = make(http.Header)
copyHeaders(w.Header(), i.headers)
return &i
}
// Header implements http.ResponseWriter
func (i *errorInterceptor) Header() http.Header {
return i.headers
}
// WriteHeader implements http.ResponseWriter
func (i *errorInterceptor) WriteHeader(code int) {
if i.gotCode {
panic("errorInterceptor.WriteHeader() called twice")
}
i.gotCode = true
if code == i.targetCode {
i.intercepted = true
} else {
copyHeaders(i.headers, i.originalWriter.Header())
i.originalWriter.WriteHeader(code)
}
}
// Write implements http.ResponseWriter
func (i *errorInterceptor) Write(data []byte) (int, error) {
if !i.gotCode {
i.WriteHeader(http.StatusOK)
}
if !i.intercepted {
return i.originalWriter.Write(data)
}
return len(data), nil
}
// errorInterceptor also implements net.Hijacker, to let the downstream Handler
// hijack the connection. This is needed, for example, for working with websockets.
func (i *errorInterceptor) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj, ok := i.originalWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("error interceptor: can't cast original ResponseWriter to Hijacker")
}
i.gotCode = true
return hj.Hijack()
}
-84
View File
@@ -1,84 +0,0 @@
package middleware
import (
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus"
)
// Instrument is a Middleware which records timings for every HTTP request
type Instrument struct {
RouteMatcher interface {
Match(*http.Request, *mux.RouteMatch) bool
}
Duration *prometheus.HistogramVec
}
func isWSHandshakeRequest(req *http.Request) bool {
return strings.ToLower(req.Header.Get("Upgrade")) == "websocket" &&
strings.ToLower(req.Header.Get("Connection")) == "upgrade"
}
// Wrap implements middleware.Interface
func (i Instrument) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
isWS := strconv.FormatBool(isWSHandshakeRequest(r))
interceptor := &interceptor{ResponseWriter: w, statusCode: http.StatusOK}
route := i.getRouteName(r)
next.ServeHTTP(interceptor, r)
var (
status = strconv.Itoa(interceptor.statusCode)
took = time.Since(begin)
)
i.Duration.WithLabelValues(r.Method, route, status, isWS).Observe(took.Seconds())
})
}
// Return a name identifier for ths request. There are three options:
// 1. The request matches a gorilla mux route, with a name. Use that.
// 2. The request matches an unamed gorilla mux router. Munge the path
// template such that templates like '/api/{org}/foo' come out as
// 'api_org_foo'.
// 3. The request doesn't match a mux route. Munge the Path in the same
// manner as (2).
// We do all this as we do not wish to emit high cardinality labels to
// prometheus.
func (i Instrument) getRouteName(r *http.Request) string {
var routeMatch mux.RouteMatch
if i.RouteMatcher != nil && i.RouteMatcher.Match(r, &routeMatch) {
if name := routeMatch.Route.GetName(); name != "" {
return name
}
if tmpl, err := routeMatch.Route.GetPathTemplate(); err != nil {
return MakeLabelValue(tmpl)
}
}
return MakeLabelValue(r.URL.Path)
}
var invalidChars = regexp.MustCompile(`[^a-zA-Z0-9]+`)
// MakeLabelValue converts a Gorilla mux path to a string suitable for use in
// a Prometheus label value.
func MakeLabelValue(path string) string {
// Convert non-alnums to underscores.
result := invalidChars.ReplaceAllString(path, "_")
// Trim leading and trailing underscores.
result = strings.Trim(result, "_")
// Make it all lowercase
result = strings.ToLower(result)
// Special case.
if result == "" {
result = "root"
}
return result
}
-30
View File
@@ -1,30 +0,0 @@
package middleware_test
import (
"testing"
"github.com/weaveworks/scope/common/middleware"
)
func TestMakeLabelValue(t *testing.T) {
for input, want := range map[string]string{
"/": "root", // special case
"//": "root", // unintended consequence of special case
"a": "a",
"/foo": "foo",
"foo/": "foo",
"/foo/": "foo",
"/foo/bar": "foo_bar",
"foo/bar/": "foo_bar",
"/foo/bar/": "foo_bar",
"/foo/{orgName}/Bar": "foo_orgname_bar",
"/foo/{org_name}/Bar": "foo_org_name_bar",
"/foo/{org__name}/Bar": "foo_org_name_bar",
"/foo/{org___name}/_Bar": "foo_org_name_bar",
"/foo.bar/baz.qux/": "foo_bar_baz_qux",
} {
if have := middleware.MakeLabelValue(input); want != have {
t.Errorf("%q: want %q, have %q", input, want, have)
}
}
}
-69
View File
@@ -1,69 +0,0 @@
package middleware
import (
"bufio"
"fmt"
"net"
"net/http"
"time"
log "github.com/Sirupsen/logrus"
)
// Log middleware logs http requests
type Log struct {
LogSuccess bool // LogSuccess true -> log successful queries; false -> only log failed queries
}
// Wrap implements Middleware
func (l Log) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
uri := r.RequestURI // capture the URI before running next, as it may get rewritten
i := &interceptor{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(i, r)
if l.LogSuccess || !(100 <= i.statusCode && i.statusCode < 400) {
log.Infof("%s %s (%d) %s", r.Method, uri, i.statusCode, time.Since(begin))
}
})
}
// Logging middleware logs each HTTP request method, path, response code and
// duration for all HTTP requests.
var Logging = Log{
LogSuccess: true,
}
// LogFailed middleware logs each HTTP request method, path, response code and
// duration for non-2xx HTTP requests.
var LogFailed = Log{
LogSuccess: false,
}
// interceptor implements WriteHeader to intercept status codes. WriteHeader
// may not be called on success, so initialize statusCode with the status you
// want to report on success, i.e. http.StatusOK.
//
// interceptor also implements net.Hijacker, to let the downstream Handler
// hijack the connection. This is needed, for example, for working with websockets.
type interceptor struct {
http.ResponseWriter
statusCode int
recorded bool
}
func (i *interceptor) WriteHeader(code int) {
if !i.recorded {
i.statusCode = code
i.recorded = true
}
i.ResponseWriter.WriteHeader(code)
}
func (i *interceptor) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hj, ok := i.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("interceptor: can't cast parent ResponseWriter to Hijacker")
}
return hj.Hijack()
}
-33
View File
@@ -1,33 +0,0 @@
package middleware
import (
"net/http"
)
// Interface is the shared contract for all middlesware, and allows middlesware
// to wrap handlers.
type Interface interface {
Wrap(http.Handler) http.Handler
}
// Func is to Interface as http.HandlerFunc is to http.Handler
type Func func(http.Handler) http.Handler
// Wrap implements Interface
func (m Func) Wrap(next http.Handler) http.Handler {
return m(next)
}
// Identity is an Interface which doesn't do anything.
var Identity Interface = Func(func(h http.Handler) http.Handler { return h })
// Merge produces a middleware that applies multiple middlesware in turn;
// ie Merge(f,g,h).Wrap(handler) == f.Wrap(g.Wrap(h.Wrap(handler)))
func Merge(middlesware ...Interface) Interface {
return Func(func(next http.Handler) http.Handler {
for i := len(middlesware) - 1; i >= 0; i-- {
next = middlesware[i].Wrap(next)
}
return next
})
}
-42
View File
@@ -1,42 +0,0 @@
package middleware
import (
"net/http"
"regexp"
)
// PathRewrite supports regex matching and replace on Request URIs
func PathRewrite(regexp *regexp.Regexp, replacement string) Interface {
return pathRewrite{
regexp: regexp,
replacement: replacement,
}
}
type pathRewrite struct {
regexp *regexp.Regexp
replacement string
}
func (p pathRewrite) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.RequestURI = p.regexp.ReplaceAllString(r.RequestURI, p.replacement)
r.URL.Path = p.regexp.ReplaceAllString(r.URL.Path, p.replacement)
next.ServeHTTP(w, r)
})
}
// PathReplace replcase Request.RequestURI with the specified string.
func PathReplace(replacement string) Interface {
return pathReplace(replacement)
}
type pathReplace string
func (p pathReplace) Wrap(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.URL.Path = string(p)
r.RequestURI = string(p)
next.ServeHTTP(w, r)
})
}
-16
View File
@@ -1,16 +0,0 @@
package mtime
import "time"
// Now returns the current time.
var Now = func() time.Time { return time.Now() }
// NowForce sets the time returned by Now to t.
func NowForce(t time.Time) {
Now = func() time.Time { return t }
}
// NowReset makes Now returns the current time again.
func NowReset() {
Now = func() time.Time { return time.Now() }
}
-33
View File
@@ -1,33 +0,0 @@
package network
import (
"fmt"
"net"
)
// GetFirstAddressOf returns the first IPv4 address of the supplied interface name.
func GetFirstAddressOf(name string) (string, error) {
inf, err := net.InterfaceByName(name)
if err != nil {
return "", err
}
addrs, err := inf.Addrs()
if err != nil {
return "", err
}
if len(addrs) <= 0 {
return "", fmt.Errorf("No address found for %s", name)
}
for _, addr := range addrs {
switch v := addr.(type) {
case *net.IPNet:
if ip := v.IP.To4(); ip != nil {
return v.IP.String(), nil
}
}
}
return "", fmt.Errorf("No address found for %s", name)
}
-44
View File
@@ -1,44 +0,0 @@
package sanitize
import (
"fmt"
"net"
"net/url"
"strings"
log "github.com/Sirupsen/logrus"
)
// URL returns a function that sanitizes a URL string. It lets underspecified
// strings to be converted to usable URLs via some default arguments.
func URL(defaultScheme string, defaultPort int, defaultPath string) func(string) string {
if defaultScheme == "" {
defaultScheme = "http://"
}
return func(s string) string {
if s == "" {
return s // can't do much here
}
if !strings.Contains(s, "://") {
s = defaultScheme + s
}
u, err := url.Parse(s)
if err != nil {
log.Errorf("%q: %v", s, err)
return s // oh well
}
if _, port, err := net.SplitHostPort(u.Host); err != nil && defaultPort > 0 {
u.Host += fmt.Sprintf(":%d", defaultPort)
} else if port == "443" {
if u.Scheme == "ws" {
u.Scheme = "wss"
} else {
u.Scheme = "https"
}
}
if defaultPath != "" && u.Path != defaultPath {
u.Path = defaultPath
}
return u.String()
}
}
-37
View File
@@ -1,37 +0,0 @@
package sanitize_test
import (
"testing"
"github.com/weaveworks/scope/common/sanitize"
)
func TestSanitizeURL(t *testing.T) {
for _, input := range []struct {
scheme string
port int
path string
input string
want string
}{
{"", 0, "", "", ""},
{"", 0, "", "foo", "http://foo"},
{"", 80, "", "foo", "http://foo:80"},
{"", 0, "some/path", "foo", "http://foo/some/path"},
{"", 0, "/some/path", "foo", "http://foo/some/path"},
{"https://", 0, "", "foo", "https://foo"},
{"https://", 80, "", "foo", "https://foo:80"},
{"https://", 0, "some/path", "foo", "https://foo/some/path"},
{"https://", 0, "", "http://foo", "http://foo"}, // specified scheme beats default...
{"", 0, "", "https://foo", "https://foo"}, // https can be a specified scheme without default...
{"http://", 0, "", "https://foo", "https://foo"}, // https can be a specified scheme with default...
{"", 9999, "", "foo:80", "http://foo:80"}, // specified port beats default...
{"", 0, "/bar", "foo/baz", "http://foo/bar"}, // ...but default path beats specified!
{"", 0, "", "foo:443", "https://foo:443"}, // port 443 addrs default to https scheme
} {
if want, have := input.want, sanitize.URL(input.scheme, input.port, input.path)(input.input); want != have {
t.Errorf("sanitize.URL(%q, %d, %q)(%q): want %q, have %q", input.scheme, input.port, input.path, input.input, want, have)
continue
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"github.com/ugorji/go/codec"
"github.com/weaveworks/scope/common/exec"
"github.com/weaveworks/common/exec"
)
// Client for Weave Net API
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"sync"
"testing"
"github.com/weaveworks/scope/common/exec"
"github.com/weaveworks/common/exec"
"github.com/weaveworks/scope/common/weave"
"github.com/weaveworks/scope/test"
testExec "github.com/weaveworks/scope/test/exec"
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"github.com/gorilla/websocket"
"github.com/ugorji/go/codec"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
)
const (
+1 -1
View File
@@ -12,7 +12,7 @@ import (
log "github.com/Sirupsen/logrus"
docker "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -7,7 +7,7 @@ import (
client "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
+1 -1
View File
@@ -11,7 +11,7 @@ import (
client "github.com/fsouza/go-dockerclient"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/report"
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/report"
+1 -1
View File
@@ -12,7 +12,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/weaveworks/scope/common/exec"
"github.com/weaveworks/common/exec"
)
const (
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/exec"
"github.com/weaveworks/common/exec"
"github.com/weaveworks/scope/test"
testexec "github.com/weaveworks/scope/test/exec"
)
+1 -1
View File
@@ -3,7 +3,7 @@ package endpoint
import (
"testing"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/reflect"
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"testing"
"time"
fs_hook "github.com/weaveworks/scope/common/fs"
fs_hook "github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/test/fs"
)
+1 -1
View File
@@ -13,7 +13,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/armon/go-metrics"
"github.com/weaveworks/scope/common/fs"
"github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/common/marshal"
"github.com/weaveworks/scope/probe/process"
)
@@ -6,7 +6,7 @@ import (
"testing"
"time"
fs_hook "github.com/weaveworks/scope/common/fs"
fs_hook "github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/test"
)
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"sync"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/probe/host"
"github.com/weaveworks/scope/report"
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/probe/docker"
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"sync"
"time"
"github.com/weaveworks/scope/common/backoff"
"github.com/weaveworks/common/backoff"
"github.com/weaveworks/scope/common/weave"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/host"
+2 -2
View File
@@ -19,8 +19,8 @@ import (
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
"github.com/weaveworks/scope/common/backoff"
"github.com/weaveworks/scope/common/fs"
"github.com/weaveworks/common/backoff"
"github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/common/xfer"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/report"
+1 -1
View File
@@ -18,7 +18,7 @@ import (
"github.com/paypal/ionet"
"github.com/ugorji/go/codec"
fs_hook "github.com/weaveworks/scope/common/fs"
fs_hook "github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/common/xfer"
"github.com/weaveworks/scope/probe/controls"
"github.com/weaveworks/scope/report"
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"time"
"github.com/ugorji/go/codec"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/reflect"
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"github.com/armon/go-metrics"
"github.com/coocood/freecache"
"github.com/weaveworks/scope/common/fs"
"github.com/weaveworks/common/fs"
)
const (
+1 -1
View File
@@ -3,7 +3,7 @@ package process
import (
"strconv"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/report"
)
+1 -1
View File
@@ -10,7 +10,7 @@ import (
linuxproc "github.com/c9s/goprocinfo/linux"
"github.com/weaveworks/scope/common/fs"
"github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/probe/host"
)
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"reflect"
"testing"
fs_hook "github.com/weaveworks/scope/common/fs"
fs_hook "github.com/weaveworks/common/fs"
"github.com/weaveworks/scope/probe/process"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/fs"
+2 -2
View File
@@ -21,10 +21,10 @@ import (
"github.com/weaveworks/go-checkpoint"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/common/middleware"
"github.com/weaveworks/common/network"
"github.com/weaveworks/scope/app"
"github.com/weaveworks/scope/app/multitenant"
"github.com/weaveworks/scope/common/middleware"
"github.com/weaveworks/scope/common/network"
"github.com/weaveworks/scope/common/weave"
"github.com/weaveworks/scope/probe/docker"
)
+2 -2
View File
@@ -16,9 +16,9 @@ import (
"github.com/weaveworks/go-checkpoint"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/common/network"
"github.com/weaveworks/common/sanitize"
"github.com/weaveworks/scope/common/hostname"
"github.com/weaveworks/scope/common/network"
"github.com/weaveworks/scope/common/sanitize"
"github.com/weaveworks/scope/common/weave"
"github.com/weaveworks/scope/common/xfer"
"github.com/weaveworks/scope/probe"
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/host"
"github.com/weaveworks/scope/probe/process"
+1 -1
View File
@@ -3,7 +3,7 @@ package render
import (
"strings"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/endpoint"
"github.com/weaveworks/scope/probe/kubernetes"
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt"
"testing"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/endpoint"
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"time"
"github.com/ugorji/go/codec"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
)
// Controls describe the control tags within the Nodes
+1 -1
View File
@@ -3,7 +3,7 @@ package report
import (
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
)
// Node describes a superset of the metadata that probes can collect about a
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
"github.com/weaveworks/scope/test/reflect"
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/common/xfer"
)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
"time"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
s_reflect "github.com/weaveworks/scope/test/reflect"
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"time"
log "github.com/Sirupsen/logrus"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/common/mtime"
)
// MaxTableRows sets the limit on the table size to render
-22
View File
@@ -1,22 +0,0 @@
package test
import (
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
)
// Diff diffs two arbitrary data structures, giving human-readable output.
func Diff(want, have interface{}) string {
config := spew.NewDefaultConfig()
config.ContinueOnMethod = true
config.SortKeys = true
config.SpewKeys = true
text, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(config.Sdump(want)),
B: difflib.SplitLines(config.Sdump(have)),
FromFile: "want",
ToFile: "have",
Context: 3,
})
return "\n" + text
}
-79
View File
@@ -1,79 +0,0 @@
package exec
import (
"bytes"
"io"
"io/ioutil"
"github.com/weaveworks/scope/common/exec"
)
type mockCmd struct {
io.ReadCloser
quit chan struct{}
}
type blockingReader struct {
quit chan struct{}
}
// NewMockCmdString creates a new mock Cmd which has s on its stdout pipe
func NewMockCmdString(s string) exec.Cmd {
return &mockCmd{
ReadCloser: struct {
io.Reader
io.Closer
}{
bytes.NewBufferString(s),
ioutil.NopCloser(nil),
},
quit: make(chan struct{}),
}
}
// NewMockCmd creates a new mock Cmd with rc as its stdout pipe
func NewMockCmd(rc io.ReadCloser) exec.Cmd {
return &mockCmd{
ReadCloser: rc,
quit: make(chan struct{}),
}
}
func (c *mockCmd) Start() error {
return nil
}
func (c *mockCmd) Wait() error {
return nil
}
func (c *mockCmd) StdoutPipe() (io.ReadCloser, error) {
return c.ReadCloser, nil
}
func (c *mockCmd) StderrPipe() (io.ReadCloser, error) {
return &blockingReader{c.quit}, nil
}
func (c *mockCmd) Kill() error {
close(c.quit)
return nil
}
func (c *mockCmd) Output() ([]byte, error) {
return ioutil.ReadAll(c.ReadCloser)
}
func (c *mockCmd) Run() error {
return nil
}
func (b *blockingReader) Read(p []byte) (n int, err error) {
<-b.quit
return 0, nil
}
func (b *blockingReader) Close() error {
<-b.quit
return nil
}
-287
View File
@@ -1,287 +0,0 @@
package fs
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"syscall"
"time"
"github.com/weaveworks/scope/common/fs"
)
type mockInode struct{}
type dir struct {
mockInode
name string
entries map[string]Entry
stat syscall.Stat_t
}
// File is a mock file
type File struct {
mockInode
FName string
FContents string
FReader io.Reader
FWriter io.Writer
FCloser io.Closer
FStat syscall.Stat_t
}
// Entry is an entry in the mock filesystem
type Entry interface {
os.FileInfo
fs.Interface
Add(path string, e Entry) error
Remove(path string) error
}
// Dir creates a new directory with the given entries.
func Dir(name string, entries ...Entry) Entry {
result := dir{
name: name,
entries: map[string]Entry{},
}
for _, entry := range entries {
result.entries[entry.Name()] = entry
}
return result
}
func split(path string) (string, string) {
if !strings.HasPrefix(path, "/") {
panic(path)
}
comps := strings.SplitN(path, "/", 3)
if len(comps) == 2 {
return comps[1], "/"
}
return comps[1], "/" + comps[2]
}
func (mockInode) Size() int64 { return 0 }
func (mockInode) Mode() os.FileMode { return 0 }
func (mockInode) ModTime() time.Time { return time.Now() }
func (mockInode) Sys() interface{} { return nil }
func (p dir) Name() string { return p.name }
func (p dir) IsDir() bool { return true }
func (p dir) ReadDir(path string) ([]os.FileInfo, error) {
if path == "/" {
result := []os.FileInfo{}
for _, v := range p.entries {
result = append(result, v)
}
return result, nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil, fmt.Errorf("Not found: %s", path)
}
return fs.ReadDir(tail)
}
func (p dir) ReadDirNames(path string) ([]string, error) {
if path == "/" {
result := []string{}
for _, v := range p.entries {
result = append(result, v.Name())
}
return result, nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil, fmt.Errorf("Not found: %s", path)
}
return fs.ReadDirNames(tail)
}
func (p dir) ReadFile(path string) ([]byte, error) {
if path == "/" {
return nil, fmt.Errorf("I'm a directory")
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil, fmt.Errorf("Not found: %s", path)
}
return fs.ReadFile(tail)
}
func (p dir) Lstat(path string, stat *syscall.Stat_t) error {
if path == "/" {
*stat = syscall.Stat_t{Mode: syscall.S_IFDIR}
return nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return fmt.Errorf("Not found: %s", path)
}
return fs.Lstat(tail, stat)
}
func (p dir) Stat(path string, stat *syscall.Stat_t) error {
if path == "/" {
*stat = syscall.Stat_t{Mode: syscall.S_IFDIR}
return nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return fmt.Errorf("Not found: %s", path)
}
return fs.Stat(tail, stat)
}
func (p dir) Open(path string) (io.ReadWriteCloser, error) {
if path == "/" {
return nil, fmt.Errorf("I'm a directory")
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil, fmt.Errorf("Not found: %s", path)
}
return fs.Open(tail)
}
func (p dir) Add(path string, e Entry) error {
if path == "/" {
p.entries[e.Name()] = e
return nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
fs = Dir(head)
p.entries[head] = fs
}
return fs.Add(tail, e)
}
func (p dir) Remove(path string) error {
if _, ok := p.entries[strings.TrimPrefix(path, "/")]; ok {
delete(p.entries, strings.TrimPrefix(path, "/"))
return nil
}
head, tail := split(path)
fs, ok := p.entries[head]
if !ok {
return nil
}
return fs.Remove(tail)
}
// Name implements os.FileInfo
func (p File) Name() string { return p.FName }
// IsDir implements os.FileInfo
func (p File) IsDir() bool { return false }
// ReadDir implements FS
func (p File) ReadDir(path string) ([]os.FileInfo, error) {
return nil, fmt.Errorf("I'm a file")
}
// ReadDirNames implements FS
func (p File) ReadDirNames(path string) ([]string, error) {
return nil, fmt.Errorf("I'm a file")
}
// ReadFile implements FS
func (p File) ReadFile(path string) ([]byte, error) {
if path != "/" {
return nil, fmt.Errorf("I'm a file")
}
if p.FReader != nil {
return ioutil.ReadAll(p.FReader)
}
return []byte(p.FContents), nil
}
// Lstat implements FS
func (p File) Lstat(path string, stat *syscall.Stat_t) error {
if path != "/" {
return fmt.Errorf("I'm a file")
}
*stat = p.FStat
return nil
}
// Stat implements FS
func (p File) Stat(path string, stat *syscall.Stat_t) error {
if path != "/" {
return fmt.Errorf("I'm a file")
}
*stat = p.FStat
return nil
}
// Open implements FS
func (p File) Open(path string) (io.ReadWriteCloser, error) {
if path != "/" {
return nil, fmt.Errorf("I'm a file")
}
buf := bytes.NewBuffer([]byte(p.FContents))
s := struct {
io.Reader
io.Writer
io.Closer
}{
buf, buf, ioutil.NopCloser(nil),
}
if p.FReader != nil {
s.Reader = p.FReader
}
if p.FWriter != nil {
s.Writer = p.FWriter
}
if p.FCloser != nil {
s.Closer = p.FCloser
}
return s, nil
}
// Add adds a new node to the fs
func (p File) Add(path string, e Entry) error {
if path != "/" {
return fmt.Errorf("I'm a file")
}
return nil
}
// Remove removes a node from the fs
func (p File) Remove(path string) error {
if path != "/" {
return fmt.Errorf("I'm a file")
}
return nil
}