ape: Remove all chains by target #1031

Merged
acid-ant merged 6 commits from acid-ant/frostfs-node:feature/976-remove-all-rules into master 2024-09-04 19:51:07 +00:00
16 changed files with 185 additions and 51 deletions

View file

@ -36,4 +36,5 @@ const (
HomomorphicHashDisabledInitFlag = "network.homomorphic_hash_disabled"
CustomZoneFlag = "domain"
AlphabetSizeFlag = "size"
AllFlag = "all"
)

View file

@ -114,8 +114,9 @@ func initRemoveRuleChainCmd() {
removeRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
_ = removeRuleChainCmd.MarkFlagRequired(targetNameFlag)
removeRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
_ = removeRuleChainCmd.MarkFlagRequired(chainIDFlag)
removeRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
removeRuleChainCmd.Flags().Bool(commonflags.AllFlag, false, "Remove all chains for target")
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, chainIDFlag)
}
func initListRuleChainsCmd() {
@ -157,14 +158,23 @@ func addRuleChain(cmd *cobra.Command, _ []string) {
}
func removeRuleChain(cmd *cobra.Command, _ []string) {
chainID := parseChainID(cmd)
target := parseTarget(cmd)
pci, ac := newPolicyContractInterface(cmd)
h, vub, err := pci.RemoveMorphRuleChain(parseChainName(cmd), target, chainID)
cmd.Println("Waiting for transaction to persist...")
_, err = ac.Wait(h, vub, err)
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
cmd.Println("Rule chain removed successfully")
removeAll, _ := cmd.Flags().GetBool(commonflags.AllFlag)
if removeAll {
h, vub, err := pci.RemoveMorphRuleChainsByTarget(parseChainName(cmd), target)
cmd.Println("Waiting for transaction to persist...")
_, err = ac.Wait(h, vub, err)
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
cmd.Println("All chains for target removed successfully")
} else {
chainID := parseChainID(cmd)
h, vub, err := pci.RemoveMorphRuleChain(parseChainName(cmd), target, chainID)
cmd.Println("Waiting for transaction to persist...")
_, err = ac.Wait(h, vub, err)
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
cmd.Println("Rule chain removed successfully")
}
}
func listRuleChains(cmd *cobra.Command, _ []string) {

View file

@ -2,6 +2,7 @@ package control
import (
"encoding/hex"
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
@ -13,21 +14,48 @@ import (
const (
chainIDFlag = "chain-id"
chainIDHexFlag = "chain-id-hex"
allFlag = "all"
)
var removeRuleCmd = &cobra.Command{
Use: "remove-rule",
Short: "Remove local override",
Long: "Remove local APE override of the node",
Run: removeRule,
}
var (
errEmptyChainID = errors.New("chain id cannot be empty")
removeRuleCmd = &cobra.Command{
Use: "remove-rule",
Short: "Remove local override",
Long: "Remove local APE override of the node",
Run: removeRule,
}
)
func removeRule(cmd *cobra.Command, _ []string) {
pk := key.Get(cmd)
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
removeAll, _ := cmd.Flags().GetBool(allFlag)
if removeAll {
req := &control.RemoveChainLocalOverridesByTargetRequest{
Body: &control.RemoveChainLocalOverridesByTargetRequest_Body{
Target: parseTarget(cmd),
},
}
signRequest(cmd, pk, req)
cli := getClient(cmd, pk)
var resp *control.RemoveChainLocalOverridesByTargetResponse
var err error
err = cli.ExecRaw(func(client *client.Client) error {
resp, err = control.RemoveChainLocalOverridesByTarget(client, req)
return err
})
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
verifyResponse(cmd, resp.GetSignature(), resp.GetBody())
cmd.Println("All rules have been removed.")
return
}
chainID, _ := cmd.Flags().GetString(chainIDFlag)
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
if chainID == "" {
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
}
chainIDRaw := []byte(chainID)
if hexEncoded {
@ -69,4 +97,6 @@ func initControlRemoveRuleCmd() {
_ = removeRuleCmd.MarkFlagRequired(targetTypeFlag)
ff.String(chainIDFlag, "", "Chain id")
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
ff.Bool(allFlag, false, "Remove all chains")
removeRuleCmd.MarkFlagsMutuallyExclusive(allFlag, chainIDFlag)
}

View file

@ -1 +1 @@
password: ""
password: ""

View file

@ -96,9 +96,9 @@ Shard IDs: 54Y8aot9uc7BSadw2XtYr3. Evacuated 618 objects out of 618, failed to e
### Start trees evacuation and await it completes
```bash
frostfs-cli control shards evacuation start --id FxR6QujButNCHn7jjdhxGP --endpoint s01.frostfs.devenv:8081 --wallet ./../frostfs-dev-env/services/storage/wallet01.json --await --scope trees
Enter password >
Enter password >
Shard evacuation has been successfully started.
Progress will be reported every 5 seconds.
Shard evacuation has been completed.
Shard IDs: FxR6QujButNCHn7jjdhxGP. Evacuated 0 objects out of 0, failed to evacuate: 0, skipped: 0; evacuated 2 trees out of 2, failed to evacuate: 0. Started at: 2024-02-08T08:44:17Z UTC. Duration: 00:00:00.
```
```

View file

@ -51,4 +51,4 @@ Shard can automatically switch to a `degraded-read-only` mode in 3 cases:
To detach a shard use `frostfs-cli control shards detach` command. This command removes the shards from the storage
engine and closes all resources associated with the shards.
Limitation: `SIGHUP` or storage node restart lead to detached shard will be again online.
Limitation: `SIGHUP` or storage node restart lead to detached shard will be again online.

4
go.mod
View file

@ -5,11 +5,11 @@ go 1.20
require (
code.gitea.io/sdk/gitea v0.17.1
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215124401-634e24aba715
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20240115082915-f2a82aa635aa
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.0
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20231101111734-b3ad3335ff65
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b
git.frostfs.info/TrueCloudLab/hrw v1.2.1
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240304151211-839f22e1a36d
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240307151106-2ec958cbfdfd
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
github.com/cheggaaa/pb v1.0.29

BIN
go.sum

Binary file not shown.

View file

@ -100,7 +100,7 @@ func (cs *boltLocalOverrideStorage) Close() error {
return err
}
func getTargetBucket(tx *bbolt.Tx, name chain.Name, target policyengine.Target) (*bbolt.Bucket, error) {
func getTypeBucket(tx *bbolt.Tx, name chain.Name, target policyengine.Target) (*bbolt.Bucket, error) {
cbucket := tx.Bucket(chainBucket)
if cbucket == nil {
return nil, ErrRootBucketNotFound
@ -110,16 +110,25 @@ func getTargetBucket(tx *bbolt.Tx, name chain.Name, target policyengine.Target)
if nbucket == nil {
return nil, fmt.Errorf("%w: %w: %s", policyengine.ErrChainNotFound, ErrGlobalNamespaceBucketNotFound, name)
}
return nbucket.Bucket([]byte{byte(target.Type)}), nil
}
typeBucket := nbucket.Bucket([]byte{byte(target.Type)})
func normalizeTargetName(target *policyengine.Target) {
if target.Type == policyengine.Namespace && target.Name == "" {
target.Name = "root"
}
}
func getTargetBucket(tx *bbolt.Tx, name chain.Name, target policyengine.Target) (*bbolt.Bucket, error) {
typeBucket, err := getTypeBucket(tx, name, target)
if err != nil {
return nil, err
}
if typeBucket == nil {
return nil, fmt.Errorf("%w: %w: %c", policyengine.ErrChainNotFound, ErrTargetTypeBucketNotFound, target.Type)
}
if target.Type == policyengine.Namespace && target.Name == "" {
target.Name = "root"
}
normalizeTargetName(&target)
rbucket := typeBucket.Bucket([]byte(target.Name))
if rbucket == nil {
return nil, fmt.Errorf("%w: %w: %s", policyengine.ErrChainNotFound, ErrTargetNameBucketNotFound, target.Name)
@ -151,10 +160,7 @@ func getTargetBucketCreateIfEmpty(tx *bbolt.Tx, name chain.Name, target policyen
}
}
if target.Type == policyengine.Namespace && target.Name == "" {
target.Name = "root"
}
normalizeTargetName(&target)
rbucket := typeBucket.Bucket([]byte(target.Name))
if rbucket == nil {
var err error
@ -220,6 +226,17 @@ func (cs *boltLocalOverrideStorage) RemoveOverride(name chain.Name, target polic
})
}
func (cs *boltLocalOverrideStorage) RemoveOverridesByTarget(name chain.Name, target policyengine.Target) error {
return cs.db.Update(func(tx *bbolt.Tx) error {
typeBucket, err := getTypeBucket(tx, name, target)
if err != nil {
return err
}
normalizeTargetName(&target)
return typeBucket.DeleteBucket([]byte(target.Name))
})
}
func (cs *boltLocalOverrideStorage) ListOverrides(name chain.Name, target policyengine.Target) ([]*chain.Chain, error) {
var serializedChains [][]byte
var serializedChain []byte

View file

@ -1,11 +1,13 @@
package client
import (
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
type actorProvider interface {
@ -118,3 +120,15 @@ func (a *SwitchRPCGuardedActor) Sign(tx *transaction.Transaction) error {
func (a *SwitchRPCGuardedActor) SignAndSend(tx *transaction.Transaction) (util.Uint256, uint32, error) {
return a.actorProvider.GetActor().SignAndSend(tx)
}
func (a *SwitchRPCGuardedActor) CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...any) (*result.Invoke, error) {
return a.actorProvider.GetActor().CallAndExpandIterator(contract, method, maxItems, params...)
}
func (a *SwitchRPCGuardedActor) TerminateSession(sessionID uuid.UUID) error {
return a.actorProvider.GetActor().TerminateSession(sessionID)
}
func (a *SwitchRPCGuardedActor) TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) {
return a.actorProvider.GetActor().TraverseIterator(sessionID, iterator, num)
}

View file

@ -8,26 +8,27 @@ import (
const serviceName = "control.ControlService"
const (
rpcHealthCheck = "HealthCheck"
rpcSetNetmapStatus = "SetNetmapStatus"
rpcDropObjects = "DropObjects"
rpcListShards = "ListShards"
rpcSetShardMode = "SetShardMode"
rpcSynchronizeTree = "SynchronizeTree"
rpcEvacuateShard = "EvacuateShard"
rpcStartShardEvacuation = "StartShardEvacuation"
rpcGetShardEvacuationStatus = "GetShardEvacuationStatus"
rpcResetShardEvacuationStatus = "ResetShardEvacuationStatus"
rpcStopShardEvacuation = "StopShardEvacuation"
rpcFlushCache = "FlushCache"
rpcDoctor = "Doctor"
rpcAddChainLocalOverride = "AddChainLocalOverride"
rpcGetChainLocalOverride = "GetChainLocalOverride"
rpcListChainLocalOverrides = "ListChainLocalOverrides"
rpcRemoveChainLocalOverride = "RemoveChainLocalOverride"
rpcSealWriteCache = "SealWriteCache"
rpcListTargetsLocalOverrides = "ListTargetsLocalOverrides"
rpcDetachShards = "DetachShards"
rpcHealthCheck = "HealthCheck"
rpcSetNetmapStatus = "SetNetmapStatus"
rpcDropObjects = "DropObjects"
rpcListShards = "ListShards"
rpcSetShardMode = "SetShardMode"
rpcSynchronizeTree = "SynchronizeTree"
rpcEvacuateShard = "EvacuateShard"
rpcStartShardEvacuation = "StartShardEvacuation"
rpcGetShardEvacuationStatus = "GetShardEvacuationStatus"
rpcResetShardEvacuationStatus = "ResetShardEvacuationStatus"
rpcStopShardEvacuation = "StopShardEvacuation"
rpcFlushCache = "FlushCache"
rpcDoctor = "Doctor"
rpcAddChainLocalOverride = "AddChainLocalOverride"
rpcGetChainLocalOverride = "GetChainLocalOverride"
rpcListChainLocalOverrides = "ListChainLocalOverrides"
rpcRemoveChainLocalOverride = "RemoveChainLocalOverride"
rpcRemoveChainLocalOverridesByTarget = "RemoveChainLocalOverridesByTarget"
rpcSealWriteCache = "SealWriteCache"
rpcListTargetsLocalOverrides = "ListTargetsLocalOverrides"
rpcDetachShards = "DetachShards"
)
// HealthCheck executes ControlService.HealthCheck RPC.
@ -295,6 +296,19 @@ func RemoveChainLocalOverride(cli *client.Client, req *RemoveChainLocalOverrideR
return wResp.message, nil
}
// RemoveChainLocalOverridesByTarget executes ControlService.RemoveChainLocalOverridesByTarget RPC.
func RemoveChainLocalOverridesByTarget(cli *client.Client, req *RemoveChainLocalOverridesByTargetRequest, opts ...client.CallOption) (*RemoveChainLocalOverridesByTargetResponse, error) {
wResp := newResponseWrapper[RemoveChainLocalOverridesByTargetResponse]()
wReq := &requestWrapper{m: req}
err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceName, rpcRemoveChainLocalOverridesByTarget), wReq, wResp, opts...)
if err != nil {
return nil, err
}
return wResp.message, nil
}
// SealWriteCache executes ControlService.SealWriteCache RPC.
func SealWriteCache(cli *client.Client, req *SealWriteCacheRequest, opts ...client.CallOption) (*SealWriteCacheResponse, error) {
wResp := newResponseWrapper[SealWriteCacheResponse]()

View file

@ -174,6 +174,31 @@ func (s *Server) RemoveChainLocalOverride(_ context.Context, req *control.Remove
return resp, nil
}
func (s *Server) RemoveChainLocalOverridesByTarget(_ context.Context, req *control.RemoveChainLocalOverridesByTargetRequest) (*control.RemoveChainLocalOverridesByTargetResponse, 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
}
if err = s.localOverrideStorage.LocalStorage().RemoveOverridesByTarget(apechain.Ingress, target); err != nil {
if code := getCodeByLocalStorageErr(err); code != codes.NotFound {
return nil, status.Error(code, err.Error())
}
}
resp := &control.RemoveChainLocalOverridesByTargetResponse{
Body: &control.RemoveChainLocalOverridesByTargetResponse_Body{},
}
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())

Binary file not shown.

View file

@ -60,6 +60,9 @@ service ControlService {
// Remove local access policy engine overrides stored in the node by chaind id.
rpc RemoveChainLocalOverride (RemoveChainLocalOverrideRequest) returns (RemoveChainLocalOverrideResponse);
// Remove local access policy engine overrides stored in the node by chaind id.
rpc RemoveChainLocalOverridesByTarget (RemoveChainLocalOverridesByTargetRequest) returns (RemoveChainLocalOverridesByTargetResponse);
// List targets of the local APE overrides stored in the node.
rpc ListTargetsLocalOverrides (ListTargetsLocalOverridesRequest) returns (ListTargetsLocalOverridesResponse);
@ -592,6 +595,26 @@ message RemoveChainLocalOverrideResponse {
Signature signature = 2;
}
message RemoveChainLocalOverridesByTargetRequest {
message Body {
// Target for which the overrides are applied.
ChainTarget target = 1;
}
Body body = 1;
Signature signature = 2;
}
message RemoveChainLocalOverridesByTargetResponse {
message Body {
}
Body body = 1;
Signature signature = 2;
}
message SealWriteCacheRequest {
// Request body structure.
message Body {

Binary file not shown.

Binary file not shown.