-
Notifications
You must be signed in to change notification settings - Fork 712
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Have the app periodically register with weaveDNS, and the probe do lo…
…okups there.
- Loading branch information
Showing
75 changed files
with
21,984 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package app | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"strings" | ||
|
||
fsouza "github.com/fsouza/go-dockerclient" | ||
|
||
"github.com/weaveworks/scope/common/backoff" | ||
"github.com/weaveworks/scope/common/weave" | ||
"github.com/weaveworks/scope/probe/docker" | ||
) | ||
|
||
// Default values for weave app integration | ||
const ( | ||
DefaultHostname = "scope.weave.local." | ||
DefaultWeaveURL = "http://127.0.0.1:6784" | ||
DefaultContainerName = "weavescope" | ||
DefaultDockerEndpoint = "unix:///var/run/docker.sock" | ||
) | ||
|
||
// Weave is a thing which periodically registers this app with WeaveDNS. | ||
type Weave struct { | ||
url string | ||
containerName string | ||
hostname string | ||
dockerClient docker.Client | ||
weaveClient weave.Client | ||
backoff backoff.Backoff | ||
} | ||
|
||
// NewWeave makes a new Weave. | ||
func NewWeave(weaveURL, hostname, containerName, dockerEndpoint string) (*Weave, error) { | ||
client, err := docker.NewDockerClientStub(dockerEndpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
w := &Weave{ | ||
url: weaveURL, | ||
containerName: containerName, | ||
hostname: hostname, | ||
dockerClient: client, | ||
weaveClient: weave.NewClient(weaveURL), | ||
} | ||
w.backoff = backoff.New(w.updateDNS) | ||
w.backoff.Message = "updating weaveDNS" | ||
go w.backoff.Start() | ||
return w, nil | ||
} | ||
|
||
// Stop the Weave. | ||
func (w *Weave) Stop() { | ||
w.backoff.Stop() | ||
} | ||
|
||
func (w *Weave) updateDNS() (bool, error) { | ||
// 1. work out my IP addresses | ||
ifaces, err := net.Interfaces() | ||
if err != nil { | ||
return false, err | ||
} | ||
ips := []net.IP{} | ||
for _, i := range ifaces { | ||
if strings.HasPrefix(i.Name, "lo") || | ||
strings.HasPrefix(i.Name, "docker") || | ||
strings.HasPrefix(i.Name, "veth") { | ||
continue | ||
} | ||
|
||
addrs, err := i.Addrs() | ||
if err != nil { | ||
continue | ||
} | ||
for _, addr := range addrs { | ||
var ip net.IP | ||
switch v := addr.(type) { | ||
case *net.IPAddr: | ||
ip = v.IP | ||
case *net.IPNet: | ||
ip = v.IP | ||
} | ||
if ip != nil && ip.To4() != nil { | ||
ips = append(ips, ip) | ||
} | ||
} | ||
} | ||
|
||
// 2. work out my container name | ||
containers, err := w.dockerClient.ListContainers(fsouza.ListContainersOptions{}) | ||
if err != nil { | ||
return false, err | ||
} | ||
containerID := "" | ||
outer: | ||
for _, container := range containers { | ||
for _, name := range container.Names { | ||
if name == "/"+w.containerName { | ||
containerID = container.ID | ||
break outer | ||
} | ||
} | ||
} | ||
if containerID == "" { | ||
return false, fmt.Errorf("Container %s not found", w.containerName) | ||
} | ||
|
||
// 3. Register these with weave dns | ||
for _, ip := range ips { | ||
if err := w.weaveClient.AddDNSEntry(w.hostname, containerID, ip); err != nil { | ||
return false, err | ||
} | ||
} | ||
return false, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package weave | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"net" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
) | ||
|
||
// Client for Weave Net API | ||
type Client interface { | ||
Status() (Status, error) | ||
AddDNSEntry(fqdn, containerid string, ip net.IP) error | ||
} | ||
|
||
// Status describes whats happen in the Weave Net router. | ||
type Status struct { | ||
Router Router | ||
DNS DNS | ||
} | ||
|
||
// Router describes the status of the Weave Router | ||
type Router struct { | ||
Peers []struct { | ||
Name string | ||
NickName string | ||
} | ||
} | ||
|
||
// DNS descirbes the status of Weave DNS | ||
type DNS struct { | ||
Entries []struct { | ||
Hostname string | ||
ContainerID string | ||
Tombstone int64 | ||
} | ||
} | ||
|
||
type client struct { | ||
url string | ||
} | ||
|
||
// NewClient makes a new Client | ||
func NewClient(url string) Client { | ||
return &client{ | ||
url: url, | ||
} | ||
} | ||
|
||
func (c *client) Status() (Status, error) { | ||
req, err := http.NewRequest("GET", c.url+"/report", nil) | ||
if err != nil { | ||
return Status{}, err | ||
} | ||
req.Header.Add("Accept", "application/json") | ||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
return Status{}, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
return Status{}, fmt.Errorf("Got %d", resp.StatusCode) | ||
} | ||
|
||
var status Status | ||
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil { | ||
return Status{}, err | ||
} | ||
return status, nil | ||
} | ||
|
||
func (c *client) AddDNSEntry(fqdn, containerID string, ip net.IP) error { | ||
data := url.Values{ | ||
"fqdn": []string{fqdn}, | ||
} | ||
url := fmt.Sprintf("%s/name/%s/%s", c.url, containerID, ip.String()) | ||
req, err := http.NewRequest("PUT", url, bytes.NewBufferString(data.Encode())) | ||
if err != nil { | ||
return err | ||
} | ||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | ||
req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) | ||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
if err := resp.Body.Close(); err != nil { | ||
return err | ||
} | ||
if resp.StatusCode != http.StatusNoContent { | ||
return fmt.Errorf("Got %d", resp.StatusCode) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package weave_test | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/weaveworks/scope/common/weave" | ||
"github.com/weaveworks/scope/test" | ||
) | ||
|
||
const ( | ||
mockHostID = "host1" | ||
mockWeavePeerName = "winnebago" | ||
mockWeavePeerNickName = "winny" | ||
mockContainerID = "83183a667c01" | ||
mockContainerMAC = "d6:f2:5a:12:36:a8" | ||
mockContainerIP = "10.0.0.123" | ||
mockContainerIPWithScope = ";10.0.0.123" | ||
mockHostname = "hostname.weave.local" | ||
) | ||
|
||
var ( | ||
mockResponse = fmt.Sprintf(`{ | ||
"Router": { | ||
"Peers": [{ | ||
"Name": "%s", | ||
"Nickname": "%s" | ||
}] | ||
}, | ||
"DNS": { | ||
"Entries": [{ | ||
"ContainerID": "%s", | ||
"Hostname": "%s.", | ||
"Tombstone": 0 | ||
}] | ||
} | ||
}`, mockWeavePeerName, mockWeavePeerNickName, mockContainerID, mockHostname) | ||
) | ||
|
||
func mockWeaveRouter(w http.ResponseWriter, r *http.Request) { | ||
if _, err := w.Write([]byte(mockResponse)); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func TestClient(t *testing.T) { | ||
s := httptest.NewServer(http.HandlerFunc(mockWeaveRouter)) | ||
defer s.Close() | ||
|
||
client := weave.NewClient(s.URL) | ||
status, err := client.Status() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
want := weave.Status{ | ||
Router: weave.Router{ | ||
Peers: []struct { | ||
Name string | ||
NickName string | ||
}{ | ||
{ | ||
Name: mockWeavePeerName, | ||
NickName: mockWeavePeerNickName, | ||
}, | ||
}, | ||
}, | ||
DNS: weave.DNS{ | ||
Entries: []struct { | ||
Hostname string | ||
ContainerID string | ||
Tombstone int64 | ||
}{ | ||
{ | ||
Hostname: mockHostname + ".", | ||
ContainerID: mockContainerID, | ||
Tombstone: 0, | ||
}, | ||
}, | ||
}, | ||
} | ||
if !reflect.DeepEqual(status, want) { | ||
t.Fatal(test.Diff(status, want)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.