forked from TrueCloudLab/frostfs-s3-gw
[#XX] Support AddPolicy method to control API
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
4bb0872191
commit
e28c445a50
11 changed files with 585 additions and 28 deletions
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue