From b3fc4b1cf4a61e6a38007742d7c54c7fb15436f9 Mon Sep 17 00:00:00 2001 From: George Date: Tue, 3 Jan 2023 11:33:55 +0000 Subject: [PATCH] feat(metadata): authenticate /meta endpoints (#1250) * feat(metadata): authenticate /meta endpoints * refactor(metadata): simplify marshal json * fix(test): update meta endpoints to require authenticated --- cmd/flipt/main.go | 2 +- internal/cmd/grpc.go | 4 + internal/cmd/http.go | 17 ++- internal/server/metadata/server.go | 68 +++++++++ rpc/flipt/auth/auth.pb.gw.go | 4 +- rpc/flipt/flipt.pb.gw.go | 4 +- rpc/flipt/flipt.yaml | 5 + rpc/flipt/meta/meta.pb.go | 123 ++++++++++++++++ rpc/flipt/meta/meta.pb.gw.go | 225 +++++++++++++++++++++++++++++ rpc/flipt/meta/meta.proto | 74 ++++++++++ rpc/flipt/meta/meta_grpc.pb.go | 143 ++++++++++++++++++ test/api.sh | 4 +- 12 files changed, 661 insertions(+), 12 deletions(-) create mode 100644 internal/server/metadata/server.go create mode 100644 rpc/flipt/meta/meta.pb.go create mode 100644 rpc/flipt/meta/meta.pb.gw.go create mode 100644 rpc/flipt/meta/meta.proto create mode 100644 rpc/flipt/meta/meta_grpc.pb.go diff --git a/cmd/flipt/main.go b/cmd/flipt/main.go index 44eea237f4..b36de540f0 100644 --- a/cmd/flipt/main.go +++ b/cmd/flipt/main.go @@ -328,7 +328,7 @@ func run(ctx context.Context, logger *zap.Logger) error { migrator.Close() - grpcServer, err := cmd.NewGRPCServer(ctx, logger, cfg) + grpcServer, err := cmd.NewGRPCServer(ctx, logger, cfg, info) if err != nil { return err } diff --git a/internal/cmd/grpc.go b/internal/cmd/grpc.go index b78693634f..f9b0425fb7 100644 --- a/internal/cmd/grpc.go +++ b/internal/cmd/grpc.go @@ -9,10 +9,12 @@ import ( "time" "go.flipt.io/flipt/internal/config" + "go.flipt.io/flipt/internal/info" fliptserver "go.flipt.io/flipt/internal/server" "go.flipt.io/flipt/internal/server/cache" "go.flipt.io/flipt/internal/server/cache/memory" "go.flipt.io/flipt/internal/server/cache/redis" + "go.flipt.io/flipt/internal/server/metadata" middlewaregrpc "go.flipt.io/flipt/internal/server/middleware/grpc" "go.flipt.io/flipt/internal/storage" authsql "go.flipt.io/flipt/internal/storage/auth/sql" @@ -81,6 +83,7 @@ func NewGRPCServer( ctx context.Context, logger *zap.Logger, cfg *config.Config, + info info.Flipt, ) (*GRPCServer, error) { logger = logger.With(zap.String("server", "grpc")) server := &GRPCServer{ @@ -245,6 +248,7 @@ func NewGRPCServer( // initialize server register.Add(fliptserver.New(logger, store)) + register.Add(metadata.NewServer(cfg, info)) // initialize grpc server server.Server = grpc.NewServer(grpcOpts...) diff --git a/internal/cmd/http.go b/internal/cmd/http.go index 3b565ffe52..9833af0ce7 100644 --- a/internal/cmd/http.go +++ b/internal/cmd/http.go @@ -14,11 +14,13 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/prometheus/client_golang/prometheus/promhttp" "go.flipt.io/flipt/internal/config" "go.flipt.io/flipt/internal/gateway" "go.flipt.io/flipt/internal/info" "go.flipt.io/flipt/rpc/flipt" + "go.flipt.io/flipt/rpc/flipt/meta" "go.flipt.io/flipt/ui" "go.uber.org/zap" "google.golang.org/grpc" @@ -101,11 +103,16 @@ func NewHTTPServer( // to the chi router. authenticationHTTPMount(ctx, cfg.Authentication, r, conn) - r.Route("/meta", func(r chi.Router) { - r.Use(middleware.SetHeader("Content-Type", "application/json")) - r.Handle("/info", info) - r.Handle("/config", cfg) - }) + // mount the metadata service to the chi router under /meta. + r.Mount("/meta", runtime.NewServeMux( + runtime.WithMarshalerOption("application/json", &runtime.HTTPBodyMarshaler{}), + runtime.WithMarshalerOption("application/json+pretty", &runtime.HTTPBodyMarshaler{}), + registerFunc( + ctx, + conn, + meta.RegisterMetadataServiceHandler, + ), + )) if cfg.UI.Enabled { u, err := fs.Sub(ui.UI, "dist") diff --git a/internal/server/metadata/server.go b/internal/server/metadata/server.go new file mode 100644 index 0000000000..c273e99674 --- /dev/null +++ b/internal/server/metadata/server.go @@ -0,0 +1,68 @@ +package metadata + +import ( + "context" + "encoding/json" + + "go.flipt.io/flipt/internal/config" + "go.flipt.io/flipt/internal/info" + "go.flipt.io/flipt/rpc/flipt/meta" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/types/known/emptypb" +) + +type Server struct { + cfg *config.Config + info info.Flipt + + meta.UnimplementedMetadataServiceServer +} + +func NewServer(cfg *config.Config, info info.Flipt) *Server { + return &Server{ + cfg: cfg, + info: info, + } +} + +// RegisterGRPC registers the server on the provided gRPC server instance. +func (s *Server) RegisterGRPC(server *grpc.Server) { + meta.RegisterMetadataServiceServer(server, s) +} + +// GetConfiguration returns a HttpBody instance containing the Flipt instance's +// configuration structure marshalled as JSON. +func (s *Server) GetConfiguration(ctx context.Context, _ *emptypb.Empty) (*httpbody.HttpBody, error) { + return response(ctx, s.cfg) +} + +// GetInfo returns a HttpBody instance containing the Flipt instance's +// runtime information marshalled as JSON. +func (s *Server) GetInfo(ctx context.Context, _ *emptypb.Empty) (*httpbody.HttpBody, error) { + return response(ctx, s.info) +} + +func response(ctx context.Context, v any) (*httpbody.HttpBody, error) { + data, err := marshal(ctx, v) + if err != nil { + return nil, err + } + + return &httpbody.HttpBody{ + ContentType: "application/json", + Data: data, + }, nil +} + +func marshal(ctx context.Context, v any) ([]byte, error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { + accept := md.Get("grpcgateway-accept") + if len(accept) > 0 && accept[0] == "application/json+pretty" { + return json.MarshalIndent(v, "", " ") + } + } + + return json.Marshal(v) +} diff --git a/rpc/flipt/auth/auth.pb.gw.go b/rpc/flipt/auth/auth.pb.gw.go index 2140752440..f24ec51f92 100644 --- a/rpc/flipt/auth/auth.pb.gw.go +++ b/rpc/flipt/auth/auth.pb.gw.go @@ -243,7 +243,7 @@ func local_request_AuthenticationMethodTokenService_CreateToken_0(ctx context.Co } var ( - filter_AuthenticationMethodOIDCService_AuthorizeURL_0 = &utilities.DoubleArray{Encoding: map[string]int{"provider": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} + filter_AuthenticationMethodOIDCService_AuthorizeURL_0 = &utilities.DoubleArray{Encoding: map[string]int{"provider": 0}, Base: []int{1, 2, 0, 0}, Check: []int{0, 1, 2, 2}} ) func request_AuthenticationMethodOIDCService_AuthorizeURL_0(ctx context.Context, marshaler runtime.Marshaler, client AuthenticationMethodOIDCServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -313,7 +313,7 @@ func local_request_AuthenticationMethodOIDCService_AuthorizeURL_0(ctx context.Co } var ( - filter_AuthenticationMethodOIDCService_Callback_0 = &utilities.DoubleArray{Encoding: map[string]int{"provider": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} + filter_AuthenticationMethodOIDCService_Callback_0 = &utilities.DoubleArray{Encoding: map[string]int{"provider": 0}, Base: []int{1, 2, 0, 0}, Check: []int{0, 1, 2, 2}} ) func request_AuthenticationMethodOIDCService_Callback_0(ctx context.Context, marshaler runtime.Marshaler, client AuthenticationMethodOIDCServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { diff --git a/rpc/flipt/flipt.pb.gw.go b/rpc/flipt/flipt.pb.gw.go index 740cfc5fe5..0983e453b4 100644 --- a/rpc/flipt/flipt.pb.gw.go +++ b/rpc/flipt/flipt.pb.gw.go @@ -642,7 +642,7 @@ func local_request_Flipt_GetRule_0(ctx context.Context, marshaler runtime.Marsha } var ( - filter_Flipt_ListRules_0 = &utilities.DoubleArray{Encoding: map[string]int{"flag_key": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} + filter_Flipt_ListRules_0 = &utilities.DoubleArray{Encoding: map[string]int{"flag_key": 0, "flagKey": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) func request_Flipt_ListRules_0(ctx context.Context, marshaler runtime.Marshaler, client FliptClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -1204,7 +1204,7 @@ func local_request_Flipt_UpdateDistribution_0(ctx context.Context, marshaler run } var ( - filter_Flipt_DeleteDistribution_0 = &utilities.DoubleArray{Encoding: map[string]int{"flag_key": 0, "rule_id": 1, "id": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} + filter_Flipt_DeleteDistribution_0 = &utilities.DoubleArray{Encoding: map[string]int{"flag_key": 0, "flagKey": 1, "rule_id": 2, "ruleId": 3, "id": 4}, Base: []int{1, 1, 2, 3, 4, 6, 0, 0, 0, 0, 0, 0}, Check: []int{0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 6}} ) func request_Flipt_DeleteDistribution_0(ctx context.Context, marshaler runtime.Marshaler, client FliptClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { diff --git a/rpc/flipt/flipt.yaml b/rpc/flipt/flipt.yaml index 7cfa14d1ff..cb94dcf9c2 100644 --- a/rpc/flipt/flipt.yaml +++ b/rpc/flipt/flipt.yaml @@ -73,6 +73,11 @@ http: body: "*" - selector: flipt.Flipt.DeleteConstraint delete: /api/v1/segments/{segment_key}/constraints/{id} + # metadata + - selector: flipt.meta.MetadataService.GetConfiguration + get: /meta/config + - selector: flipt.meta.MetadataService.GetInfo + get: /meta/info # authentication public routes - selector: flipt.auth.PublicAuthenticationService.ListAuthenticationMethods get: /auth/v1/method diff --git a/rpc/flipt/meta/meta.pb.go b/rpc/flipt/meta/meta.pb.go new file mode 100644 index 0000000000..17d77b4530 --- /dev/null +++ b/rpc/flipt/meta/meta.pb.go @@ -0,0 +1,123 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1-devel +// protoc (unknown) +// source: meta/meta.proto + +package meta + +import ( + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + httpbody "google.golang.org/genproto/googleapis/api/httpbody" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var File_meta_meta_proto protoreflect.FileDescriptor + +var file_meta_meta_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0a, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x1a, 0x19, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x62, 0x6f, + 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, + 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x8c, 0x02, 0x0a, 0x0f, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x85, 0x01, 0x0a, 0x10, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x43, 0x92, 0x41, + 0x40, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x21, 0x47, 0x65, 0x74, + 0x20, 0x46, 0x6c, 0x69, 0x70, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x2a, 0x11, + 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x71, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x38, 0x92, 0x41, 0x35, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x1f, 0x47, 0x65, 0x74, 0x20, 0x46, + 0x6c, 0x69, 0x70, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x2a, 0x08, 0x67, 0x65, 0x74, 0x5f, + 0x69, 0x6e, 0x66, 0x6f, 0x42, 0xce, 0x03, 0x5a, 0x20, 0x67, 0x6f, 0x2e, 0x66, 0x6c, 0x69, 0x70, + 0x74, 0x2e, 0x69, 0x6f, 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x66, + 0x6c, 0x69, 0x70, 0x74, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x92, 0x41, 0xa8, 0x03, 0x12, 0xaa, 0x01, + 0x0a, 0x13, 0x46, 0x6c, 0x69, 0x70, 0x74, 0x20, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x41, 0x50, 0x49, 0x73, 0x22, 0x3d, 0x0a, 0x0a, 0x46, 0x6c, 0x69, 0x70, 0x74, 0x20, 0x54, + 0x65, 0x61, 0x6d, 0x12, 0x21, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2d, 0x69, 0x6f, + 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x1a, 0x0c, 0x64, 0x65, 0x76, 0x40, 0x66, 0x6c, 0x69, 0x70, + 0x74, 0x2e, 0x69, 0x6f, 0x2a, 0x4c, 0x0a, 0x0b, 0x4d, 0x49, 0x54, 0x20, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2d, 0x69, 0x6f, + 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, + 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, + 0x53, 0x45, 0x32, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, + 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, + 0x6f, 0x6e, 0x52, 0x63, 0x0a, 0x03, 0x34, 0x30, 0x31, 0x12, 0x5c, 0x0a, 0x3d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x28, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x29, 0x2e, 0x12, 0x1b, 0x0a, 0x19, 0x1a, 0x17, + 0x23, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x72, 0x70, + 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5a, 0x2a, 0x0a, 0x28, 0x0a, 0x11, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x65, 0x61, 0x72, 0x65, 0x72, 0x12, 0x13, + 0x08, 0x02, 0x1a, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x02, 0x62, 0x17, 0x0a, 0x15, 0x0a, 0x11, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x65, 0x61, 0x72, 0x65, 0x72, 0x12, 0x00, 0x72, 0x27, 0x0a, 0x0a, + 0x46, 0x6c, 0x69, 0x70, 0x74, 0x20, 0x44, 0x6f, 0x63, 0x73, 0x12, 0x19, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x66, 0x6c, 0x69, 0x70, 0x74, 0x2e, 0x69, 0x6f, + 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_meta_meta_proto_goTypes = []interface{}{ + (*emptypb.Empty)(nil), // 0: google.protobuf.Empty + (*httpbody.HttpBody)(nil), // 1: google.api.HttpBody +} +var file_meta_meta_proto_depIdxs = []int32{ + 0, // 0: flipt.meta.MetadataService.GetConfiguration:input_type -> google.protobuf.Empty + 0, // 1: flipt.meta.MetadataService.GetInfo:input_type -> google.protobuf.Empty + 1, // 2: flipt.meta.MetadataService.GetConfiguration:output_type -> google.api.HttpBody + 1, // 3: flipt.meta.MetadataService.GetInfo:output_type -> google.api.HttpBody + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_meta_meta_proto_init() } +func file_meta_meta_proto_init() { + if File_meta_meta_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_meta_meta_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_meta_meta_proto_goTypes, + DependencyIndexes: file_meta_meta_proto_depIdxs, + }.Build() + File_meta_meta_proto = out.File + file_meta_meta_proto_rawDesc = nil + file_meta_meta_proto_goTypes = nil + file_meta_meta_proto_depIdxs = nil +} diff --git a/rpc/flipt/meta/meta.pb.gw.go b/rpc/flipt/meta/meta.pb.gw.go new file mode 100644 index 0000000000..b6cf86da3b --- /dev/null +++ b/rpc/flipt/meta/meta.pb.gw.go @@ -0,0 +1,225 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: meta/meta.proto + +/* +Package meta is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package meta + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/emptypb" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_MetadataService_GetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, client MetadataServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GetConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_MetadataService_GetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, server MetadataServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := server.GetConfiguration(ctx, &protoReq) + return msg, metadata, err + +} + +func request_MetadataService_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, client MetadataServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := client.GetInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_MetadataService_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, server MetadataServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := server.GetInfo(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterMetadataServiceHandlerServer registers the http handlers for service MetadataService to "mux". +// UnaryRPC :call MetadataServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMetadataServiceHandlerFromEndpoint instead. +func RegisterMetadataServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MetadataServiceServer) error { + + mux.Handle("GET", pattern_MetadataService_GetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/flipt.meta.MetadataService/GetConfiguration", runtime.WithHTTPPathPattern("/meta/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_MetadataService_GetConfiguration_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetadataService_GetConfiguration_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_MetadataService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/flipt.meta.MetadataService/GetInfo", runtime.WithHTTPPathPattern("/meta/info")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_MetadataService_GetInfo_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetadataService_GetInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterMetadataServiceHandlerFromEndpoint is same as RegisterMetadataServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterMetadataServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterMetadataServiceHandler(ctx, mux, conn) +} + +// RegisterMetadataServiceHandler registers the http handlers for service MetadataService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterMetadataServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterMetadataServiceHandlerClient(ctx, mux, NewMetadataServiceClient(conn)) +} + +// RegisterMetadataServiceHandlerClient registers the http handlers for service MetadataService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MetadataServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MetadataServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "MetadataServiceClient" to call the correct interceptors. +func RegisterMetadataServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MetadataServiceClient) error { + + mux.Handle("GET", pattern_MetadataService_GetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/flipt.meta.MetadataService/GetConfiguration", runtime.WithHTTPPathPattern("/meta/config")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_MetadataService_GetConfiguration_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetadataService_GetConfiguration_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_MetadataService_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/flipt.meta.MetadataService/GetInfo", runtime.WithHTTPPathPattern("/meta/info")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_MetadataService_GetInfo_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_MetadataService_GetInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_MetadataService_GetConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"meta", "config"}, "")) + + pattern_MetadataService_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"meta", "info"}, "")) +) + +var ( + forward_MetadataService_GetConfiguration_0 = runtime.ForwardResponseMessage + + forward_MetadataService_GetInfo_0 = runtime.ForwardResponseMessage +) diff --git a/rpc/flipt/meta/meta.proto b/rpc/flipt/meta/meta.proto new file mode 100644 index 0000000000..8f670869ac --- /dev/null +++ b/rpc/flipt/meta/meta.proto @@ -0,0 +1,74 @@ +syntax = "proto3"; + +package flipt.meta; + +import "google/api/httpbody.proto"; +import "google/protobuf/empty.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "go.flipt.io/flipt/rpc/flipt/meta"; +option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { + info: { + title: "Flipt Metadata APIs"; + version: "latest"; + contact: { + name: "Flipt Team"; + url: "https://github.com/flipt-io/flipt"; + email: "dev@flipt.io" + }; + license: { + name: "MIT License"; + url: "https://github.com/flipt-io/flipt/blob/main/rpc/flipt/LICENSE"; + }; + }; + external_docs: { + url: "https://www.flipt.io/docs"; + description: "Flipt Docs"; + }; + schemes: HTTP; + schemes: HTTPS; + consumes: "application/json"; + produces: "application/json"; + security_definitions: { + security: { + key: "ClientTokenBearer"; + value: { + type: TYPE_API_KEY; + in: IN_HEADER; + name: "Authorization"; + } + } + }; + security: { + security_requirement: { + key: "ClientTokenBearer"; + value: {}; + } + }; + responses: { + key: "401"; + value: { + description: "Request could not be authenticated (authentication required)."; + schema: { + json_schema: {ref: "#/definitions/rpcStatus"}; + }; + }; + }; +}; + +service MetadataService { + rpc GetConfiguration(google.protobuf.Empty) returns (google.api.HttpBody) { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + operation_id: "get_configuration", + description: "Get Flipt instance configuration.", + tags: "metadata", + }; + } + rpc GetInfo(google.protobuf.Empty) returns (google.api.HttpBody) { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + operation_id: "get_info", + description: "Get Flipt instance information.", + tags: "metadata", + }; + } +} diff --git a/rpc/flipt/meta/meta_grpc.pb.go b/rpc/flipt/meta/meta_grpc.pb.go new file mode 100644 index 0000000000..0e52459480 --- /dev/null +++ b/rpc/flipt/meta/meta_grpc.pb.go @@ -0,0 +1,143 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc (unknown) +// source: meta/meta.proto + +package meta + +import ( + context "context" + httpbody "google.golang.org/genproto/googleapis/api/httpbody" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// MetadataServiceClient is the client API for MetadataService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type MetadataServiceClient interface { + GetConfiguration(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) + GetInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) +} + +type metadataServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMetadataServiceClient(cc grpc.ClientConnInterface) MetadataServiceClient { + return &metadataServiceClient{cc} +} + +func (c *metadataServiceClient) GetConfiguration(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + out := new(httpbody.HttpBody) + err := c.cc.Invoke(ctx, "/flipt.meta.MetadataService/GetConfiguration", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *metadataServiceClient) GetInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + out := new(httpbody.HttpBody) + err := c.cc.Invoke(ctx, "/flipt.meta.MetadataService/GetInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MetadataServiceServer is the server API for MetadataService service. +// All implementations must embed UnimplementedMetadataServiceServer +// for forward compatibility +type MetadataServiceServer interface { + GetConfiguration(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) + GetInfo(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) + mustEmbedUnimplementedMetadataServiceServer() +} + +// UnimplementedMetadataServiceServer must be embedded to have forward compatible implementations. +type UnimplementedMetadataServiceServer struct { +} + +func (UnimplementedMetadataServiceServer) GetConfiguration(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetConfiguration not implemented") +} +func (UnimplementedMetadataServiceServer) GetInfo(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented") +} +func (UnimplementedMetadataServiceServer) mustEmbedUnimplementedMetadataServiceServer() {} + +// UnsafeMetadataServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MetadataServiceServer will +// result in compilation errors. +type UnsafeMetadataServiceServer interface { + mustEmbedUnimplementedMetadataServiceServer() +} + +func RegisterMetadataServiceServer(s grpc.ServiceRegistrar, srv MetadataServiceServer) { + s.RegisterService(&MetadataService_ServiceDesc, srv) +} + +func _MetadataService_GetConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetadataServiceServer).GetConfiguration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/flipt.meta.MetadataService/GetConfiguration", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetadataServiceServer).GetConfiguration(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _MetadataService_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MetadataServiceServer).GetInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/flipt.meta.MetadataService/GetInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MetadataServiceServer).GetInfo(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +// MetadataService_ServiceDesc is the grpc.ServiceDesc for MetadataService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MetadataService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "flipt.meta.MetadataService", + HandlerType: (*MetadataServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetConfiguration", + Handler: _MetadataService_GetConfiguration_Handler, + }, + { + MethodName: "GetInfo", + Handler: _MetadataService_GetInfo_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "meta/meta.proto", +} diff --git a/test/api.sh b/test/api.sh index 40e2f709d0..da1400f1ed 100755 --- a/test/api.sh +++ b/test/api.sh @@ -281,12 +281,12 @@ step_7_test_delete() step_8_test_meta() { - shakedown GET "/meta/info" + authedShakedown GET "/meta/info" status 200 contains "\"buildDate\"" contains "\"goVersion\"" - shakedown GET "/meta/config" + authedShakedown GET "/meta/config" status 200 contains "\"log\"" contains "\"ui\""