예제 #1
0
파일: server.go 프로젝트: ably-forks/flynn
func (s *Server) Start() error {
	var err error
	sl, err := net.Listen("tcp", s.conf.SyslogAddr)
	if err != nil {
		return err
	}
	s.syslogListener = keepalive.Listener(sl)

	al, err := net.Listen("tcp", s.conf.ApiAddr)
	if err != nil {
		return err
	}
	s.apiListener = keepalive.Listener(al)

	if s.conf.Discoverd != nil {
		s.hb, err = s.conf.Discoverd.AddServiceAndRegister(s.conf.ServiceName, s.conf.SyslogAddr)
		if err != nil {
			return err
		}
	}

	go s.runSyslog()
	go http.Serve(s.apiListener, s.api)

	return nil
}
예제 #2
0
파일: main.go 프로젝트: ably-forks/flynn
func httpServer(sn *subnet.SubnetManager, publicIP, port string) error {
	overlayListener, err := net.Listen("tcp", net.JoinHostPort(sn.Lease().Network.IP.String(), port))
	if err != nil {
		return err
	}
	publicListener, err := net.Listen("tcp", net.JoinHostPort(publicIP, port))

	http.HandleFunc("/ping", func(http.ResponseWriter, *http.Request) {})
	status.AddHandler(status.SimpleHandler(func() error {
		return pingLeases(sn.Leases())
	}))
	go http.Serve(keepalive.Listener(overlayListener), nil)
	go http.Serve(keepalive.Listener(publicListener), nil)
	return nil
}
예제 #3
0
파일: main.go 프로젝트: ably-forks/flynn
// Run executes the program.
func (m *Main) Run() error {
	m.Logger.Info("running")

	// Read or generate the instance identifier from file.
	id, err := m.readID(filepath.Join(m.DataDir, "instance_id"))
	if err != nil {
		return err
	}
	m.Process.ID = id
	m.Process.DataDir = m.DataDir
	m.Process.Logger = m.Logger.New("component", "process", "id", id)

	// Start process.
	m.Logger.Info("starting process", "id", id)
	if err := m.Process.Start(); err != nil {
		m.Logger.Error("error starting process", "err", err)
		return err
	}

	// Add service to discoverd registry.
	m.Logger.Info("adding service", "name", m.ServiceName)
	if err = m.DiscoverdClient.AddService(m.ServiceName, nil); err != nil && !httphelper.IsObjectExistsError(err) {
		m.Logger.Error("error adding discoverd service", "err", err)
		return err
	}
	inst := &discoverd.Instance{
		Addr: ":" + m.Process.Port,
		Meta: map[string]string{"REDIS_ID": id},
	}

	// Register instance and retain heartbeater.
	m.Logger.Info("registering instance", "addr", inst.Addr, "meta", inst.Meta)
	hb, err := m.DiscoverdClient.RegisterInstance(m.ServiceName, inst)
	if err != nil {
		m.Logger.Error("error registering discoverd instance", "err", err)
		return err
	}
	m.hb = hb
	shutdown.BeforeExit(func() { hb.Close() })

	m.Logger.Info("opening port", "addr", m.Addr)

	// Open HTTP port.
	ln, err := net.Listen("tcp", m.Addr)
	if err != nil {
		m.Logger.Error("error opening port", "err", err)
		return err
	}
	m.ln = keepalive.Listener(ln)

	// Initialize and server handler.
	m.Logger.Info("serving http api")
	h := redis.NewHandler()
	h.Process = m.Process
	h.Heartbeater = m.hb
	h.Logger = m.Logger.New("component", "http")
	go func() { http.Serve(ln, h) }()

	return nil
}
예제 #4
0
파일: http.go 프로젝트: imjorge/flynn
func newHTTPListener(addr string) (net.Listener, error) {
	fdEnv := os.Getenv("FLYNN_HTTP_FD")
	if fdEnv == "" {
		l, err := net.Listen("tcp", addr)
		if err != nil {
			return nil, err
		}
		return keepalive.Listener(l), nil
	}
	fd, err := strconv.Atoi(fdEnv)
	if err != nil {
		return nil, err
	}
	file := os.NewFile(uintptr(fd), "http")
	defer file.Close()
	return net.FileListener(file)
}
예제 #5
0
파일: main.go 프로젝트: imjorge/flynn
// Run executes the program.
func (m *Main) Run(args ...string) error {
	// Create logger.
	m.logger = log.New(m.Stdout, "", log.LstdFlags)

	// Parse command line flags.
	opt, err := m.ParseFlags(args...)
	if err != nil {
		return err
	}

	// Set up advertised address and default peer set.
	m.advertiseAddr = MergeHostPort(opt.Host, opt.Addr)
	if len(opt.Peers) == 0 {
		opt.Peers = []string{m.advertiseAddr}
	}

	// Create a slice of peers with their HTTP address set instead.
	httpPeers, err := SetPortSlice(opt.Peers, opt.Addr)
	if err != nil {
		return fmt.Errorf("set port slice: %s", err)
	}
	m.peers = httpPeers

	// Initialise the default client using the peer list
	os.Setenv("DISCOVERD", strings.Join(opt.Peers, ","))
	discoverd.DefaultClient = discoverd.NewClient()

	// if there is a discoverd process already running on this
	// address perform a deployment by starting a proxy DNS server
	// and shutting down the old discoverd job
	var deploy *dd.Deployment
	var targetLogIndex dt.TargetLogIndex

	target := fmt.Sprintf("http://%s:1111", opt.Host)
	m.logger.Println("checking for existing discoverd process at", target)
	if err := discoverd.NewClientWithURL(target).Ping(target); err == nil {
		m.logger.Println("discoverd responding at", target, "taking over")

		deploy, err = dd.NewDeployment("discoverd")
		if err != nil {
			return err
		}
		m.logger.Println("Created deployment")
		if err := deploy.MarkPerforming(m.advertiseAddr, 60); err != nil {
			return err
		}
		m.logger.Println("marked", m.advertiseAddr, "as performing in deployent")
		addr, resolvers := waitHostDNSConfig()
		if opt.DNSAddr != "" {
			addr = opt.DNSAddr
		}
		if len(opt.Recursors) > 0 {
			resolvers = opt.Recursors
		}
		m.logger.Println("starting proxy DNS server")
		if err := m.openDNSServer(addr, resolvers); err != nil {
			return fmt.Errorf("Failed to start DNS server: %s", err)
		}
		m.logger.Printf("discoverd listening for DNS on %s", addr)

		targetLogIndex, err = discoverd.NewClientWithURL(target).Shutdown(target)
		if err != nil {
			return err
		}
		// Sleep for 2x the election timeout.
		// This is to work around an issue with hashicorp/raft that can allow us to be elected with
		// no log entries, hence truncating the log and losing all data!
		time.Sleep(2 * time.Second)
	} else {
		m.logger.Println("failed to contact existing discoverd server, starting up without takeover")
		m.logger.Println("err:", err)
	}

	// Open listener.
	ln, err := net.Listen("tcp4", opt.Addr)
	if err != nil {
		return err
	}
	m.ln = keepalive.Listener(ln)

	// Open mux
	m.mux = mux.New(m.ln)
	go m.mux.Serve()

	m.dataDir = opt.DataDir

	// if the advertise addr is not in the peer list we are proxying
	proxying := true
	for _, addr := range m.peers {
		if addr == m.advertiseAddr {
			proxying = false
			break
		}
	}

	if proxying {
		// Notify user that we're proxying if the store wasn't initialized.
		m.logger.Println("advertised address not in peer set, joining as proxy")
	} else {
		// Open store if we are not proxying.
		if err := m.openStore(); err != nil {
			return fmt.Errorf("Failed to open store: %s", err)
		}
	}

	// Wait for the store to catchup before switching to local store if we are doing a deployment
	if m.store != nil && targetLogIndex.LastIndex > 0 {
		for m.store.LastIndex() < targetLogIndex.LastIndex {
			m.logger.Println("Waiting for store to catchup, current:", m.store.LastIndex(), "target:", targetLogIndex.LastIndex)
			time.Sleep(100 * time.Millisecond)
		}
	}

	// If we already started the DNS server as part of a deployment above,
	// and we have an initialized store, just switch from the proxy store
	// to the initialized store.
	//
	// Else 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 m.dnsServer != nil && m.store != nil {
		m.dnsServer.SetStore(m.store)
	} else if opt.DNSAddr != "" {
		if err := m.openDNSServer(opt.DNSAddr, opt.Recursors); err != nil {
			return fmt.Errorf("Failed to start DNS server: %s", err)
		}
		m.logger.Printf("discoverd listening for DNS on %s", opt.DNSAddr)
	} else if opt.WaitNetDNS {
		go func() {
			addr, resolvers := waitHostDNSConfig()
			m.mu.Lock()
			if err := m.openDNSServer(addr, resolvers); err != nil {
				log.Fatalf("Failed to start DNS server: %s", err)
			}
			m.mu.Unlock()
			m.logger.Printf("discoverd listening for DNS on %s", addr)

			// Notify webhook.
			if opt.Notify != "" {
				m.Notify(opt.Notify, addr)
			}
		}()
	}

	if err := m.openHTTPServer(); err != nil {
		return fmt.Errorf("Failed to start HTTP server: %s", err)
	}

	if deploy != nil {
		if err := deploy.MarkDone(m.advertiseAddr); err != nil {
			return err
		}
		m.logger.Println("marked", m.advertiseAddr, "as done in deployment")
	}

	// Notify user that the servers are listening.
	m.logger.Printf("discoverd listening for HTTP on %s", opt.Addr)

	// Wait for leadership.
	if err := m.waitForLeader(IndefiniteTimeout); err != nil {
		return err
	}

	// Notify URL that discoverd is running.
	httpAddr := ln.Addr().String()
	host, port, _ := net.SplitHostPort(httpAddr)
	if host == "0.0.0.0" {
		httpAddr = net.JoinHostPort(os.Getenv("EXTERNAL_IP"), port)
	}
	m.Notify(opt.Notify, opt.DNSAddr)
	go func() {
		for {
			hb, err := discoverd.AddServiceAndRegister("discoverd", httpAddr)
			if err != nil {
				m.logger.Println("failed to register service/instance, retrying in 5 seconds:", err)
				time.Sleep(5 * time.Second)
				continue
			}
			m.mu.Lock()
			m.hb = hb
			m.mu.Unlock()
			break
		}
	}()
	return nil
}