diff --git a/docker/Dockerfile b/docker/Dockerfile index cb93e00c..1ce7b72a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,4 +2,4 @@ FROM scratch # EXPOSE 53/udp WORKDIR /home/weave ADD ./weavedns /home/weave/ -ENTRYPOINT ["/home/weave/weavedns", "-wait", "5", "-iface", "ethwe"] +ENTRYPOINT ["/home/weave/weavedns", "-wait", "5", "-iface", "ethwe", "--watch", "--api", "unix:///var/run/docker.sock"] diff --git a/docker/Makefile b/docker/Makefile index 2a164f43..fa46ea64 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,28 +1,19 @@ .DEFAULT: all -all: server-image updater-image +all: server-image weavedns: ../server/*.go ../main.go go get -tags netgo ../ && go build -tags netgo -ldflags '-linkmode external -extldflags "-static"' -o $@ -v ../ -updater: ../updater/main.go - go get -tags netgo ../updater/ && go build -tags netgo -ldflags '-linkmode external -extldflags "-static"' -o $@ -v ../updater/ +.PHONY: server-image -.PHONY: server-image updater-image - -updater-image: /var/tmp/updater.tar server-image: /var/tmp/weavedns.tar /var/tmp/weavedns.tar: Dockerfile weavedns sudo -E docker build -t zettio/weavedns . sudo -E docker save zettio/weavedns > $@ -/var/tmp/updater.tar: ../updater/Dockerfile updater - sudo -E docker build -t zettio/updater ../updater/ - sudo -E docker save zettio/updater > $@ - clean: -sudo docker rmi zettio/weavedns - -sudo docker rmi zettio/updater - rm -f weavedns updater - rm -f /var/tmp/{updater,weavedns}.tar + rm -f weavedns + rm -f /var/tmp/weavedns.tar diff --git a/main.go b/main.go index 5ebcc087..b88917ab 100644 --- a/main.go +++ b/main.go @@ -9,18 +9,31 @@ import ( func main() { var ( ifaceName string + apiPath string dnsPort int httpPort int wait int + watch bool ) flag.StringVar(&ifaceName, "iface", "", "name of interface to use for multicast") + flag.StringVar(&apiPath, "api", "unix:///var/run/docker.sock", "Path to Docker API socket") flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0)") flag.IntVar(&dnsPort, "dnsport", 53, "port to listen to dns requests (defaults to 53)") flag.IntVar(&httpPort, "httpport", 6785, "port to listen to HTTP requests (defaults to 6785)") + flag.BoolVar(&watch, "watch", false, "watch the docker socket for container events") flag.Parse() - err := weavedns.StartServer(ifaceName, dnsPort, httpPort, wait) + var zone = new(weavedns.ZoneDb) + + if watch { + err := weavedns.StartUpdater(apiPath, zone) + if err != nil { + log.Fatal("Unable to start watcher", err) + } + } + + err := weavedns.StartServer(zone, ifaceName, dnsPort, httpPort, wait) if err != nil { log.Fatalf("Failed to start server: %s", err) } diff --git a/server/mdns_server.go b/server/mdns_server.go index d289b642..42249b09 100644 --- a/server/mdns_server.go +++ b/server/mdns_server.go @@ -9,10 +9,10 @@ import ( type MDNSServer struct { localAddrs []net.Addr sendconn *net.UDPConn - zone *ZoneDb + zone Zone } -func NewMDNSServer(zone *ZoneDb) (*MDNSServer, error) { +func NewMDNSServer(zone Zone) (*MDNSServer, error) { //log.Println("minimalServer sending:", buf) // This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work sendconn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) diff --git a/server/server.go b/server/server.go index beee303e..51148bb5 100644 --- a/server/server.go +++ b/server/server.go @@ -100,9 +100,8 @@ func notUsHandler() dns.HandlerFunc { } } -func StartServer(ifaceName string, dnsPort int, httpPort int, wait int) error { +func StartServer(zone Zone, ifaceName string, dnsPort int, httpPort int, wait int) error { - var zone = new(ZoneDb) go ListenHttp(zone, httpPort) var iface *net.Interface = nil diff --git a/server/updater.go b/server/updater.go new file mode 100644 index 00000000..f9527648 --- /dev/null +++ b/server/updater.go @@ -0,0 +1,34 @@ +package weavedns + +import ( + "github.com/fsouza/go-dockerclient" + "log" +) + +func StartUpdater(apiPath string, zone Zone) error { + client, err := docker.NewClient(apiPath) + if err != nil { + log.Fatalf("Unable to connect to Docker API on %s: %s", apiPath, err) + } + + events := make(chan *docker.APIEvents) + client.AddEventListener(events) + + log.Printf("Using Docker API on %s", apiPath) + + go func() { + for event := range events { + handleEvent(zone, event, client) + } + }() + return nil +} + +func handleEvent(zone Zone, event *docker.APIEvents, client *docker.Client) error { + switch event.Status { + case "die": + id := event.ID + zone.DeleteRecordsFor(id) + } + return nil +} diff --git a/server/zone.go b/server/zone.go index d3173949..0cd2adc5 100644 --- a/server/zone.go +++ b/server/zone.go @@ -10,6 +10,7 @@ import ( type Zone interface { AddRecord(string, string, net.IP, net.IP, *net.IPNet) error DeleteRecord(ident string, weave_ip net.IP) error + DeleteRecordsFor(ident string) error MatchLocal(string) (net.IP, error) } @@ -99,3 +100,18 @@ func (zone *ZoneDb) DeleteRecord(ident string, weave_ip net.IP) error { return nil } + +func (zone *ZoneDb) DeleteRecordsFor(ident string) error { + zone.mx.Lock() + defer zone.mx.Unlock() + w := 0 // write index + + for _, r := range zone.recs { + if r.Ident != ident { + zone.recs[w] = r + w++ + } + } + zone.recs = zone.recs[:w] + return nil +} diff --git a/server/zone_test.go b/server/zone_test.go index a3c7b252..1e2bc77c 100644 --- a/server/zone_test.go +++ b/server/zone_test.go @@ -48,4 +48,34 @@ func TestZone(t *testing.T) { if _, ok := err.(LookupError); !ok { t.Fatal("Unexpected result when deleting record", success_test_name, err) } + +} + +func TestDeleteFor(t *testing.T) { + var ( + id = "foobar" + name = "foo.weave." + addr1 = "10.1.2.3/24" + addr2 = "10.2.7.8/24" + docker_ip = "172.16.0.4" + ) + zone := new(ZoneDb) + ip := net.ParseIP(docker_ip) + for _, addr := range []string{addr1, addr2} { + weave_ip, subnet, _ := net.ParseCIDR(addr) + err := zone.AddRecord(id, name, ip, weave_ip, subnet) + if err != nil { + t.Fatal(err) + } + } + + _, err := zone.MatchLocal(name) + if err != nil { + t.Fatal("Did not get result for lookup") + } + err = zone.DeleteRecordsFor(id) + _, err = zone.MatchLocal(name) + if _, ok := err.(LookupError); !ok { + t.Fatal("Expected no results after deleting records for ident") + } } diff --git a/updater/main.go b/updater/main.go deleted file mode 100644 index 63fdcefc..00000000 --- a/updater/main.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "github.com/fsouza/go-dockerclient" - "log" - "net/http" -) - -func main() { - var ( - updatePath string - apiPath string - ) - flag.StringVar(&updatePath, "endpoint", "", "Endpoint to which to send updates") - flag.StringVar(&apiPath, "api", "unix:///var/run/docker.sock", "Path to Docker API socket") - flag.Parse() - - // TODO: check status on endpoint - - client, err := docker.NewClient(apiPath) - if err != nil { - log.Fatalf("Unable to connect to Docker API on %s: %s", apiPath, err) - } - - events := make(chan *docker.APIEvents) - done := make(chan bool) - client.AddEventListener(events) - - log.Printf("Using Docker API on %s", apiPath) - log.Printf("Posting updates to ", updatePath) - - go func() { - for event := range events { - handleEvent(event, client, updatePath) - } - done <- true - }() - <-done -} - -func handleEvent(event *docker.APIEvents, client *docker.Client, endpoint string) error { - switch event.Status { - case "die": - id := event.ID - url := fmt.Sprintf("%s/name/%s", endpoint, id) - client := &http.Client{} - req, _ := http.NewRequest("DELETE", url, nil) - client.Do(req) - } - return nil -}