diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d9e94a7b..cfb5f055d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ This document outlines major changes between releases. - Add `X-Amz-Content-Sha256` header validation (#218) - Support frostfsid contract. See `frostfsid` config section (#260) - Support per namespace placement policies configuration (see `namespaces.config` config param) (#266) +- Support control api to manage policies. See `control` config section (#258) ### Changed - Update prometheus to v1.15.0 (#94) diff --git a/Makefile b/Makefile index 5822bcbae..0c10a9b92 100755 --- a/Makefile +++ b/Makefile @@ -151,10 +151,16 @@ clean: # Generate code from .proto files protoc: + # Install specific version for protobuf lib + @GOBIN=$(abspath $(BINDIR)) go install -mod=mod -v git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/protogen @for f in `find . -type f -name '*.proto' -not -path './vendor/*'`; do \ echo "⇒ Processing $$f "; \ protoc \ - --go_out=paths=source_relative:. $$f; \ + --go_out=paths=source_relative:. \ + --plugin=protoc-gen-go-frostfs=$(BINDIR)/protogen \ + --go-frostfs_out=. --go-frostfs_opt=paths=source_relative \ + --go-grpc_opt=require_unimplemented_servers=false \ + --go-grpc_out=. --go-grpc_opt=paths=source_relative $$f; \ done rm -rf vendor diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 8bbf29229..b4182c654 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -4,8 +4,10 @@ import ( "context" "encoding/hex" "encoding/xml" + "errors" "fmt" "io" + "net" "net/http" "os" "os/signal" @@ -33,6 +35,8 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics" + "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control" + controlSvc "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control/server" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/tree" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool" @@ -65,6 +69,8 @@ type ( servers []Server + controlAPI *grpc.Server + metrics *metrics.AppMetrics bucketResolver *resolver.BucketResolver services []*Service @@ -91,6 +97,7 @@ type ( md5Enabled bool namespaceHeader string defaultNamespaces []string + authorizedControlAPIKeys [][]byte } maxClientsConfig struct { @@ -121,7 +128,7 @@ func newApp(ctx context.Context, log *Logger, v *viper.Viper) *App { webDone: make(chan struct{}, 1), wrkDone: make(chan struct{}, 1), - settings: newAppSettings(log, v), + settings: newAppSettings(log, v, key), } app.init(ctx) @@ -132,6 +139,7 @@ func newApp(ctx context.Context, log *Logger, v *viper.Viper) *App { func (a *App) init(ctx context.Context) { a.setRuntimeParameters() a.initAPI(ctx) + a.initControlAPI() a.initMetrics() a.initFrostfsID(ctx) a.initServers(ctx) @@ -177,7 +185,7 @@ func (a *App) initLayer(ctx context.Context) { } } -func newAppSettings(log *Logger, v *viper.Viper) *appSettings { +func newAppSettings(log *Logger, v *viper.Viper, key *keys.PrivateKey) *appSettings { settings := &appSettings{ logLevel: log.lvl, maxClient: newMaxClients(v), @@ -199,6 +207,7 @@ func newAppSettings(log *Logger, v *viper.Viper) *appSettings { settings.initPlacementPolicy(log.logger, v) settings.setBufferMaxSizeForPut(v.GetUint64(cfgBufferMaxSizeForPut)) settings.setMD5Enabled(v.GetBool(cfgMD5Enabled)) + settings.setAuthorizedControlAPIKeys(append(fetchAuthorizedKeys(log.logger, v), key.PublicKey())) return settings } @@ -355,11 +364,39 @@ func (s *appSettings) setDefaultNamespaces(namespaces []string) { s.mu.Unlock() } +func (s *appSettings) FetchRawKeys() [][]byte { + s.mu.RLock() + defer s.mu.RUnlock() + return s.authorizedControlAPIKeys +} + +func (s *appSettings) setAuthorizedControlAPIKeys(keys keys.PublicKeys) { + rawPubs := make([][]byte, len(keys)) + for i := range keys { + rawPubs[i] = keys[i].Bytes() + } + + s.mu.Lock() + s.authorizedControlAPIKeys = rawPubs + s.mu.Unlock() +} + func (a *App) initAPI(ctx context.Context) { a.initLayer(ctx) a.initHandler() } +func (a *App) initControlAPI() { + svc := controlSvc.New( + controlSvc.WithAuthorizedKeysFetcher(a.settings), + controlSvc.WithLogger(a.log), + ) + + a.controlAPI = grpc.NewServer() + + control.RegisterControlServiceServer(a.controlAPI, svc) +} + func (a *App) initMetrics() { a.metrics = metrics.NewAppMetrics(a.log, frostfs.NewPoolStatistic(a.pool), a.cfg.GetBool(cfgPrometheusEnabled)) a.metrics.State().SetHealth(metrics.HealthStatusStarting) @@ -608,6 +645,16 @@ func (a *App) Serve(ctx context.Context) { }(i) } + go func() { + address := a.cfg.GetString(cfgControlGRPCEndpoint) + a.log.Info(logs.StartingControlAPI, zap.String("address", address)) + if listener, err := net.Listen("tcp", address); err != nil { + a.log.Fatal(logs.ListenAndServe, zap.Error(err)) + } else if err = a.controlAPI.Serve(listener); err != nil { + a.log.Fatal(logs.ListenAndServe, zap.Error(err)) + } + }() + sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGHUP) @@ -626,6 +673,7 @@ LOOP: a.log.Info(logs.StoppingServer, zap.Error(srv.Shutdown(ctx))) + a.stopControlAPI() a.metrics.Shutdown() a.stopServices() a.shutdownTracing() @@ -637,6 +685,25 @@ func shutdownContext() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), defaultShutdownTimeout) } +func (a *App) stopControlAPI() { + ctx, cancel := shutdownContext() + defer cancel() + + go func() { + a.controlAPI.GracefulStop() + cancel() + }() + + <-ctx.Done() + + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + a.log.Info(logs.ControlAPICannotShutdownGracefully) + a.controlAPI.Stop() + } + + a.log.Info(logs.ControlAPIServiceStopped) +} + func (a *App) configReload(ctx context.Context) { a.log.Info(logs.SIGHUPConfigReloadStarted) @@ -687,6 +754,7 @@ func (a *App) updateSettings() { a.settings.setBufferMaxSizeForPut(a.cfg.GetUint64(cfgBufferMaxSizeForPut)) a.settings.setMD5Enabled(a.cfg.GetBool(cfgMD5Enabled)) a.settings.setDefaultNamespaces(a.cfg.GetStringSlice(cfgKludgeDefaultNamespaces)) + a.settings.setAuthorizedControlAPIKeys(append(fetchAuthorizedKeys(a.log, a.cfg), a.key.PublicKey())) } func (a *App) startServices() { diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index 37ed8cc07..fe473764c 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -21,6 +21,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool" "git.frostfs.info/TrueCloudLab/zapjournald" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/ssgreg/journald" @@ -79,6 +80,10 @@ const ( // Settings. cfgTLSKeyFile = "tls.key_file" cfgTLSCertFile = "tls.cert_file" + // Control API. + cfgControlAuthorizedKeys = "control.authorized_keys" + cfgControlGRPCEndpoint = "control.grpc.endpoint" + // Pool config. cfgConnectTimeout = "connect_timeout" cfgStreamTimeout = "stream_timeout" @@ -585,6 +590,23 @@ func fetchServers(v *viper.Viper) []ServerInfo { return servers } +func fetchAuthorizedKeys(l *zap.Logger, v *viper.Viper) keys.PublicKeys { + strKeys := v.GetStringSlice(cfgControlAuthorizedKeys) + pubs := make(keys.PublicKeys, 0, len(strKeys)) + + for i := range strKeys { + pub, err := keys.NewPublicKeyFromString(strKeys[i]) + if err != nil { + l.Warn(logs.FailedToParsePublicKey, zap.String("key", strKeys[i])) + continue + } + + pubs = append(pubs, pub) + } + + return pubs +} + func newSettings() *viper.Viper { v := viper.New() @@ -641,6 +663,8 @@ func newSettings() *viper.Viper { v.SetDefault(cfgPProfAddress, "localhost:8085") v.SetDefault(cfgPrometheusAddress, "localhost:8086") + v.SetDefault(cfgControlGRPCEndpoint, "localhost:8083") + // frostfs v.SetDefault(cfgBufferMaxSizeForPut, 1024*1024) // 1mb diff --git a/config/config.env b/config/config.env index af305f471..d44d16805 100644 --- a/config/config.env +++ b/config/config.env @@ -33,6 +33,12 @@ S3_GW_SERVER_1_TLS_ENABLED=true S3_GW_SERVER_1_TLS_CERT_FILE=/path/to/tls/cert S3_GW_SERVER_1_TLS_KEY_FILE=/path/to/tls/key +# Control API +# List of hex-encoded public keys that have rights to use the Control Service +S3_GW_CONTROL_AUTHORIZED_KEYS=035839e45d472a3b7769a2a1bd7d54c4ccd4943c3b40f547870e83a8fcbfb3ce11 028f42cfcb74499d7b15b35d9bff260a1c8d27de4f446a627406a382d8961486d6 +# Endpoint that is listened by the Control Service +S3_GW_CONTROL_GRPC_ENDPOINT=localhost:8083 + # Domains to be able to use virtual-hosted-style access to bucket. S3_GW_LISTEN_DOMAINS=s3dev.frostfs.devenv diff --git a/config/config.yaml b/config/config.yaml index 7a4962eb6..421d937c0 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -37,6 +37,15 @@ server: cert_file: /path/to/cert key_file: /path/to/key +control: + # List of hex-encoded public keys that have rights to use the Control Service + authorized_keys: + - 035839e45d472a3b7769a2a1bd7d54c4ccd4943c3b40f547870e83a8fcbfb3ce11 + - 028f42cfcb74499d7b15b35d9bff260a1c8d27de4f446a627406a382d8961486d6 + grpc: + # Endpoint that is listened by the Control Service + endpoint: localhost:8083 + # Domains to be able to use virtual-hosted-style access to bucket. listen_domains: - s3dev.frostfs.devenv diff --git a/docs/configuration.md b/docs/configuration.md index e270540ec..c9c0baeef 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -175,6 +175,7 @@ There are some custom types used for brevity: | `peers` | [Nodes configuration](#peers-section) | | `placement_policy` | [Placement policy configuration](#placement_policy-section) | | `server` | [Server configuration](#server-section) | +| `control` | [Control API configuration](#control-section) | | `logger` | [Logger configuration](#logger-section) | | `cache` | [Cache configuration](#cache-section) | | `nats` | [NATS configuration](#nats-section) | @@ -352,6 +353,24 @@ server: | `tls.cert_file` | `string` | yes | | Path to the TLS certificate. | | `tls.key_file` | `string` | yes | | Path to the key. | +### `control` section + +Control API parameters. + +```yaml +control: + authorized_keys: + - 035839e45d472a3b7769a2a1bd7d54c4ccd4943c3b40f547870e83a8fcbfb3ce11 + - 028f42cfcb74499d7b15b35d9bff260a1c8d27de4f446a627406a382d8961486d6 + grpc: + endpoint: localhost:8083 +``` + +| Parameter | Type | SIGHUP reload | Default value | Description | +|-------------------|------------|---------------|------------------|------------------------------------------------------------------------------| +| `authorized_keys` | `[]string` | yes | | List of hex-encoded public keys that have rights to use the Control Service. | +| `grpc.endpoint` | `string` | | `localhost:8083` | Endpoint that is listened by the Control Service. | + ### `logger` section ```yaml diff --git a/internal/logs/logs.go b/internal/logs/logs.go index 0ad17d142..2113da7ed 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -21,6 +21,7 @@ const ( ApplicationFinished = "application finished" // Info in ../../cmd/s3-gw/app.go FetchDomainsPrepareToUseAPI = "fetch domains, prepare to use API" // Info in ../../cmd/s3-gw/app.go StartingServer = "starting server" // Info in ../../cmd/s3-gw/app.go + StartingControlAPI = "starting control API server" // Info in ../../cmd/s3-gw/app.go StoppingServer = "stopping server" // Info in ../../cmd/s3-gw/app.go SIGHUPConfigReloadStarted = "SIGHUP config reload started" // Info in ../../cmd/s3-gw/app.go FailedToReloadConfigBecauseItsMissed = "failed to reload config because it's missed" // Warn in ../../cmd/s3-gw/app.go @@ -32,6 +33,8 @@ const ( FailedToAddServer = "failed to add server" // Warn in ../../cmd/s3-gw/app.go AddServer = "add server" // Info in ../../cmd/s3-gw/app.go ResolverNNSWontBeUsedSinceRPCEndpointIsntProvided = "resolver 'nns' won't be used since 'rpc_endpoint' isn't provided" // Warn in ../../cmd/s3-gw/app.go + ControlAPICannotShutdownGracefully = "control API cannot shutdown gracefully, forcing stop" // Info in ../../cmd/s3-gw/app.go + ControlAPIServiceStopped = "control API service stopped" // Info in ../../cmd/s3-gw/app.go InvalidLifetimeUsingDefaultValue = "invalid lifetime, using default value (in seconds)" // Error in ../../cmd/s3-gw/app_settings.go InvalidCacheSizeUsingDefaultValue = "invalid cache size, using default value" // Error in ../../cmd/s3-gw/app_settings.go FailedToParseDefaultLocationConstraint = "failed to parse 'default' location constraint, default one will be used" // Warn in cmd/s3-gw/app_settings.go @@ -40,6 +43,7 @@ const ( FailedToParseLocationConstraint = "failed to parse location constraint, it cannot be used" // Warn in cmd/s3-gw/app_settings.go FailedToParseDefaultCopiesNumbers = "failed to parse 'default' copies numbers, default one will be used" // Warn in cmd/s3-gw/app_settings.go FailedToParseCopiesNumbers = "failed to parse copies numbers, skip" // Warn in cmd/s3-gw/app_settings.go + FailedToParsePublicKey = "failed to parse public key, skip" // Warn in cmd/s3-gw/app_settings.go DefaultNamespacesCannotBeEmpty = "default namespaces cannot be empty, defaults will be used" // Warn in cmd/s3-gw/app_settings.go FailedToParseNamespacesConfig = "failed to unmarshal namespaces config" // Warn in cmd/s3-gw/app_settings.go DefaultNamespaceConfigValuesBeOverwritten = "default namespace config value be overwritten by values from 'namespaces.config'" // Warn in cmd/s3-gw/app_settings.go diff --git a/pkg/service/control/client/client.go b/pkg/service/control/client/client.go new file mode 100644 index 000000000..b87d5eaeb --- /dev/null +++ b/pkg/service/control/client/client.go @@ -0,0 +1,56 @@ +package client + +import ( + "context" + "fmt" + + "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control" + controlSvc "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control/server" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Client struct { + svc control.ControlServiceClient + key *keys.PrivateKey +} + +type Config struct { + Logger *zap.Logger +} + +func New(ctx context.Context, addr string, key *keys.PrivateKey) (*Client, error) { + conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, fmt.Errorf("failed to dial s3 gw control api: %w", err) + } + + svc := control.NewControlServiceClient(conn) + + cli := &Client{ + svc: svc, + key: key, + } + + return cli, cli.Healthcheck(ctx) +} + +func (c *Client) Healthcheck(ctx context.Context) error { + req := &control.HealthCheckRequest{} + if err := controlSvc.SignMessage(&c.key.PrivateKey, req); err != nil { + return err + } + + res, err := c.svc.HealthCheck(ctx, req) + if err != nil { + return err + } + + if res.Body.HealthStatus != control.HealthStatus_READY { + return fmt.Errorf("service isn't ready, status: %s", res.Body.HealthStatus) + } + + return nil +} diff --git a/pkg/service/control/server/server.go b/pkg/service/control/server/server.go new file mode 100644 index 000000000..c45cf017c --- /dev/null +++ b/pkg/service/control/server/server.go @@ -0,0 +1,180 @@ +package server + +import ( + "bytes" + "context" + "crypto/ecdsa" + "encoding/hex" + "errors" + "fmt" + + "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control" + frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" + frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" + "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type Server struct { + *cfg +} + +type AuthorizedKeysFetcher interface { + FetchRawKeys() [][]byte +} + +type emptyKeysFetcher struct{} + +func (f emptyKeysFetcher) FetchRawKeys() [][]byte { return nil } + +// Option of the Server's constructor. +type Option func(*cfg) + +type cfg struct { + log *zap.Logger + + keysFetcher AuthorizedKeysFetcher +} + +func defaultCfg() *cfg { + return &cfg{ + log: zap.NewNop(), + keysFetcher: emptyKeysFetcher{}, + } +} + +// New creates, initializes and returns new Server instance. +func New(opts ...Option) *Server { + c := defaultCfg() + + for _, opt := range opts { + opt(c) + } + + c.log = c.log.With(zap.String("service", "control API")) + + return &Server{ + cfg: c, + } +} + +// WithAuthorizedKeysFetcher returns option to add list of public +// keys that have rights to use Control service. +func WithAuthorizedKeysFetcher(fetcher AuthorizedKeysFetcher) Option { + return func(c *cfg) { + c.keysFetcher = fetcher + } +} + +// WithLogger returns option to set logger. +func WithLogger(log *zap.Logger) Option { + return func(c *cfg) { + c.log = log + } +} + +// HealthCheck returns health status of the local node. +// +// If request is unsigned or signed by disallowed key, permission error returns. +func (s *Server) HealthCheck(_ context.Context, req *control.HealthCheckRequest) (*control.HealthCheckResponse, error) { + s.log.Info("healthcheck", zap.String("key", hex.EncodeToString(req.Signature.Key))) + + // verify request + if err := s.isValidRequest(req); err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + + resp := &control.HealthCheckResponse{ + Body: &control.HealthCheckResponse_Body{ + HealthStatus: control.HealthStatus_READY, + }, + } + + return resp, nil +} + +// SignedMessage is an interface of Control service message. +type SignedMessage interface { + ReadSignedData([]byte) ([]byte, error) + GetSignature() *control.Signature + SetSignature(*control.Signature) +} + +var errDisallowedKey = errors.New("key is not in the allowed list") +var errMissingSignature = errors.New("missing signature") +var errInvalidSignature = errors.New("invalid signature") + +func (s *Server) isValidRequest(req SignedMessage) error { + sign := req.GetSignature() + if sign == nil { + return errMissingSignature + } + + var ( + key = sign.GetKey() + allowed = false + ) + + // check if key is allowed + for _, authKey := range s.keysFetcher.FetchRawKeys() { + if allowed = bytes.Equal(authKey, key); allowed { + break + } + } + + if !allowed { + return errDisallowedKey + } + + // verify signature + binBody, err := req.ReadSignedData(nil) + if err != nil { + return fmt.Errorf("marshal request body: %w", err) + } + + // TODO(@cthulhu-rider): #468 use Signature message from FrostFS API to avoid conversion + var sigV2 refs.Signature + sigV2.SetKey(sign.GetKey()) + sigV2.SetSign(sign.GetSign()) + sigV2.SetScheme(refs.ECDSA_SHA512) + + var sig frostfscrypto.Signature + if err := sig.ReadFromV2(sigV2); err != nil { + return fmt.Errorf("can't read signature: %w", err) + } + + if !sig.Verify(binBody) { + return errInvalidSignature + } + + return nil +} + +// SignMessage signs Control service message with private key. +func SignMessage(key *ecdsa.PrivateKey, msg SignedMessage) error { + binBody, err := msg.ReadSignedData(nil) + if err != nil { + return fmt.Errorf("marshal request body: %w", err) + } + + var sig frostfscrypto.Signature + + err = sig.Calculate(frostfsecdsa.Signer(*key), binBody) + if err != nil { + return fmt.Errorf("calculate signature: %w", err) + } + + // TODO(@cthulhu-rider): #468 use Signature message from FrostFS API to avoid conversion + var sigV2 refs.Signature + sig.WriteToV2(&sigV2) + + var sigControl control.Signature + sigControl.Key = sigV2.GetKey() + sigControl.Sign = sigV2.GetSign() + + msg.SetSignature(&sigControl) + + return nil +} diff --git a/pkg/service/control/service.pb.go b/pkg/service/control/service.pb.go new file mode 100644 index 000000000..3565cdf8a --- /dev/null +++ b/pkg/service/control/service.pb.go @@ -0,0 +1,514 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: pkg/service/control/service.proto + +package control + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +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) +) + +// Health status of the storage node application. +type HealthStatus int32 + +const ( + // Undefined status, default value. + HealthStatus_HEALTH_STATUS_UNDEFINED HealthStatus = 0 + // Storage node application is starting. + HealthStatus_STARTING HealthStatus = 1 + // Storage node application is started and serves all services. + HealthStatus_READY HealthStatus = 2 + // Storage node application is shutting down. + HealthStatus_SHUTTING_DOWN HealthStatus = 3 +) + +// Enum value maps for HealthStatus. +var ( + HealthStatus_name = map[int32]string{ + 0: "HEALTH_STATUS_UNDEFINED", + 1: "STARTING", + 2: "READY", + 3: "SHUTTING_DOWN", + } + HealthStatus_value = map[string]int32{ + "HEALTH_STATUS_UNDEFINED": 0, + "STARTING": 1, + "READY": 2, + "SHUTTING_DOWN": 3, + } +) + +func (x HealthStatus) Enum() *HealthStatus { + p := new(HealthStatus) + *p = x + return p +} + +func (x HealthStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HealthStatus) Descriptor() protoreflect.EnumDescriptor { + return file_pkg_service_control_service_proto_enumTypes[0].Descriptor() +} + +func (HealthStatus) Type() protoreflect.EnumType { + return &file_pkg_service_control_service_proto_enumTypes[0] +} + +func (x HealthStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HealthStatus.Descriptor instead. +func (HealthStatus) EnumDescriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{0} +} + +// Signature of some message. +type Signature struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Public key used for signing. + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // Binary signature. + Sign []byte `protobuf:"bytes,2,opt,name=sign,json=signature,proto3" json:"sign,omitempty"` +} + +func (x *Signature) Reset() { + *x = Signature{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_service_control_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Signature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Signature) ProtoMessage() {} + +func (x *Signature) ProtoReflect() protoreflect.Message { + mi := &file_pkg_service_control_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Signature.ProtoReflect.Descriptor instead. +func (*Signature) Descriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{0} +} + +func (x *Signature) GetKey() []byte { + if x != nil { + return x.Key + } + return nil +} + +func (x *Signature) GetSign() []byte { + if x != nil { + return x.Sign + } + return nil +} + +// Health check request. +type HealthCheckRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Body of health check request message. + Body *HealthCheckRequest_Body `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + // Body signature. + Signature *Signature `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *HealthCheckRequest) Reset() { + *x = HealthCheckRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_service_control_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HealthCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthCheckRequest) ProtoMessage() {} + +func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_service_control_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. +func (*HealthCheckRequest) Descriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{1} +} + +func (x *HealthCheckRequest) GetBody() *HealthCheckRequest_Body { + if x != nil { + return x.Body + } + return nil +} + +func (x *HealthCheckRequest) GetSignature() *Signature { + if x != nil { + return x.Signature + } + return nil +} + +// Health check response. +type HealthCheckResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Body of health check response message. + Body *HealthCheckResponse_Body `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + Signature *Signature `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *HealthCheckResponse) Reset() { + *x = HealthCheckResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_service_control_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HealthCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthCheckResponse) ProtoMessage() {} + +func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_service_control_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. +func (*HealthCheckResponse) Descriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{2} +} + +func (x *HealthCheckResponse) GetBody() *HealthCheckResponse_Body { + if x != nil { + return x.Body + } + return nil +} + +func (x *HealthCheckResponse) GetSignature() *Signature { + if x != nil { + return x.Signature + } + return nil +} + +type HealthCheckRequest_Body struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *HealthCheckRequest_Body) Reset() { + *x = HealthCheckRequest_Body{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_service_control_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HealthCheckRequest_Body) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthCheckRequest_Body) ProtoMessage() {} + +func (x *HealthCheckRequest_Body) ProtoReflect() protoreflect.Message { + mi := &file_pkg_service_control_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthCheckRequest_Body.ProtoReflect.Descriptor instead. +func (*HealthCheckRequest_Body) Descriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{1, 0} +} + +// Health check response body +type HealthCheckResponse_Body struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Health status of storage node application. + HealthStatus HealthStatus `protobuf:"varint,1,opt,name=health_status,json=healthStatus,proto3,enum=s3gw.control.HealthStatus" json:"health_status,omitempty"` +} + +func (x *HealthCheckResponse_Body) Reset() { + *x = HealthCheckResponse_Body{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_service_control_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HealthCheckResponse_Body) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthCheckResponse_Body) ProtoMessage() {} + +func (x *HealthCheckResponse_Body) ProtoReflect() protoreflect.Message { + mi := &file_pkg_service_control_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthCheckResponse_Body.ProtoReflect.Descriptor instead. +func (*HealthCheckResponse_Body) Descriptor() ([]byte, []int) { + return file_pkg_service_control_service_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *HealthCheckResponse_Body) GetHealthStatus() HealthStatus { + if x != nil { + return x.HealthStatus + } + return HealthStatus_HEALTH_STATUS_UNDEFINED +} + +var File_pkg_service_control_service_proto protoreflect.FileDescriptor + +var file_pkg_service_control_service_proto_rawDesc = []byte{ + 0x0a, 0x21, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x22, 0x36, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x17, 0x0a, 0x04, 0x73, 0x69, 0x67, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x8e, 0x01, 0x0a, 0x12, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x39, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, 0x0a, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x1a, 0x06, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x22, 0xd1, 0x01, 0x0a, 0x13, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x35, + 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x1a, 0x47, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3f, 0x0a, + 0x0d, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x0c, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x57, + 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, + 0x0a, 0x17, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, + 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, + 0x44, 0x59, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, + 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x32, 0x64, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0b, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x20, 0x2e, 0x73, 0x33, 0x67, 0x77, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x33, 0x67, + 0x77, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x41, 0x5a, + 0x3f, 0x67, 0x69, 0x74, 0x2e, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2e, 0x69, 0x6e, 0x66, + 0x6f, 0x2f, 0x54, 0x72, 0x75, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4c, 0x61, 0x62, 0x2f, 0x66, + 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2d, 0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_pkg_service_control_service_proto_rawDescOnce sync.Once + file_pkg_service_control_service_proto_rawDescData = file_pkg_service_control_service_proto_rawDesc +) + +func file_pkg_service_control_service_proto_rawDescGZIP() []byte { + file_pkg_service_control_service_proto_rawDescOnce.Do(func() { + file_pkg_service_control_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_service_control_service_proto_rawDescData) + }) + return file_pkg_service_control_service_proto_rawDescData +} + +var file_pkg_service_control_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_pkg_service_control_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_pkg_service_control_service_proto_goTypes = []interface{}{ + (HealthStatus)(0), // 0: s3gw.control.HealthStatus + (*Signature)(nil), // 1: s3gw.control.Signature + (*HealthCheckRequest)(nil), // 2: s3gw.control.HealthCheckRequest + (*HealthCheckResponse)(nil), // 3: s3gw.control.HealthCheckResponse + (*HealthCheckRequest_Body)(nil), // 4: s3gw.control.HealthCheckRequest.Body + (*HealthCheckResponse_Body)(nil), // 5: s3gw.control.HealthCheckResponse.Body +} +var file_pkg_service_control_service_proto_depIdxs = []int32{ + 4, // 0: s3gw.control.HealthCheckRequest.body:type_name -> s3gw.control.HealthCheckRequest.Body + 1, // 1: s3gw.control.HealthCheckRequest.signature:type_name -> s3gw.control.Signature + 5, // 2: s3gw.control.HealthCheckResponse.body:type_name -> s3gw.control.HealthCheckResponse.Body + 1, // 3: s3gw.control.HealthCheckResponse.signature:type_name -> s3gw.control.Signature + 0, // 4: s3gw.control.HealthCheckResponse.Body.health_status:type_name -> s3gw.control.HealthStatus + 2, // 5: s3gw.control.ControlService.HealthCheck:input_type -> s3gw.control.HealthCheckRequest + 3, // 6: s3gw.control.ControlService.HealthCheck:output_type -> s3gw.control.HealthCheckResponse + 6, // [6:7] is the sub-list for method output_type + 5, // [5:6] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_pkg_service_control_service_proto_init() } +func file_pkg_service_control_service_proto_init() { + if File_pkg_service_control_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pkg_service_control_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Signature); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_service_control_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HealthCheckRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_service_control_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HealthCheckResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_service_control_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HealthCheckRequest_Body); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_service_control_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HealthCheckResponse_Body); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pkg_service_control_service_proto_rawDesc, + NumEnums: 1, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_pkg_service_control_service_proto_goTypes, + DependencyIndexes: file_pkg_service_control_service_proto_depIdxs, + EnumInfos: file_pkg_service_control_service_proto_enumTypes, + MessageInfos: file_pkg_service_control_service_proto_msgTypes, + }.Build() + File_pkg_service_control_service_proto = out.File + file_pkg_service_control_service_proto_rawDesc = nil + file_pkg_service_control_service_proto_goTypes = nil + file_pkg_service_control_service_proto_depIdxs = nil +} diff --git a/pkg/service/control/service.proto b/pkg/service/control/service.proto new file mode 100644 index 000000000..a48b1eb77 --- /dev/null +++ b/pkg/service/control/service.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +package s3gw.control; + +option go_package = "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"; + +// `ControlService` provides an interface for internal work with the storage node. +service ControlService { + // Performs health check of the storage node. + rpc HealthCheck (HealthCheckRequest) returns (HealthCheckResponse); +} + +// Signature of some message. +message Signature { + // Public key used for signing. + bytes key = 1 [json_name = "key"]; + + // Binary signature. + bytes sign = 2 [json_name = "signature"]; +} + +// Health check request. +message HealthCheckRequest { + message Body { + } + + // Body of health check request message. + Body body = 1; + + // Body signature. + Signature signature = 2; +} + +// Health check response. +message HealthCheckResponse { + // Health check response body + message Body { + // Health status of storage node application. + HealthStatus health_status = 1; + } + + // Body of health check response message. + Body body = 1; + + Signature signature = 2; +} + + +// Health status of the storage node application. +enum HealthStatus { + // Undefined status, default value. + HEALTH_STATUS_UNDEFINED = 0; + + // Storage node application is starting. + STARTING = 1; + + // Storage node application is started and serves all services. + READY = 2; + + // Storage node application is shutting down. + SHUTTING_DOWN = 3; +} \ No newline at end of file diff --git a/pkg/service/control/service_frostfs.pb.go b/pkg/service/control/service_frostfs.pb.go new file mode 100644 index 000000000..4a1964996 --- /dev/null +++ b/pkg/service/control/service_frostfs.pb.go @@ -0,0 +1,201 @@ +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package control + +import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/proto" + +// StableSize returns the size of x in protobuf format. +// +// Structures with the same field values have the same binary size. +func (x *Signature) StableSize() (size int) { + if x == nil { + return 0 + } + size += proto.BytesSize(1, x.Key) + size += proto.BytesSize(2, x.Sign) + return size +} + +// StableMarshal marshals x in protobuf binary format with stable field order. +// +// If buffer length is less than x.StableSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same binary format. +func (x *Signature) StableMarshal(buf []byte) []byte { + if x == nil { + return []byte{} + } + if buf == nil { + buf = make([]byte, x.StableSize()) + } + var offset int + offset += proto.BytesMarshal(1, buf[offset:], x.Key) + offset += proto.BytesMarshal(2, buf[offset:], x.Sign) + return buf +} + +// StableSize returns the size of x in protobuf format. +// +// Structures with the same field values have the same binary size. +func (x *HealthCheckRequest_Body) StableSize() (size int) { + if x == nil { + return 0 + } + return size +} + +// StableMarshal marshals x in protobuf binary format with stable field order. +// +// If buffer length is less than x.StableSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same binary format. +func (x *HealthCheckRequest_Body) StableMarshal(buf []byte) []byte { + return buf +} + +// StableSize returns the size of x in protobuf format. +// +// Structures with the same field values have the same binary size. +func (x *HealthCheckRequest) StableSize() (size int) { + if x == nil { + return 0 + } + size += proto.NestedStructureSize(1, x.Body) + size += proto.NestedStructureSize(2, x.Signature) + return size +} + +// StableMarshal marshals x in protobuf binary format with stable field order. +// +// If buffer length is less than x.StableSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same binary format. +func (x *HealthCheckRequest) StableMarshal(buf []byte) []byte { + if x == nil { + return []byte{} + } + if buf == nil { + buf = make([]byte, x.StableSize()) + } + var offset int + offset += proto.NestedStructureMarshal(1, buf[offset:], x.Body) + offset += proto.NestedStructureMarshal(2, buf[offset:], x.Signature) + return buf +} + +// ReadSignedData fills buf with signed data of x. +// If buffer length is less than x.SignedDataSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same signed data. +func (x *HealthCheckRequest) SignedDataSize() int { + return x.GetBody().StableSize() +} + +// SignedDataSize returns size of the request signed data in bytes. +// +// Structures with the same field values have the same signed data size. +func (x *HealthCheckRequest) ReadSignedData(buf []byte) ([]byte, error) { + return x.GetBody().StableMarshal(buf), nil +} + +func (x *HealthCheckRequest) SetSignature(sig *Signature) { + x.Signature = sig +} + +// StableSize returns the size of x in protobuf format. +// +// Structures with the same field values have the same binary size. +func (x *HealthCheckResponse_Body) StableSize() (size int) { + if x == nil { + return 0 + } + size += proto.EnumSize(1, int32(x.HealthStatus)) + return size +} + +// StableMarshal marshals x in protobuf binary format with stable field order. +// +// If buffer length is less than x.StableSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same binary format. +func (x *HealthCheckResponse_Body) StableMarshal(buf []byte) []byte { + if x == nil { + return []byte{} + } + if buf == nil { + buf = make([]byte, x.StableSize()) + } + var offset int + offset += proto.EnumMarshal(1, buf[offset:], int32(x.HealthStatus)) + return buf +} + +// StableSize returns the size of x in protobuf format. +// +// Structures with the same field values have the same binary size. +func (x *HealthCheckResponse) StableSize() (size int) { + if x == nil { + return 0 + } + size += proto.NestedStructureSize(1, x.Body) + size += proto.NestedStructureSize(2, x.Signature) + return size +} + +// StableMarshal marshals x in protobuf binary format with stable field order. +// +// If buffer length is less than x.StableSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same binary format. +func (x *HealthCheckResponse) StableMarshal(buf []byte) []byte { + if x == nil { + return []byte{} + } + if buf == nil { + buf = make([]byte, x.StableSize()) + } + var offset int + offset += proto.NestedStructureMarshal(1, buf[offset:], x.Body) + offset += proto.NestedStructureMarshal(2, buf[offset:], x.Signature) + return buf +} + +// ReadSignedData fills buf with signed data of x. +// If buffer length is less than x.SignedDataSize(), new buffer is allocated. +// +// Returns any error encountered which did not allow writing the data completely. +// Otherwise, returns the buffer in which the data is written. +// +// Structures with the same field values have the same signed data. +func (x *HealthCheckResponse) SignedDataSize() int { + return x.GetBody().StableSize() +} + +// SignedDataSize returns size of the request signed data in bytes. +// +// Structures with the same field values have the same signed data size. +func (x *HealthCheckResponse) ReadSignedData(buf []byte) ([]byte, error) { + return x.GetBody().StableMarshal(buf), nil +} + +func (x *HealthCheckResponse) SetSignature(sig *Signature) { + x.Signature = sig +} diff --git a/pkg/service/control/service_grpc.pb.go b/pkg/service/control/service_grpc.pb.go new file mode 100644 index 000000000..fc6852072 --- /dev/null +++ b/pkg/service/control/service_grpc.pb.go @@ -0,0 +1,105 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.21.9 +// source: pkg/service/control/service.proto + +package control + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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 + +// ControlServiceClient is the client API for ControlService 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 ControlServiceClient interface { + // Performs health check of the storage node. + HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) +} + +type controlServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewControlServiceClient(cc grpc.ClientConnInterface) ControlServiceClient { + return &controlServiceClient{cc} +} + +func (c *controlServiceClient) HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) { + out := new(HealthCheckResponse) + err := c.cc.Invoke(ctx, "/s3gw.control.ControlService/HealthCheck", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ControlServiceServer is the server API for ControlService service. +// All implementations should embed UnimplementedControlServiceServer +// for forward compatibility +type ControlServiceServer interface { + // Performs health check of the storage node. + HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) +} + +// UnimplementedControlServiceServer should be embedded to have forward compatible implementations. +type UnimplementedControlServiceServer struct { +} + +func (UnimplementedControlServiceServer) HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method HealthCheck not implemented") +} + +// UnsafeControlServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ControlServiceServer will +// result in compilation errors. +type UnsafeControlServiceServer interface { + mustEmbedUnimplementedControlServiceServer() +} + +func RegisterControlServiceServer(s grpc.ServiceRegistrar, srv ControlServiceServer) { + s.RegisterService(&ControlService_ServiceDesc, srv) +} + +func _ControlService_HealthCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HealthCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServiceServer).HealthCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/s3gw.control.ControlService/HealthCheck", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServiceServer).HealthCheck(ctx, req.(*HealthCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ControlService_ServiceDesc is the grpc.ServiceDesc for ControlService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ControlService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "s3gw.control.ControlService", + HandlerType: (*ControlServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "HealthCheck", + Handler: _ControlService_HealthCheck_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "pkg/service/control/service.proto", +}