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 NewIpam(client *docker.Client, version string) (ipamapi.Ipam, error) { resolver := func() (string, error) { addr, err := client.GetContainerIP(WeaveContainer) if _, ok := err.(*godocker.NoSuchContainer); ok { return "", fmt.Errorf("%s container is not present. Have you launched it?", WeaveContainer) } return addr, err } return &ipam{client: client, weave: api.NewClientWithResolver(resolver)}, nil }
func NewWatcher(client *docker.Client, driver *driver) (Watcher, error) { resolver := func() (string, error) { return client.GetContainerIP(WeaveContainer) } w := &watcher{client: client, driver: driver, weave: weaveapi.NewClientWithResolver(resolver)} err := client.AddObserver(w) if err != nil { return nil, err } return w, nil }
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 NewIpam(client *docker.Client, version string) (ipamapi.Ipam, error) { resolver := func() (string, error) { return client.GetContainerIP(WeaveContainer) } return &ipam{client: client, weave: api.NewClientWithResolver(resolver)}, nil }
func main() { procs := runtime.NumCPU() // packet sniffing can block an OS thread, so we need one thread // for that plus at least one more. if procs < 2 { procs = 2 } runtime.GOMAXPROCS(procs) var ( justVersion bool config mesh.Config networkConfig weave.NetworkConfig protocolMinVersion int resume bool ifaceName string routerName string nickName string password string pktdebug bool logLevel string prof string bufSzMB int noDiscovery bool httpAddr string ipamConfig ipamConfig dockerAPI string peers []string noDNS bool dnsConfig dnsConfig datapathName string trustedSubnetStr string dbPrefix string isAWSVPC bool defaultDockerHost = "unix:///var/run/docker.sock" ) if val := os.Getenv("DOCKER_HOST"); val != "" { defaultDockerHost = val } mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit") mflag.StringVar(&config.Host, []string{"-host"}, "", "router host") mflag.IntVar(&config.Port, []string{"#port", "-port"}, mesh.Port, "router port") mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, mesh.ProtocolMinVersion, "minimum weave protocol version") mflag.BoolVar(&resume, []string{"-resume"}, false, "resume connections to previous peers") mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)") mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)") mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)") mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") mflag.BoolVar(&pktdebug, []string{"#pktdebug", "#-pktdebug", "-pkt-debug"}, false, "enable per-packet debug logging") mflag.StringVar(&prof, []string{"#profile", "-profile"}, "", "enable profiling and write profiles to given path") mflag.IntVar(&config.ConnLimit, []string{"#connlimit", "#-connlimit", "-conn-limit"}, 30, "connection limit (0 for unlimited)") mflag.BoolVar(&noDiscovery, []string{"#nodiscovery", "#-nodiscovery", "-no-discovery"}, false, "disable peer discovery") mflag.IntVar(&bufSzMB, []string{"#bufsz", "-bufsz"}, 8, "capture buffer size in MB") mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, "", "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)") mflag.StringVar(&ipamConfig.Mode, []string{"-ipalloc-init"}, "", "allocator initialisation strategy (consensus, seed or observer)") mflag.StringVar(&ipamConfig.IPRangeCIDR, []string{"#iprange", "#-iprange", "-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation") mflag.StringVar(&ipamConfig.IPSubnetCIDR, []string{"#ipsubnet", "#-ipsubnet", "-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation") mflag.IntVar(&ipamConfig.PeerCount, []string{"#initpeercount", "#-initpeercount", "-init-peer-count"}, 0, "number of peers in network (for IP address allocation)") mflag.StringVar(&dockerAPI, []string{"#api", "#-api", "-docker-api"}, defaultDockerHost, "Docker API endpoint") mflag.BoolVar(&noDNS, []string{"-no-dns"}, false, "disable DNS server") mflag.StringVar(&dnsConfig.Domain, []string{"-dns-domain"}, nameserver.DefaultDomain, "local domain to server requests for") mflag.StringVar(&dnsConfig.ListenAddress, []string{"-dns-listen-address"}, nameserver.DefaultListenAddress, "address to listen on for DNS requests") mflag.IntVar(&dnsConfig.TTL, []string{"-dns-ttl"}, nameserver.DefaultTTL, "TTL for DNS request from our domain") mflag.DurationVar(&dnsConfig.ClientTimeout, []string{"-dns-fallback-timeout"}, nameserver.DefaultClientTimeout, "timeout for fallback DNS requests") mflag.StringVar(&dnsConfig.EffectiveListenAddress, []string{"-dns-effective-listen-address"}, "", "address DNS will actually be listening, after Docker port mapping") mflag.StringVar(&dnsConfig.ResolvConf, []string{"-resolv-conf"}, "", "path to resolver configuration for fallback DNS lookups") mflag.StringVar(&datapathName, []string{"-datapath"}, "", "ODP datapath name") mflag.StringVar(&trustedSubnetStr, []string{"-trusted-subnets"}, "", "comma-separated list of trusted subnets in CIDR notation") mflag.StringVar(&dbPrefix, []string{"-db-prefix"}, "/weavedb/weave", "pathname/prefix of filename to store data") mflag.BoolVar(&isAWSVPC, []string{"-awsvpc"}, false, "use AWS VPC for routing") // crude way of detecting that we probably have been started in a // container, with `weave launch` --> suppress misleading paths in // mflags error messages. if os.Args[0] == "/home/weave/weaver" { // matches the Dockerfile ENTRYPOINT os.Args[0] = "weave" mflag.CommandLine.Init("weave", mflag.ExitOnError) } mflag.Parse() peers = mflag.Args() if resume && len(peers) > 0 { Log.Fatalf("You must not specify an initial peer list in conjunction with --resume") } common.SetLogLevel(logLevel) if justVersion { fmt.Printf("weave router %s\n", version) os.Exit(0) } Log.Println("Command line options:", options()) if prof != "" { defer profile.Start(profile.CPUProfile, profile.ProfilePath(prof), profile.NoShutdownHook).Stop() } if protocolMinVersion < mesh.ProtocolMinVersion || protocolMinVersion > mesh.ProtocolMaxVersion { Log.Fatalf("--min-protocol-version must be in range [%d,%d]", mesh.ProtocolMinVersion, mesh.ProtocolMaxVersion) } config.ProtocolMinVersion = byte(protocolMinVersion) if pktdebug { networkConfig.PacketLogging = packetLogging{} } else { networkConfig.PacketLogging = nopPacketLogging{} } overlay, bridge := createOverlay(datapathName, ifaceName, isAWSVPC, config.Host, config.Port, bufSzMB) networkConfig.Bridge = bridge name := peerName(routerName, bridge.Interface()) if nickName == "" { var err error nickName, err = os.Hostname() checkFatal(err) } config.Password = determinePassword(password) config.TrustedSubnets = parseTrustedSubnets(trustedSubnetStr) config.PeerDiscovery = !noDiscovery if isAWSVPC && len(config.Password) > 0 { Log.Fatalf("--awsvpc mode is not compatible with the --password option") } db, err := db.NewBoltDB(dbPrefix + "data.db") checkFatal(err) defer db.Close() router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlay, db) Log.Println("Our name is", router.Ourself) if peers, err = router.InitialPeers(resume, peers); err != nil { Log.Fatal("Unable to get initial peer set: ", err) } var dockerCli *docker.Client dockerVersion := "none" if dockerAPI != "" { dc, err := docker.NewClient(dockerAPI) if err != nil { Log.Fatal("Unable to start docker client: ", err) } else { Log.Info(dc.Info()) } dockerCli = dc dockerVersion = dockerCli.DockerVersion() } network := "" if isAWSVPC { network = "awsvpc" } checkForUpdates(dockerVersion, network) observeContainers := func(o docker.ContainerObserver) { if dockerCli != nil { if err := dockerCli.AddObserver(o); err != nil { Log.Fatal("Unable to start watcher", err) } } } isKnownPeer := func(name mesh.PeerName) bool { return router.Peers.Fetch(name) != nil } var ( allocator *ipam.Allocator defaultSubnet address.CIDR trackerName string ) if ipamConfig.Enabled() { var t tracker.LocalRangeTracker if isAWSVPC { Log.Infoln("Creating AWSVPC LocalRangeTracker") t, err = tracker.NewAWSVPCTracker() if err != nil { Log.Fatalf("Cannot create AWSVPC LocalRangeTracker: %s", err) } trackerName = "awsvpc" } allocator, defaultSubnet = createAllocator(router, ipamConfig, db, t, isKnownPeer) observeContainers(allocator) if dockerCli != nil { ids, err := dockerCli.AllContainerIDs() checkFatal(err) allocator.PruneOwned(ids) } } var ( ns *nameserver.Nameserver dnsserver *nameserver.DNSServer ) if !noDNS { ns, dnsserver = createDNSServer(dnsConfig, router.Router, isKnownPeer) observeContainers(ns) ns.Start() defer ns.Stop() dnsserver.ActivateAndServe() defer dnsserver.Stop() } router.Start() if errors := router.InitiateConnections(peers, false); len(errors) > 0 { Log.Fatal(common.ErrorMessages(errors)) } // The weave script always waits for a status call to succeed, // so there is no point in doing "weave launch --http-addr ''". // This is here to support stand-alone use of weaver. if httpAddr != "" { muxRouter := mux.NewRouter() if allocator != nil { allocator.HandleHTTP(muxRouter, defaultSubnet, trackerName, dockerCli) } if ns != nil { ns.HandleHTTP(muxRouter, dockerCli) } router.HandleHTTP(muxRouter) HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver) http.Handle("/", common.LoggingHTTPHandler(muxRouter)) Log.Println("Listening for HTTP control messages on", httpAddr) go listenAndServeHTTP(httpAddr) } common.SignalHandlerLoop(router) }
func main() { var ( justVersion bool dockerCli *docker.Client ifaceName string apiPath string domain string dnsPort int httpIfaceName string httpPort int wait int ttl int negTTL int timeout int udpbuf int fallback string refreshInterval int relevantTime int maxAnswers int cacheLen int cacheDisabled bool watch bool logLevel string err error ) mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit") mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to use for multicast") mflag.StringVar(&apiPath, []string{"#api", "-api"}, "unix:///var/run/docker.sock", "path to Docker API socket") mflag.StringVar(&domain, []string{"#domain", "-domain"}, weavedns.DefaultLocalDomain, "local domain (ie, 'weave.local.')") mflag.IntVar(&wait, []string{"#wait", "-wait"}, -1, "number of seconds to wait for interfaces to come up (0=don't wait, -1=wait forever)") mflag.IntVar(&dnsPort, []string{"#dnsport", "#-dnsport", "-dns-port"}, weavedns.DefaultServerPort, "port to listen to DNS requests") mflag.StringVar(&httpIfaceName, []string{"#httpiface", "#-httpiface", "-http-iface"}, "", "interface on which to listen for HTTP requests (empty string means listen on all interfaces)") mflag.IntVar(&httpPort, []string{"#httpport", "#-httpport", "-http-port"}, weavedns.DefaultHTTPPort, "port to listen to HTTP requests") mflag.IntVar(&cacheLen, []string{"#cache", "-cache"}, weavedns.DefaultCacheLen, "cache length") mflag.IntVar(&ttl, []string{"#ttl", "-ttl"}, weavedns.DefaultLocalTTL, "TTL (in secs) for responses for local names") mflag.BoolVar(&watch, []string{"#watch", "-watch"}, true, "watch the docker socket for container events") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") // advanced options mflag.IntVar(&negTTL, []string{"#neg-ttl", "-neg-ttl"}, 0, "negative TTL (in secs) for unanswered queries for local names (0=same value as --ttl") mflag.IntVar(&refreshInterval, []string{"#refresh", "-refresh"}, weavedns.DefaultRefreshInterval, "refresh interval (in secs) for local names (0=disable)") mflag.IntVar(&maxAnswers, []string{"#max-answers", "#-max-answers", "-dns-max-answers"}, weavedns.DefaultMaxAnswers, "maximum number of answers returned to clients (0=unlimited)") mflag.IntVar(&relevantTime, []string{"#relevant", "-relevant"}, weavedns.DefaultRelevantTime, "life time for info in the absence of queries (in secs)") mflag.IntVar(&udpbuf, []string{"#udpbuf", "#-udpbuf", "-dns-udpbuf"}, weavedns.DefaultUDPBuflen, "UDP buffer length for DNS") mflag.IntVar(&timeout, []string{"#timeout", "#-timeout", "-dns-timeout"}, weavedns.DefaultTimeout, "timeout for resolutions (in millisecs)") mflag.BoolVar(&cacheDisabled, []string{"#no-cache", "-no-cache"}, false, "disable the cache") mflag.StringVar(&fallback, []string{"#fallback", "#-fallback", "-dns-fallback"}, "", "force a fallback server (ie, '8.8.8.8:53') (instead of /etc/resolv.conf values)") mflag.Parse() if justVersion { fmt.Printf("weave DNS %s\n", version) os.Exit(0) } SetLogLevel(logLevel) Log.Infof("[main] WeaveDNS version %s", version) // first thing in log: the version var iface *net.Interface if ifaceName != "" { var err error Log.Infoln("[main] Waiting for mDNS interface", ifaceName, "to come up") iface, err = weavenet.EnsureInterface(ifaceName, wait) if err != nil { Log.Fatal(err) } else { Log.Infoln("[main] Interface", ifaceName, "is up") } } var httpIP string if httpIfaceName == "" { httpIP = "0.0.0.0" } else { Log.Infoln("[main] Waiting for HTTP interface", httpIfaceName, "to come up") httpIface, err := weavenet.EnsureInterface(httpIfaceName, wait) if err != nil { Log.Fatal(err) } Log.Infoln("[main] Interface", httpIfaceName, "is up") addrs, err := httpIface.Addrs() if err != nil { Log.Fatal(err) } if len(addrs) == 0 { Log.Fatal("[main] No addresses on HTTP interface") } ip, _, err := net.ParseCIDR(addrs[0].String()) if err != nil { Log.Fatal(err) } httpIP = ip.String() } httpAddr := net.JoinHostPort(httpIP, strconv.Itoa(httpPort)) zoneConfig := weavedns.ZoneConfig{ Domain: domain, Iface: iface, LocalTTL: ttl, RefreshInterval: refreshInterval, RelevantTime: relevantTime, } zone, err := weavedns.NewZoneDb(zoneConfig) if err != nil { Log.Fatal("[main] Unable to initialize the Zone database", err) } if err := zone.Start(); err != nil { Log.Fatal("[main] Unable to start the Zone database", err) } defer zone.Stop() dockerCli, err = docker.NewClient(apiPath) if err != nil { Log.Fatal("[main] Unable to start docker client: ", err) } if watch { err := dockerCli.AddObserver(zone) if err != nil { Log.Fatal("[main] Unable to start watcher", err) } } srvConfig := weavedns.DNSServerConfig{ Zone: zone, Port: dnsPort, CacheLen: cacheLen, LocalTTL: ttl, CacheNegLocalTTL: negTTL, MaxAnswers: maxAnswers, Timeout: timeout, UDPBufLen: udpbuf, CacheDisabled: cacheDisabled, } if len(fallback) > 0 { fallbackHost, fallbackPort, err := net.SplitHostPort(fallback) if err != nil { Log.Fatal("[main] Could not parse fallback host and port", err) } srvConfig.UpstreamCfg = &dns.ClientConfig{Servers: []string{fallbackHost}, Port: fallbackPort} Log.Debugf("[main] DNS fallback at %s:%s", fallbackHost, fallbackPort) } srv, err := weavedns.NewDNSServer(srvConfig) if err != nil { Log.Fatal("[main] Failed to initialize the WeaveDNS server", err) } httpListener, err := net.Listen("tcp", httpAddr) if err != nil { Log.Fatal("[main] Unable to create http listener: ", err) } Log.Infoln("[main] HTTP API listening on", httpAddr) go SignalHandlerLoop(srv) go weavedns.ServeHTTP(httpListener, version, srv, dockerCli) err = srv.Start() if err != nil { Log.Fatal("[main] Failed to start the WeaveDNS server: ", err) } srv.ActivateAndServe() }
func main() { procs := runtime.NumCPU() // packet sniffing can block an OS thread, so we need one thread // for that plus at least one more. if procs < 2 { procs = 2 } runtime.GOMAXPROCS(procs) var ( config weave.Config justVersion bool protocolMinVersion int ifaceName string routerName string nickName string password string pktdebug bool logLevel string prof string bufSzMB int noDiscovery bool httpAddr string iprangeCIDR string ipsubnetCIDR string peerCount int dockerAPI string peers []string noDNS bool dnsDomain string dnsListenAddress string dnsTTL int dnsClientTimeout time.Duration dnsEffectiveListenAddress string iface *net.Interface ) mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit") mflag.IntVar(&config.Port, []string{"#port", "-port"}, weave.Port, "router port") mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, weave.ProtocolMinVersion, "minimum weave protocol version") mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)") mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)") mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)") mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") mflag.BoolVar(&pktdebug, []string{"#pktdebug", "#-pktdebug", "-pkt-debug"}, false, "enable per-packet debug logging") mflag.StringVar(&prof, []string{"#profile", "-profile"}, "", "enable profiling and write profiles to given path") mflag.IntVar(&config.ConnLimit, []string{"#connlimit", "#-connlimit", "-conn-limit"}, 30, "connection limit (0 for unlimited)") mflag.BoolVar(&noDiscovery, []string{"#nodiscovery", "#-nodiscovery", "-no-discovery"}, false, "disable peer discovery") mflag.IntVar(&bufSzMB, []string{"#bufsz", "-bufsz"}, 8, "capture buffer size in MB") mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, fmt.Sprintf(":%d", weave.HTTPPort), "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)") mflag.StringVar(&iprangeCIDR, []string{"#iprange", "#-iprange", "-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation") mflag.StringVar(&ipsubnetCIDR, []string{"#ipsubnet", "#-ipsubnet", "-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation") mflag.IntVar(&peerCount, []string{"#initpeercount", "#-initpeercount", "-init-peer-count"}, 0, "number of peers in network (for IP address allocation)") mflag.StringVar(&dockerAPI, []string{"#api", "#-api", "-docker-api"}, "", "Docker API endpoint, e.g. unix:///var/run/docker.sock") mflag.BoolVar(&noDNS, []string{"-no-dns"}, false, "disable DNS server") mflag.StringVar(&dnsDomain, []string{"-dns-domain"}, nameserver.DefaultDomain, "local domain to server requests for") mflag.StringVar(&dnsListenAddress, []string{"-dns-listen-address"}, nameserver.DefaultListenAddress, "address to listen on for DNS requests") mflag.IntVar(&dnsTTL, []string{"-dns-ttl"}, nameserver.DefaultTTL, "TTL for DNS request from our domain") mflag.DurationVar(&dnsClientTimeout, []string{"-dns-fallback-timeout"}, nameserver.DefaultClientTimeout, "timeout for fallback DNS requests") mflag.StringVar(&dnsEffectiveListenAddress, []string{"-dns-effective-listen-address"}, "", "address DNS will actually be listening, after Docker port mapping") // crude way of detecting that we probably have been started in a // container, with `weave launch` --> suppress misleading paths in // mflags error messages. if os.Args[0] == "/home/weave/weaver" { // matches the Dockerfile ENTRYPOINT os.Args[0] = "weave" mflag.CommandLine.Init("weave", mflag.ExitOnError) } mflag.Parse() peers = mflag.Args() SetLogLevel(logLevel) if justVersion { fmt.Printf("weave router %s\n", version) os.Exit(0) } Log.Println("Command line options:", options()) Log.Println("Command line peers:", peers) if protocolMinVersion < weave.ProtocolMinVersion || protocolMinVersion > weave.ProtocolMaxVersion { Log.Fatalf("--min-protocol-version must be in range [%d,%d]", weave.ProtocolMinVersion, weave.ProtocolMaxVersion) } config.ProtocolMinVersion = byte(protocolMinVersion) var err error if ifaceName != "" { iface, err := weavenet.EnsureInterface(ifaceName) if err != nil { Log.Fatal(err) } // bufsz flag is in MB config.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024) if err != nil { Log.Fatal(err) } } if routerName == "" { if iface == nil { Log.Fatal("Either an interface must be specified with --iface or a name with -name") } routerName = iface.HardwareAddr.String() } name, err := weave.PeerNameFromUserInput(routerName) if err != nil { Log.Fatal(err) } if nickName == "" { nickName, err = os.Hostname() if err != nil { Log.Fatal(err) } } if password == "" { password = os.Getenv("WEAVE_PASSWORD") } if password == "" { Log.Println("Communication between peers is unencrypted.") } else { config.Password = []byte(password) Log.Println("Communication between peers is encrypted.") } if prof != "" { p := *profile.CPUProfile p.ProfilePath = prof p.NoShutdownHook = true defer profile.Start(&p).Stop() } config.PeerDiscovery = !noDiscovery config.Overlay = weave.NewSleeveOverlay(config.Port) if pktdebug { config.PacketLogging = packetLogging{} } else { config.PacketLogging = nopPacketLogging{} } router := weave.NewRouter(config, name, nickName) Log.Println("Our name is", router.Ourself) var dockerCli *docker.Client if dockerAPI != "" { dc, err := docker.NewClient(dockerAPI) if err != nil { Log.Fatal("Unable to start docker client: ", err) } dockerCli = dc } observeContainers := func(o docker.ContainerObserver) { if dockerCli != nil { if err = dockerCli.AddObserver(o); err != nil { Log.Fatal("Unable to start watcher", err) } } } var allocator *ipam.Allocator var defaultSubnet address.CIDR if iprangeCIDR != "" { allocator, defaultSubnet = createAllocator(router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers)) observeContainers(allocator) } else if peerCount > 0 { Log.Fatal("--init-peer-count flag specified without --ipalloc-range") } var ( ns *nameserver.Nameserver dnsserver *nameserver.DNSServer ) if !noDNS { ns = nameserver.New(router.Ourself.Peer.Name, router.Peers, dnsDomain) ns.SetGossip(router.NewGossip("nameserver", ns)) observeContainers(ns) ns.Start() defer ns.Stop() dnsserver, err = nameserver.NewDNSServer(ns, dnsDomain, dnsListenAddress, dnsEffectiveListenAddress, uint32(dnsTTL), dnsClientTimeout) if err != nil { Log.Fatal("Unable to start dns server: ", err) } dnsserver.ActivateAndServe() defer dnsserver.Stop() } router.Start() if errors := router.ConnectionMaker.InitiateConnections(peers, false); len(errors) > 0 { Log.Fatal(ErrorMessages(errors)) } // The weave script always waits for a status call to succeed, // so there is no point in doing "weave launch --http-addr ''". // This is here to support stand-alone use of weaver. if httpAddr != "" { muxRouter := mux.NewRouter() if allocator != nil { allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli) } if ns != nil { ns.HandleHTTP(muxRouter, dockerCli) } router.HandleHTTP(muxRouter) HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver) http.Handle("/", muxRouter) go listenAndServeHTTP(httpAddr, muxRouter) } SignalHandlerLoop(router) }
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 main() { procs := runtime.NumCPU() // packet sniffing can block an OS thread, so we need one thread // for that plus at least one more. if procs < 2 { procs = 2 } runtime.GOMAXPROCS(procs) var ( // flags that cause immediate exit justVersion bool createDatapath bool deleteDatapath bool addDatapathInterface string config mesh.Config networkConfig weave.NetworkConfig protocolMinVersion int ifaceName string routerName string nickName string password string pktdebug bool logLevel string prof string bufSzMB int noDiscovery bool httpAddr string iprangeCIDR string ipsubnetCIDR string peerCount int dockerAPI string peers []string noDNS bool dnsDomain string dnsListenAddress string dnsTTL int dnsClientTimeout time.Duration dnsEffectiveListenAddress string iface *net.Interface datapathName string trustedSubnetStr string defaultDockerHost = "unix:///var/run/docker.sock" ) if val := os.Getenv("DOCKER_HOST"); val != "" { defaultDockerHost = val } mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit") mflag.BoolVar(&createDatapath, []string{"-create-datapath"}, false, "create ODP datapath and exit") mflag.BoolVar(&deleteDatapath, []string{"-delete-datapath"}, false, "delete ODP datapath and exit") mflag.StringVar(&addDatapathInterface, []string{"-add-datapath-iface"}, "", "add a network interface to the ODP datapath and exit") mflag.IntVar(&config.Port, []string{"#port", "-port"}, mesh.Port, "router port") mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, mesh.ProtocolMinVersion, "minimum weave protocol version") mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)") mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)") mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)") mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") mflag.BoolVar(&pktdebug, []string{"#pktdebug", "#-pktdebug", "-pkt-debug"}, false, "enable per-packet debug logging") mflag.StringVar(&prof, []string{"#profile", "-profile"}, "", "enable profiling and write profiles to given path") mflag.IntVar(&config.ConnLimit, []string{"#connlimit", "#-connlimit", "-conn-limit"}, 30, "connection limit (0 for unlimited)") mflag.BoolVar(&noDiscovery, []string{"#nodiscovery", "#-nodiscovery", "-no-discovery"}, false, "disable peer discovery") mflag.IntVar(&bufSzMB, []string{"#bufsz", "-bufsz"}, 8, "capture buffer size in MB") mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, "", "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)") mflag.StringVar(&iprangeCIDR, []string{"#iprange", "#-iprange", "-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation") mflag.StringVar(&ipsubnetCIDR, []string{"#ipsubnet", "#-ipsubnet", "-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation") mflag.IntVar(&peerCount, []string{"#initpeercount", "#-initpeercount", "-init-peer-count"}, 0, "number of peers in network (for IP address allocation)") mflag.StringVar(&dockerAPI, []string{"#api", "#-api", "-docker-api"}, defaultDockerHost, "Docker API endpoint") mflag.BoolVar(&noDNS, []string{"-no-dns"}, false, "disable DNS server") mflag.StringVar(&dnsDomain, []string{"-dns-domain"}, nameserver.DefaultDomain, "local domain to server requests for") mflag.StringVar(&dnsListenAddress, []string{"-dns-listen-address"}, nameserver.DefaultListenAddress, "address to listen on for DNS requests") mflag.IntVar(&dnsTTL, []string{"-dns-ttl"}, nameserver.DefaultTTL, "TTL for DNS request from our domain") mflag.DurationVar(&dnsClientTimeout, []string{"-dns-fallback-timeout"}, nameserver.DefaultClientTimeout, "timeout for fallback DNS requests") mflag.StringVar(&dnsEffectiveListenAddress, []string{"-dns-effective-listen-address"}, "", "address DNS will actually be listening, after Docker port mapping") mflag.StringVar(&datapathName, []string{"-datapath"}, "", "ODP datapath name") mflag.StringVar(&trustedSubnetStr, []string{"-trusted-subnets"}, "", "Command separated list of trusted subnets in CIDR notation") // crude way of detecting that we probably have been started in a // container, with `weave launch` --> suppress misleading paths in // mflags error messages. if os.Args[0] == "/home/weave/weaver" { // matches the Dockerfile ENTRYPOINT os.Args[0] = "weave" mflag.CommandLine.Init("weave", mflag.ExitOnError) } mflag.Parse() peers = mflag.Args() SetLogLevel(logLevel) switch { case justVersion: fmt.Printf("weave router %s\n", version) os.Exit(0) case createDatapath: odpSupported, err := odp.CreateDatapath(datapathName) if !odpSupported { if err != nil { Log.Error(err) } // When the kernel lacks ODP support, exit // with a special status to distinguish it for // the weave script. os.Exit(17) } checkFatal(err) os.Exit(0) case deleteDatapath: checkFatal(odp.DeleteDatapath(datapathName)) os.Exit(0) case addDatapathInterface != "": checkFatal(odp.AddDatapathInterface(datapathName, addDatapathInterface)) os.Exit(0) } Log.Println("Command line options:", options()) Log.Println("Command line peers:", peers) if protocolMinVersion < mesh.ProtocolMinVersion || protocolMinVersion > mesh.ProtocolMaxVersion { Log.Fatalf("--min-protocol-version must be in range [%d,%d]", mesh.ProtocolMinVersion, mesh.ProtocolMaxVersion) } config.ProtocolMinVersion = byte(protocolMinVersion) overlays := weave.NewOverlaySwitch() if datapathName != "" { // A datapath name implies that "Bridge" and "Overlay" // packet handling use fast datapath, although other // options can override that below. Even if both // things are overridden, we might need bridging on // the datapath. fastdp, err := weave.NewFastDatapath(datapathName, config.Port) checkFatal(err) networkConfig.Bridge = fastdp.Bridge() overlays.Add("fastdp", fastdp.Overlay()) } sleeve := weave.NewSleeveOverlay(config.Port) overlays.Add("sleeve", sleeve) overlays.SetCompatOverlay(sleeve) if ifaceName != "" { // -iface can coexist with -datapath, because // pcap-based packet capture is a bit more efficient // than capture via ODP misses, even when using an // ODP-based bridge. So when using weave encyption, // it's preferable to use -iface. var err error iface, err = weavenet.EnsureInterface(ifaceName) checkFatal(err) // bufsz flag is in MB networkConfig.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024) checkFatal(err) } if password == "" { password = os.Getenv("WEAVE_PASSWORD") } if password == "" { Log.Println("Communication between peers is unencrypted.") } else { config.Password = []byte(password) Log.Println("Communication between peers via untrusted networks is encrypted.") } if routerName == "" { if iface == nil { Log.Fatal("Either an interface must be specified with --iface or a name with -name") } routerName = iface.HardwareAddr.String() } name, err := mesh.PeerNameFromUserInput(routerName) checkFatal(err) if nickName == "" { nickName, err = os.Hostname() checkFatal(err) } if prof != "" { p := *profile.CPUProfile p.ProfilePath = prof p.NoShutdownHook = true defer profile.Start(&p).Stop() } config.PeerDiscovery = !noDiscovery if pktdebug { networkConfig.PacketLogging = packetLogging{} } else { networkConfig.PacketLogging = nopPacketLogging{} } if config.TrustedSubnets, err = parseTrustedSubnets(trustedSubnetStr); err != nil { Log.Fatal("Unable to parse trusted subnets: ", err) } router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlays) Log.Println("Our name is", router.Ourself) var dockerCli *docker.Client if dockerAPI != "" { dc, err := docker.NewClient(dockerAPI) if err != nil { Log.Fatal("Unable to start docker client: ", err) } else { Log.Info(dc.Info()) } dockerCli = dc } observeContainers := func(o docker.ContainerObserver) { if dockerCli != nil { if err = dockerCli.AddObserver(o); err != nil { Log.Fatal("Unable to start watcher", err) } } } isKnownPeer := func(name mesh.PeerName) bool { return router.Peers.Fetch(name) != nil } var allocator *ipam.Allocator var defaultSubnet address.CIDR if iprangeCIDR != "" { allocator, defaultSubnet = createAllocator(router.Router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer) observeContainers(allocator) } else if peerCount > 0 { Log.Fatal("--init-peer-count flag specified without --ipalloc-range") } var ( ns *nameserver.Nameserver dnsserver *nameserver.DNSServer ) if !noDNS { ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer) router.Peers.OnGC(func(peer *mesh.Peer) { ns.PeerGone(peer.Name) }) ns.SetGossip(router.NewGossip("nameserver", ns)) observeContainers(ns) ns.Start() defer ns.Stop() dnsserver, err = nameserver.NewDNSServer(ns, dnsDomain, dnsListenAddress, dnsEffectiveListenAddress, uint32(dnsTTL), dnsClientTimeout) if err != nil { Log.Fatal("Unable to start dns server: ", err) } listenAddr := dnsListenAddress if dnsEffectiveListenAddress != "" { listenAddr = dnsEffectiveListenAddress } Log.Println("Listening for DNS queries on", listenAddr) dnsserver.ActivateAndServe() defer dnsserver.Stop() } router.Start() if errors := router.ConnectionMaker.InitiateConnections(peers, false); len(errors) > 0 { Log.Fatal(ErrorMessages(errors)) } // The weave script always waits for a status call to succeed, // so there is no point in doing "weave launch --http-addr ''". // This is here to support stand-alone use of weaver. if httpAddr != "" { muxRouter := mux.NewRouter() if allocator != nil { allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli) } if ns != nil { ns.HandleHTTP(muxRouter, dockerCli) } router.HandleHTTP(muxRouter) HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver) http.Handle("/", muxRouter) Log.Println("Listening for HTTP control messages on", httpAddr) go listenAndServeHTTP(httpAddr, muxRouter) } SignalHandlerLoop(router) }
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) } }
func main() { procs := runtime.NumCPU() // packet sniffing can block an OS thread, so we need one thread // for that plus at least one more. if procs < 2 { procs = 2 } runtime.GOMAXPROCS(procs) var ( config weave.Config justVersion bool ifaceName string routerName string nickName string password string wait int pktdebug bool logLevel string prof string bufSzMB int noDiscovery bool httpAddr string iprangeCIDR string ipsubnetCIDR string peerCount int apiPath string peers []string ) flag.BoolVar(&justVersion, "version", false, "print version and exit") flag.IntVar(&config.Port, "port", weave.Port, "router port") flag.StringVar(&ifaceName, "iface", "", "name of interface to capture/inject from (disabled if blank)") flag.StringVar(&routerName, "name", "", "name of router (defaults to MAC of interface)") flag.StringVar(&nickName, "nickname", "", "nickname of peer (defaults to hostname)") flag.StringVar(&password, "password", "", "network password") flag.IntVar(&wait, "wait", -1, "number of seconds to wait for interface to come up (0=don't wait, -1=wait forever)") flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)") flag.BoolVar(&pktdebug, "pktdebug", false, "enable per-packet debug logging") flag.StringVar(&prof, "profile", "", "enable profiling and write profiles to given path") flag.IntVar(&config.ConnLimit, "connlimit", 30, "connection limit (0 for unlimited)") flag.BoolVar(&noDiscovery, "nodiscovery", false, "disable peer discovery") flag.IntVar(&bufSzMB, "bufsz", 8, "capture buffer size in MB") flag.StringVar(&httpAddr, "httpaddr", fmt.Sprintf(":%d", weave.HTTPPort), "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)") flag.StringVar(&iprangeCIDR, "iprange", "", "IP address range reserved for automatic allocation, in CIDR notation") flag.StringVar(&ipsubnetCIDR, "ipsubnet", "", "subnet to allocate within by default, in CIDR notation") flag.IntVar(&peerCount, "initpeercount", 0, "number of peers in network (for IP address allocation)") flag.StringVar(&apiPath, "api", "unix:///var/run/docker.sock", "Path to Docker API socket") flag.Parse() peers = flag.Args() SetLogLevel(logLevel) if justVersion { fmt.Printf("weave router %s\n", version) os.Exit(0) } Log.Println("Command line options:", options()) Log.Println("Command line peers:", peers) var err error if ifaceName != "" { config.Iface, err = weavenet.EnsureInterface(ifaceName, wait) if err != nil { Log.Fatal(err) } } if routerName == "" { if config.Iface == nil { Log.Fatal("Either an interface must be specified with -iface or a name with -name") } routerName = config.Iface.HardwareAddr.String() } name, err := weave.PeerNameFromUserInput(routerName) if err != nil { Log.Fatal(err) } if nickName == "" { nickName, err = os.Hostname() if err != nil { Log.Fatal(err) } } if password == "" { password = os.Getenv("WEAVE_PASSWORD") } if password == "" { Log.Println("Communication between peers is unencrypted.") } else { config.Password = []byte(password) Log.Println("Communication between peers is encrypted.") } if prof != "" { p := *profile.CPUProfile p.ProfilePath = prof p.NoShutdownHook = true defer profile.Start(&p).Stop() } config.BufSz = bufSzMB * 1024 * 1024 config.LogFrame = logFrameFunc(pktdebug) config.PeerDiscovery = !noDiscovery router := weave.NewRouter(config, name, nickName) Log.Println("Our name is", router.Ourself) var allocator *ipam.Allocator var defaultSubnet address.CIDR var dockerCli *docker.Client if iprangeCIDR != "" { allocator, defaultSubnet = createAllocator(router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers)) dockerCli, err = docker.NewClient(apiPath) if err != nil { Log.Fatal("Unable to start docker client: ", err) } if err = dockerCli.AddObserver(allocator); err != nil { Log.Fatal("Unable to start watcher", err) } } else if peerCount > 0 { Log.Fatal("-initpeercount flag specified without -iprange") } router.Start() if errors := router.ConnectionMaker.InitiateConnections(peers, false); len(errors) > 0 { Log.Fatal(errorMessages(errors)) } // The weave script always waits for a status call to succeed, // so there is no point in doing "weave launch -httpaddr ''". // This is here to support stand-alone use of weaver. if httpAddr != "" { go handleHTTP(router, httpAddr, allocator, defaultSubnet, dockerCli) } SignalHandlerLoop(router) }
func NewWatcher(client *docker.Client, weave *weaveapi.Client, driver *driver) (Watcher, error) { w := &watcher{client: client, weave: weave, driver: driver} return w, client.AddObserver(w) }