github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/cmd/serve.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/spf13/cobra" 9 10 "github.com/authzed/spicedb/internal/telemetry" 11 "github.com/authzed/spicedb/pkg/cmd/datastore" 12 "github.com/authzed/spicedb/pkg/cmd/server" 13 "github.com/authzed/spicedb/pkg/cmd/termination" 14 "github.com/authzed/spicedb/pkg/cmd/util" 15 ) 16 17 const PresharedKeyFlag = "grpc-preshared-key" 18 19 var ( 20 namespaceCacheDefaults = &server.CacheConfig{ 21 Name: "namespace", 22 Enabled: true, 23 Metrics: true, 24 NumCounters: 1_000, 25 MaxCost: "32MiB", 26 } 27 28 dispatchCacheDefaults = &server.CacheConfig{ 29 Name: "dispatch", 30 Enabled: true, 31 Metrics: true, 32 NumCounters: 10_000, 33 MaxCost: "30%", 34 } 35 36 dispatchClusterCacheDefaults = &server.CacheConfig{ 37 Name: "cluster_dispatch", 38 Enabled: true, 39 Metrics: true, 40 NumCounters: 100_000, 41 MaxCost: "70%", 42 } 43 ) 44 45 func RegisterServeFlags(cmd *cobra.Command, config *server.Config) error { 46 // sets default values, but does not expose it as CLI arguments 47 config.DispatchClusterMetricsEnabled = true 48 config.DispatchClientMetricsEnabled = true 49 50 // Flags for logging 51 cmd.Flags().BoolVar(&config.EnableRequestLogs, "grpc-log-requests-enabled", false, "logs API request payloads") 52 cmd.Flags().BoolVar(&config.EnableResponseLogs, "grpc-log-responses-enabled", false, "logs API response payloads") 53 54 // Flags for the gRPC API server 55 util.RegisterGRPCServerFlags(cmd.Flags(), &config.GRPCServer, "grpc", "gRPC", ":50051", true) 56 cmd.Flags().StringSliceVar(&config.PresharedSecureKey, PresharedKeyFlag, []string{}, "preshared key(s) to require for authenticated requests") 57 cmd.Flags().DurationVar(&config.ShutdownGracePeriod, "grpc-shutdown-grace-period", 0*time.Second, "amount of time after receiving sigint to continue serving") 58 if err := cmd.MarkFlagRequired(PresharedKeyFlag); err != nil { 59 return fmt.Errorf("failed to mark flag as required: %w", err) 60 } 61 62 // Flags for the datastore 63 if err := datastore.RegisterDatastoreFlags(cmd, &config.DatastoreConfig); err != nil { 64 return err 65 } 66 67 // Flags for configuring the API usage of the datastore 68 cmd.Flags().Uint64Var(&config.MaxDatastoreReadPageSize, "max-datastore-read-page-size", 1_000, "limit on the maximum page size that we will load into memory from the datastore at one time") 69 70 // Flags for the namespace cache 71 cmd.Flags().Duration("ns-cache-expiration", 1*time.Minute, "amount of time a namespace entry should remain cached") 72 if err := cmd.Flags().MarkHidden("ns-cache-expiration"); err != nil { 73 return fmt.Errorf("failed to mark flag as hidden: %w", err) 74 } 75 server.RegisterCacheFlags(cmd.Flags(), "ns-cache", &config.NamespaceCacheConfig, namespaceCacheDefaults) 76 77 cmd.Flags().BoolVar(&config.EnableExperimentalWatchableSchemaCache, "enable-experimental-watchable-schema-cache", false, "enables the experimental schema cache which makes use of the Watch API for automatic updates") 78 cmd.Flags().DurationVar(&config.SchemaWatchHeartbeat, "datastore-schema-watch-heartbeat", 1*time.Second, "heartbeat time on the schema watch in the datastore (if supported). 0 means to default to the datastore's minimum.") 79 80 // Flags for parsing and validating schemas. 81 cmd.Flags().BoolVar(&config.SchemaPrefixesRequired, "schema-prefixes-required", false, "require prefixes on all object definitions in schemas") 82 83 // Flags for HTTP gateway 84 util.RegisterHTTPServerFlags(cmd.Flags(), &config.HTTPGateway, "http", "gateway", ":8443", false) 85 cmd.Flags().StringVar(&config.HTTPGatewayUpstreamAddr, "http-upstream-override-addr", "", "Override the upstream to point to a different gRPC server") 86 if err := cmd.Flags().MarkHidden("http-upstream-override-addr"); err != nil { 87 return fmt.Errorf("failed to mark flag as hidden: %w", err) 88 } 89 cmd.Flags().StringVar(&config.HTTPGatewayUpstreamTLSCertPath, "http-upstream-override-tls-cert-path", "", "Override the upstream TLS certificate") 90 if err := cmd.Flags().MarkHidden("http-upstream-override-tls-cert-path"); err != nil { 91 return fmt.Errorf("failed to mark flag as hidden: %w", err) 92 } 93 cmd.Flags().BoolVar(&config.HTTPGatewayCorsEnabled, "http-cors-enabled", false, "DANGEROUS: Enable CORS on the http gateway") 94 if err := cmd.Flags().MarkHidden("http-cors-enabled"); err != nil { 95 return fmt.Errorf("failed to mark flag as hidden: %w", err) 96 } 97 cmd.Flags().StringSliceVar(&config.HTTPGatewayCorsAllowedOrigins, "http-cors-allowed-origins", []string{"*"}, "Set CORS allowed origins for http gateway, defaults to all origins") 98 if err := cmd.Flags().MarkHidden("http-cors-allowed-origins"); err != nil { 99 return fmt.Errorf("failed to mark flag as hidden: %w", err) 100 } 101 102 // Flags for configuring the dispatch server 103 util.RegisterGRPCServerFlags(cmd.Flags(), &config.DispatchServer, "dispatch-cluster", "dispatch", ":50053", false) 104 server.RegisterCacheFlags(cmd.Flags(), "dispatch-cache", &config.DispatchCacheConfig, dispatchCacheDefaults) 105 server.RegisterCacheFlags(cmd.Flags(), "dispatch-cluster-cache", &config.ClusterDispatchCacheConfig, dispatchClusterCacheDefaults) 106 107 // Flags for configuring dispatch requests 108 cmd.Flags().Uint32Var(&config.DispatchMaxDepth, "dispatch-max-depth", 50, "maximum recursion depth for nested calls") 109 cmd.Flags().StringVar(&config.DispatchUpstreamAddr, "dispatch-upstream-addr", "", "upstream grpc address to dispatch to") 110 cmd.Flags().StringVar(&config.DispatchUpstreamCAPath, "dispatch-upstream-ca-path", "", "local path to the TLS CA used when connecting to the dispatch cluster") 111 cmd.Flags().DurationVar(&config.DispatchUpstreamTimeout, "dispatch-upstream-timeout", 60*time.Second, "maximum duration of a dispatch call an upstream cluster before it times out") 112 113 cmd.Flags().Uint16Var(&config.GlobalDispatchConcurrencyLimit, "dispatch-concurrency-limit", 50, "maximum number of parallel goroutines to create for each request or subrequest") 114 115 cmd.Flags().Uint16Var(&config.DispatchConcurrencyLimits.Check, "dispatch-check-permission-concurrency-limit", 0, "maximum number of parallel goroutines to create for each check request or subrequest. defaults to --dispatch-concurrency-limit") 116 cmd.Flags().Uint16Var(&config.DispatchConcurrencyLimits.LookupResources, "dispatch-lookup-resources-concurrency-limit", 0, "maximum number of parallel goroutines to create for each lookup resources request or subrequest. defaults to --dispatch-concurrency-limit") 117 cmd.Flags().Uint16Var(&config.DispatchConcurrencyLimits.LookupSubjects, "dispatch-lookup-subjects-concurrency-limit", 0, "maximum number of parallel goroutines to create for each lookup subjects request or subrequest. defaults to --dispatch-concurrency-limit") 118 cmd.Flags().Uint16Var(&config.DispatchConcurrencyLimits.ReachableResources, "dispatch-reachable-resources-concurrency-limit", 0, "maximum number of parallel goroutines to create for each reachable resources request or subrequest. defaults to --dispatch-concurrency-limit") 119 120 cmd.Flags().Uint16Var(&config.DispatchHashringReplicationFactor, "dispatch-hashring-replication-factor", 100, "set the replication factor of the consistent hasher used for the dispatcher") 121 cmd.Flags().Uint8Var(&config.DispatchHashringSpread, "dispatch-hashring-spread", 1, "set the spread of the consistent hasher used for the dispatcher") 122 123 cmd.Flags().StringToStringVar(&config.DispatchSecondaryUpstreamAddrs, "experimental-dispatch-secondary-upstream-addrs", nil, "secondary upstream addresses for dispatches, each with a name") 124 cmd.Flags().StringToStringVar(&config.DispatchSecondaryUpstreamExprs, "experimental-dispatch-secondary-upstream-exprs", nil, "map from request type (currently supported: `check`) to its associated CEL expression, which returns the secondary upstream(s) to be used for the request") 125 126 // Flags for configuring API behavior 127 cmd.Flags().BoolVar(&config.DisableV1SchemaAPI, "disable-v1-schema-api", false, "disables the V1 schema API") 128 cmd.Flags().BoolVar(&config.DisableVersionResponse, "disable-version-response", false, "disables version response support in the API") 129 cmd.Flags().Uint16Var(&config.MaximumUpdatesPerWrite, "write-relationships-max-updates-per-call", 1000, "maximum number of updates allowed for WriteRelationships calls") 130 cmd.Flags().Uint16Var(&config.MaximumPreconditionCount, "update-relationships-max-preconditions-per-call", 1000, "maximum number of preconditions allowed for WriteRelationships and DeleteRelationships calls") 131 cmd.Flags().IntVar(&config.MaxCaveatContextSize, "max-caveat-context-size", 4096, "maximum allowed size of request caveat context in bytes. A value of zero or less means no limit") 132 cmd.Flags().IntVar(&config.MaxRelationshipContextSize, "max-relationship-context-size", 25000, "maximum allowed size of the context to be stored in a relationship") 133 cmd.Flags().DurationVar(&config.StreamingAPITimeout, "streaming-api-response-delay-timeout", 30*time.Second, "max duration time elapsed between messages sent by the server-side to the client (responses) before the stream times out") 134 cmd.Flags().DurationVar(&config.WatchHeartbeat, "watch-api-heartbeat", 1*time.Second, "heartbeat time on the watch in the API. 0 means to default to the datastore's minimum.") 135 136 cmd.Flags().Uint32Var(&config.MaxReadRelationshipsLimit, "max-read-relationships-limit", 1000, "maximum number of relationships that can be read in a single request") 137 cmd.Flags().Uint32Var(&config.MaxDeleteRelationshipsLimit, "max-delete-relationships-limit", 1000, "maximum number of relationships that can be deleted in a single request") 138 cmd.Flags().Uint32Var(&config.MaxLookupResourcesLimit, "max-lookup-resources-limit", 1000, "maximum number of resources that can be looked up in a single request") 139 cmd.Flags().Uint32Var(&config.MaxBulkExportRelationshipsLimit, "max-bulk-export-relationships-limit", 10_000, "maximum number of relationships that can be exported in a single request") 140 141 cmd.Flags().BoolVar(&config.V1SchemaAdditiveOnly, "testing-only-schema-additive-writes", false, "append new definitions to the existing schema, rather than overwriting it") 142 if err := cmd.Flags().MarkHidden("testing-only-schema-additive-writes"); err != nil { 143 return fmt.Errorf("failed to mark flag as required: %w", err) 144 } 145 146 // Flags for misc services 147 util.RegisterHTTPServerFlags(cmd.Flags(), &config.MetricsAPI, "metrics", "metrics", ":9090", true) 148 149 if err := util.RegisterDeprecatedHTTPServerFlags(cmd, "dashboard", "dashboard"); err != nil { 150 return err 151 } 152 153 // Flags for telemetry 154 cmd.Flags().StringVar(&config.TelemetryEndpoint, "telemetry-endpoint", telemetry.DefaultEndpoint, "endpoint to which telemetry is reported, empty string to disable") 155 cmd.Flags().StringVar(&config.TelemetryCAOverridePath, "telemetry-ca-override-path", "", "TODO") 156 cmd.Flags().DurationVar(&config.TelemetryInterval, "telemetry-interval", telemetry.DefaultInterval, "approximate period between telemetry reports, minimum 1 minute") 157 158 return nil 159 } 160 161 func NewServeCommand(programName string, config *server.Config) *cobra.Command { 162 return &cobra.Command{ 163 Use: "serve", 164 Short: "serve the permissions database", 165 Long: "A database that stores, computes, and validates application permissions", 166 PreRunE: server.DefaultPreRunE(programName), 167 RunE: termination.PublishError(func(cmd *cobra.Command, args []string) error { 168 server, err := config.Complete(cmd.Context()) 169 if err != nil { 170 return err 171 } 172 signalctx := SignalContextWithGracePeriod( 173 context.Background(), 174 config.ShutdownGracePeriod, 175 ) 176 return server.Run(signalctx) 177 }), 178 Example: server.ServeExample(programName), 179 } 180 }