package client import ( "context" "fmt" policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy" "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/policy-engine/pkg/chain" "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 } type PolicyData struct { Kind policycontract.Kind Name string Chain *chain.Chain } type PolicyInfo struct { Kind policycontract.Kind Name string ChainID chain.ID } func kindToTarget(k policycontract.Kind) control.PolicyTarget { switch k { case policycontract.Container: return control.PolicyTarget_CONTAINER case policycontract.Namespace: return control.PolicyTarget_NAMESPACE case 'u': return control.PolicyTarget_USER case 'g': return control.PolicyTarget_GROUP default: return control.PolicyTarget_TARGET_UNDEFINED } } 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 } func (c *Client) PutPolicies(ctx context.Context, policies []PolicyData) error { chainDatas := make([]*control.PutPoliciesRequest_ChainData, len(policies)) for i := range policies { chainDatas[i] = &control.PutPoliciesRequest_ChainData{ Target: kindToTarget(policies[i].Kind), Name: policies[i].Name, Chain: policies[i].Chain.Bytes(), } } req := &control.PutPoliciesRequest{ Body: &control.PutPoliciesRequest_Body{ ChainDatas: chainDatas, }, } if err := controlSvc.SignMessage(&c.key.PrivateKey, req); err != nil { return err } _, err := c.svc.PutPolicies(ctx, req) return err } func (c *Client) RemovePolicies(ctx context.Context, policies []PolicyInfo) error { chainInfos := make([]*control.RemovePoliciesRequest_ChainInfo, len(policies)) for i := range policies { chainInfos[i] = &control.RemovePoliciesRequest_ChainInfo{ Target: kindToTarget(policies[i].Kind), Name: policies[i].Name, ChainID: []byte(policies[i].ChainID), } } req := &control.RemovePoliciesRequest{ Body: &control.RemovePoliciesRequest_Body{ ChainInfos: chainInfos, }, } if err := controlSvc.SignMessage(&c.key.PrivateKey, req); err != nil { return err } _, err := c.svc.RemovePolicies(ctx, req) return err } func (c *Client) GetPolicy(ctx context.Context, kind policycontract.Kind, name string, chainID chain.ID) (*chain.Chain, error) { req := &control.GetPolicyRequest{ Body: &control.GetPolicyRequest_Body{ Target: kindToTarget(kind), Name: name, ChainID: []byte(chainID), }, } if err := controlSvc.SignMessage(&c.key.PrivateKey, req); err != nil { return nil, err } resp, err := c.svc.GetPolicy(ctx, req) if err != nil { return nil, err } var policyChain chain.Chain if err = policyChain.DecodeBytes(resp.GetBody().GetChain()); err != nil { return nil, err } return &policyChain, nil } func (c *Client) ListPolicies(ctx context.Context, kind policycontract.Kind, name string) ([]chain.ID, error) { req := &control.ListPoliciesRequest{ Body: &control.ListPoliciesRequest_Body{ Target: kindToTarget(kind), Name: name, }, } if err := controlSvc.SignMessage(&c.key.PrivateKey, req); err != nil { return nil, err } resp, err := c.svc.ListPolicies(ctx, req) if err != nil { return nil, err } res := make([]chain.ID, len(resp.GetBody().GetChainIDs())) for i, chainID := range resp.GetBody().GetChainIDs() { res[i] = chain.ID(chainID) } return res, nil }