Skip to content

Commit

Permalink
gateway: extract into package and add metrics
Browse files Browse the repository at this point in the history
Signed-off-by: Jimmy Zelinskie <jimmy@zelinskie.com>
  • Loading branch information
jzelinskie committed Oct 25, 2021
1 parent 89576ad commit f42234a
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 38 deletions.
55 changes: 17 additions & 38 deletions cmd/spicedb/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ import (
"time"

"github.com/alecthomas/units"
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/grpcutil"
"github.com/fatih/color"
grpcauth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpczerolog "github.com/grpc-ecosystem/go-grpc-middleware/providers/zerolog/v2"
grpclog "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/jzelinskie/cobrautil"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
Expand All @@ -37,6 +34,7 @@ import (
"github.com/authzed/spicedb/internal/dispatch/client/consistentbackend"
"github.com/authzed/spicedb/internal/dispatch/graph"
"github.com/authzed/spicedb/internal/dispatch/remote"
"github.com/authzed/spicedb/internal/gateway"
"github.com/authzed/spicedb/internal/middleware/servicespecific"
"github.com/authzed/spicedb/internal/namespace"
"github.com/authzed/spicedb/internal/services"
Expand Down Expand Up @@ -354,7 +352,6 @@ func serveRun(cmd *cobra.Command, args []string) {
prefixRequiredOption,
v1SchemaServiceOption,
)

go func() {
addr := cobrautil.MustGetStringExpanded(cmd, "grpc-addr")
l, err := net.Listen("tcp", addr)
Expand Down Expand Up @@ -383,11 +380,24 @@ func serveRun(cmd *cobra.Command, args []string) {
}
}()

gatewaySrv, err := newRestGateway(context.TODO(), cmd)
// Start the REST gateway to serve HTTP/JSON.
gatewaySrv, err := gateway.NewHttpServer(context.TODO(), gateway.Config{
Addr: cobrautil.MustGetStringExpanded(cmd, "http-addr"),
UpstreamAddr: cobrautil.MustGetStringExpanded(cmd, "grpc-addr"),
UpstreamTlsDisabled: cobrautil.MustGetBool(cmd, "grpc-no-tls"),
UpstreamTlsCaPath: cobrautil.MustGetStringExpanded(cmd, "grpc-cert-path"),
})
if err != nil {
log.Fatal().Err(err).Msg("failed to listen on addr for gRPC REST gateway server")
log.Fatal().Err(err).Msg("failed to initialize rest gateway")
}
go func() {
log.Info().Str("addr", gatewaySrv.Addr).Msg("rest gateway server started listening")
if err := gatewaySrv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("failed while serving rest gateway")
}
}()

// Start the metrics endpoint.
metricsrv := cobrautil.MetricsServerFromFlags(cmd)
go func() {
addr := cobrautil.MustGetStringExpanded(cmd, "metrics-addr")
Expand All @@ -397,6 +407,7 @@ func serveRun(cmd *cobra.Command, args []string) {
}
}()

// Start a dashboard.
dashboardAddr := cobrautil.MustGetStringExpanded(cmd, "dashboard-addr")
dashboard := dashboard.NewDashboard(dashboardAddr, dashboard.Args{
GrpcNoTLS: cobrautil.MustGetBool(cmd, "grpc-no-tls"),
Expand Down Expand Up @@ -458,35 +469,3 @@ func serveRun(cmd *cobra.Command, args []string) {
}
}
}

func newRestGateway(ctx context.Context, cmd *cobra.Command) (*http.Server, error) {
opts := []grpc.DialOption{grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())}
if cobrautil.MustGetBool(cmd, "grpc-no-tls") {
opts = append(opts, grpc.WithInsecure())
} else {
opts = append(opts, grpcutil.WithCustomCerts(
cobrautil.MustGetStringExpanded(cmd, "grpc-cert-path"),
grpcutil.SkipVerifyCA,
))
}

mux := runtime.NewServeMux(runtime.WithMetadata(auth.PresharedKeyAnnotator))
upstream := cobrautil.MustGetStringExpanded(cmd, "grpc-addr")
v1.RegisterSchemaServiceHandlerFromEndpoint(ctx, mux, upstream, opts)
v1.RegisterPermissionsServiceHandlerFromEndpoint(ctx, mux, upstream, opts)

addr := cobrautil.MustGetStringExpanded(cmd, "http-addr")
gatewaySrv := &http.Server{
Addr: addr,
Handler: mux,
}

go func() {
log.Info().Str("addr", addr).Msg("http server started listening")
if err := gatewaySrv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("failed while serving rest gateway")
}
}()

return gatewaySrv, nil
}
55 changes: 55 additions & 0 deletions internal/gateway/gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Package gateway implements an HTTP server that forwards JSON requests to
// an upstream SpiceDB gRPC server.
package gateway

import (
"context"
"net/http"

v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/grpcutil"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"google.golang.org/grpc"

"github.com/authzed/spicedb/internal/auth"
)

var histogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "spicedb_rest_gateway_request_duration_seconds",
Help: "A histogram of the duration spent processing requests to the SpiceDB REST Gateway.",
}, []string{"method"})

// Config represents the require configuration for initializing a REST gateway.
type Config struct {
Addr string
UpstreamAddr string
UpstreamTlsDisabled bool
UpstreamTlsCaPath string
}

// NewHttpServer initializes a new HTTP server with the provided configuration.
func NewHttpServer(ctx context.Context, cfg Config) (*http.Server, error) {
opts := []grpc.DialOption{grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())}
if cfg.UpstreamTlsDisabled {
opts = append(opts, grpc.WithInsecure())
} else {
opts = append(opts, grpcutil.WithCustomCerts(cfg.UpstreamTlsCaPath, grpcutil.SkipVerifyCA))
}

mux := runtime.NewServeMux(runtime.WithMetadata(auth.PresharedKeyAnnotator))
if err := v1.RegisterSchemaServiceHandlerFromEndpoint(ctx, mux, cfg.UpstreamAddr, opts); err != nil {
return nil, err
}
if err := v1.RegisterPermissionsServiceHandlerFromEndpoint(ctx, mux, cfg.UpstreamAddr, opts); err != nil {
return nil, err
}

return &http.Server{
Addr: cfg.Addr,
Handler: promhttp.InstrumentHandlerDuration(histogram, mux),
}, nil
}

0 comments on commit f42234a

Please sign in to comment.