func main() { defer shutdown.Exit() httpAddr := flag.String("http-addr", ":1111", "address to serve HTTP API from") dnsAddr := flag.String("dns-addr", "", "address to service DNS from") resolvers := flag.String("recursors", "8.8.8.8,8.8.4.4", "upstream recursive DNS servers") etcdAddrs := flag.String("etcd", "http://127.0.0.1:2379", "etcd servers (comma separated)") notify := flag.String("notify", "", "url to send webhook to after starting listener") waitNetDNS := flag.Bool("wait-net-dns", false, "start DNS server after host network is configured") flag.Parse() etcdClient := etcd.NewClient(strings.Split(*etcdAddrs, ",")) // Check to make sure that etcd is online and accepting connections // etcd takes a while to come online, so we attempt a GET multiple times err := attempt.Strategy{ Min: 5, Total: 10 * time.Minute, Delay: 200 * time.Millisecond, }.Run(func() (err error) { _, err = etcdClient.Get("/", false, false) if e, ok := err.(*etcd.EtcdError); ok && e.ErrorCode == 100 { // Valid 404 from etcd (> v2.0) err = nil } return }) if err != nil { log.Fatalf("Failed to connect to etcd at %v: %q", etcdAddrs, err) } state := server.NewState() backend := server.NewEtcdBackend(etcdClient, "/discoverd", state) if err := backend.StartSync(); err != nil { log.Fatalf("Failed to perform initial etcd sync: %s", err) } // if we have a DNS address, start a DNS server right away, otherwise // wait for the host network to come up and then start a DNS server. if *dnsAddr != "" { var recursors []string if *resolvers != "" { recursors = strings.Split(*resolvers, ",") } if err := startDNSServer(state, *dnsAddr, recursors); err != nil { log.Fatalf("Failed to start DNS server: %s", err) } log.Printf("discoverd listening for DNS on %s", *dnsAddr) } else if *waitNetDNS { go func() { status, err := waitForHostNetwork() if err != nil { log.Fatal(err) } ip, _, err := net.ParseCIDR(status.Network.Subnet) if err != nil { log.Fatal(err) } addr := net.JoinHostPort(ip.String(), "53") if err := startDNSServer(state, addr, status.Network.Resolvers); err != nil { log.Fatalf("Failed to start DNS server: %s", err) } log.Printf("discoverd listening for DNS on %s", addr) if *notify != "" { notifyWebhook(*notify, "", addr) } }() } l, err := net.Listen("tcp4", *httpAddr) if err != nil { log.Fatalf("Failed to start HTTP listener: %s", err) } log.Printf("discoverd listening for HTTP on %s", *httpAddr) if *notify != "" { addr := l.Addr().String() host, port, _ := net.SplitHostPort(addr) if host == "0.0.0.0" { addr = net.JoinHostPort(os.Getenv("EXTERNAL_IP"), port) } notifyWebhook(*notify, fmt.Sprintf("http://%s", addr), *dnsAddr) } http.Serve(l, server.NewHTTPHandler(server.NewBasicDatastore(state, backend))) }
func main() { defer shutdown.Exit() httpAddr := flag.String("http-addr", ":1111", "address to serve HTTP API from") dnsAddr := flag.String("dns-addr", ":53", "address to service DNS from") resolvers := flag.String("recursors", "8.8.8.8,8.8.4.4", "upstream recursive DNS servers") etcdAddrs := flag.String("etcd", "http://127.0.0.1:2379", "etcd servers (comma separated)") notify := flag.String("notify", "", "url to send webhook to after starting listener") flag.Parse() etcdClient := etcd.NewClient(strings.Split(*etcdAddrs, ",")) // Check to make sure that etcd is online and accepting connections // etcd takes a while to come online, so we attempt a GET multiple times err := attempt.Strategy{ Min: 5, Total: 10 * time.Minute, Delay: 200 * time.Millisecond, }.Run(func() (err error) { _, err = etcdClient.Get("/", false, false) if e, ok := err.(*etcd.EtcdError); ok && e.ErrorCode == 100 { // Valid 404 from etcd (> v2.0) err = nil } return }) if err != nil { log.Fatalf("Failed to connect to etcd at %v: %q", etcdAddrs, err) } state := server.NewState() backend := server.NewEtcdBackend(etcdClient, "/discoverd", state) if err := backend.StartSync(); err != nil { log.Fatalf("Failed to perform initial etcd sync: %s", err) } dns := server.DNSServer{ UDPAddr: *dnsAddr, TCPAddr: *dnsAddr, Store: state, } if *resolvers != "" { dns.Recursors = strings.Split(*resolvers, ",") } if err := dns.ListenAndServe(); err != nil { log.Fatalf("Failed to start DNS server: %s", err) } l, err := net.Listen("tcp4", *httpAddr) if err != nil { log.Fatalf("Failed to start HTTP listener: %s", err) } log.Printf("discoverd listening for HTTP on %s and DNS on %s", *httpAddr, *dnsAddr) if *notify != "" { addr := l.Addr().String() host, port, _ := net.SplitHostPort(addr) if host == "0.0.0.0" { // try to get real address from dns addr if dnsHost, _, _ := net.SplitHostPort(*dnsAddr); dnsHost != "" { addr = net.JoinHostPort(dnsHost, port) } } data := struct { URL string `json:"url"` }{fmt.Sprintf("http://%s", addr)} payload, _ := json.Marshal(data) res, err := http.Post(*notify, "application/json", bytes.NewReader(payload)) if err != nil { log.Printf("failed to notify: %s", err) } else { res.Body.Close() } } http.Serve(l, server.NewHTTPHandler(server.NewBasicDatastore(state, backend))) }