Example #1
0
File: daemon.go Project: kgrz/flynn
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)))
}
Example #2
0
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)))
}