Example #1
0
func main() {
	flag.Parse()
	if err := flagenv.Populate(flag.CommandLine, "DOORMAN"); err != nil {
		log.Exit(err)
	}

	if *config == "" {
		log.Exit("--config cannot be empty")
	}
	var (
		etcdEndpointsSlice = strings.Split(*etcdEndpoints, ",")
		masterElection     election.Election
	)
	if *masterElectionLock != "" {

		if len(etcdEndpointsSlice) == 1 && etcdEndpointsSlice[0] == "" {
			log.Exit("-etcd_endpoints cannot be empty if -master_election_lock is provided")
		}

		masterElection = election.Etcd(etcdEndpointsSlice, *masterElectionLock, *masterDelay)
	} else {
		masterElection = election.Trivial()
	}

	dm, err := doorman.New(context.Background(), getServerID(*port), *parent, masterElection,
		connection.MinimumRefreshInterval(*minimumRefreshInterval),
		connection.DialOpts(
			rpc.WithTimeout(*rpcDialTimeout)))
	if err != nil {
		log.Exitf("doorman.NewIntermediate: %v", err)
	}

	var opts []rpc.ServerOption
	if *tls {
		log.Infof("Loading credentials from %v and %v.", *certFile, *keyFile)
		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
		if err != nil {
			log.Exitf("Failed to generate credentials %v", err)
		}
		opts = []rpc.ServerOption{rpc.Creds(creds)}
	}
	server := rpc.NewServer(opts...)

	pb.RegisterCapacityServer(server, dm)

	if *config == "" {
		log.Exit("-config cannot be empty")
	}

	var cfg configuration.Source
	kind, path := configuration.ParseSource(*config)
	switch {
	case kind == "file":
		cfg = configuration.LocalFile(path)
	case kind == "etcd":
		if len(etcdEndpointsSlice) == 1 && etcdEndpointsSlice[0] == "" {
			log.Exit("-etcd_endpoints cannot be empty if a config source etcd is provided")
		}
		cfg = configuration.Etcd(path, etcdEndpointsSlice)
	default:
		panic("unreachable")
	}

	// Try to load the background. If there's a problem with loading
	// the server for the first time, the server will keep running,
	// but will not serve traffic.
	go func() {
		for {
			data, err := cfg(context.Background())
			if err != nil {
				log.Errorf("cannot load config data: %v", err)
				continue
			}
			cfg := new(pb.ResourceRepository)
			if err := yaml.Unmarshal(data, cfg); err != nil {
				log.Errorf("cannot unmarshal config data: %q", data)
				continue
			}

			if err := dm.LoadConfig(context.Background(), cfg, map[string]*time.Time{}); err != nil {
				log.Errorf("cannot load config: %v", err)
			}
		}
	}()

	status.AddStatusPart("Doorman", statusz, func(context.Context) interface{} { return dm.Status() })

	// Redirect form / to /debug/status.
	http.Handle("/", http.RedirectHandler("/debug/status", http.StatusMovedPermanently))
	AddServer(dm)

	http.Handle("/metrics", prometheus.Handler())

	go http.ListenAndServe(fmt.Sprintf(":%v", *debugPort), nil)

	// Waits for the server to get its initial configuration. This guarantees that
	// the server will never run without a valid configuration.
	log.Info("Waiting for the server to be configured...")
	dm.WaitUntilConfigured()

	// Runs the server.
	log.Info("Server is configured, ready to go!")

	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Exit(err)
	}

	server.Serve(lis)

}
Example #2
0
// MinimumRefreshInterval sets the minimum refresh interval for
// establishing the client's connection with the server.
func MinimumRefreshInterval(t time.Duration) Option {
	return Option(connection.MinimumRefreshInterval(t))
}
Example #3
0
// MakeTestIntermediateServer creates a test intermediate server with
// specified name and connected to the lower-level server with address addr.
func MakeTestIntermediateServer(name string, addr string, resources ...*pb.ResourceTemplate) (*Server, error) {
	// Creates a new test server that is the master.
	server, err := NewIntermediate(context.Background(), name, addr, election.Trivial(), connection.MinimumRefreshInterval(0), connection.DialOpts(grpc.WithInsecure()))
	if err != nil {
		return nil, fmt.Errorf("server.NewIntermediate: %v", err)
	}

	// If this is a root server, then it should not be configured until we explicitly call LoadConfig
	// with the initial resources configuration. For intermediate server it is not the case.
	if addr == "" {
		if err := server.LoadConfig(context.Background(), &pb.ResourceRepository{
			Resources: resources,
		}, map[string]*time.Time{}); err != nil {
			return nil, fmt.Errorf("server.LoadConfig: %v", err)
		}
	}

	// Waits until the server is configured. This should not block and immediately fall through.
	server.WaitUntilConfigured()

	return server, nil
}