package control import ( "context" "errors" "fmt" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/server/ape" apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func apeTarget(chainTarget *control.ChainTarget) (engine.Target, error) { switch chainTarget.GetType() { case control.ChainTarget_CONTAINER: return engine.ContainerTarget(chainTarget.GetName()), nil case control.ChainTarget_NAMESPACE: return engine.NamespaceTarget(chainTarget.GetName()), nil default: } return engine.Target{}, status.Error(codes.InvalidArgument, fmt.Errorf("target type is not supported: %s", chainTarget.GetType().String()).Error()) } func controlTarget(chainTarget *engine.Target) (control.ChainTarget, error) { switch chainTarget.Type { case engine.Container: return control.ChainTarget{ Name: chainTarget.Name, Type: control.ChainTarget_CONTAINER, }, nil case engine.Namespace: // If namespace is empty, we take it for root namespace. nm := chainTarget.Name if nm == "root" { nm = "" } return control.ChainTarget{ Name: nm, Type: control.ChainTarget_NAMESPACE, }, nil default: } return control.ChainTarget{}, status.Error(codes.InvalidArgument, fmt.Errorf("target type is not supported: %c", chainTarget.Type).Error()) } func (s *Server) AddChainLocalOverride(_ context.Context, req *control.AddChainLocalOverrideRequest) (*control.AddChainLocalOverrideResponse, error) { if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) } var chain apechain.Chain if err := chain.DecodeBytes(req.GetBody().GetChain()); err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } for _, rule := range chain.Rules { for _, name := range rule.Resources.Names { if err := ape.ValidateResourceName(name); err != nil { return nil, status.Error(codes.InvalidArgument, fmt.Errorf("invalid resource: %w", err).Error()) } } } s.apeChainCounter.Add(1) // TODO (aarifullin): the such chain id is not well-designed yet. if len(chain.ID) == 0 { chain.ID = apechain.ID(fmt.Sprintf("%s:%d", apechain.Ingress, s.apeChainCounter.Load())) } target, err := apeTarget(req.GetBody().GetTarget()) if err != nil { return nil, err } if _, err = s.localOverrideStorage.LocalStorage().AddOverride(apechain.Ingress, target, &chain); err != nil { return nil, status.Error(getCodeByLocalStorageErr(err), err.Error()) } resp := &control.AddChainLocalOverrideResponse{ Body: &control.AddChainLocalOverrideResponse_Body{ ChainId: []byte(chain.ID), }, } err = SignMessage(s.key, resp) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return resp, nil } func (s *Server) GetChainLocalOverride(_ context.Context, req *control.GetChainLocalOverrideRequest) (*control.GetChainLocalOverrideResponse, error) { if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) } target, err := apeTarget(req.GetBody().GetTarget()) if err != nil { return nil, err } chain, err := s.localOverrideStorage.LocalStorage().GetOverride(apechain.Ingress, target, apechain.ID(req.GetBody().GetChainId())) if err != nil { return nil, status.Error(getCodeByLocalStorageErr(err), err.Error()) } resp := &control.GetChainLocalOverrideResponse{ Body: &control.GetChainLocalOverrideResponse_Body{ Chain: chain.Bytes(), }, } err = SignMessage(s.key, resp) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return resp, nil } func (s *Server) ListChainLocalOverrides(_ context.Context, req *control.ListChainLocalOverridesRequest) (*control.ListChainLocalOverridesResponse, error) { if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) } target, err := apeTarget(req.GetBody().GetTarget()) if err != nil { return nil, err } chains, err := s.localOverrideStorage.LocalStorage().ListOverrides(apechain.Ingress, target) if err != nil { return nil, status.Error(getCodeByLocalStorageErr(err), err.Error()) } serializedChains := make([][]byte, 0, len(chains)) for _, chain := range chains { serializedChains = append(serializedChains, chain.Bytes()) } resp := &control.ListChainLocalOverridesResponse{ Body: &control.ListChainLocalOverridesResponse_Body{ Chains: serializedChains, }, } err = SignMessage(s.key, resp) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return resp, nil } func (s *Server) RemoveChainLocalOverride(_ context.Context, req *control.RemoveChainLocalOverrideRequest) (*control.RemoveChainLocalOverrideResponse, error) { if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) } target, err := apeTarget(req.GetBody().GetTarget()) if err != nil { return nil, err } removed := true if err = s.localOverrideStorage.LocalStorage().RemoveOverride(apechain.Ingress, target, apechain.ID(req.GetBody().GetChainId())); err != nil { code := getCodeByLocalStorageErr(err) if code == codes.NotFound { removed = false } else { return nil, status.Error(code, err.Error()) } } resp := &control.RemoveChainLocalOverrideResponse{ Body: &control.RemoveChainLocalOverrideResponse_Body{ Removed: removed, }, } err = SignMessage(s.key, resp) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return resp, nil } func (s *Server) ListTargetsLocalOverrides(_ context.Context, req *control.ListTargetsLocalOverridesRequest) (*control.ListTargetsLocalOverridesResponse, error) { if err := s.isValidRequest(req); err != nil { return nil, status.Error(codes.PermissionDenied, err.Error()) } apeChainName := apechain.Name(req.GetBody().GetChainName()) apeTargets, err := s.localOverrideStorage.LocalStorage().ListOverrideDefinedTargets(apeChainName) if err != nil { return nil, status.Error(getCodeByLocalStorageErr(err), err.Error()) } targets := make([]*control.ChainTarget, 0, len(apeTargets)) for i := range apeTargets { target, err := controlTarget(&apeTargets[i]) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } targets = append(targets, &target) } resp := &control.ListTargetsLocalOverridesResponse{ Body: &control.ListTargetsLocalOverridesResponse_Body{ Targets: targets, }, } err = SignMessage(s.key, resp) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return resp, nil } func getCodeByLocalStorageErr(err error) codes.Code { if errors.Is(err, engine.ErrChainNotFound) || errors.Is(err, engine.ErrChainNameNotFound) { return codes.NotFound } return codes.Internal }