mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 18:51:17 +00:00
Now that we enter the container namespace to fetch IPs for every container, there is no need to have 'weave ps' do it. This does mean we lose Weave MAC addresses, but that is a rather idiosyncratic feature anyway.
203 lines
4.4 KiB
Go
203 lines
4.4 KiB
Go
package weave
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
realexec "os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
|
|
"github.com/ugorji/go/codec"
|
|
|
|
"github.com/weaveworks/common/exec"
|
|
)
|
|
|
|
const dockerAPIVersion = "1.22" // Support Docker Engine >= 1.10
|
|
|
|
// Client for Weave Net API
|
|
type Client interface {
|
|
Status() (Status, error)
|
|
AddDNSEntry(fqdn, containerid string, ip net.IP) error
|
|
Expose() error // on the interface for mocking
|
|
}
|
|
|
|
// Status describes whats happen in the Weave Net router.
|
|
type Status struct {
|
|
Version string
|
|
Router Router
|
|
DNS *DNS
|
|
IPAM *IPAM
|
|
Proxy *Proxy
|
|
Plugin *Plugin
|
|
}
|
|
|
|
// Router describes the status of the Weave Router
|
|
type Router struct {
|
|
Name string
|
|
Encryption bool
|
|
ProtocolMinVersion int
|
|
ProtocolMaxVersion int
|
|
PeerDiscovery bool
|
|
Peers []Peer
|
|
Connections []struct {
|
|
Address string
|
|
Outbound bool
|
|
State string
|
|
Info string
|
|
}
|
|
Targets []string
|
|
TrustedSubnets []string
|
|
}
|
|
|
|
// Peer describes a peer in the weave network
|
|
type Peer struct {
|
|
Name string
|
|
NickName string
|
|
Connections []struct {
|
|
Name string
|
|
NickName string
|
|
Address string
|
|
Outbound bool
|
|
Established bool
|
|
}
|
|
}
|
|
|
|
// DNS describes the status of Weave DNS
|
|
type DNS struct {
|
|
Domain string
|
|
Upstream []string
|
|
TTL uint32
|
|
Entries []struct {
|
|
Hostname string
|
|
ContainerID string
|
|
Tombstone int64
|
|
}
|
|
}
|
|
|
|
// IPAM describes the status of Weave IPAM
|
|
type IPAM struct {
|
|
Paxos *struct {
|
|
Elector bool
|
|
KnownNodes int
|
|
Quorum uint
|
|
}
|
|
Range string
|
|
DefaultSubnet string
|
|
Entries []struct {
|
|
Size uint32
|
|
IsKnownPeer bool
|
|
}
|
|
PendingAllocates []string
|
|
}
|
|
|
|
// Proxy describes the status of Weave Proxy
|
|
type Proxy struct {
|
|
Addresses []string
|
|
}
|
|
|
|
// Plugin describes the status of the Weave Plugin
|
|
type Plugin struct {
|
|
DriverName string
|
|
}
|
|
|
|
var ipMatch = regexp.MustCompile(`([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(/[0-9]+)`)
|
|
|
|
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{}, errorf("%v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return Status{}, fmt.Errorf("Got %d", resp.StatusCode)
|
|
}
|
|
|
|
var status Status
|
|
decoder := codec.NewDecoder(resp.Body, &codec.JsonHandle{})
|
|
if err := decoder.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 errorf("%v", err)
|
|
}
|
|
if err := resp.Body.Close(); err != nil {
|
|
return err
|
|
}
|
|
if resp.StatusCode != http.StatusNoContent {
|
|
return fmt.Errorf("Got %d", resp.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *client) Expose() error {
|
|
cmd := weaveCommand("--local", "ps", "weave:expose")
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
stdErr := []byte{}
|
|
if exitErr, ok := err.(*realexec.ExitError); ok {
|
|
stdErr = exitErr.Stderr
|
|
}
|
|
return errorf("Error running weave ps: %s: %q", err, stdErr)
|
|
}
|
|
ips := ipMatch.FindAllSubmatch(output, -1)
|
|
if ips != nil {
|
|
// Alread exposed!
|
|
return nil
|
|
}
|
|
cmd = weaveCommand("--local", "expose")
|
|
if _, err := cmd.Output(); err != nil {
|
|
stdErr := []byte{}
|
|
if exitErr, ok := err.(*realexec.ExitError); ok {
|
|
stdErr = exitErr.Stderr
|
|
}
|
|
return errorf("Error running weave expose: %s: %q", err, stdErr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func weaveCommand(arg ...string) exec.Cmd {
|
|
cmd := exec.Command("weave", arg...)
|
|
cmd.SetEnv(append(os.Environ(), "DOCKER_API_VERSION="+dockerAPIVersion))
|
|
return cmd
|
|
}
|
|
|
|
func errorf(format string, a ...interface{}) error {
|
|
return fmt.Errorf(format+". If you are not running Weave Net, you may wish to suppress this warning by launching scope with the `--weave=false` option.", a...)
|
|
}
|