[#XX] Support AddPolicy method to control API

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2023-10-19 16:37:35 +03:00
parent 4bb0872191
commit e28c445a50
11 changed files with 585 additions and 28 deletions

View file

@ -2,9 +2,11 @@ package middleware
import (
"crypto/elliptic"
"encoding/hex"
stderrors "errors"
"fmt"
"net/http"
"strings"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
@ -12,6 +14,8 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
engine "git.frostfs.info/TrueCloudLab/policy-engine"
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"go.uber.org/zap"
)
@ -112,3 +116,282 @@ func validateBearerToken(frostfsID FrostFSID, bt *bearer.Token) error {
return nil
}
type policyRequest struct {
properties map[string]string
operation string
resource *policyResource
}
func (r *policyRequest) Operation() string {
return r.operation
}
func (r *policyRequest) Property(key string) string {
return r.properties[key]
}
func (r *policyRequest) Resource() engine.Resource {
return r.resource
}
type policyResource struct {
name string
properties map[string]string
}
func (r *policyResource) Name() string {
return r.name
}
func (r *policyResource) Property(key string) string {
return r.properties[key]
}
func PolicyCheck(storage engine.CachedChainStorage, log *zap.Logger) Func {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req := getPolicyRequest(r)
st, _ := storage.IsAllowed(engine.Ingress, "root", req)
if st != engine.Allow && st != engine.NoRuleFound {
err := fmt.Errorf("access denied")
reqLogOrDefault(ctx, log).Error(logs.PolicyValidationFailed, zap.String("status", st.String()), zap.Error(err))
WriteErrorResponse(w, GetReqInfo(ctx), err)
return
}
h.ServeHTTP(w, r)
})
}
}
// todo consider update bucket, object and api in request info
func getPolicyRequest(r *http.Request) *policyRequest {
var requestOwnerKey []byte
ctx := r.Context()
bd, err := GetBoxData(ctx)
if err == nil && bd.Gate.BearerToken != nil {
requestOwnerKey = bd.Gate.BearerToken.SigningKeyBytes()
}
op, res := determineOperationAndResource(r)
return &policyRequest{
properties: map[string]string{
engineiam.RequestOwnerProperty: hex.EncodeToString(requestOwnerKey),
},
operation: "s3:" + op,
resource: &policyResource{
name: "arn:aws:s3:::" + res,
},
}
}
type ReqType int
const (
noneType ReqType = iota
bucketType
objectType
)
func determineOperationAndResource(r *http.Request) (string, string) {
reqType := noneType
trimmed := strings.TrimPrefix(r.URL.Path, "/") // todo consider unescape
if trimmed != "" {
if arr := strings.Split(trimmed, "/"); len(arr) == 1 {
reqType = bucketType
} else {
reqType = objectType
}
}
var operation string
switch reqType {
case objectType:
operation = determineObjectOperation(r)
case bucketType:
operation = determineBucketOperation(r)
default:
operation = determineGeneralOperation(r)
}
return operation, trimmed
}
func determineBucketOperation(r *http.Request) string {
query := r.URL.Query()
switch r.Method {
case http.MethodOptions:
return "Options"
case http.MethodHead:
return "HeadBucket"
case http.MethodGet:
switch {
case query.Has("uploads"):
return "ListMultipartUploads"
case query.Has("location"):
return "GetBucketLocation"
case query.Has("policy"):
return "GetBucketPolicy"
case query.Has("lifecycle"):
return "GetBucketLifecycle"
case query.Has("encryption"):
return "GetBucketEncryption"
case query.Has("cors"):
return "GetBucketCors"
case query.Has("acl"):
return "GetBucketACL"
case query.Has("website"):
return "GetBucketWebsite"
case query.Has("accelerate"):
return "GetBucketAccelerate"
case query.Has("requestPayment"):
return "GetBucketRequestPayment"
case query.Has("logging"):
return "GetBucketLogging"
case query.Has("replication"):
return "GetBucketReplication"
case query.Has("tagging"):
return "GetBucketTagging"
case query.Has("object"):
return "GetBucketObjectLockConfig"
case query.Has("versioning"):
return "GetBucketVersioning"
case query.Has("notification"):
return "GetBucketNotification"
case query.Has("events"):
return "ListenBucketNotification"
case query.Has("versions"):
return "ListBucketObjectVersions"
case query.Get("list-type") == "2" && query.Get("metadata") == "true":
return "ListObjectsV2M"
case query.Get("list-type") == "2":
return "ListObjectsV2"
default:
return "ListObjectsV1"
}
case http.MethodPut:
switch {
case query.Has("cors"):
return "PutBucketCors"
case query.Has("acl"):
return "PutBucketACL"
case query.Has("lifecycle"):
return "PutBucketLifecycle"
case query.Has("encryption"):
return "PutBucketEncryption"
case query.Has("policy"):
return "PutBucketPolicy"
case query.Has("object"):
return "PutBucketObjectLockConfig"
case query.Has("tagging"):
return "PutBucketTagging"
case query.Has("versioning"):
return "PutBucketVersioning"
case query.Has("notification"):
return "PutBucketNotification"
default:
return "CreateBucket"
}
case http.MethodPost:
switch {
case query.Has("delete"):
return "DeleteMultipleObjects"
default:
return "PostObject"
}
case http.MethodDelete:
switch {
case query.Has("cors"):
return "DeleteBucketCors"
case query.Has("website"):
return "DeleteBucketWebsite"
case query.Has("tagging"):
return "DeleteBucketTagging"
case query.Has("policy"):
return "PutBucketPolicy"
case query.Has("lifecycle"):
return "PutBucketLifecycle"
case query.Has("encryption"):
return "DeleteBucketEncryption"
default:
return "DeleteBucket"
}
}
return ""
}
func determineObjectOperation(r *http.Request) string {
query := r.URL.Query()
switch r.Method {
case http.MethodHead:
return "HeadObject"
case http.MethodGet:
switch {
case query.Has("uploadId"):
return "ListParts"
case query.Has("acl"):
return "GetObjectACL"
case query.Has("tagging"):
return "GetObjectTagging"
case query.Has("retention"):
return "GetObjectRetention"
case query.Has("legal"):
return "GetObjectLegalHold"
case query.Has("attributes"):
return "GetObjectAttributes"
default:
return "GetObject"
}
case http.MethodPut:
switch {
case query.Has("partNumber") && query.Has("uploadId") && r.Header.Get("X-Amz-Copy-Source") != "":
return "UploadPartCopy"
case query.Has("partNumber") && query.Has("uploadId"):
return "UploadPart"
case query.Has("acl"):
return "PutObjectACL"
case query.Has("tagging"):
return "PutObjectTagging"
case r.Header.Get("X-Amz-Copy-Source") != "":
return "CopyObject"
case query.Has("retention"):
return "PutObjectRetention"
case query.Has("legal-hold"):
return "PutObjectLegalHold"
default:
return "PutObject"
}
case http.MethodPost:
switch {
case query.Has("uploadId"):
return "CompleteMultipartUpload"
case query.Has("uploads"):
return "CreateMultipartUpload"
default:
return "SelectObjectContent"
}
case http.MethodDelete:
switch {
case query.Has("uploadId"):
return "AbortMultipartUpload"
case query.Has("tagging"):
return "DeleteObjectTagging"
default:
return "DeleteObject"
}
}
return ""
}
func determineGeneralOperation(r *http.Request) string {
if r.Method == http.MethodGet {
return "ListBuckets"
}
return ""
}

View file

@ -10,6 +10,7 @@ import (
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
engine "git.frostfs.info/TrueCloudLab/policy-engine"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"go.uber.org/zap"
@ -101,6 +102,8 @@ type Config struct {
// FrostfsID optional. If nil middleware.IAM won't be attached.
FrostfsID s3middleware.FrostFSID
PolicyStorage engine.CachedChainStorage
}
func NewRouter(cfg Config) *chi.Mux {
@ -119,6 +122,10 @@ func NewRouter(cfg Config) *chi.Mux {
api.Use(s3middleware.IAM(cfg.FrostfsID, cfg.Log))
}
if cfg.PolicyStorage != nil {
api.Use(s3middleware.PolicyCheck(cfg.PolicyStorage, cfg.Log))
}
defaultRouter := chi.NewRouter()
defaultRouter.Mount(fmt.Sprintf("/{%s}", s3middleware.BucketURLPrm), bucketRouter(cfg.Handler, cfg.Log))
defaultRouter.Get("/", named("ListBuckets", cfg.Handler.ListBucketsHandler))

View file

@ -40,6 +40,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
engine "git.frostfs.info/TrueCloudLab/policy-engine"
"github.com/go-chi/chi/v5/middleware"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/spf13/viper"
@ -62,7 +63,8 @@ type (
obj layer.Client
api api.Handler
frostfsid *frostfsid.FrostFSID
frostfsid *frostfsid.FrostFSID
policyStorage engine.CachedChainStorage
servers []Server
@ -322,10 +324,13 @@ func (a *App) initControlAPI() {
rawPubs = append(rawPubs, pubs[i].Bytes())
}
a.policyStorage = engine.NewInMemory()
svc := controlSvc.New(
controlSvc.WithKey(&a.key.PrivateKey),
controlSvc.WithAuthorizedKeys(rawPubs),
controlSvc.WithLogger(a.log),
controlSvc.WithChainStorage(a.policyStorage),
)
a.controlAPI = grpc.NewServer()
@ -546,6 +551,8 @@ func (a *App) Serve(ctx context.Context) {
Log: a.log,
Metrics: a.metrics,
Domains: domains,
PolicyStorage: a.policyStorage,
}
// We cannot make direct assignment if frostfsid.FrostFSID is nil

1
go.mod
View file

@ -7,6 +7,7 @@ require (
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231004065251-4194633db7bb
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230821090303-202412230a05
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20231023124434-31a308ea61fb
github.com/aws/aws-sdk-go v1.44.6
github.com/bluele/gcache v0.0.2
github.com/go-chi/chi/v5 v5.0.8

2
go.sum
View file

@ -397,6 +397,8 @@ git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230821090303-202412230a05
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20230821090303-202412230a05/go.mod h1:t1akKcUH7iBrFHX8rSXScYMP17k2kYQXMbZooiL5Juw=
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20231023124434-31a308ea61fb h1:yMAz3bHUoy0lpzVd8qqJaVjb1ytjUjG8ePgaLOUUt3Q=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20231023124434-31a308ea61fb/go.mod h1:qf3B9hSz6gCMfcfvqkhTu5ak+Gx2R+wo4Hc87LnKxPg=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA=
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=

View file

@ -120,4 +120,5 @@ const (
RuntimeSoftMemoryLimitUpdated = "soft runtime memory limit value updated" // Info in ../../cmd/s3-gw/app.go
AnonRequestSkipIAMValidation = "anon request, skip IAM validation" // Debug in ../../api/middleware/auth.go
IAMValidationFailed = "IAM validation failed" // Error in ../../api/middleware/auth.go
PolicyValidationFailed = "Policy validation failed" // Error in ../../api/middleware/auth.go
)

View file

@ -2,10 +2,12 @@ package client
import (
"context"
"encoding/json"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"
controlSvc "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control/server"
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"go.uber.org/zap"
"google.golang.org/grpc"
@ -29,6 +31,9 @@ func New(ctx context.Context, addr string, key *keys.PrivateKey) (*Client, error
svc := control.NewControlServiceClient(conn)
// todo consider add invoking healthcheck
// c.Healthcheck(ctx)
return &Client{
svc: svc,
key: key,
@ -54,3 +59,28 @@ func (c *Client) Healthcheck(ctx context.Context) error {
return nil
}
func (c *Client) AddPolicy(ctx context.Context, policy string) error {
var p engineiam.Policy
if err := json.Unmarshal([]byte(policy), &p); err != nil {
return err
}
chain, err := p.ToChain()
if err != nil {
return err
}
req := &control.AddPolicyRequest{
Body: chain.Bytes(),
}
sig, err := controlSvc.SignMessage(&c.key.PrivateKey, req.Body)
if err != nil {
return err
}
req.Signature = sig
_, err = c.svc.AddPolicy(ctx, req)
return err
}

View file

@ -12,6 +12,7 @@ import (
"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"
engine "git.frostfs.info/TrueCloudLab/policy-engine"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -30,6 +31,8 @@ type cfg struct {
log *zap.Logger
allowedKeys [][]byte
chainStorage engine.CachedChainStorage
}
func defaultCfg() *cfg {
@ -50,6 +53,10 @@ func New(opts ...Option) *Server {
c.log = c.log.With(zap.String("service", "control API"))
if c.chainStorage == nil {
c.chainStorage = engine.NewInMemory()
}
return &Server{
cfg: c,
}
@ -78,6 +85,13 @@ func WithLogger(log *zap.Logger) Option {
}
}
// WithChainStorage returns option to set logger.
func WithChainStorage(chainStorage engine.CachedChainStorage) Option {
return func(c *cfg) {
c.chainStorage = chainStorage
}
}
// HealthCheck returns health status of the local node.
//
// If request is unsigned or signed by disallowed key, permission error returns.
@ -98,6 +112,29 @@ func (s *Server) HealthCheck(_ context.Context, req *control.HealthCheckRequest)
return resp, nil
}
// AddPolicy adds new policy.
//
// If request is unsigned or signed by disallowed key, permission error returns.
func (s *Server) AddPolicy(_ context.Context, req *control.AddPolicyRequest) (*control.AddPolicyResponse, error) {
s.log.Info("add policy", 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())
}
req.GetBody()
var chain engine.Chain
if err := chain.DecodeBytes(req.Body); err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to parse body: %s", err.Error()))
}
s.chainStorage.AddNameSpaceChain(engine.Ingress, "root", &chain)
return &control.AddPolicyResponse{}, nil
}
// SignedMessage is an interface of Control service message.
type SignedMessage interface {
GetSignature() *control.Signature

View file

@ -242,6 +242,103 @@ func (x *HealthCheckResponse) GetBody() *HealthCheckResponse_Body {
return nil
}
// Add policy request.
type AddPolicyRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Body of health check request message.
Body []byte `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 *AddPolicyRequest) Reset() {
*x = AddPolicyRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_pkg_service_control_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddPolicyRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddPolicyRequest) ProtoMessage() {}
func (x *AddPolicyRequest) 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 AddPolicyRequest.ProtoReflect.Descriptor instead.
func (*AddPolicyRequest) Descriptor() ([]byte, []int) {
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{3}
}
func (x *AddPolicyRequest) GetBody() []byte {
if x != nil {
return x.Body
}
return nil
}
func (x *AddPolicyRequest) GetSignature() *Signature {
if x != nil {
return x.Signature
}
return nil
}
// Add policy response.
type AddPolicyResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *AddPolicyResponse) Reset() {
*x = AddPolicyResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_pkg_service_control_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AddPolicyResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AddPolicyResponse) ProtoMessage() {}
func (x *AddPolicyResponse) 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 AddPolicyResponse.ProtoReflect.Descriptor instead.
func (*AddPolicyResponse) Descriptor() ([]byte, []int) {
return file_pkg_service_control_service_proto_rawDescGZIP(), []int{4}
}
// Health check response body
type HealthCheckResponse_Body struct {
state protoimpl.MessageState
@ -255,7 +352,7 @@ type HealthCheckResponse_Body struct {
func (x *HealthCheckResponse_Body) Reset() {
*x = HealthCheckResponse_Body{}
if protoimpl.UnsafeEnabled {
mi := &file_pkg_service_control_service_proto_msgTypes[3]
mi := &file_pkg_service_control_service_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -268,7 +365,7 @@ func (x *HealthCheckResponse_Body) String() string {
func (*HealthCheckResponse_Body) ProtoMessage() {}
func (x *HealthCheckResponse_Body) ProtoReflect() protoreflect.Message {
mi := &file_pkg_service_control_service_proto_msgTypes[3]
mi := &file_pkg_service_control_service_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -315,23 +412,34 @@ var file_pkg_service_control_service_proto_rawDesc = []byte{
0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15,
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, 0x5a, 0x0a, 0x0e,
0x74, 0x75, 0x73, 0x22, 0x58, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x30, 0x0a, 0x09, 0x73,
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,
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, 0x22, 0x13, 0x0a,
0x11, 0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 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, 0x9e, 0x01, 0x0a, 0x0e,
0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48,
0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1b, 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, 0x1c, 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,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e,
0x41, 0x64, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x41, 0x64, 0x64, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x79, 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 (
@ -347,25 +455,30 @@ func file_pkg_service_control_service_proto_rawDescGZIP() []byte {
}
var file_pkg_service_control_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_pkg_service_control_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_pkg_service_control_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_pkg_service_control_service_proto_goTypes = []interface{}{
(HealthStatus)(0), // 0: control.HealthStatus
(*Signature)(nil), // 1: control.Signature
(*HealthCheckRequest)(nil), // 2: control.HealthCheckRequest
(*HealthCheckResponse)(nil), // 3: control.HealthCheckResponse
(*HealthCheckResponse_Body)(nil), // 4: control.HealthCheckResponse.Body
(*AddPolicyRequest)(nil), // 4: control.AddPolicyRequest
(*AddPolicyResponse)(nil), // 5: control.AddPolicyResponse
(*HealthCheckResponse_Body)(nil), // 6: control.HealthCheckResponse.Body
}
var file_pkg_service_control_service_proto_depIdxs = []int32{
1, // 0: control.HealthCheckRequest.signature:type_name -> control.Signature
4, // 1: control.HealthCheckResponse.body:type_name -> control.HealthCheckResponse.Body
0, // 2: control.HealthCheckResponse.Body.health_status:type_name -> control.HealthStatus
2, // 3: control.ControlService.HealthCheck:input_type -> control.HealthCheckRequest
3, // 4: control.ControlService.HealthCheck:output_type -> control.HealthCheckResponse
4, // [4:5] is the sub-list for method output_type
3, // [3:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
6, // 1: control.HealthCheckResponse.body:type_name -> control.HealthCheckResponse.Body
1, // 2: control.AddPolicyRequest.signature:type_name -> control.Signature
0, // 3: control.HealthCheckResponse.Body.health_status:type_name -> control.HealthStatus
2, // 4: control.ControlService.HealthCheck:input_type -> control.HealthCheckRequest
4, // 5: control.ControlService.AddPolicy:input_type -> control.AddPolicyRequest
3, // 6: control.ControlService.HealthCheck:output_type -> control.HealthCheckResponse
5, // 7: control.ControlService.AddPolicy:output_type -> control.AddPolicyResponse
6, // [6:8] is the sub-list for method output_type
4, // [4:6] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_pkg_service_control_service_proto_init() }
@ -411,6 +524,30 @@ func file_pkg_service_control_service_proto_init() {
}
}
file_pkg_service_control_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AddPolicyRequest); 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.(*AddPolicyResponse); 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[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HealthCheckResponse_Body); i {
case 0:
return &v.state
@ -429,7 +566,7 @@ func file_pkg_service_control_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_pkg_service_control_service_proto_rawDesc,
NumEnums: 1,
NumMessages: 4,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},

View file

@ -8,6 +8,8 @@ option go_package = "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/con
service ControlService {
// Performs health check of the storage node.
rpc HealthCheck (HealthCheckRequest) returns (HealthCheckResponse);
rpc AddPolicy (AddPolicyRequest) returns (AddPolicyResponse);
}
// Signature of some message.
@ -54,4 +56,18 @@ enum HealthStatus {
// Storage node application is shutting down.
SHUTTING_DOWN = 3;
}
}
// Add policy request.
message AddPolicyRequest {
// Body of health check request message.
bytes body = 1;
// Body signature.
Signature signature = 2;
}
// Add policy response.
message AddPolicyResponse {
}

View file

@ -24,6 +24,7 @@ const _ = grpc.SupportPackageIsVersion7
type ControlServiceClient interface {
// Performs health check of the storage node.
HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
AddPolicy(ctx context.Context, in *AddPolicyRequest, opts ...grpc.CallOption) (*AddPolicyResponse, error)
}
type controlServiceClient struct {
@ -43,12 +44,22 @@ func (c *controlServiceClient) HealthCheck(ctx context.Context, in *HealthCheckR
return out, nil
}
func (c *controlServiceClient) AddPolicy(ctx context.Context, in *AddPolicyRequest, opts ...grpc.CallOption) (*AddPolicyResponse, error) {
out := new(AddPolicyResponse)
err := c.cc.Invoke(ctx, "/control.ControlService/AddPolicy", 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)
AddPolicy(context.Context, *AddPolicyRequest) (*AddPolicyResponse, error)
}
// UnimplementedControlServiceServer should be embedded to have forward compatible implementations.
@ -58,6 +69,9 @@ type UnimplementedControlServiceServer struct {
func (UnimplementedControlServiceServer) HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method HealthCheck not implemented")
}
func (UnimplementedControlServiceServer) AddPolicy(context.Context, *AddPolicyRequest) (*AddPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddPolicy 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
@ -88,6 +102,24 @@ func _ControlService_HealthCheck_Handler(srv interface{}, ctx context.Context, d
return interceptor(ctx, in, info, handler)
}
func _ControlService_AddPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddPolicyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServiceServer).AddPolicy(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/control.ControlService/AddPolicy",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServiceServer).AddPolicy(ctx, req.(*AddPolicyRequest))
}
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)
@ -99,6 +131,10 @@ var ControlService_ServiceDesc = grpc.ServiceDesc{
MethodName: "HealthCheck",
Handler: _ControlService_HealthCheck_Handler,
},
{
MethodName: "AddPolicy",
Handler: _ControlService_AddPolicy_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "pkg/service/control/service.proto",