control: Extend api with ListOverrideDefinedTargets #936

Merged
fyrchik merged 5 commits from acid-ant/frostfs-node:feature/ext-with-list-targets into master 2024-02-02 12:09:54 +00:00
23 changed files with 252 additions and 27 deletions

View file

@ -0,0 +1,82 @@
package control
import (
"bytes"
"crypto/sha256"
"fmt"
"strconv"
"text/tabwriter"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/spf13/cobra"
)
const (
chainNameFlag = "chain-name"
chainNameFlagUsage = "Chain name(ingress|s3)"
)
var listTargetsCmd = &cobra.Command{
Use: "list-targets",
Short: "List local targets",
Long: "List local APE overrides of the node",
Run: listTargets,
}
func listTargets(cmd *cobra.Command, _ []string) {
pk := key.Get(cmd)
var cnr cid.ID
chainName, _ := cmd.Flags().GetString(chainNameFlag)
rawCID := make([]byte, sha256.Size)
cnr.Encode(rawCID)
req := &control.ListTargetsLocalOverridesRequest{
Body: &control.ListTargetsLocalOverridesRequest_Body{
ChainName: chainName,
},
}
signRequest(cmd, pk, req)
cli := getClient(cmd, pk)
var resp *control.ListTargetsLocalOverridesResponse
var err error
err = cli.ExecRaw(func(client *client.Client) error {
resp, err = control.ListTargetsLocalOverrides(client, req)
return err
})
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
verifyResponse(cmd, resp.GetSignature(), resp.GetBody())
targets := resp.GetBody().GetTargets()
if len(targets) == 0 {
cmd.Println("Local overrides are not defined for the container.")
return
}
buf := bytes.NewBuffer(nil)
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
_, _ = tw.Write([]byte("#\tName\tType\n"))
for i, t := range targets {
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%s\t%s\n", strconv.Itoa(i), t.GetName(), t.GetType())))
}
_ = tw.Flush()
cmd.Print(buf.String())
}
func initControlListTargetsCmd() {
initControlFlags(listTargetsCmd)
ff := listTargetsCmd.Flags()
ff.String(chainNameFlag, "", chainNameFlagUsage)
_ = cobra.MarkFlagRequired(ff, chainNameFlag)
}

View file

@ -38,6 +38,7 @@ func init() {
removeRuleCmd, removeRuleCmd,
listRulesCmd, listRulesCmd,
getRuleCmd, getRuleCmd,
listTargetsCmd,
) )
initControlHealthCheckCmd() initControlHealthCheckCmd()
@ -50,4 +51,5 @@ func init() {
initControlRemoveRuleCmd() initControlRemoveRuleCmd()
initControlListRulesCmd() initControlListRulesCmd()
initControGetRuleCmd() initControGetRuleCmd()
initControlListTargetsCmd()
} }

View file

@ -66,4 +66,3 @@
"Tokens": null "Tokens": null
} }
} }

4
go.mod
View file

@ -8,7 +8,7 @@ require (
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20231101111734-b3ad3335ff65 git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20231101111734-b3ad3335ff65
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240126141009-65b4525b3bf0 git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240126141009-65b4525b3bf0
git.frostfs.info/TrueCloudLab/hrw v1.2.1 git.frostfs.info/TrueCloudLab/hrw v1.2.1
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240122104724-06cbfe8691ad git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240129064140-8d21ab2d99d9
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 git.frostfs.info/TrueCloudLab/tzhash v1.8.0
github.com/cheggaaa/pb v1.0.29 github.com/cheggaaa/pb v1.0.29
github.com/chzyer/readline v1.5.1 github.com/chzyer/readline v1.5.1
@ -76,8 +76,10 @@ require (
github.com/holiman/uint256 v1.2.4 // indirect github.com/holiman/uint256 v1.2.4 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect github.com/ipfs/go-cid v0.4.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect

BIN
go.sum

Binary file not shown.

View file

@ -167,8 +167,8 @@ func getTargetBucketCreateIfEmpty(tx *bbolt.Tx, name chain.Name, target policyen
} }
func (cs *boltLocalOverrideStorage) AddOverride(name chain.Name, target policyengine.Target, c *chain.Chain) (chain.ID, error) { func (cs *boltLocalOverrideStorage) AddOverride(name chain.Name, target policyengine.Target, c *chain.Chain) (chain.ID, error) {
if c.ID == "" { if len(c.ID) == 0 {
return "", fmt.Errorf("chain ID is not set") return chain.ID{}, fmt.Errorf("chain ID is not set")
} }
serializedChain := c.Bytes() serializedChain := c.Bytes()
@ -264,3 +264,48 @@ func (cs *boltLocalOverrideStorage) DropAllOverrides(name chain.Name) error {
return tx.DeleteBucket([]byte(name)) return tx.DeleteBucket([]byte(name))
}) })
} }
func (cs *boltLocalOverrideStorage) ListOverrideDefinedTargets(name chain.Name) ([]policyengine.Target, error) {
var targets []policyengine.Target
if err := cs.db.View(func(tx *bbolt.Tx) error {
var err error
targets, err = getTargets(tx, name)
if err != nil {
return err
}
return nil
}); err != nil {
return nil, err
}
return targets, nil
}
func getTargets(tx *bbolt.Tx, name chain.Name) ([]policyengine.Target, error) {
var targets []policyengine.Target
cbucket := tx.Bucket(chainBucket)
if cbucket == nil {
return nil, ErrRootBucketNotFound
}
nbucket := cbucket.Bucket([]byte(name))
if nbucket == nil {
return nil, fmt.Errorf("%w: %w: %s", policyengine.ErrChainNotFound, ErrGlobalNamespaceBucketNotFound, name)
}
if err := nbucket.ForEachBucket(func(k []byte) error {
ttype := policyengine.TargetType(k[0])
if err := nbucket.Bucket(k).ForEachBucket(func(k []byte) error {
targets = append(targets, policyengine.Target{
Type: ttype,
Name: string(slice.Copy(k)),
})
return nil
}); err != nil {
return err
}
return nil
}); err != nil {
return nil, err
}
return targets, nil
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -25,6 +25,7 @@ const (
rpcListChainLocalOverrides = "ListChainLocalOverrides" rpcListChainLocalOverrides = "ListChainLocalOverrides"
rpcRemoveChainLocalOverride = "RemoveChainLocalOverride" rpcRemoveChainLocalOverride = "RemoveChainLocalOverride"
rpcSealWriteCache = "SealWriteCache" rpcSealWriteCache = "SealWriteCache"
rpcListTargetsLocalOverrides = "ListTargetsLocalOverrides"
) )
// HealthCheck executes ControlService.HealthCheck RPC. // HealthCheck executes ControlService.HealthCheck RPC.
@ -240,6 +241,19 @@ func ListChainLocalOverrides(cli *client.Client, req *ListChainLocalOverridesReq
return wResp.message, nil return wResp.message, nil
} }
// ListTargetsLocalOverrides executes ControlService.ListTargetsLocalOverrides RPC.
func ListTargetsLocalOverrides(cli *client.Client, req *ListTargetsLocalOverridesRequest, opts ...client.CallOption) (*ListTargetsLocalOverridesResponse, error) {
wResp := newResponseWrapper[ListTargetsLocalOverridesResponse]()
wReq := &requestWrapper{m: req}
err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceName, rpcListTargetsLocalOverrides), wReq, wResp, opts...)
if err != nil {
return nil, err
}
return wResp.message, nil
}
// RemoveChainLocalOverride executes ControlService.RemoveChainLocalOverride RPC. // RemoveChainLocalOverride executes ControlService.RemoveChainLocalOverride RPC.
func GetChainLocalOverride(cli *client.Client, req *GetChainLocalOverrideRequest, opts ...client.CallOption) (*GetChainLocalOverrideResponse, error) { func GetChainLocalOverride(cli *client.Client, req *GetChainLocalOverrideRequest, opts ...client.CallOption) (*GetChainLocalOverrideResponse, error) {
wResp := newResponseWrapper[GetChainLocalOverrideResponse]() wResp := newResponseWrapper[GetChainLocalOverrideResponse]()

View file

@ -25,6 +25,29 @@ func apeTarget(chainTarget *control.ChainTarget) (engine.Target, error) {
fmt.Errorf("target type is not supported: %s", chainTarget.GetType().String()).Error()) 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) { func (s *Server) AddChainLocalOverride(_ context.Context, req *control.AddChainLocalOverrideRequest) (*control.AddChainLocalOverrideResponse, error) {
if err := s.isValidRequest(req); err != nil { if err := s.isValidRequest(req); err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error()) return nil, status.Error(codes.PermissionDenied, err.Error())
@ -44,7 +67,7 @@ func (s *Server) AddChainLocalOverride(_ context.Context, req *control.AddChainL
s.apeChainCounter.Add(1) s.apeChainCounter.Add(1)
// TODO (aarifullin): the such chain id is not well-designed yet. // TODO (aarifullin): the such chain id is not well-designed yet.
if chain.ID == "" { if len(chain.ID) == 0 {
chain.ID = apechain.ID(fmt.Sprintf("%s:%d", apechain.Ingress, s.apeChainCounter.Load())) chain.ID = apechain.ID(fmt.Sprintf("%s:%d", apechain.Ingress, s.apeChainCounter.Load()))
} }
@ -157,6 +180,37 @@ func (s *Server) RemoveChainLocalOverride(_ context.Context, req *control.Remove
return resp, nil 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 { func getCodeByLocalStorageErr(err error) codes.Code {
if errors.Is(err, engine.ErrChainNotFound) || errors.Is(err, engine.ErrChainNameNotFound) { if errors.Is(err, engine.ErrChainNotFound) || errors.Is(err, engine.ErrChainNameNotFound) {
return codes.NotFound return codes.NotFound

Binary file not shown.

View file

@ -57,6 +57,9 @@ service ControlService {
// Remove local access policy engine overrides stored in the node by chaind id. // Remove local access policy engine overrides stored in the node by chaind id.
rpc RemoveChainLocalOverride (RemoveChainLocalOverrideRequest) returns (RemoveChainLocalOverrideResponse); rpc RemoveChainLocalOverride (RemoveChainLocalOverrideRequest) returns (RemoveChainLocalOverrideResponse);
// List targets of the local APE overrides stored in the node.
rpc ListTargetsLocalOverrides (ListTargetsLocalOverridesRequest) returns (ListTargetsLocalOverridesResponse);
// Flush objects from write-cache and move it to degraded read only mode. // Flush objects from write-cache and move it to degraded read only mode.
rpc SealWriteCache(SealWriteCacheRequest) returns (SealWriteCacheResponse); rpc SealWriteCache(SealWriteCacheRequest) returns (SealWriteCacheResponse);
} }
@ -505,6 +508,30 @@ message ListChainLocalOverridesResponse {
Signature signature = 2; Signature signature = 2;
} }
// ListTargetsLocalOverrides request.
message ListTargetsLocalOverridesRequest {
message Body {
// Target for which the overrides are applied.
string chainName = 1;
}
Body body = 1;
Signature signature = 2;
}
// ListTargetsLocalOverrides response.
message ListTargetsLocalOverridesResponse {
message Body {
// The list of chain targets.
repeated ChainTarget targets = 1;
}
Body body = 1;
Signature signature = 2;
}
message RemoveChainLocalOverrideRequest { message RemoveChainLocalOverrideRequest {
message Body { message Body {
// Target for which the overrides are applied. // Target for which the overrides are applied.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.