func (alloc *Allocator) handleHTTPAllocate(dockerCli *docker.Client, w http.ResponseWriter, ident string, checkAlive bool, subnet address.CIDR) { closedChan := w.(http.CloseNotifier).CloseNotify() addr, err := alloc.Allocate(ident, subnet.HostRange(), func() bool { select { case <-closedChan: return true default: res := checkAlive && dockerCli != nil && dockerCli.IsContainerNotRunning(ident) checkAlive = false // we check only once; if the container dies later we learn about that through events return res } }) if err != nil { if _, ok := err.(*errorCancelled); ok { // cancellation is not really an error common.Log.Infoln("[allocator]:", err.Error()) fmt.Fprint(w, "cancelled") return } badRequest(w, err) return } fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen) }
func hasBeenCancelled(dockerCli *docker.Client, closedChan <-chan bool, ident string, checkAlive bool) func() bool { return func() bool { select { case <-closedChan: return true default: res := checkAlive && dockerCli != nil && dockerCli.IsContainerNotRunning(ident) checkAlive = false // we check only once; if the container dies later we learn about that through events return res } } }
func (alloc *Allocator) handleHTTPAllocate(dockerCli *docker.Client, w http.ResponseWriter, ident string, checkAlive bool, subnet address.CIDR) { closedChan := w.(http.CloseNotifier).CloseNotify() addr, err := alloc.Allocate(ident, subnet.HostRange(), closedChan) if err != nil { if _, ok := err.(*errorCancelled); ok { // cancellation is not really an error common.Log.Infoln("[allocator]:", err.Error()) fmt.Fprint(w, "cancelled") return } badRequest(w, err) return } if checkAlive && dockerCli != nil && dockerCli.IsContainerNotRunning(ident) { common.Log.Infof("[allocator] '%s' is not running: freeing %s", ident, addr) alloc.Free(ident, addr) fmt.Fprint(w, "cancelled") return } fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen) }
// HandleHTTP wires up ipams HTTP endpoints to the provided mux. func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, dockerCli *docker.Client) { router.Methods("PUT").Path("/ip/{id}/{ip}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { closedChan := w.(http.CloseNotifier).CloseNotify() vars := mux.Vars(r) ident := vars["id"] ipStr := vars["ip"] if ip, err := address.ParseIP(ipStr); err != nil { badRequest(w, err) return } else if err := alloc.Claim(ident, ip, closedChan); err != nil { badRequest(w, fmt.Errorf("Unable to claim: %s", err)) return } w.WriteHeader(204) }) router.Methods("GET").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) cidr := vars["ip"] + "/" + vars["prefixlen"] _, subnet, err := address.ParseCIDR(cidr) if err != nil { badRequest(w, err) return } addr, err := alloc.Lookup(vars["id"], subnet.HostRange()) if err != nil { http.NotFound(w, r) return } fmt.Fprintf(w, "%s/%d", addr, subnet.PrefixLen) }) router.Methods("GET").Path("/ip/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { addr, err := alloc.Lookup(mux.Vars(r)["id"], defaultSubnet.HostRange()) if err != nil { http.NotFound(w, r) return } fmt.Fprintf(w, "%s/%d", addr, defaultSubnet.PrefixLen) }) router.Methods("POST").Path("/ip/{id}/{ip}/{prefixlen}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { closedChan := w.(http.CloseNotifier).CloseNotify() vars := mux.Vars(r) ident := vars["id"] cidrStr := vars["ip"] + "/" + vars["prefixlen"] subnetAddr, cidr, err := address.ParseCIDR(cidrStr) if err != nil { badRequest(w, err) return } if cidr.Start != subnetAddr { badRequest(w, fmt.Errorf("Invalid subnet %s - bits after network prefix are not all zero", cidrStr)) return } addr, err := alloc.Allocate(ident, cidr.HostRange(), closedChan) if err != nil { badRequest(w, fmt.Errorf("Unable to allocate: %s", err)) return } if dockerCli != nil && dockerCli.IsContainerNotRunning(ident) { common.Log.Infof("[allocator] '%s' is not running: freeing %s", ident, addr) alloc.Free(ident, addr) return } fmt.Fprintf(w, "%s/%d", addr, cidr.PrefixLen) }) router.Methods("POST").Path("/ip/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { closedChan := w.(http.CloseNotifier).CloseNotify() ident := mux.Vars(r)["id"] newAddr, err := alloc.Allocate(ident, defaultSubnet.HostRange(), closedChan) if err != nil { badRequest(w, err) return } if dockerCli != nil && dockerCli.IsContainerNotRunning(ident) { common.Log.Infof("[allocator] '%s' is not running: freeing %s", ident, newAddr) alloc.Free(ident, newAddr) return } fmt.Fprintf(w, "%s/%d", newAddr, defaultSubnet.PrefixLen) }) router.Methods("DELETE").Path("/ip/{id}/{ip}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) ident := vars["id"] ipStr := vars["ip"] if ip, err := address.ParseIP(ipStr); err != nil { badRequest(w, err) return } else if err := alloc.Free(ident, ip); err != nil { badRequest(w, fmt.Errorf("Unable to free: %s", err)) return } w.WriteHeader(204) }) router.Methods("DELETE").Path("/ip/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ident := mux.Vars(r)["id"] if err := alloc.Delete(ident); err != nil { badRequest(w, err) return } w.WriteHeader(204) }) router.Methods("DELETE").Path("/peer").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { alloc.Shutdown() w.WriteHeader(204) }) router.Methods("DELETE").Path("/peer/{id}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ident := mux.Vars(r)["id"] if err := alloc.AdminTakeoverRanges(ident); err != nil { badRequest(w, err) return } w.WriteHeader(204) }) }
func (n *Nameserver) HandleHTTP(router *mux.Router, dockerCli *docker.Client) { router.Methods("GET").Path("/domain").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, n.domain) }) router.Methods("PUT").Path("/name/{container}/{ip}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( vars = mux.Vars(r) container = vars["container"] ipStr = vars["ip"] hostname = dns.Fqdn(r.FormValue("fqdn")) ip, err = address.ParseIP(ipStr) ) if err != nil { n.badRequest(w, err) return } if err := n.AddEntry(hostname, container, n.ourName, ip); err != nil { n.badRequest(w, fmt.Errorf("Unable to add entry: %v", err)) return } if r.FormValue("check-alive") == "true" && dockerCli != nil && dockerCli.IsContainerNotRunning(container) { n.infof("container '%s' is not running: removing", container) if err := n.Delete(hostname, container, ipStr, ip); err != nil { n.infof("failed to remove: %v", err) } } w.WriteHeader(204) }) deleteHandler := func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) hostname := r.FormValue("fqdn") if hostname == "" { hostname = "*" } else { hostname = dns.Fqdn(hostname) } container, ok := vars["container"] if !ok { container = "*" } ipStr, ok := vars["ip"] ip, err := address.ParseIP(ipStr) if ok && err != nil { n.badRequest(w, err) return } else if !ok { ipStr = "*" } if err := n.Delete(hostname, container, ipStr, ip); err != nil { n.badRequest(w, fmt.Errorf("Unable to delete entries: %v", err)) return } w.WriteHeader(204) } router.Methods("DELETE").Path("/name/{container}/{ip}").HandlerFunc(deleteHandler) router.Methods("DELETE").Path("/name/{container}").HandlerFunc(deleteHandler) router.Methods("DELETE").Path("/name").HandlerFunc(deleteHandler) router.Methods("GET").Path("/name").Headers("Accept", "application/json").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { n.RLock() defer n.RUnlock() if err := json.NewEncoder(w).Encode(n.entries); err != nil { n.badRequest(w, fmt.Errorf("Error marshalling response: %v", err)) } }) }
func ServeHTTP(listener net.Listener, version string, server *DNSServer, dockerCli *docker.Client) { muxRouter := mux.NewRouter() muxRouter.Methods("GET").Path("/status").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "weave DNS", version) fmt.Fprintln(w, server.Status()) fmt.Fprintln(w, server.Zone.Status()) }) muxRouter.Methods("GET").Path("/domain").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, server.Zone.Domain()) }) muxRouter.Methods("PUT").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reqError := func(msg string, logmsg string, logargs ...interface{}) { httpErrorAndLog(Warning, w, msg, http.StatusBadRequest, logmsg, logargs...) } vars := mux.Vars(r) idStr := vars["id"] ipStr := vars["ip"] name := r.FormValue("fqdn") if name == "" { reqError("Invalid FQDN", "Invalid FQDN in request: %s, %s", r.URL, r.Form) return } ip := net.ParseIP(ipStr) if ip == nil { reqError("Invalid IP", "Invalid IP in request: %s", ipStr) return } domain := server.Zone.Domain() if !dns.IsSubDomain(domain, name) { Info.Printf("[http] Ignoring name %s, not in %s", name, domain) return } Info.Printf("[http] Adding %s -> %s", name, ipStr) if err := server.Zone.AddRecord(idStr, name, ip); err != nil { if _, ok := err.(DuplicateError); !ok { httpErrorAndLog( Error, w, "Internal error", http.StatusInternalServerError, "Unexpected error from DB: %s", err) return } // oh, I already know this. whatever. } if dockerCli != nil && dockerCli.IsContainerNotRunning(idStr) { Info.Printf("[http] '%s' is not running: removing", idStr) server.Zone.DeleteRecords(idStr, name, ip) } }) muxRouter.Methods("DELETE").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) idStr := vars["id"] ipStr := vars["ip"] ip := net.ParseIP(ipStr) if ip == nil { httpErrorAndLog( Warning, w, "Invalid IP in request", http.StatusBadRequest, "Invalid IP in request: %s", ipStr) return } fqdnStr, fqdn := extractFQDN(r) Info.Printf("[http] Deleting ID %s, IP %s, FQDN %s", idStr, ipStr, fqdnStr) server.Zone.DeleteRecords(idStr, fqdn, ip) }) muxRouter.Methods("DELETE").Path("/name/{id:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) idStr := vars["id"] fqdnStr, fqdn := extractFQDN(r) Info.Printf("[http] Deleting ID %s, IP *, FQDN %s", idStr, fqdnStr) server.Zone.DeleteRecords(idStr, fqdn, net.IP{}) }) muxRouter.Methods("DELETE").Path("/name").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fqdnStr, fqdn := extractFQDN(r) Info.Printf("[http] Deleting ID *, IP *, FQDN %s", fqdnStr) server.Zone.DeleteRecords("", fqdn, net.IP{}) }) http.Handle("/", muxRouter) if err := http.Serve(listener, nil); err != nil { Error.Fatal("[http] Unable to serve http: ", err) } }