mirror of
https://github.com/weaveworks/scope.git
synced 2026-08-23 22:36:24 +00:00
Use 'common' library
This commit is contained in:
+1
-1
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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{}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/weaveworks/scope/common/exec"
|
||||
"github.com/weaveworks/common/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -3,7 +3,7 @@ package process
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/common/mtime"
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/common/mtime"
|
||||
"github.com/weaveworks/common/mtime"
|
||||
"github.com/weaveworks/scope/common/xfer"
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user