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) }
// 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)) }
// 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 }