mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
common/sanitize + relevant updates
This commit is contained in:
39
common/sanitize/sanitize.go
Normal file
39
common/sanitize/sanitize.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package sanitize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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(scheme string, port int, path string) func(string) string {
|
||||
if scheme == "" {
|
||||
scheme = "http://"
|
||||
}
|
||||
return func(s string) string {
|
||||
if s == "" {
|
||||
return s // can't do much here
|
||||
}
|
||||
if !strings.HasPrefix(s, "http") {
|
||||
s = scheme + s
|
||||
}
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
log.Printf("%q: %v", s, err)
|
||||
return s // oh well
|
||||
}
|
||||
if port > 0 {
|
||||
if _, _, err = net.SplitHostPort(u.Host); err != nil {
|
||||
u.Host += fmt.Sprintf(":%d", port)
|
||||
}
|
||||
}
|
||||
if path != "" && u.Path != path {
|
||||
u.Path = path
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
}
|
||||
34
common/sanitize/sanitize_test.go
Normal file
34
common/sanitize/sanitize_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
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...
|
||||
{"", 9999, "", "foo:80", "http://foo:80"}, // specified port beats default...
|
||||
{"", 0, "/bar", "foo/baz", "http://foo/bar"}, // ...but default path beats specified!
|
||||
} {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func main() {
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
publisher, err := xfer.NewHTTPPublisher(*publish, "demoprobe", "demoprobe")
|
||||
_, publisher, err := xfer.NewHTTPPublisher(*publish, "demoprobe", "demoprobe")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func main() {
|
||||
}
|
||||
f.Close()
|
||||
|
||||
publisher, err := xfer.NewHTTPPublisher(*publish, "fixprobe", "fixprobe")
|
||||
_, publisher, err := xfer.NewHTTPPublisher(*publish, "fixprobe", "fixprobe")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func main() {
|
||||
}
|
||||
|
||||
publisherFactory := func(target string) (xfer.Publisher, error) {
|
||||
publisher, err := xfer.NewHTTPPublisher(target, *token, probeID)
|
||||
_, publisher, err := xfer.NewHTTPPublisher(target, *token, probeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -133,10 +133,7 @@ func main() {
|
||||
}
|
||||
|
||||
if *weaveRouterAddr != "" {
|
||||
weave, err := overlay.NewWeave(hostID, *weaveRouterAddr)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to start Weave tagger: %v", err)
|
||||
}
|
||||
weave := overlay.NewWeave(hostID, *weaveRouterAddr)
|
||||
tickers = append(tickers, weave)
|
||||
taggers = append(taggers, weave)
|
||||
reporters = append(reporters, weave)
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/weaveworks/scope/common/sanitize"
|
||||
|
||||
"github.com/weaveworks/scope/common/exec"
|
||||
"github.com/weaveworks/scope/probe/docker"
|
||||
"github.com/weaveworks/scope/report"
|
||||
@@ -68,15 +68,11 @@ type weaveStatus struct {
|
||||
|
||||
// NewWeave returns a new Weave tagger based on the Weave router at
|
||||
// address. The address should be an IP or FQDN, no port.
|
||||
func NewWeave(hostID, weaveRouterAddress string) (*Weave, error) {
|
||||
s, err := sanitize("http://", 6784, "/report")(weaveRouterAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func NewWeave(hostID, weaveRouterAddress string) *Weave {
|
||||
return &Weave{
|
||||
url: s,
|
||||
url: sanitize.URL("http://", 6784, "/report")(weaveRouterAddress),
|
||||
hostID: hostID,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Tick implements Ticker
|
||||
@@ -202,25 +198,3 @@ func (w *Weave) Report() (report.Report, error) {
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func sanitize(scheme string, port int, path string) func(string) (string, error) {
|
||||
return func(s string) (string, error) {
|
||||
if s == "" {
|
||||
return "", fmt.Errorf("no host")
|
||||
}
|
||||
if !strings.HasPrefix(s, "http") {
|
||||
s = scheme + s
|
||||
}
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, _, err = net.SplitHostPort(u.Host); err != nil {
|
||||
u.Host += fmt.Sprintf(":%d", port)
|
||||
}
|
||||
if u.Path != path {
|
||||
u.Path = path
|
||||
}
|
||||
return u.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,7 @@ func TestWeaveTaggerOverlayTopology(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter))
|
||||
defer s.Close()
|
||||
|
||||
w, err := overlay.NewWeave(mockHostID, s.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w := overlay.NewWeave(mockHostID, s.URL)
|
||||
w.Tick()
|
||||
|
||||
{
|
||||
|
||||
@@ -2,13 +2,15 @@ package xfer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/scope/common/sanitize"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,7 +19,7 @@ const (
|
||||
)
|
||||
|
||||
// Publisher is something which can send a buffered set of data somewhere,
|
||||
// probably to a collector.
|
||||
// probably to a remote collector.
|
||||
type Publisher interface {
|
||||
Publish(*bytes.Buffer) error
|
||||
Stop()
|
||||
@@ -25,9 +27,9 @@ type Publisher interface {
|
||||
|
||||
// HTTPPublisher publishes reports by POST to a fixed endpoint.
|
||||
type HTTPPublisher struct {
|
||||
url string
|
||||
token string
|
||||
id string
|
||||
url string
|
||||
token string
|
||||
probeID string
|
||||
}
|
||||
|
||||
// ScopeProbeIDHeader is the header we use to carry the probe's unique ID. The
|
||||
@@ -37,21 +39,23 @@ type HTTPPublisher struct {
|
||||
const ScopeProbeIDHeader = "X-Scope-Probe-ID"
|
||||
|
||||
// NewHTTPPublisher returns an HTTPPublisher ready for use.
|
||||
func NewHTTPPublisher(target, token, id string) (*HTTPPublisher, error) {
|
||||
if !strings.HasPrefix(target, "http") {
|
||||
target = "http://" + target
|
||||
}
|
||||
u, err := url.Parse(target)
|
||||
func NewHTTPPublisher(target, token, probeID string) (string, *HTTPPublisher, error) {
|
||||
targetAPI := sanitize.URL("http://", 0, "/api")(target)
|
||||
resp, err := http.Get(targetAPI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
if u.Path == "" {
|
||||
u.Path = "/api/report"
|
||||
defer resp.Body.Close()
|
||||
var apiResponse struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
return &HTTPPublisher{
|
||||
url: u.String(),
|
||||
token: token,
|
||||
id: id,
|
||||
if err := json.NewDecoder(resp.Body).Decode(&apiResponse); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return apiResponse.ID, &HTTPPublisher{
|
||||
url: sanitize.URL("http://", 0, "/api/report")(target),
|
||||
token: token,
|
||||
probeID: probeID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -65,9 +69,8 @@ func (p HTTPPublisher) Publish(buf *bytes.Buffer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", AuthorizationHeader(p.token))
|
||||
req.Header.Set(ScopeProbeIDHeader, p.id)
|
||||
req.Header.Set(ScopeProbeIDHeader, p.probeID)
|
||||
req.Header.Set("Content-Encoding", "gzip")
|
||||
// req.Header.Set("Content-Type", "application/binary") // TODO: we should use http.DetectContentType(..) on the gob'ed
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
@@ -27,6 +28,11 @@ func TestHTTPPublisher(t *testing.T) {
|
||||
)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/api" {
|
||||
json.NewEncoder(w).Encode(map[string]string{"id": "irrelevant"})
|
||||
return
|
||||
}
|
||||
|
||||
if want, have := xfer.AuthorizationHeader(token), r.Header.Get("Authorization"); want != have {
|
||||
t.Errorf("want %q, have %q", want, have)
|
||||
}
|
||||
@@ -61,7 +67,7 @@ func TestHTTPPublisher(t *testing.T) {
|
||||
s := httptest.NewServer(handlers.CompressHandler(handler))
|
||||
defer s.Close()
|
||||
|
||||
p, err := xfer.NewHTTPPublisher(s.URL, token, id)
|
||||
_, p, err := xfer.NewHTTPPublisher(s.URL, token, id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user