forked from TrueCloudLab/frostfs-node
Compare commits
47 commits
master
...
bugfix/ref
Author | SHA1 | Date | |
---|---|---|---|
16afbf1369 | |||
635a292ae4 | |||
edfa3f4825 | |||
e0ac3a583f | |||
00c608c05e | |||
bba1892fa1 | |||
01acec708f | |||
aac65001e5 | |||
1170370753 | |||
9e275d44c8 | |||
2469e0c683 | |||
a6ef4ab524 | |||
49959c4166 | |||
61ee1b5610 | |||
b10c954377 | |||
1605391628 | |||
b1766e47c7 | |||
caa4253249 | |||
7eac5fb18b | |||
0e5524dac7 | |||
3ebd560f42 | |||
1ed7ab75fb | |||
99f9e59de9 | |||
256f96e252 | |||
e5ea95c045 | |||
9073e555db | |||
2771fdb8c7 | |||
efa4ce00b8 | |||
f12f04199e | |||
2e2c62147d | |||
6ae8667fb4 | |||
49a4e727fd | |||
2e974f734c | |||
3042490340 | |||
a339b52a60 | |||
4ab4ed6f96 | |||
3b1364e4cf | |||
daff77b273 | |||
7a7ee71a4d | |||
ffe9906266 | |||
ae31ef3602 | |||
e2cb0640f1 | |||
9f4ce600ac | |||
d82f0d1926 | |||
acd5babd86 | |||
b65874d1c3 | |||
69c63006da |
100 changed files with 1059 additions and 1248 deletions
|
@ -1,6 +1,10 @@
|
|||
name: Build
|
||||
|
||||
on: [pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Pre-commit hooks
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
precommit:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Tests and linters
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Vulncheck
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
vulncheck:
|
||||
|
|
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -9,6 +9,30 @@ Changelog for FrostFS Node
|
|||
### Removed
|
||||
### Updated
|
||||
|
||||
## [v0.44.0] - 2024-25-11 - Rongbuk
|
||||
|
||||
### Added
|
||||
- Allow to prioritize nodes during GET traversal via attributes (#1439)
|
||||
- Add metrics for the frostfsid cache (#1464)
|
||||
- Customize constant attributes attached to every tracing span (#1488)
|
||||
- Manage additional keys in the `frostfsid` contract (#1505)
|
||||
- Describe `--rule` flag in detail for `frostfs-cli ape-manager` subcommands (#1519)
|
||||
|
||||
### Changed
|
||||
- Support richer interaction with the console in `frostfs-cli container policy-playground` (#1396)
|
||||
- Print address in base58 format in `frostfs-adm morph policy set-admin` (#1515)
|
||||
|
||||
### Fixed
|
||||
- Fix EC object search (#1408)
|
||||
- Fix EC object put when one of the nodes is unavailable (#1427)
|
||||
|
||||
### Removed
|
||||
- Drop most of the eACL-related code (#1425)
|
||||
- Remove `--basic-acl` flag from `frostfs-cli container create` (#1483)
|
||||
|
||||
### Upgrading from v0.43.0
|
||||
The metabase schema has changed completely, resync is required.
|
||||
|
||||
## [v0.42.0]
|
||||
|
||||
### Added
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
v0.42.0
|
||||
v0.44.0
|
||||
|
|
|
@ -20,6 +20,7 @@ const (
|
|||
AlphabetWalletsFlagDesc = "Path to alphabet wallets dir"
|
||||
|
||||
LocalDumpFlag = "local-dump"
|
||||
ProtoConfigPath = "protocol"
|
||||
ContractsInitFlag = "contracts"
|
||||
ContractsInitFlagDesc = "Path to archive with compiled FrostFS contracts (the default is to fetch the latest release from the official repository)"
|
||||
ContractsURLFlag = "contracts-url"
|
||||
|
|
|
@ -5,35 +5,19 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
jsonFlag = "json"
|
||||
jsonFlagDesc = "Output rule chains in JSON format"
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDDesc = "Rule chain ID"
|
||||
ruleFlag = "rule"
|
||||
ruleFlagDesc = "Rule chain in text format"
|
||||
pathFlag = "path"
|
||||
pathFlagDesc = "path to encoded chain in JSON or binary format"
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
addrAdminFlag = "addr"
|
||||
addrAdminDesc = "The address of the admins wallet"
|
||||
chainNameFlag = "chain-name"
|
||||
chainNameFlagDesc = "Chain name(ingress|s3)"
|
||||
jsonFlag = "json"
|
||||
jsonFlagDesc = "Output rule chains in JSON format"
|
||||
addrAdminFlag = "addr"
|
||||
addrAdminDesc = "The address of the admins wallet"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -101,17 +85,17 @@ func initAddRuleChainCmd() {
|
|||
addRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
addRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
addRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
||||
addRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||
|
||||
addRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(chainIDFlag)
|
||||
addRuleChainCmd.Flags().StringArray(ruleFlag, []string{}, ruleFlagDesc)
|
||||
addRuleChainCmd.Flags().String(pathFlag, "", pathFlagDesc)
|
||||
addRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
addRuleChainCmd.MarkFlagsMutuallyExclusive(ruleFlag, pathFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||
addRuleChainCmd.Flags().StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||
addRuleChainCmd.Flags().String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||
addRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
addRuleChainCmd.MarkFlagsMutuallyExclusive(apeCmd.RuleFlag, apeCmd.PathFlag)
|
||||
}
|
||||
|
||||
func initRemoveRuleChainCmd() {
|
||||
|
@ -120,26 +104,25 @@ func initRemoveRuleChainCmd() {
|
|||
removeRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
removeRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
||||
removeRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
||||
removeRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
||||
removeRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
removeRuleChainCmd.Flags().Bool(commonflags.AllFlag, false, "Remove all chains for target")
|
||||
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, chainIDFlag)
|
||||
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, apeCmd.ChainIDFlag)
|
||||
}
|
||||
|
||||
func initListRuleChainsCmd() {
|
||||
Cmd.AddCommand(listRuleChainsCmd)
|
||||
|
||||
listRuleChainsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
listRuleChainsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(targetTypeFlag)
|
||||
listRuleChainsCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(targetNameFlag)
|
||||
listRuleChainsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
listRuleChainsCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
listRuleChainsCmd.Flags().Bool(jsonFlag, false, jsonFlagDesc)
|
||||
listRuleChainsCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
listRuleChainsCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
}
|
||||
|
||||
func initSetAdminCmd() {
|
||||
|
@ -161,15 +144,15 @@ func initListTargetsCmd() {
|
|||
Cmd.AddCommand(listTargetsCmd)
|
||||
|
||||
listTargetsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
listTargetsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
||||
_ = listTargetsCmd.MarkFlagRequired(targetTypeFlag)
|
||||
listTargetsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listTargetsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
||||
func addRuleChain(cmd *cobra.Command, _ []string) {
|
||||
chain := parseChain(cmd)
|
||||
chain := apeCmd.ParseChain(cmd)
|
||||
target := parseTarget(cmd)
|
||||
pci, ac := newPolicyContractInterface(cmd)
|
||||
h, vub, err := pci.AddMorphRuleChain(parseChainName(cmd), target, chain)
|
||||
h, vub, err := pci.AddMorphRuleChain(apeCmd.ParseChainName(cmd), target, chain)
|
||||
cmd.Println("Waiting for transaction to persist...")
|
||||
_, err = ac.Wait(h, vub, err)
|
||||
commonCmd.ExitOnErr(cmd, "add rule chain error: %w", err)
|
||||
|
@ -181,14 +164,14 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
|
|||
pci, ac := newPolicyContractInterface(cmd)
|
||||
removeAll, _ := cmd.Flags().GetBool(commonflags.AllFlag)
|
||||
if removeAll {
|
||||
h, vub, err := pci.RemoveMorphRuleChainsByTarget(parseChainName(cmd), target)
|
||||
h, vub, err := pci.RemoveMorphRuleChainsByTarget(apeCmd.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)
|
||||
chainID := apeCmd.ParseChainID(cmd)
|
||||
h, vub, err := pci.RemoveMorphRuleChain(apeCmd.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)
|
||||
|
@ -199,7 +182,7 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
|
|||
func listRuleChains(cmd *cobra.Command, _ []string) {
|
||||
target := parseTarget(cmd)
|
||||
pci, _ := newPolicyContractReaderInterface(cmd)
|
||||
chains, err := pci.ListMorphRuleChains(parseChainName(cmd), target)
|
||||
chains, err := pci.ListMorphRuleChains(apeCmd.ParseChainName(cmd), target)
|
||||
commonCmd.ExitOnErr(cmd, "list rule chains error: %w", err)
|
||||
if len(chains) == 0 {
|
||||
return
|
||||
|
@ -210,14 +193,14 @@ func listRuleChains(cmd *cobra.Command, _ []string) {
|
|||
prettyJSONFormat(cmd, chains)
|
||||
} else {
|
||||
for _, c := range chains {
|
||||
parseutil.PrintHumanReadableAPEChain(cmd, c)
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setAdmin(cmd *cobra.Command, _ []string) {
|
||||
s, _ := cmd.Flags().GetString(addrAdminFlag)
|
||||
addr, err := util.Uint160DecodeStringLE(s)
|
||||
addr, err := address.StringToUint160(s)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode admin addr: %w", err)
|
||||
pci, ac := newPolicyContractInterface(cmd)
|
||||
h, vub, err := pci.SetAdmin(addr)
|
||||
|
@ -231,12 +214,11 @@ func getAdmin(cmd *cobra.Command, _ []string) {
|
|||
pci, _ := newPolicyContractReaderInterface(cmd)
|
||||
addr, err := pci.GetAdmin()
|
||||
commonCmd.ExitOnErr(cmd, "unable to get admin: %w", err)
|
||||
cmd.Println(addr.StringLE())
|
||||
cmd.Println(address.Uint160ToString(addr))
|
||||
}
|
||||
|
||||
func listTargets(cmd *cobra.Command, _ []string) {
|
||||
typ, err := parseTargetType(cmd)
|
||||
commonCmd.ExitOnErr(cmd, "parse target type error: %w", err)
|
||||
typ := apeCmd.ParseTargetType(cmd)
|
||||
pci, inv := newPolicyContractReaderInterface(cmd)
|
||||
|
||||
sid, it, err := pci.ListTargetsIterator(typ)
|
||||
|
|
|
@ -2,13 +2,12 @@ package ape
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
|
@ -18,90 +17,29 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
ingress = "ingress"
|
||||
s3 = "s3"
|
||||
)
|
||||
|
||||
var mChainName = map[string]apechain.Name{
|
||||
ingress: apechain.Ingress,
|
||||
s3: apechain.S3,
|
||||
}
|
||||
|
||||
var (
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
|
||||
errRuleIsNotParsed = errors.New("rule is not passed")
|
||||
errUnsupportedChainName = errors.New("unsupported chain name")
|
||||
)
|
||||
var errUnknownTargetType = errors.New("unknown target type")
|
||||
|
||||
func parseTarget(cmd *cobra.Command) policyengine.Target {
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
typ, err := parseTargetType(cmd)
|
||||
|
||||
// interpret "root" namespace as empty
|
||||
if typ == policyengine.Namespace && name == "root" {
|
||||
name = ""
|
||||
}
|
||||
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", err)
|
||||
|
||||
return policyengine.Target{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
}
|
||||
}
|
||||
|
||||
func parseTargetType(cmd *cobra.Command) (policyengine.TargetType, error) {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
typ := apeCmd.ParseTargetType(cmd)
|
||||
name, _ := cmd.Flags().GetString(apeCmd.TargetNameFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
return policyengine.Namespace, nil
|
||||
case containerTarget:
|
||||
return policyengine.Container, nil
|
||||
case userTarget:
|
||||
return policyengine.User, nil
|
||||
case groupTarget:
|
||||
return policyengine.Group, nil
|
||||
case policyengine.Namespace:
|
||||
if name == "root" {
|
||||
name = ""
|
||||
}
|
||||
return policyengine.NamespaceTarget(name)
|
||||
case policyengine.Container:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return policyengine.ContainerTarget(name)
|
||||
case policyengine.User:
|
||||
return policyengine.UserTarget(name)
|
||||
case policyengine.Group:
|
||||
return policyengine.GroupTarget(name)
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
return -1, errUnknownTargetType
|
||||
}
|
||||
|
||||
func parseChainID(cmd *cobra.Command) apechain.ID {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
|
||||
errChainIDCannotBeEmpty)
|
||||
}
|
||||
return apechain.ID(chainID)
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errRuleIsNotParsed)
|
||||
}
|
||||
|
||||
chain.ID = parseChainID(cmd)
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
parseutil.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func parseChainName(cmd *cobra.Command) apechain.Name {
|
||||
chainName, _ := cmd.Flags().GetString(chainNameFlag)
|
||||
apeChainName, ok := mChainName[strings.ToLower(chainName)]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "", errUnsupportedChainName)
|
||||
}
|
||||
return apeChainName
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// invokerAdapter adapats invoker.Invoker to ContractStorageInvoker interface.
|
||||
|
@ -115,16 +53,15 @@ func (n *invokerAdapter) GetRPCInvoker() invoker.RPCInvoke {
|
|||
}
|
||||
|
||||
func newPolicyContractReaderInterface(cmd *cobra.Command) (*morph.ContractStorageReader, *invoker.Invoker) {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||
|
||||
inv := invoker.New(c, nil)
|
||||
var ch util.Uint160
|
||||
r := management.NewReader(inv)
|
||||
nnsCs, err := helper.GetContractByID(r, 1)
|
||||
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
||||
|
||||
ch, err = helper.NNSResolveHash(inv, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
|
||||
ch, err := helper.NNSResolveHash(inv, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
|
||||
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
|
||||
|
||||
invokerAdapter := &invokerAdapter{
|
||||
|
@ -136,7 +73,7 @@ func newPolicyContractReaderInterface(cmd *cobra.Command) (*morph.ContractStorag
|
|||
}
|
||||
|
||||
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *helper.LocalActor) {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||
|
||||
ac, err := helper.NewLocalActor(cmd, c, constants.ConsensusAccountName)
|
||||
|
|
|
@ -51,7 +51,7 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
|
|||
nmHash util.Uint160
|
||||
)
|
||||
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
const forceConfigSet = "force"
|
||||
|
||||
func dumpNetworkConfig(cmd *cobra.Command, _ []string) error {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create N3 client: %w", err)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import "time"
|
|||
|
||||
const (
|
||||
ConsensusAccountName = "consensus"
|
||||
ProtoConfigPath = "protocol"
|
||||
|
||||
// MaxAlphabetNodes is the maximum number of candidates allowed, which is currently limited by the size
|
||||
// of the invocation script.
|
||||
|
|
|
@ -76,7 +76,7 @@ func dumpContainers(cmd *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("invalid filename: %w", err)
|
||||
}
|
||||
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create N3 client: %w", err)
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func dumpSingleContainer(bw *io.BufBinWriter, ch util.Uint160, inv *invoker.Invo
|
|||
}
|
||||
|
||||
func listContainers(cmd *cobra.Command, _ []string) error {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create N3 client: %w", err)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ type contractDumpInfo struct {
|
|||
}
|
||||
|
||||
func dumpContractHashes(cmd *cobra.Command, _ []string) error {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't create N3 client: %w", err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
frostfsidAddSubjectKeyCmd = &cobra.Command{
|
||||
Use: "add-subject-key",
|
||||
Short: "Add a public key to the subject in frostfsid contract",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidAddSubjectKey,
|
||||
}
|
||||
frostfsidRemoveSubjectKeyCmd = &cobra.Command{
|
||||
Use: "remove-subject-key",
|
||||
Short: "Remove a public key from the subject in frostfsid contract",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidRemoveSubjectKey,
|
||||
}
|
||||
)
|
||||
|
||||
func initFrostfsIDAddSubjectKeyCmd() {
|
||||
Cmd.AddCommand(frostfsidAddSubjectKeyCmd)
|
||||
|
||||
ff := frostfsidAddSubjectKeyCmd.Flags()
|
||||
ff.StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
ff.String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
ff.String(subjectAddressFlag, "", "Subject address")
|
||||
_ = frostfsidAddSubjectKeyCmd.MarkFlagRequired(subjectAddressFlag)
|
||||
|
||||
ff.String(subjectKeyFlag, "", "Public key to add")
|
||||
_ = frostfsidAddSubjectKeyCmd.MarkFlagRequired(subjectKeyFlag)
|
||||
}
|
||||
|
||||
func initFrostfsIDRemoveSubjectKeyCmd() {
|
||||
Cmd.AddCommand(frostfsidRemoveSubjectKeyCmd)
|
||||
|
||||
ff := frostfsidRemoveSubjectKeyCmd.Flags()
|
||||
ff.StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
ff.String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
ff.String(subjectAddressFlag, "", "Subject address")
|
||||
_ = frostfsidAddSubjectKeyCmd.MarkFlagRequired(subjectAddressFlag)
|
||||
|
||||
ff.String(subjectKeyFlag, "", "Public key to remove")
|
||||
_ = frostfsidAddSubjectKeyCmd.MarkFlagRequired(subjectKeyFlag)
|
||||
}
|
||||
|
||||
func frostfsidAddSubjectKey(cmd *cobra.Command, _ []string) {
|
||||
addr := getFrostfsIDSubjectAddress(cmd)
|
||||
pub := getFrostfsIDSubjectKey(cmd)
|
||||
|
||||
ffsid, err := newFrostfsIDClient(cmd)
|
||||
commonCmd.ExitOnErr(cmd, "init contract client: %w", err)
|
||||
|
||||
ffsid.addCall(ffsid.roCli.AddSubjectKeyCall(addr, pub))
|
||||
|
||||
err = ffsid.sendWait()
|
||||
commonCmd.ExitOnErr(cmd, "add subject key: %w", err)
|
||||
}
|
||||
|
||||
func frostfsidRemoveSubjectKey(cmd *cobra.Command, _ []string) {
|
||||
addr := getFrostfsIDSubjectAddress(cmd)
|
||||
pub := getFrostfsIDSubjectKey(cmd)
|
||||
|
||||
ffsid, err := newFrostfsIDClient(cmd)
|
||||
commonCmd.ExitOnErr(cmd, "init contract client: %w", err)
|
||||
|
||||
ffsid.addCall(ffsid.roCli.RemoveSubjectKeyCall(addr, pub))
|
||||
|
||||
err = ffsid.sendWait()
|
||||
commonCmd.ExitOnErr(cmd, "remove subject key: %w", err)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
@ -61,7 +60,6 @@ var (
|
|||
Use: "list-namespaces",
|
||||
Short: "List all namespaces in frostfsid",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidListNamespaces,
|
||||
|
@ -91,7 +89,6 @@ var (
|
|||
Use: "list-subjects",
|
||||
Short: "List subjects in namespace",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidListSubjects,
|
||||
|
@ -121,7 +118,6 @@ var (
|
|||
Use: "list-groups",
|
||||
Short: "List groups in namespace",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidListGroups,
|
||||
|
@ -151,7 +147,6 @@ var (
|
|||
Use: "list-group-subjects",
|
||||
Short: "List subjects in group",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
},
|
||||
Run: frostfsidListGroupSubjects,
|
||||
|
@ -169,7 +164,6 @@ func initFrostfsIDCreateNamespaceCmd() {
|
|||
func initFrostfsIDListNamespacesCmd() {
|
||||
Cmd.AddCommand(frostfsidListNamespacesCmd)
|
||||
frostfsidListNamespacesCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
frostfsidListNamespacesCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
}
|
||||
|
||||
func initFrostfsIDCreateSubjectCmd() {
|
||||
|
@ -193,7 +187,6 @@ func initFrostfsIDListSubjectsCmd() {
|
|||
frostfsidListSubjectsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
frostfsidListSubjectsCmd.Flags().String(namespaceFlag, "", "Namespace to list subjects")
|
||||
frostfsidListSubjectsCmd.Flags().Bool(includeNamesFlag, false, "Whether include subject name (require additional requests)")
|
||||
frostfsidListSubjectsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
}
|
||||
|
||||
func initFrostfsIDCreateGroupCmd() {
|
||||
|
@ -217,7 +210,6 @@ func initFrostfsIDListGroupsCmd() {
|
|||
Cmd.AddCommand(frostfsidListGroupsCmd)
|
||||
frostfsidListGroupsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
frostfsidListGroupsCmd.Flags().String(namespaceFlag, "", "Namespace to list groups")
|
||||
frostfsidListGroupsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
}
|
||||
|
||||
func initFrostfsIDAddSubjectToGroupCmd() {
|
||||
|
@ -242,7 +234,6 @@ func initFrostfsIDListGroupSubjectsCmd() {
|
|||
frostfsidListGroupSubjectsCmd.Flags().String(namespaceFlag, "", "Namespace name")
|
||||
frostfsidListGroupSubjectsCmd.Flags().Int64(groupIDFlag, 0, "Group id")
|
||||
frostfsidListGroupSubjectsCmd.Flags().Bool(includeNamesFlag, false, "Whether include subject name (require additional requests)")
|
||||
frostfsidListGroupSubjectsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
}
|
||||
|
||||
func frostfsidCreateNamespace(cmd *cobra.Command, _ []string) {
|
||||
|
@ -497,10 +488,6 @@ func (f *frostfsidClient) sendWaitRes() (*state.AppExecResult, error) {
|
|||
}
|
||||
f.bw.Reset()
|
||||
|
||||
if len(f.wCtx.SentTxs) == 0 {
|
||||
return nil, errors.New("no transactions to wait")
|
||||
}
|
||||
|
||||
f.wCtx.Command.Println("Waiting for transactions to persist...")
|
||||
return f.roCli.Wait(f.wCtx.SentTxs[0].Hash, f.wCtx.SentTxs[0].Vub, nil)
|
||||
}
|
||||
|
@ -522,7 +509,7 @@ func readIterator(inv *invoker.Invoker, iter *result.Iterator, batchSize int, se
|
|||
}
|
||||
|
||||
func initInvoker(cmd *cobra.Command) (*invoker.Invoker, *state.Contract, util.Uint160) {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "can't create N3 client: %w", err)
|
||||
|
||||
inv := invoker.New(c, nil)
|
||||
|
|
|
@ -1,59 +1,12 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/ape"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFrostfsIDConfig(t *testing.T) {
|
||||
pks := make([]*keys.PrivateKey, 4)
|
||||
for i := range pks {
|
||||
pk, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
pks[i] = pk
|
||||
}
|
||||
|
||||
fmts := []string{
|
||||
pks[0].GetScriptHash().StringLE(),
|
||||
address.Uint160ToString(pks[1].GetScriptHash()),
|
||||
hex.EncodeToString(pks[2].PublicKey().UncompressedBytes()),
|
||||
hex.EncodeToString(pks[3].PublicKey().Bytes()),
|
||||
}
|
||||
|
||||
for i := range fmts {
|
||||
v := viper.New()
|
||||
v.Set("frostfsid.admin", fmts[i])
|
||||
|
||||
actual, found, err := helper.GetFrostfsIDAdmin(v)
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Equal(t, pks[i].GetScriptHash(), actual)
|
||||
}
|
||||
|
||||
t.Run("bad key", func(t *testing.T) {
|
||||
v := viper.New()
|
||||
v.Set("frostfsid.admin", "abc")
|
||||
|
||||
_, found, err := helper.GetFrostfsIDAdmin(v)
|
||||
require.Error(t, err)
|
||||
require.True(t, found)
|
||||
})
|
||||
t.Run("missing key", func(t *testing.T) {
|
||||
v := viper.New()
|
||||
|
||||
_, found, err := helper.GetFrostfsIDAdmin(v)
|
||||
require.NoError(t, err)
|
||||
require.False(t, found)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNamespaceRegexp(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
|
|
|
@ -12,4 +12,6 @@ func init() {
|
|||
initFrostfsIDAddSubjectToGroupCmd()
|
||||
initFrostfsIDRemoveSubjectFromGroupCmd()
|
||||
initFrostfsIDListGroupSubjectsCmd()
|
||||
initFrostfsIDAddSubjectKeyCmd()
|
||||
initFrostfsIDRemoveSubjectKeyCmd()
|
||||
}
|
||||
|
|
|
@ -38,38 +38,24 @@ func NewLocalActor(cmd *cobra.Command, c actor.RPCActor, accName string) (*Local
|
|||
walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
|
||||
var act *actor.Actor
|
||||
var accounts []*wallet.Account
|
||||
if walletDir == "" {
|
||||
account, err := wallet.NewAccount()
|
||||
commonCmd.ExitOnErr(cmd, "unable to create dummy account: %w", err)
|
||||
act, err = actor.New(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: account.Contract.ScriptHash(),
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
Account: account,
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
wallets, err := GetAlphabetWallets(viper.GetViper(), walletDir)
|
||||
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
|
||||
|
||||
for _, w := range wallets {
|
||||
acc, err := GetWalletAccount(w, accName)
|
||||
commonCmd.ExitOnErr(cmd, fmt.Sprintf("can't find %s account: %%w", accName), err)
|
||||
accounts = append(accounts, acc)
|
||||
}
|
||||
act, err = actor.New(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: accounts[0].Contract.ScriptHash(),
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
Account: accounts[0],
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wallets, err := GetAlphabetWallets(viper.GetViper(), walletDir)
|
||||
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
|
||||
|
||||
for _, w := range wallets {
|
||||
acc, err := GetWalletAccount(w, accName)
|
||||
commonCmd.ExitOnErr(cmd, fmt.Sprintf("can't find %s account: %%w", accName), err)
|
||||
accounts = append(accounts, acc)
|
||||
}
|
||||
act, err = actor.New(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: accounts[0].Contract.ScriptHash(),
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
Account: accounts[0],
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LocalActor{
|
||||
neoActor: act,
|
||||
|
|
|
@ -82,7 +82,7 @@ func GetContractDeployData(c *InitializeContext, ctrName string, keysParam []any
|
|||
h, found, err = getFrostfsIDAdminFromContract(c.ReadOnlyInvoker)
|
||||
}
|
||||
if method != constants.UpdateMethodName || err == nil && !found {
|
||||
h, found, err = GetFrostfsIDAdmin(viper.GetViper())
|
||||
h, found, err = getFrostfsIDAdmin(viper.GetViper())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
const frostfsIDAdminConfigKey = "frostfsid.admin"
|
||||
|
||||
func GetFrostfsIDAdmin(v *viper.Viper) (util.Uint160, bool, error) {
|
||||
func getFrostfsIDAdmin(v *viper.Viper) (util.Uint160, bool, error) {
|
||||
admin := v.GetString(frostfsIDAdminConfigKey)
|
||||
if admin == "" {
|
||||
return util.Uint160{}, false, nil
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package helper
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFrostfsIDConfig(t *testing.T) {
|
||||
pks := make([]*keys.PrivateKey, 4)
|
||||
for i := range pks {
|
||||
pk, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
pks[i] = pk
|
||||
}
|
||||
|
||||
fmts := []string{
|
||||
pks[0].GetScriptHash().StringLE(),
|
||||
address.Uint160ToString(pks[1].GetScriptHash()),
|
||||
hex.EncodeToString(pks[2].PublicKey().UncompressedBytes()),
|
||||
hex.EncodeToString(pks[3].PublicKey().Bytes()),
|
||||
}
|
||||
|
||||
for i := range fmts {
|
||||
v := viper.New()
|
||||
v.Set("frostfsid.admin", fmts[i])
|
||||
|
||||
actual, found, err := getFrostfsIDAdmin(v)
|
||||
require.NoError(t, err)
|
||||
require.True(t, found)
|
||||
require.Equal(t, pks[i].GetScriptHash(), actual)
|
||||
}
|
||||
|
||||
t.Run("bad key", func(t *testing.T) {
|
||||
v := viper.New()
|
||||
v.Set("frostfsid.admin", "abc")
|
||||
|
||||
_, found, err := getFrostfsIDAdmin(v)
|
||||
require.Error(t, err)
|
||||
require.True(t, found)
|
||||
})
|
||||
t.Run("missing key", func(t *testing.T) {
|
||||
v := viper.New()
|
||||
|
||||
_, found, err := getFrostfsIDAdmin(v)
|
||||
require.NoError(t, err)
|
||||
require.False(t, found)
|
||||
})
|
||||
}
|
|
@ -134,12 +134,12 @@ func NewInitializeContext(cmd *cobra.Command, v *viper.Viper) (*InitializeContex
|
|||
return nil, err
|
||||
}
|
||||
|
||||
accounts, err := createWalletAccounts(wallets)
|
||||
accounts, err := getSingleAccounts(wallets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cliCtx, err := DefaultClientContext(c, committeeAcc)
|
||||
cliCtx, err := defaultClientContext(c, committeeAcc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("client context: %w", err)
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ func createClient(cmd *cobra.Command, v *viper.Viper, wallets []*wallet.Wallet)
|
|||
}
|
||||
c, err = NewLocalClient(cmd, v, wallets, ldf.Value.String())
|
||||
} else {
|
||||
c, err = GetN3Client(v)
|
||||
c, err = NewRemoteClient(v)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't create N3 client: %w", err)
|
||||
|
@ -211,7 +211,7 @@ func getContractsPath(cmd *cobra.Command, needContracts bool) (string, error) {
|
|||
return ctrPath, nil
|
||||
}
|
||||
|
||||
func createWalletAccounts(wallets []*wallet.Wallet) ([]*wallet.Account, error) {
|
||||
func getSingleAccounts(wallets []*wallet.Wallet) ([]*wallet.Account, error) {
|
||||
accounts := make([]*wallet.Account, len(wallets))
|
||||
for i, w := range wallets {
|
||||
acc, err := GetWalletAccount(w, constants.SingleAccountName)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
|
@ -47,7 +48,7 @@ type LocalClient struct {
|
|||
}
|
||||
|
||||
func NewLocalClient(cmd *cobra.Command, v *viper.Viper, wallets []*wallet.Wallet, dumpPath string) (*LocalClient, error) {
|
||||
cfg, err := config.LoadFile(v.GetString(constants.ProtoConfigPath))
|
||||
cfg, err := config.LoadFile(v.GetString(commonflags.ProtoConfigPath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -57,17 +58,59 @@ func NewLocalClient(cmd *cobra.Command, v *viper.Viper, wallets []*wallet.Wallet
|
|||
return nil, err
|
||||
}
|
||||
|
||||
m := smartcontract.GetDefaultHonestNodeCount(int(cfg.ProtocolConfiguration.ValidatorsCount))
|
||||
accounts := make([]*wallet.Account, len(wallets))
|
||||
for i := range accounts {
|
||||
accounts[i], err = GetWalletAccount(wallets[i], constants.ConsensusAccountName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
go bc.Run()
|
||||
|
||||
accounts, err := getBlockSigningAccounts(cfg.ProtocolConfiguration, wallets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmd.Name() != "init" {
|
||||
if err := restoreDump(bc, dumpPath); err != nil {
|
||||
return nil, fmt.Errorf("restore dump: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &LocalClient{
|
||||
bc: bc,
|
||||
dumpPath: dumpPath,
|
||||
accounts: accounts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func restoreDump(bc *core.Blockchain, dumpPath string) error {
|
||||
f, err := os.OpenFile(dumpPath, os.O_RDONLY, 0o600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't open local dump: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := io.NewBinReaderFromIO(f)
|
||||
|
||||
var skip uint32
|
||||
if bc.BlockHeight() != 0 {
|
||||
skip = bc.BlockHeight() + 1
|
||||
}
|
||||
|
||||
count := r.ReadU32LE() - skip
|
||||
if err := chaindump.Restore(bc, r, skip, count, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBlockSigningAccounts(cfg config.ProtocolConfiguration, wallets []*wallet.Wallet) ([]*wallet.Account, error) {
|
||||
accounts := make([]*wallet.Account, len(wallets))
|
||||
for i := range accounts {
|
||||
acc, err := GetWalletAccount(wallets[i], constants.ConsensusAccountName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accounts[i] = acc
|
||||
}
|
||||
|
||||
indexMap := make(map[string]int)
|
||||
for i, pub := range cfg.ProtocolConfiguration.StandbyCommittee {
|
||||
for i, pub := range cfg.StandbyCommittee {
|
||||
indexMap[pub] = i
|
||||
}
|
||||
|
||||
|
@ -76,37 +119,12 @@ func NewLocalClient(cmd *cobra.Command, v *viper.Viper, wallets []*wallet.Wallet
|
|||
pj := accounts[j].PrivateKey().PublicKey().Bytes()
|
||||
return indexMap[string(pi)] < indexMap[string(pj)]
|
||||
})
|
||||
sort.Slice(accounts[:cfg.ProtocolConfiguration.ValidatorsCount], func(i, j int) bool {
|
||||
sort.Slice(accounts[:cfg.ValidatorsCount], func(i, j int) bool {
|
||||
return accounts[i].PublicKey().Cmp(accounts[j].PublicKey()) == -1
|
||||
})
|
||||
|
||||
go bc.Run()
|
||||
|
||||
if cmd.Name() != "init" {
|
||||
f, err := os.OpenFile(dumpPath, os.O_RDONLY, 0o600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't open local dump: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := io.NewBinReaderFromIO(f)
|
||||
|
||||
var skip uint32
|
||||
if bc.BlockHeight() != 0 {
|
||||
skip = bc.BlockHeight() + 1
|
||||
}
|
||||
|
||||
count := r.ReadU32LE() - skip
|
||||
if err := chaindump.Restore(bc, r, skip, count, nil); err != nil {
|
||||
return nil, fmt.Errorf("can't restore local dump: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &LocalClient{
|
||||
bc: bc,
|
||||
dumpPath: dumpPath,
|
||||
accounts: accounts[:m],
|
||||
}, nil
|
||||
m := smartcontract.GetDefaultHonestNodeCount(int(cfg.ValidatorsCount))
|
||||
return accounts[:m], nil
|
||||
}
|
||||
|
||||
func (l *LocalClient) GetBlockCount() (uint32, error) {
|
||||
|
@ -127,11 +145,6 @@ func (l *LocalClient) GetApplicationLog(h util.Uint256, t *trigger.Type) (*resul
|
|||
return &a, nil
|
||||
}
|
||||
|
||||
func (l *LocalClient) GetCommittee() (keys.PublicKeys, error) {
|
||||
// not used by `morph init` command
|
||||
panic("unexpected call")
|
||||
}
|
||||
|
||||
// InvokeFunction is implemented via `InvokeScript`.
|
||||
func (l *LocalClient) InvokeFunction(h util.Uint160, method string, sPrm []smartcontract.Parameter, ss []transaction.Signer) (*result.Invoke, error) {
|
||||
var err error
|
||||
|
@ -295,13 +308,7 @@ func (l *LocalClient) InvokeScript(script []byte, signers []transaction.Signer)
|
|||
}
|
||||
|
||||
func (l *LocalClient) SendRawTransaction(tx *transaction.Transaction) (util.Uint256, error) {
|
||||
// We need to test that transaction was formed correctly to catch as many errors as we can.
|
||||
bs := tx.Bytes()
|
||||
_, err := transaction.NewTransactionFromBytes(bs)
|
||||
if err != nil {
|
||||
return tx.Hash(), fmt.Errorf("invalid transaction: %w", err)
|
||||
}
|
||||
|
||||
tx = tx.Copy()
|
||||
l.transactions = append(l.transactions, tx)
|
||||
return tx.Hash(), nil
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
|
@ -25,15 +24,10 @@ import (
|
|||
// Client represents N3 client interface capable of test-invoking scripts
|
||||
// and sending signed transactions to chain.
|
||||
type Client interface {
|
||||
invoker.RPCInvoke
|
||||
actor.RPCActor
|
||||
|
||||
GetBlockCount() (uint32, error)
|
||||
GetNativeContracts() ([]state.Contract, error)
|
||||
GetApplicationLog(util.Uint256, *trigger.Type) (*result.ApplicationLog, error)
|
||||
GetVersion() (*result.Version, error)
|
||||
SendRawTransaction(*transaction.Transaction) (util.Uint256, error)
|
||||
GetCommittee() (keys.PublicKeys, error)
|
||||
CalculateNetworkFee(tx *transaction.Transaction) (int64, error)
|
||||
}
|
||||
|
||||
type HashVUBPair struct {
|
||||
|
@ -48,7 +42,7 @@ type ClientContext struct {
|
|||
SentTxs []HashVUBPair
|
||||
}
|
||||
|
||||
func GetN3Client(v *viper.Viper) (Client, error) {
|
||||
func NewRemoteClient(v *viper.Viper) (Client, error) {
|
||||
// number of opened connections
|
||||
// by neo-go client per one host
|
||||
const (
|
||||
|
@ -88,8 +82,14 @@ func GetN3Client(v *viper.Viper) (Client, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func DefaultClientContext(c Client, committeeAcc *wallet.Account) (*ClientContext, error) {
|
||||
commAct, err := NewActor(c, committeeAcc)
|
||||
func defaultClientContext(c Client, committeeAcc *wallet.Account) (*ClientContext, error) {
|
||||
commAct, err := actor.New(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: committeeAcc.Contract.ScriptHash(),
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
Account: committeeAcc,
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,8 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -87,16 +85,6 @@ func openAlphabetWallets(v *viper.Viper, walletDir string) ([]*wallet.Wallet, er
|
|||
return wallets, nil
|
||||
}
|
||||
|
||||
func NewActor(c actor.RPCActor, committeeAcc *wallet.Account) (*actor.Actor, error) {
|
||||
return actor.New(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: committeeAcc.Contract.ScriptHash(),
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
Account: committeeAcc,
|
||||
}})
|
||||
}
|
||||
|
||||
func ReadContract(ctrPath, ctrName string) (*ContractState, error) {
|
||||
rawNef, err := os.ReadFile(filepath.Join(ctrPath, ctrName+"_contract.nef"))
|
||||
if err != nil {
|
||||
|
|
|
@ -62,7 +62,7 @@ func testInitialize(t *testing.T, committeeSize int) {
|
|||
v := viper.GetViper()
|
||||
|
||||
require.NoError(t, generateTestData(testdataDir, committeeSize))
|
||||
v.Set(constants.ProtoConfigPath, filepath.Join(testdataDir, protoFileName))
|
||||
v.Set(commonflags.ProtoConfigPath, filepath.Join(testdataDir, protoFileName))
|
||||
|
||||
// Set to the path or remove the next statement to download from the network.
|
||||
require.NoError(t, Cmd.Flags().Set(commonflags.ContractsInitFlag, contractsPath))
|
||||
|
|
|
@ -2,7 +2,6 @@ package initialize
|
|||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -32,7 +31,7 @@ var Cmd = &cobra.Command{
|
|||
_ = viper.BindPFlag(commonflags.ContainerFeeInitFlag, cmd.Flags().Lookup(containerFeeCLIFlag))
|
||||
_ = viper.BindPFlag(commonflags.ContainerAliasFeeInitFlag, cmd.Flags().Lookup(containerAliasFeeCLIFlag))
|
||||
_ = viper.BindPFlag(commonflags.WithdrawFeeInitFlag, cmd.Flags().Lookup(withdrawFeeCLIFlag))
|
||||
_ = viper.BindPFlag(constants.ProtoConfigPath, cmd.Flags().Lookup(constants.ProtoConfigPath))
|
||||
_ = viper.BindPFlag(commonflags.ProtoConfigPath, cmd.Flags().Lookup(commonflags.ProtoConfigPath))
|
||||
},
|
||||
RunE: initializeSideChainCmd,
|
||||
}
|
||||
|
@ -48,7 +47,7 @@ func initInitCmd() {
|
|||
// Defaults are taken from neo-preodolenie.
|
||||
Cmd.Flags().Uint64(containerFeeCLIFlag, 1000, "Container registration fee")
|
||||
Cmd.Flags().Uint64(containerAliasFeeCLIFlag, 500, "Container alias fee")
|
||||
Cmd.Flags().String(constants.ProtoConfigPath, "", "Path to the consensus node configuration")
|
||||
Cmd.Flags().String(commonflags.ProtoConfigPath, "", "Path to the consensus node configuration")
|
||||
Cmd.Flags().String(commonflags.LocalDumpFlag, "", "Path to the blocks dump file")
|
||||
Cmd.MarkFlagsMutuallyExclusive(commonflags.ContractsInitFlag, commonflags.ContractsURLFlag)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
func listNetmapCandidatesNodes(cmd *cobra.Command, _ []string) {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "can't create N3 client: %w", err)
|
||||
|
||||
inv := invoker.New(c, nil)
|
||||
|
|
|
@ -12,7 +12,6 @@ var (
|
|||
Short: "List netmap candidates nodes",
|
||||
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||
},
|
||||
Run: listNetmapCandidatesNodes,
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func initRegisterCmd() {
|
|||
}
|
||||
|
||||
func registerDomain(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
email, _ := cmd.Flags().GetString(nnsEmailFlag)
|
||||
|
@ -53,7 +53,7 @@ func initDeleteCmd() {
|
|||
}
|
||||
|
||||
func deleteDomain(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
h, vub, err := c.DeleteDomain(name)
|
||||
|
|
|
@ -5,15 +5,15 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func getRPCClient(cmd *cobra.Command) (*client.Contract, *helper.LocalActor, util.Uint160) {
|
||||
func nnsWriter(cmd *cobra.Command) (*client.Contract, *helper.LocalActor) {
|
||||
v := viper.GetViper()
|
||||
c, err := helper.GetN3Client(v)
|
||||
c, err := helper.NewRemoteClient(v)
|
||||
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||
|
||||
ac, err := helper.NewLocalActor(cmd, c, constants.CommitteeAccountName)
|
||||
|
@ -22,5 +22,17 @@ func getRPCClient(cmd *cobra.Command) (*client.Contract, *helper.LocalActor, uti
|
|||
r := management.NewReader(ac.Invoker)
|
||||
nnsCs, err := helper.GetContractByID(r, 1)
|
||||
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
||||
return client.New(ac, nnsCs.Hash), ac, nnsCs.Hash
|
||||
return client.New(ac, nnsCs.Hash), ac
|
||||
}
|
||||
|
||||
func nnsReader(cmd *cobra.Command) (*client.ContractReader, *invoker.Invoker) {
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||
|
||||
inv := invoker.New(c, nil)
|
||||
r := management.NewReader(inv)
|
||||
nnsCs, err := helper.GetContractByID(r, 1)
|
||||
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
||||
|
||||
return client.NewReader(inv, nnsCs.Hash), inv
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -29,7 +28,6 @@ func initAddRecordCmd() {
|
|||
func initGetRecordsCmd() {
|
||||
Cmd.AddCommand(getRecordsCmd)
|
||||
getRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
getRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
getRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||
getRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
|
||||
|
||||
|
@ -61,7 +59,7 @@ func initDelRecordCmd() {
|
|||
}
|
||||
|
||||
func addRecord(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
data, _ := cmd.Flags().GetString(nnsRecordDataFlag)
|
||||
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||
|
@ -77,16 +75,16 @@ func addRecord(cmd *cobra.Command, _ []string) {
|
|||
}
|
||||
|
||||
func getRecords(cmd *cobra.Command, _ []string) {
|
||||
c, act, hash := getRPCClient(cmd)
|
||||
c, inv := nnsReader(cmd)
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||
if recordType == "" {
|
||||
sid, r, err := unwrap.SessionIterator(act.Invoker.Call(hash, "getAllRecords", name))
|
||||
sid, r, err := c.GetAllRecords(name)
|
||||
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||
defer func() {
|
||||
_ = act.Invoker.TerminateSession(sid)
|
||||
_ = inv.TerminateSession(sid)
|
||||
}()
|
||||
items, err := act.Invoker.TraverseIterator(sid, &r, 0)
|
||||
items, err := inv.TraverseIterator(sid, &r, 0)
|
||||
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||
for len(items) != 0 {
|
||||
for j := range items {
|
||||
|
@ -97,7 +95,7 @@ func getRecords(cmd *cobra.Command, _ []string) {
|
|||
recordTypeToString(nns.RecordType(rs[1].Value().(*big.Int).Int64())),
|
||||
string(bs))
|
||||
}
|
||||
items, err = act.Invoker.TraverseIterator(sid, &r, 0)
|
||||
items, err = inv.TraverseIterator(sid, &r, 0)
|
||||
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||
}
|
||||
} else {
|
||||
|
@ -114,7 +112,7 @@ func getRecords(cmd *cobra.Command, _ []string) {
|
|||
}
|
||||
|
||||
func delRecords(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||
typ, err := getRecordType(recordType)
|
||||
|
@ -129,7 +127,7 @@ func delRecords(cmd *cobra.Command, _ []string) {
|
|||
}
|
||||
|
||||
func delRecord(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
data, _ := cmd.Flags().GetString(nnsRecordDataFlag)
|
||||
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||
|
|
|
@ -14,7 +14,7 @@ func initRenewCmd() {
|
|||
}
|
||||
|
||||
func renewDomain(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
h, vub, err := c.Renew(name)
|
||||
commonCmd.ExitOnErr(cmd, "unable to renew domain: %w", err)
|
||||
|
|
|
@ -18,12 +18,11 @@ const (
|
|||
func initTokensCmd() {
|
||||
Cmd.AddCommand(tokensCmd)
|
||||
tokensCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
tokensCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
tokensCmd.Flags().BoolP(commonflags.Verbose, commonflags.VerboseShorthand, false, verboseDesc)
|
||||
}
|
||||
|
||||
func listTokens(cmd *cobra.Command, _ []string) {
|
||||
c, _, _ := getRPCClient(cmd)
|
||||
c, _ := nnsReader(cmd)
|
||||
it, err := c.Tokens()
|
||||
commonCmd.ExitOnErr(cmd, "unable to get tokens: %w", err)
|
||||
for toks, err := it.Next(10); err == nil && len(toks) > 0; toks, err = it.Next(10) {
|
||||
|
@ -41,7 +40,7 @@ func listTokens(cmd *cobra.Command, _ []string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getCnameRecord(c *client.Contract, token []byte) (string, error) {
|
||||
func getCnameRecord(c *client.ContractReader, token []byte) (string, error) {
|
||||
items, err := c.GetRecords(string(token), big.NewInt(int64(nns.CNAME)))
|
||||
|
||||
// GetRecords returns the error "not an array" if the domain does not contain records.
|
||||
|
|
|
@ -30,7 +30,7 @@ func initUpdateCmd() {
|
|||
}
|
||||
|
||||
func updateSOA(cmd *cobra.Command, _ []string) {
|
||||
c, actor, _ := getRPCClient(cmd)
|
||||
c, actor := nnsWriter(cmd)
|
||||
|
||||
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||
email, _ := cmd.Flags().GetString(nnsEmailFlag)
|
||||
|
|
|
@ -89,7 +89,7 @@ func depositNotary(cmd *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
func transferGas(cmd *cobra.Command, acc *wallet.Account, accHash util.Uint160, gasAmount fixedn.Fixed8, till int64) error {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func SetPolicyCmd(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
func dumpPolicyCmd(cmd *cobra.Command, _ []string) error {
|
||||
c, err := helper.GetN3Client(viper.GetViper())
|
||||
c, err := helper.NewRemoteClient(viper.GetViper())
|
||||
commonCmd.ExitOnErr(cmd, "can't create N3 client:", err)
|
||||
|
||||
inv := invoker.New(c, nil)
|
||||
|
|
|
@ -1,44 +1,19 @@
|
|||
package apemanager
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
)
|
||||
|
||||
const (
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
)
|
||||
|
||||
const (
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
)
|
||||
|
||||
var errUnknownTargetType = errors.New("unknown target type")
|
||||
|
||||
var addCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add rule chain for a target",
|
||||
|
@ -49,55 +24,28 @@ var addCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func parseTarget(cmd *cobra.Command) (ct apeSDK.ChainTarget) {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
t := apeCmd.ParseTarget(cmd)
|
||||
|
||||
ct.Name = name
|
||||
ct.Name = t.Name
|
||||
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
switch t.Type {
|
||||
case engine.Namespace:
|
||||
ct.TargetType = apeSDK.TargetTypeNamespace
|
||||
case containerTarget:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
case engine.Container:
|
||||
ct.TargetType = apeSDK.TargetTypeContainer
|
||||
case userTarget:
|
||||
case engine.User:
|
||||
ct.TargetType = apeSDK.TargetTypeUser
|
||||
case groupTarget:
|
||||
case engine.Group:
|
||||
ct.TargetType = apeSDK.TargetTypeGroup
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
commonCmd.ExitOnErr(cmd, "conversion error: %w", fmt.Errorf("unknown type '%c'", t.Type))
|
||||
}
|
||||
return ct
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) apeSDK.Chain {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = apechain.ID(chainIDRaw)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", util.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", util.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
util.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
serialized := chain.Bytes()
|
||||
c := apeCmd.ParseChain(cmd)
|
||||
serialized := c.Bytes()
|
||||
return apeSDK.Chain{
|
||||
Raw: serialized,
|
||||
}
|
||||
|
@ -126,13 +74,13 @@ func initAddCmd() {
|
|||
commonflags.Init(addCmd)
|
||||
|
||||
ff := addCmd.Flags()
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||
ff.String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, apeCmd.ChainIDHexFlagDesc)
|
||||
|
||||
addCmd.MarkFlagsMutuallyExclusive(pathFlag, ruleFlag)
|
||||
addCmd.MarkFlagsMutuallyExclusive(apeCmd.PathFlag, apeCmd.RuleFlag)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -35,7 +35,7 @@ func list(cmd *cobra.Command, _ []string) {
|
|||
for _, respChain := range resp.Chains {
|
||||
var chain apechain.Chain
|
||||
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(respChain.Raw))
|
||||
apeutil.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ func initListCmd() {
|
|||
commonflags.Init(listCmd)
|
||||
|
||||
ff := listCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = listCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
|
|
@ -1,29 +1,23 @@
|
|||
package apemanager
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
||||
|
||||
removeCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "Remove rule chain for a target",
|
||||
Run: remove,
|
||||
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||
commonflags.Bind(cmd)
|
||||
},
|
||||
}
|
||||
)
|
||||
var removeCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "Remove rule chain for a target",
|
||||
Run: remove,
|
||||
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||
commonflags.Bind(cmd)
|
||||
},
|
||||
}
|
||||
|
||||
func remove(cmd *cobra.Command, _ []string) {
|
||||
target := parseTarget(cmd)
|
||||
|
@ -31,19 +25,9 @@ func remove(cmd *cobra.Command, _ []string) {
|
|||
key := key.Get(cmd)
|
||||
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
||||
}
|
||||
chainID := apeCmd.ParseChainID(cmd)
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
_, err := cli.APEManagerRemoveChain(cmd.Context(), client_sdk.PrmAPEManagerRemoveChain{
|
||||
ChainTarget: target,
|
||||
ChainID: chainIDRaw,
|
||||
|
@ -58,9 +42,10 @@ func initRemoveCmd() {
|
|||
commonflags.Init(removeCmd)
|
||||
|
||||
ff := removeCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = removeCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(chainIDFlag, "", "Chain id")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = removeCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
_ = removeCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, apeCmd.ChainIDHexFlagDesc)
|
||||
}
|
||||
|
|
|
@ -1,31 +1,20 @@
|
|||
package bearer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
|
||||
errRuleIsNotParsed = errors.New("rule is not passed")
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
outputFlag = "output"
|
||||
outputFlag = "output"
|
||||
)
|
||||
|
||||
var generateAPEOverrideCmd = &cobra.Command{
|
||||
|
@ -40,7 +29,7 @@ Generated APE override can be dumped to a file in JSON format that is passed to
|
|||
}
|
||||
|
||||
func genereateAPEOverride(cmd *cobra.Command, _ []string) {
|
||||
c := parseChain(cmd)
|
||||
c := apeCmd.ParseChain(cmd)
|
||||
|
||||
targetCID, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||
var cid cidSDK.ID
|
||||
|
@ -77,39 +66,11 @@ func init() {
|
|||
ff.StringP(commonflags.CIDFlag, "", "", "Target container ID.")
|
||||
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.CIDFlag)
|
||||
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
|
||||
ff.String(outputFlag, "", "Output path to dump result JSON-encoded APE override")
|
||||
_ = cobra.MarkFlagFilename(createCmd.Flags(), outputFlag)
|
||||
}
|
||||
|
||||
func parseChainID(cmd *cobra.Command) apechain.ID {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
|
||||
errChainIDCannotBeEmpty)
|
||||
}
|
||||
return apechain.ID(chainID)
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errRuleIsNotParsed)
|
||||
}
|
||||
|
||||
chain.ID = parseChainID(cmd)
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
parseutil.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
)
|
||||
|
||||
var addRuleCmd = &cobra.Command{
|
||||
Use: "add-rule",
|
||||
Short: "Add local override",
|
||||
|
@ -31,41 +22,12 @@ control add-rule --endpoint ... -w ... --address ... --chain-id ChainID --cid ..
|
|||
Run: addRule,
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = apechain.ID(chainIDRaw)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", util.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", util.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
util.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func addRule(cmd *cobra.Command, _ []string) {
|
||||
pk := key.Get(cmd)
|
||||
|
||||
target := parseTarget(cmd)
|
||||
|
||||
parsed := parseChain(cmd)
|
||||
parsed := apeCmd.ParseChain(cmd)
|
||||
|
||||
req := &control.AddChainLocalOverrideRequest{
|
||||
Body: &control.AddChainLocalOverrideRequest_Body{
|
||||
|
@ -94,13 +56,13 @@ func initControlAddRuleCmd() {
|
|||
initControlFlags(addRuleCmd)
|
||||
|
||||
ff := addRuleCmd.Flags()
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addRuleCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
|
||||
addRuleCmd.MarkFlagsMutuallyExclusive(pathFlag, ruleFlag)
|
||||
addRuleCmd.MarkFlagsMutuallyExclusive(apeCmd.PathFlag, apeCmd.RuleFlag)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"encoding/hex"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
|
@ -24,8 +24,8 @@ func getRule(cmd *cobra.Command, _ []string) {
|
|||
|
||||
target := parseTarget(cmd)
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||
|
||||
if hexEncoded {
|
||||
chainIDBytes, err := hex.DecodeString(chainID)
|
||||
|
@ -56,16 +56,16 @@ func getRule(cmd *cobra.Command, _ []string) {
|
|||
|
||||
var chain apechain.Chain
|
||||
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(resp.GetBody().GetChain()))
|
||||
util.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
apecmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
}
|
||||
|
||||
func initControGetRuleCmd() {
|
||||
initControlFlags(getRuleCmd)
|
||||
|
||||
ff := getRuleCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = getRuleCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(chainIDFlag, "", "Chain id")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||
_ = getRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||
ff.String(apecmd.ChainIDFlag, "", "Chain id")
|
||||
ff.Bool(apecmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -23,65 +21,25 @@ var listRulesCmd = &cobra.Command{
|
|||
Run: listRules,
|
||||
}
|
||||
|
||||
const (
|
||||
defaultNamespace = "root"
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
)
|
||||
|
||||
const (
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
)
|
||||
|
||||
var (
|
||||
errSettingDefaultValueWasDeclined = errors.New("setting default value was declined")
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
)
|
||||
var engineToControlSvcType = map[policyengine.TargetType]control.ChainTarget_TargetType{
|
||||
policyengine.Namespace: control.ChainTarget_NAMESPACE,
|
||||
policyengine.Container: control.ChainTarget_CONTAINER,
|
||||
policyengine.User: control.ChainTarget_USER,
|
||||
policyengine.Group: control.ChainTarget_GROUP,
|
||||
}
|
||||
|
||||
func parseTarget(cmd *cobra.Command) *control.ChainTarget {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
if name == "" {
|
||||
ln, err := input.ReadLine(fmt.Sprintf("Target name is not set. Confirm to use %s namespace (n|Y)> ", defaultNamespace))
|
||||
commonCmd.ExitOnErr(cmd, "read line error: %w", err)
|
||||
ln = strings.ToLower(ln)
|
||||
if len(ln) > 0 && (ln[0] == 'n') {
|
||||
commonCmd.ExitOnErr(cmd, "read namespace error: %w", errSettingDefaultValueWasDeclined)
|
||||
}
|
||||
name = defaultNamespace
|
||||
}
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_NAMESPACE,
|
||||
}
|
||||
case containerTarget:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_CONTAINER,
|
||||
}
|
||||
case userTarget:
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_USER,
|
||||
}
|
||||
case groupTarget:
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_GROUP,
|
||||
}
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
target := apeCmd.ParseTarget(cmd)
|
||||
|
||||
typ, ok := engineToControlSvcType[target.Type]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "%w", fmt.Errorf("unknown type '%c", target.Type))
|
||||
}
|
||||
|
||||
return &control.ChainTarget{
|
||||
Name: target.Name,
|
||||
Type: typ,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listRules(cmd *cobra.Command, _ []string) {
|
||||
|
@ -117,7 +75,7 @@ func listRules(cmd *cobra.Command, _ []string) {
|
|||
for _, c := range chains {
|
||||
var chain apechain.Chain
|
||||
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(c))
|
||||
util.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +83,7 @@ func initControlListRulesCmd() {
|
|||
initControlFlags(listRulesCmd)
|
||||
|
||||
ff := listRulesCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = listRulesCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listRulesCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
|
|
@ -2,26 +2,20 @@ package control
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
chainNameFlag = "chain-name"
|
||||
chainNameFlagUsage = "Chain name(ingress|s3)"
|
||||
)
|
||||
|
||||
var listTargetsCmd = &cobra.Command{
|
||||
Use: "list-targets",
|
||||
Short: "List local targets",
|
||||
|
@ -32,15 +26,11 @@ var listTargetsCmd = &cobra.Command{
|
|||
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)
|
||||
chainName := apeCmd.ParseChainName(cmd)
|
||||
|
||||
req := &control.ListTargetsLocalOverridesRequest{
|
||||
Body: &control.ListTargetsLocalOverridesRequest_Body{
|
||||
ChainName: chainName,
|
||||
ChainName: string(chainName),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -82,7 +72,7 @@ func initControlListTargetsCmd() {
|
|||
initControlFlags(listTargetsCmd)
|
||||
|
||||
ff := listTargetsCmd.Flags()
|
||||
ff.String(chainNameFlag, "", chainNameFlagUsage)
|
||||
ff.String(apeCmd.ChainNameFlag, "", apeCmd.ChainNameFlagDesc)
|
||||
|
||||
_ = cobra.MarkFlagRequired(ff, chainNameFlag)
|
||||
_ = cobra.MarkFlagRequired(ff, apeCmd.ChainNameFlag)
|
||||
}
|
||||
|
|
|
@ -6,17 +6,12 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
allFlag = "all"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
||||
|
||||
|
@ -30,8 +25,8 @@ var (
|
|||
|
||||
func removeRule(cmd *cobra.Command, _ []string) {
|
||||
pk := key.Get(cmd)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
removeAll, _ := cmd.Flags().GetBool(allFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||
removeAll, _ := cmd.Flags().GetBool(apecmd.AllFlag)
|
||||
if removeAll {
|
||||
req := &control.RemoveChainLocalOverridesByTargetRequest{
|
||||
Body: &control.RemoveChainLocalOverridesByTargetRequest_Body{
|
||||
|
@ -52,7 +47,7 @@ func removeRule(cmd *cobra.Command, _ []string) {
|
|||
return
|
||||
}
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
||||
}
|
||||
|
@ -92,11 +87,11 @@ func initControlRemoveRuleCmd() {
|
|||
initControlFlags(removeRuleCmd)
|
||||
|
||||
ff := removeRuleCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = 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)
|
||||
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||
_ = removeRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||
ff.String(apecmd.ChainIDFlag, "", apecmd.ChainIDFlagDesc)
|
||||
ff.Bool(apecmd.ChainIDHexFlag, false, apecmd.ChainIDHexFlagDesc)
|
||||
ff.Bool(apecmd.AllFlag, false, "Remove all chains")
|
||||
removeRuleCmd.MarkFlagsMutuallyExclusive(apecmd.AllFlag, apecmd.ChainIDFlag)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
|
@ -507,7 +504,6 @@ func isObjectStoredOnNode(ctx context.Context, cmd *cobra.Command, cnrID cid.ID,
|
|||
}
|
||||
|
||||
func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
||||
normilizeObjectNodesResult(objects, result)
|
||||
if json, _ := cmd.Flags().GetBool(commonflags.JSON); json {
|
||||
printObjectNodesAsJSON(cmd, objID, objects, result)
|
||||
} else {
|
||||
|
@ -515,34 +511,6 @@ func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, resul
|
|||
}
|
||||
}
|
||||
|
||||
func normilizeObjectNodesResult(objects []phyObject, result *objectNodesResult) {
|
||||
slices.SortFunc(objects, func(lhs, rhs phyObject) int {
|
||||
if lhs.ecHeader == nil && rhs.ecHeader == nil {
|
||||
return bytes.Compare(lhs.objectID[:], rhs.objectID[:])
|
||||
}
|
||||
if lhs.ecHeader == nil {
|
||||
return -1
|
||||
}
|
||||
if rhs.ecHeader == nil {
|
||||
return 1
|
||||
}
|
||||
if lhs.ecHeader.parent == rhs.ecHeader.parent {
|
||||
return cmp.Compare(lhs.ecHeader.index, rhs.ecHeader.index)
|
||||
}
|
||||
return bytes.Compare(lhs.ecHeader.parent[:], rhs.ecHeader.parent[:])
|
||||
})
|
||||
for _, obj := range objects {
|
||||
op := result.placements[obj.objectID]
|
||||
slices.SortFunc(op.confirmedNodes, func(lhs, rhs netmapSDK.NodeInfo) int {
|
||||
return bytes.Compare(lhs.PublicKey(), rhs.PublicKey())
|
||||
})
|
||||
slices.SortFunc(op.requiredNodes, func(lhs, rhs netmapSDK.NodeInfo) int {
|
||||
return bytes.Compare(lhs.PublicKey(), rhs.PublicKey())
|
||||
})
|
||||
result.placements[obj.objectID] = op
|
||||
}
|
||||
}
|
||||
|
||||
func printObjectNodesAsText(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Object %s stores payload in %d data objects:\n", objID.EncodeToString(), len(objects))
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/internal/ape"
|
||||
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
|
@ -884,7 +884,10 @@ func (c *cfg) engineOpts() []engine.Option {
|
|||
)
|
||||
|
||||
if c.metricsCollector != nil {
|
||||
opts = append(opts, engine.WithMetrics(c.metricsCollector.Engine()))
|
||||
opts = append(opts,
|
||||
engine.WithEngineMetrics(c.metricsCollector.Engine()),
|
||||
engine.WithWritecacheMetrics(c.metricsCollector.Writecachce()),
|
||||
engine.WithGCMetrics(c.metricsCollector.GC()))
|
||||
}
|
||||
|
||||
return opts
|
||||
|
|
|
@ -17,11 +17,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/rand"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -164,48 +160,13 @@ func makeNotaryDeposit(ctx context.Context, c *cfg) (util.Uint256, uint32, error
|
|||
return c.cfgMorph.client.DepositEndlessNotary(ctx, depositAmount)
|
||||
}
|
||||
|
||||
var (
|
||||
errNotaryDepositFail = errors.New("notary deposit tx has faulted")
|
||||
errNotaryDepositTimeout = errors.New("notary deposit tx has not appeared in the network")
|
||||
)
|
||||
|
||||
type waiterClient struct {
|
||||
c *client.Client
|
||||
}
|
||||
|
||||
func (w *waiterClient) Context() context.Context {
|
||||
return context.Background()
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) {
|
||||
return w.c.GetApplicationLog(hash, trig)
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetBlockCount() (uint32, error) {
|
||||
return w.c.BlockCount()
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetVersion() (*result.Version, error) {
|
||||
return w.c.GetVersion()
|
||||
}
|
||||
|
||||
func waitNotaryDeposit(ctx context.Context, c *cfg, tx util.Uint256, vub uint32) error {
|
||||
w, err := waiter.NewPollingBased(&waiterClient{c: c.cfgMorph.client})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create notary deposit waiter: %w", err)
|
||||
if err := c.cfgMorph.client.WaitTxHalt(ctx, client.InvokeRes{Hash: tx, VUB: vub}); err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := w.WaitAny(ctx, vub, tx)
|
||||
if err != nil {
|
||||
if errors.Is(err, waiter.ErrTxNotAccepted) {
|
||||
return errNotaryDepositTimeout
|
||||
}
|
||||
return fmt.Errorf("could not wait for notary deposit persists in chain: %w", err)
|
||||
}
|
||||
if res.Execution.VMState.HasFlag(vmstate.Halt) {
|
||||
c.log.Info(ctx, logs.ClientNotaryDepositTransactionWasSuccessfullyPersisted)
|
||||
return nil
|
||||
}
|
||||
return errNotaryDepositFail
|
||||
|
||||
c.log.Info(ctx, logs.ClientNotaryDepositTransactionWasSuccessfullyPersisted)
|
||||
return nil
|
||||
}
|
||||
|
||||
func listenMorphNotifications(ctx context.Context, c *cfg) {
|
||||
|
|
|
@ -421,8 +421,11 @@ func (c *cfg) updateNetMapState(ctx context.Context, stateSetter func(*nmClient.
|
|||
prm.SetKey(c.key.PublicKey().Bytes())
|
||||
stateSetter(&prm)
|
||||
|
||||
_, err := c.cfgNetmap.wrapper.UpdatePeerState(ctx, prm)
|
||||
return err
|
||||
res, err := c.cfgNetmap.wrapper.UpdatePeerState(ctx, prm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.cfgNetmap.wrapper.Morph().WaitTxHalt(ctx, res)
|
||||
}
|
||||
|
||||
type netInfo struct {
|
||||
|
|
167
cmd/internal/common/ape/commands.go
Normal file
167
cmd/internal/common/ape/commands.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
package ape
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultNamespace = "root"
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
|
||||
Ingress = "ingress"
|
||||
S3 = "s3"
|
||||
)
|
||||
|
||||
var mChainName = map[string]apechain.Name{
|
||||
Ingress: apechain.Ingress,
|
||||
S3: apechain.S3,
|
||||
}
|
||||
|
||||
var (
|
||||
errSettingDefaultValueWasDeclined = errors.New("setting default value was declined")
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
errUnsupportedChainName = errors.New("unsupported chain name")
|
||||
)
|
||||
|
||||
// PrintHumanReadableAPEChain print APE chain rules.
|
||||
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
||||
cmd.Println("Chain ID: " + string(chain.ID))
|
||||
cmd.Printf(" HEX: %x\n", chain.ID)
|
||||
cmd.Println("Rules:")
|
||||
for _, rule := range chain.Rules {
|
||||
cmd.Println("\n\tStatus: " + rule.Status.String())
|
||||
cmd.Println("\tAny: " + strconv.FormatBool(rule.Any))
|
||||
cmd.Println("\tConditions:")
|
||||
for _, c := range rule.Condition {
|
||||
var ot string
|
||||
switch c.Kind {
|
||||
case apechain.KindResource:
|
||||
ot = "Resource"
|
||||
case apechain.KindRequest:
|
||||
ot = "Request"
|
||||
default:
|
||||
panic("unknown object type")
|
||||
}
|
||||
cmd.Println(fmt.Sprintf("\t\t%s %s %s %s", ot, c.Key, c.Op, c.Value))
|
||||
}
|
||||
cmd.Println("\tActions:\tInverted:" + strconv.FormatBool(rule.Actions.Inverted))
|
||||
for _, name := range rule.Actions.Names {
|
||||
cmd.Println("\t\t" + name)
|
||||
}
|
||||
cmd.Println("\tResources:\tInverted:" + strconv.FormatBool(rule.Resources.Inverted))
|
||||
for _, name := range rule.Resources.Names {
|
||||
cmd.Println("\t\t" + name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseTarget handles target parsing of an APE chain.
|
||||
func ParseTarget(cmd *cobra.Command) engine.Target {
|
||||
typ := ParseTargetType(cmd)
|
||||
name, _ := cmd.Flags().GetString(TargetNameFlag)
|
||||
switch typ {
|
||||
case engine.Namespace:
|
||||
if name == "" {
|
||||
ln, err := input.ReadLine(fmt.Sprintf("Target name is not set. Confirm to use %s namespace (n|Y)> ", defaultNamespace))
|
||||
commonCmd.ExitOnErr(cmd, "read line error: %w", err)
|
||||
ln = strings.ToLower(ln)
|
||||
if len(ln) > 0 && (ln[0] == 'n') {
|
||||
commonCmd.ExitOnErr(cmd, "read namespace error: %w", errSettingDefaultValueWasDeclined)
|
||||
}
|
||||
name = defaultNamespace
|
||||
}
|
||||
return engine.NamespaceTarget(name)
|
||||
case engine.Container:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return engine.ContainerTarget(name)
|
||||
case engine.User:
|
||||
return engine.UserTarget(name)
|
||||
case engine.Group:
|
||||
return engine.GroupTarget(name)
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ParseTargetType handles target type parsing of an APE chain.
|
||||
func ParseTargetType(cmd *cobra.Command) engine.TargetType {
|
||||
typ, _ := cmd.Flags().GetString(TargetTypeFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
return engine.Namespace
|
||||
case containerTarget:
|
||||
return engine.Container
|
||||
case userTarget:
|
||||
return engine.User
|
||||
case groupTarget:
|
||||
return engine.Group
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "parse target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ParseChainID handles the parsing of APE-chain identifier.
|
||||
// For some subcommands, chain ID is optional as an input parameter and should be generated by
|
||||
// the service instead.
|
||||
func ParseChainID(cmd *cobra.Command) (id apechain.ID) {
|
||||
chainID, _ := cmd.Flags().GetString(ChainIDFlag)
|
||||
id = apechain.ID(chainID)
|
||||
|
||||
hexEncoded, _ := cmd.Flags().GetBool(ChainIDHexFlag)
|
||||
if !hexEncoded {
|
||||
return
|
||||
}
|
||||
|
||||
chainIDRaw, err := hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
id = apechain.ID(chainIDRaw)
|
||||
return
|
||||
}
|
||||
|
||||
// ParseChain parses an APE chain which can be provided either as a rule statement
|
||||
// or loaded from a binary/JSON file path.
|
||||
func ParseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = ParseChainID(cmd)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(RuleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", apeutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(PathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", apeutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
// ParseChainName parses chain name: the place in the request lifecycle where policy is applied.
|
||||
func ParseChainName(cmd *cobra.Command) apechain.Name {
|
||||
chainName, _ := cmd.Flags().GetString(ChainNameFlag)
|
||||
apeChainName, ok := mChainName[strings.ToLower(chainName)]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "", errUnsupportedChainName)
|
||||
}
|
||||
return apeChainName
|
||||
}
|
79
cmd/internal/common/ape/flags.go
Normal file
79
cmd/internal/common/ape/flags.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package ape
|
||||
|
||||
const (
|
||||
RuleFlag = "rule"
|
||||
PathFlag = "path"
|
||||
PathFlagDesc = "Path to encoded chain in JSON or binary format"
|
||||
TargetNameFlag = "target-name"
|
||||
TargetNameFlagDesc = "Resource name in APE resource name format"
|
||||
TargetTypeFlag = "target-type"
|
||||
TargetTypeFlagDesc = "Resource type(container/namespace)"
|
||||
ChainIDFlag = "chain-id"
|
||||
ChainIDFlagDesc = "Chain id"
|
||||
ChainIDHexFlag = "chain-id-hex"
|
||||
ChainIDHexFlagDesc = "Flag to parse chain ID as hex"
|
||||
ChainNameFlag = "chain-name"
|
||||
ChainNameFlagDesc = "Chain name(ingress|s3)"
|
||||
AllFlag = "all"
|
||||
)
|
||||
|
||||
const RuleFlagDesc = `Defines an Access Policy Engine (APE) rule in the format:
|
||||
<status>[:status_detail] <action>... <condition>... <resource>...
|
||||
|
||||
Status:
|
||||
- allow Permits specified actions
|
||||
- deny Prohibits specified actions
|
||||
- deny:QuotaLimitReached Denies access due to quota limits
|
||||
|
||||
Actions:
|
||||
Object operations:
|
||||
- Object.Put, Object.Get, etc.
|
||||
- Object.* (all object operations)
|
||||
Container operations:
|
||||
- Container.Put, Container.Get, etc.
|
||||
- Container.* (all container operations)
|
||||
|
||||
Conditions:
|
||||
ResourceCondition:
|
||||
Format: ResourceCondition:"key"=value, "key"!=value
|
||||
Reserved properties (use '\' before '$'):
|
||||
- $Object:version
|
||||
- $Object:objectID
|
||||
- $Object:containerID
|
||||
- $Object:ownerID
|
||||
- $Object:creationEpoch
|
||||
- $Object:payloadLength
|
||||
- $Object:payloadHash
|
||||
- $Object:objectType
|
||||
- $Object:homomorphicHash
|
||||
|
||||
RequestCondition:
|
||||
Format: RequestCondition:"key"=value, "key"!=value
|
||||
Reserved properties (use '\' before '$'):
|
||||
- $Actor:publicKey
|
||||
- $Actor:role
|
||||
|
||||
Example:
|
||||
ResourceCondition:"check_key"!="check_value" RequestCondition:"$Actor:role"=others
|
||||
|
||||
Resources:
|
||||
For objects:
|
||||
- namespace/cid/oid (specific object)
|
||||
- namespace/cid/* (all objects in container)
|
||||
- namespace/* (all objects in namespace)
|
||||
- * (all objects)
|
||||
- /* (all objects in root namespace)
|
||||
- /cid/* (all objects in root container)
|
||||
- /cid/oid (specific object in root container)
|
||||
|
||||
For containers:
|
||||
- namespace/cid (specific container)
|
||||
- namespace/* (all containers in namespace)
|
||||
- * (all containers)
|
||||
- /cid (root container)
|
||||
- /* (all root containers)
|
||||
|
||||
Notes:
|
||||
- Cannot mix object and container operations in one rule
|
||||
- Default behavior is Any=false unless 'any' is specified
|
||||
- Use 'all' keyword to explicitly set Any=false`
|
|
@ -26,13 +26,15 @@ func ExitOnErr(cmd *cobra.Command, errFmt string, err error) {
|
|||
_ = iota
|
||||
internal
|
||||
aclDenied
|
||||
apemanagerDenied
|
||||
)
|
||||
|
||||
var (
|
||||
code int
|
||||
|
||||
internalErr = new(sdkstatus.ServerInternal)
|
||||
accessErr = new(sdkstatus.ObjectAccessDenied)
|
||||
internalErr = new(sdkstatus.ServerInternal)
|
||||
accessErr = new(sdkstatus.ObjectAccessDenied)
|
||||
apemanagerErr = new(sdkstatus.APEManagerAccessDenied)
|
||||
)
|
||||
|
||||
switch {
|
||||
|
@ -41,6 +43,9 @@ func ExitOnErr(cmd *cobra.Command, errFmt string, err error) {
|
|||
case errors.As(err, &accessErr):
|
||||
code = aclDenied
|
||||
err = fmt.Errorf("%w: %s", err, accessErr.Reason())
|
||||
case errors.As(err, &apemanagerErr):
|
||||
code = apemanagerDenied
|
||||
err = fmt.Errorf("%w: %s", err, apemanagerErr.Reason())
|
||||
default:
|
||||
code = internal
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -4,7 +4,7 @@ go 1.22
|
|||
|
||||
require (
|
||||
code.gitea.io/sdk/gitea v0.17.1
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.20.0
|
||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.0-rc.4
|
||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
|
||||
git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d
|
||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88
|
||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
|
@ -12,7 +12,7 @@ import (
|
|||
type BlobobvnizcaMetrics interface {
|
||||
SetBlobobvnizcaTreeMode(shardID, path string, mode mode.ComponentMode)
|
||||
CloseBlobobvnizcaTree(shardID, path string)
|
||||
BlobobvnizcaTreeMethodDuration(shardID, path string, method string, d time.Duration, success bool, withStorageID NullBool)
|
||||
BlobobvnizcaTreeMethodDuration(shardID, path string, method string, d time.Duration, success bool, withStorageID string)
|
||||
AddBlobobvnizcaTreePut(shardID, path string, size int)
|
||||
AddBlobobvnizcaTreeGet(shardID, path string, size int)
|
||||
|
||||
|
@ -128,13 +128,13 @@ func (b *blobovnicza) CloseBlobobvnizcaTree(shardID, path string) {
|
|||
b.treeRebuildStatus.SetMode(shardID, path, undefinedStatus)
|
||||
}
|
||||
|
||||
func (b *blobovnicza) BlobobvnizcaTreeMethodDuration(shardID, path string, method string, d time.Duration, success bool, withStorageID NullBool) {
|
||||
func (b *blobovnicza) BlobobvnizcaTreeMethodDuration(shardID, path string, method string, d time.Duration, success bool, withStorageID string) {
|
||||
b.treeReqDuration.With(prometheus.Labels{
|
||||
shardIDLabel: shardID,
|
||||
pathLabel: path,
|
||||
successLabel: strconv.FormatBool(success),
|
||||
methodLabel: method,
|
||||
withStorageIDLabel: withStorageID.String(),
|
||||
withStorageIDLabel: withStorageID,
|
||||
}).Observe(d.Seconds())
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ type BlobstoreMetrics interface {
|
|||
SetMode(shardID string, readOnly bool)
|
||||
Close(shardID string)
|
||||
|
||||
MethodDuration(shardID string, method string, d time.Duration, success bool, withStorageID NullBool)
|
||||
MethodDuration(shardID string, method string, d time.Duration, success bool, withStorageID string)
|
||||
AddPut(shardID string, size int)
|
||||
AddGet(shardID string, size int)
|
||||
}
|
||||
|
@ -65,12 +65,12 @@ func (m *blobstoreMetrics) Close(shardID string) {
|
|||
})
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) MethodDuration(shardID string, method string, d time.Duration, success bool, withStorageID NullBool) {
|
||||
func (m *blobstoreMetrics) MethodDuration(shardID string, method string, d time.Duration, success bool, withStorageID string) {
|
||||
m.reqDuration.With(prometheus.Labels{
|
||||
shardIDLabel: shardID,
|
||||
successLabel: strconv.FormatBool(success),
|
||||
methodLabel: method,
|
||||
withStorageIDLabel: withStorageID.String(),
|
||||
withStorageIDLabel: withStorageID,
|
||||
}).Observe(d.Seconds())
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,6 @@ type EngineMetrics interface {
|
|||
SetRefillPercent(shardID, path string, percent uint32)
|
||||
SetRefillStatus(shardID, path, status string)
|
||||
SetEvacuationInProgress(shardID string, value bool)
|
||||
|
||||
WriteCache() WriteCacheMetrics
|
||||
GC() GCMetrics
|
||||
}
|
||||
|
||||
type engineMetrics struct {
|
||||
|
@ -182,11 +179,11 @@ func (m *engineMetrics) SetMode(shardID string, mode mode.Mode) {
|
|||
m.mode.SetMode(shardID, mode.String())
|
||||
}
|
||||
|
||||
func (m *engineMetrics) WriteCache() WriteCacheMetrics {
|
||||
func (m *engineMetrics) WriteCache() any {
|
||||
return m.writeCache
|
||||
}
|
||||
|
||||
func (m *engineMetrics) GC() GCMetrics {
|
||||
func (m *engineMetrics) GC() any {
|
||||
return m.gc
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,14 @@ func (m *NodeMetrics) Engine() EngineMetrics {
|
|||
return m.engine
|
||||
}
|
||||
|
||||
func (m *NodeMetrics) Writecachce() WriteCacheMetrics {
|
||||
return m.engine.writeCache
|
||||
}
|
||||
|
||||
func (m *NodeMetrics) GC() GCMetrics {
|
||||
return m.engine.gc
|
||||
}
|
||||
|
||||
func (m *NodeMetrics) State() StateMetrics {
|
||||
return m.state
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type NullBool struct {
|
||||
Bool bool
|
||||
Valid bool // Valid is true if Bool is not NULL
|
||||
}
|
||||
|
||||
func (v NullBool) String() string {
|
||||
if !v.Valid {
|
||||
return ""
|
||||
}
|
||||
return strconv.FormatBool(v.Bool)
|
||||
}
|
|
@ -13,7 +13,7 @@ type WriteCacheMetrics interface {
|
|||
SetActualCount(shardID, path, storageType string, count uint64)
|
||||
SetEstimateSize(shardID, path, storageType string, size uint64)
|
||||
SetMode(shardID, mode string)
|
||||
IncOperationCounter(shardID, path, storageType, operation string, success NullBool)
|
||||
IncOperationCounter(shardID, path, storageType, operation string, success string)
|
||||
Close(shardID, path string)
|
||||
}
|
||||
|
||||
|
@ -80,12 +80,12 @@ func (m *writeCacheMetrics) SetMode(shardID string, mode string) {
|
|||
m.mode.SetMode(shardID, mode)
|
||||
}
|
||||
|
||||
func (m *writeCacheMetrics) IncOperationCounter(shardID, path, storageType, operation string, success NullBool) {
|
||||
func (m *writeCacheMetrics) IncOperationCounter(shardID, path, storageType, operation string, success string) {
|
||||
m.operationCounter.With(prometheus.Labels{
|
||||
shardIDLabel: shardID,
|
||||
storageLabel: storageType,
|
||||
operationLabel: operation,
|
||||
successLabel: success.String(),
|
||||
successLabel: success,
|
||||
pathLabel: path,
|
||||
}).Inc()
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/alphabet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
|
@ -247,7 +248,7 @@ type testMorphClient struct {
|
|||
batchTransferedGas []batchTransferGas
|
||||
}
|
||||
|
||||
func (c *testMorphClient) Invoke(_ context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (uint32, error) {
|
||||
func (c *testMorphClient) Invoke(_ context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (client.InvokeRes, error) {
|
||||
c.invokedMethods = append(c.invokedMethods,
|
||||
invokedMethod{
|
||||
contract: contract,
|
||||
|
@ -255,7 +256,7 @@ func (c *testMorphClient) Invoke(_ context.Context, contract util.Uint160, fee f
|
|||
method: method,
|
||||
args: args,
|
||||
})
|
||||
return 0, nil
|
||||
return client.InvokeRes{}, nil
|
||||
}
|
||||
|
||||
func (c *testMorphClient) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
|
@ -39,7 +40,7 @@ type (
|
|||
}
|
||||
|
||||
morphClient interface {
|
||||
Invoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (uint32, error)
|
||||
Invoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (client.InvokeRes, error)
|
||||
TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error
|
||||
BatchTransferGas(receivers []util.Uint160, amount fixedn.Fixed8) error
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func (r ListContainersRes) Containers() []cid.ID {
|
|||
//
|
||||
// Returns an error if executions are blocked (see BlockExecution).
|
||||
func (e *StorageEngine) ContainerSize(ctx context.Context, prm ContainerSizePrm) (res ContainerSizeRes, err error) {
|
||||
defer elapsed("ContainerSize", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("ContainerSize", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.containerSize(ctx, prm)
|
||||
|
@ -93,7 +93,7 @@ func (e *StorageEngine) containerSize(ctx context.Context, prm ContainerSizePrm)
|
|||
//
|
||||
// Returns an error if executions are blocked (see BlockExecution).
|
||||
func (e *StorageEngine) ListContainers(ctx context.Context, _ ListContainersPrm) (res ListContainersRes, err error) {
|
||||
defer elapsed("ListContainers", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("ListContainers", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.listContainers(ctx)
|
||||
|
|
|
@ -58,7 +58,7 @@ func (e *StorageEngine) Delete(ctx context.Context, prm DeletePrm) (res DeleteRe
|
|||
attribute.Bool("force_removal", prm.forceRemoval),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("Delete", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Delete", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.delete(ctx, prm)
|
||||
|
|
|
@ -145,7 +145,7 @@ func (e *StorageEngine) reportShardError(
|
|||
}
|
||||
|
||||
errCount := sh.errorCount.Add(1)
|
||||
e.metrics.IncErrorCounter(sh.ID().String())
|
||||
e.engineMetrics.IncErrorCounter(sh.ID().String())
|
||||
|
||||
sid := sh.ID()
|
||||
e.log.Warn(ctx, msg, append([]zap.Field{
|
||||
|
@ -187,7 +187,9 @@ type cfg struct {
|
|||
|
||||
errorsThreshold uint32
|
||||
|
||||
metrics MetricRegister
|
||||
engineMetrics EngineMetrics
|
||||
writeCacheMetrics WriteCacheMetrics
|
||||
gcMetrics GCMetrics
|
||||
|
||||
shardPoolSize uint32
|
||||
|
||||
|
@ -200,7 +202,10 @@ func defaultCfg() *cfg {
|
|||
res := &cfg{
|
||||
log: logger.NewLoggerWrapper(zap.L()),
|
||||
shardPoolSize: 20,
|
||||
metrics: noopMetrics{},
|
||||
|
||||
engineMetrics: noopMetrics{},
|
||||
writeCacheMetrics: noopWriteCacheMetrics{},
|
||||
gcMetrics: noopGCMetrics{},
|
||||
}
|
||||
res.containerSource.Store(&containerSource{})
|
||||
return res
|
||||
|
@ -231,9 +236,21 @@ func WithLogger(l *logger.Logger) Option {
|
|||
}
|
||||
}
|
||||
|
||||
func WithMetrics(v MetricRegister) Option {
|
||||
func WithEngineMetrics(v EngineMetrics) Option {
|
||||
return func(c *cfg) {
|
||||
c.metrics = v
|
||||
c.engineMetrics = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithWritecacheMetrics(v WriteCacheMetrics) Option {
|
||||
return func(c *cfg) {
|
||||
c.writeCacheMetrics = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithGCMetrics(v GCMetrics) Option {
|
||||
return func(c *cfg) {
|
||||
c.gcMetrics = v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ func (e *StorageEngine) Get(ctx context.Context, prm GetPrm) (res GetRes, err er
|
|||
attribute.String("address", prm.addr.EncodeToString()),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("Get", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Get", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.get(ctx, prm)
|
||||
|
|
|
@ -68,7 +68,7 @@ func (e *StorageEngine) Head(ctx context.Context, prm HeadPrm) (res HeadRes, err
|
|||
func (e *StorageEngine) head(ctx context.Context, prm HeadPrm) (HeadRes, error) {
|
||||
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.head")
|
||||
defer span.End()
|
||||
defer elapsed("Head", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Head", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
var (
|
||||
head *objectSDK.Object
|
||||
|
|
|
@ -70,7 +70,7 @@ var errInhumeFailure = errors.New("inhume operation failed")
|
|||
func (e *StorageEngine) Inhume(ctx context.Context, prm InhumePrm) (res InhumeRes, err error) {
|
||||
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.Inhume")
|
||||
defer span.End()
|
||||
defer elapsed("Inhume", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Inhume", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.inhume(ctx, prm)
|
||||
|
@ -360,7 +360,7 @@ func (e *StorageEngine) processZeroSizeContainers(ctx context.Context, ids []cid
|
|||
}
|
||||
|
||||
for id := range idMap {
|
||||
e.metrics.DeleteContainerSize(id.EncodeToString())
|
||||
e.engineMetrics.DeleteContainerSize(id.EncodeToString())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,7 +438,7 @@ func (e *StorageEngine) processZeroCountContainers(ctx context.Context, ids []ci
|
|||
}
|
||||
|
||||
for id := range idMap {
|
||||
e.metrics.DeleteContainerCount(id.EncodeToString())
|
||||
e.engineMetrics.DeleteContainerCount(id.EncodeToString())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ func (l ListWithCursorRes) Cursor() *Cursor {
|
|||
func (e *StorageEngine) ListWithCursor(ctx context.Context, prm ListWithCursorPrm) (ListWithCursorRes, error) {
|
||||
ctx, span := tracing.StartSpanFromContext(ctx, "StorageEngine.ListWithCursor")
|
||||
defer span.End()
|
||||
defer elapsed("ListWithCursor", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("ListWithCursor", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
result := make([]objectcore.Info, 0, prm.count)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func (e *StorageEngine) Lock(ctx context.Context, idCnr cid.ID, locker oid.ID, l
|
|||
attribute.Int("locked_count", len(locked)),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("Lock", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Lock", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
return e.execIfNotBlocked(func() error {
|
||||
return e.lock(ctx, idCnr, locker, locked)
|
||||
|
|
|
@ -7,7 +7,23 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode"
|
||||
)
|
||||
|
||||
type MetricRegister interface {
|
||||
type WriteCacheMetrics interface {
|
||||
AddMethodDuration(shardID, path, storageType, method string, success bool, d time.Duration)
|
||||
SetActualCount(shardID, path, storageType string, count uint64)
|
||||
SetEstimateSize(shardID, path, storageType string, size uint64)
|
||||
SetMode(shardID, mode string)
|
||||
IncOperationCounter(shardID, path, storageType, operation string, success string)
|
||||
Close(shardID, path string)
|
||||
}
|
||||
|
||||
type GCMetrics interface {
|
||||
AddRunDuration(shardID string, d time.Duration, success bool)
|
||||
AddDeletedCount(shardID string, deleted, failed uint64)
|
||||
AddExpiredObjectCollectionDuration(shardID string, d time.Duration, success bool, objectType string)
|
||||
AddInhumedObjectCount(shardID string, count uint64, objectType string)
|
||||
}
|
||||
|
||||
type EngineMetrics interface {
|
||||
AddMethodDuration(method string, d time.Duration)
|
||||
|
||||
SetObjectCounter(shardID, objectType string, v uint64)
|
||||
|
@ -31,9 +47,6 @@ type MetricRegister interface {
|
|||
SetRefillPercent(shardID, path string, percent uint32)
|
||||
SetRefillStatus(shardID, path, status string)
|
||||
SetEvacuationInProgress(shardID string, value bool)
|
||||
|
||||
WriteCache() metrics.WriteCacheMetrics
|
||||
GC() metrics.GCMetrics
|
||||
}
|
||||
|
||||
func elapsed(method string, addFunc func(method string, d time.Duration)) func() {
|
||||
|
@ -76,9 +89,9 @@ type (
|
|||
)
|
||||
|
||||
var (
|
||||
_ MetricRegister = noopMetrics{}
|
||||
_ metrics.WriteCacheMetrics = noopWriteCacheMetrics{}
|
||||
_ metrics.GCMetrics = noopGCMetrics{}
|
||||
_ EngineMetrics = noopMetrics{}
|
||||
_ WriteCacheMetrics = noopWriteCacheMetrics{}
|
||||
_ GCMetrics = noopGCMetrics{}
|
||||
)
|
||||
|
||||
func (noopMetrics) AddMethodDuration(string, time.Duration) {}
|
||||
|
@ -99,14 +112,12 @@ func (noopMetrics) IncRefillObjectsCount(string, string, int, bool) {}
|
|||
func (noopMetrics) SetRefillPercent(string, string, uint32) {}
|
||||
func (noopMetrics) SetRefillStatus(string, string, string) {}
|
||||
func (noopMetrics) SetEvacuationInProgress(string, bool) {}
|
||||
func (noopMetrics) WriteCache() metrics.WriteCacheMetrics { return noopWriteCacheMetrics{} }
|
||||
func (noopMetrics) GC() metrics.GCMetrics { return noopGCMetrics{} }
|
||||
|
||||
func (noopWriteCacheMetrics) AddMethodDuration(string, string, string, string, bool, time.Duration) {}
|
||||
func (noopWriteCacheMetrics) SetActualCount(string, string, string, uint64) {}
|
||||
func (noopWriteCacheMetrics) SetEstimateSize(string, string, string, uint64) {}
|
||||
func (noopWriteCacheMetrics) SetMode(string, string) {}
|
||||
func (noopWriteCacheMetrics) IncOperationCounter(string, string, string, string, metrics.NullBool) {}
|
||||
func (noopWriteCacheMetrics) IncOperationCounter(string, string, string, string, string) {}
|
||||
func (noopWriteCacheMetrics) Close(string, string) {}
|
||||
|
||||
func (noopGCMetrics) AddRunDuration(string, time.Duration, bool) {}
|
||||
|
|
|
@ -56,7 +56,7 @@ func (e *StorageEngine) Put(ctx context.Context, prm PutPrm) (err error) {
|
|||
attribute.String("address", object.AddressOf(prm.Object).EncodeToString()),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("Put", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Put", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
err = e.put(ctx, prm)
|
||||
|
|
|
@ -72,7 +72,7 @@ func (e *StorageEngine) GetRange(ctx context.Context, prm RngPrm) (res RngRes, e
|
|||
attribute.String("length", strconv.FormatUint(prm.ln, 10)),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("GetRange", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("GetRange", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.getRange(ctx, prm)
|
||||
|
|
|
@ -51,7 +51,7 @@ func (e *StorageEngine) Select(ctx context.Context, prm SelectPrm) (res SelectRe
|
|||
attribute.String("container_id", prm.cnr.EncodeToString()),
|
||||
))
|
||||
defer span.End()
|
||||
defer elapsed("Select", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("Select", e.engineMetrics.AddMethodDuration)()
|
||||
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e._select(ctx, prm)
|
||||
|
@ -98,7 +98,7 @@ func (e *StorageEngine) _select(ctx context.Context, prm SelectPrm) (SelectRes,
|
|||
//
|
||||
// Returns an error if executions are blocked (see BlockExecution).
|
||||
func (e *StorageEngine) List(ctx context.Context, limit uint64) (res SelectRes, err error) {
|
||||
defer elapsed("List", e.metrics.AddMethodDuration)()
|
||||
defer elapsed("List", e.engineMetrics.AddMethodDuration)()
|
||||
err = e.execIfNotBlocked(func() error {
|
||||
res, err = e.list(ctx, limit)
|
||||
return err
|
||||
|
|
|
@ -28,7 +28,7 @@ type hashedShard struct {
|
|||
|
||||
type metricsWithID struct {
|
||||
id string
|
||||
mw MetricRegister
|
||||
mw EngineMetrics
|
||||
}
|
||||
|
||||
func (m *metricsWithID) SetShardID(id string) {
|
||||
|
@ -116,7 +116,7 @@ func (e *StorageEngine) AddShard(ctx context.Context, opts ...shard.Option) (*sh
|
|||
return nil, fmt.Errorf("could not add %s shard: %w", sh.ID().String(), err)
|
||||
}
|
||||
|
||||
e.cfg.metrics.SetMode(sh.ID().String(), sh.GetMode())
|
||||
e.cfg.engineMetrics.SetMode(sh.ID().String(), sh.GetMode())
|
||||
|
||||
return sh.ID(), nil
|
||||
}
|
||||
|
@ -154,18 +154,18 @@ func (e *StorageEngine) appendMetrics(id *shard.ID, opts []shard.Option) []shard
|
|||
shard.WithMetricsWriter(
|
||||
&metricsWithID{
|
||||
id: id.String(),
|
||||
mw: e.metrics,
|
||||
mw: e.engineMetrics,
|
||||
},
|
||||
),
|
||||
shard.WithWriteCacheMetrics(
|
||||
&writeCacheMetrics{
|
||||
shardID: id.String(),
|
||||
metrics: e.metrics.WriteCache(),
|
||||
metrics: e.writeCacheMetrics,
|
||||
},
|
||||
),
|
||||
shard.WithGCMetrics(
|
||||
&gcMetrics{
|
||||
storage: e.metrics.GC(),
|
||||
storage: e.gcMetrics,
|
||||
shardID: id.String(),
|
||||
},
|
||||
),
|
||||
|
@ -217,7 +217,7 @@ func (e *StorageEngine) removeShards(ctx context.Context, ids ...string) {
|
|||
continue
|
||||
}
|
||||
|
||||
e.metrics.DeleteShardMetrics(id)
|
||||
e.engineMetrics.DeleteShardMetrics(id)
|
||||
|
||||
ss = append(ss, sh)
|
||||
delete(e.shards, id)
|
||||
|
@ -318,7 +318,7 @@ func (e *StorageEngine) SetShardMode(ctx context.Context, id *shard.ID, m mode.M
|
|||
if id.String() == shID {
|
||||
if resetErrorCounter {
|
||||
sh.errorCount.Store(0)
|
||||
e.metrics.ClearErrorCounter(shID)
|
||||
e.engineMetrics.ClearErrorCounter(shID)
|
||||
}
|
||||
return sh.SetMode(ctx, m)
|
||||
}
|
||||
|
@ -422,7 +422,7 @@ func (e *StorageEngine) deleteShards(ctx context.Context, ids []*shard.ID) ([]ha
|
|||
for _, sh := range ss {
|
||||
idStr := sh.ID().String()
|
||||
|
||||
e.metrics.DeleteShardMetrics(idStr)
|
||||
e.engineMetrics.DeleteShardMetrics(idStr)
|
||||
|
||||
delete(e.shards, idStr)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package engine
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -182,11 +183,11 @@ func (m *writeCacheMetrics) SetActualCounters(count uint64) {
|
|||
}
|
||||
|
||||
func (m *writeCacheMetrics) Flush(success bool, st writecache.StorageType) {
|
||||
m.metrics.IncOperationCounter(m.shardID, m.path, st.String(), "Flush", metrics.NullBool{Bool: success, Valid: true})
|
||||
m.metrics.IncOperationCounter(m.shardID, m.path, st.String(), "Flush", strconv.FormatBool(success))
|
||||
}
|
||||
|
||||
func (m *writeCacheMetrics) Evict(st writecache.StorageType) {
|
||||
m.metrics.IncOperationCounter(m.shardID, m.path, st.String(), "Evict", metrics.NullBool{})
|
||||
m.metrics.IncOperationCounter(m.shardID, m.path, st.String(), "Evict", "")
|
||||
}
|
||||
|
||||
func (m *writeCacheMetrics) Close() {
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -111,70 +110,6 @@ func (db *DB) iterateExpired(tx *bbolt.Tx, epoch uint64, h ExpiredObjectHandler)
|
|||
return nil
|
||||
}
|
||||
|
||||
// IterateCoveredByTombstones iterates over all objects in DB which are covered
|
||||
// by tombstone with string address from tss. Locked objects are not included
|
||||
// (do not confuse with objects of type LOCK).
|
||||
//
|
||||
// If h returns ErrInterruptIterator, nil returns immediately.
|
||||
// Returns other errors of h directly.
|
||||
//
|
||||
// Does not modify tss.
|
||||
func (db *DB) IterateCoveredByTombstones(ctx context.Context, tss map[string]oid.Address, h func(oid.Address) error) error {
|
||||
var (
|
||||
startedAt = time.Now()
|
||||
success = false
|
||||
)
|
||||
defer func() {
|
||||
db.metrics.AddMethodDuration("IterateCoveredByTombstones", time.Since(startedAt), success)
|
||||
}()
|
||||
_, span := tracing.StartSpanFromContext(ctx, "metabase.IterateCoveredByTombstones")
|
||||
defer span.End()
|
||||
|
||||
db.modeMtx.RLock()
|
||||
defer db.modeMtx.RUnlock()
|
||||
|
||||
if db.mode.NoMetabase() {
|
||||
return ErrDegradedMode
|
||||
}
|
||||
|
||||
return db.boltDB.View(func(tx *bbolt.Tx) error {
|
||||
return db.iterateCoveredByTombstones(tx, tss, h)
|
||||
})
|
||||
}
|
||||
|
||||
func (db *DB) iterateCoveredByTombstones(tx *bbolt.Tx, tss map[string]oid.Address, h func(oid.Address) error) error {
|
||||
bktGraveyard := tx.Bucket(graveyardBucketName)
|
||||
|
||||
err := bktGraveyard.ForEach(func(k, v []byte) error {
|
||||
var addr oid.Address
|
||||
if err := decodeAddressFromKey(&addr, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := tss[addr.EncodeToString()]; ok {
|
||||
var addr oid.Address
|
||||
|
||||
err := decodeAddressFromKey(&addr, k)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse address of the object under tombstone: %w", err)
|
||||
}
|
||||
|
||||
if objectLocked(tx, addr.Container(), addr.Object()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return h(addr)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if errors.Is(err, ErrInterruptIterator) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func iteratePhyObjects(tx *bbolt.Tx, f func(cid.ID, oid.ID, *objectSDK.Object) error) error {
|
||||
var cid cid.ID
|
||||
var oid oid.ID
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
||||
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
||||
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||
|
@ -67,65 +66,3 @@ func putWithExpiration(t *testing.T, db *meta.DB, typ objectSDK.Type, expiresAt
|
|||
|
||||
return object2.AddressOf(obj)
|
||||
}
|
||||
|
||||
func TestDB_IterateCoveredByTombstones(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer func() { require.NoError(t, db.Close(context.Background())) }()
|
||||
|
||||
cnr := cidtest.ID()
|
||||
ts := oidtest.Address()
|
||||
protected1 := oidtest.Address()
|
||||
protected2 := oidtest.Address()
|
||||
protectedLocked := oidtest.Address()
|
||||
garbage := oidtest.Address()
|
||||
ts.SetContainer(cnr)
|
||||
protected1.SetContainer(cnr)
|
||||
protected2.SetContainer(cnr)
|
||||
protectedLocked.SetContainer(cnr)
|
||||
|
||||
var prm meta.InhumePrm
|
||||
var err error
|
||||
|
||||
prm.SetAddresses(protected1, protected2, protectedLocked)
|
||||
prm.SetTombstoneAddress(ts)
|
||||
|
||||
_, err = db.Inhume(context.Background(), prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
prm.SetAddresses(garbage)
|
||||
prm.SetGCMark()
|
||||
|
||||
_, err = db.Inhume(context.Background(), prm)
|
||||
require.NoError(t, err)
|
||||
|
||||
var handled []oid.Address
|
||||
|
||||
tss := map[string]oid.Address{
|
||||
ts.EncodeToString(): ts,
|
||||
}
|
||||
|
||||
err = db.IterateCoveredByTombstones(context.Background(), tss, func(addr oid.Address) error {
|
||||
handled = append(handled, addr)
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, handled, 3)
|
||||
require.Contains(t, handled, protected1)
|
||||
require.Contains(t, handled, protected2)
|
||||
require.Contains(t, handled, protectedLocked)
|
||||
|
||||
err = db.Lock(context.Background(), protectedLocked.Container(), oidtest.ID(), []oid.ID{protectedLocked.Object()})
|
||||
require.NoError(t, err)
|
||||
|
||||
handled = handled[:0]
|
||||
|
||||
err = db.IterateCoveredByTombstones(context.Background(), tss, func(addr oid.Address) error {
|
||||
handled = append(handled, addr)
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, handled, 2)
|
||||
require.NotContains(t, handled, protectedLocked)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
metrics_impl "git.frostfs.info/TrueCloudLab/frostfs-node/internal/metrics"
|
||||
|
@ -56,40 +57,40 @@ func (m *blobovniczaTreeMetrics) ObjectMoved(d time.Duration) {
|
|||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) Delete(d time.Duration, success, withStorageID bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Delete", d, success, metrics_impl.NullBool{Valid: true, Bool: withStorageID})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Delete", d, success, strconv.FormatBool(withStorageID))
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) Exists(d time.Duration, success, withStorageID bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Exists", d, success, metrics_impl.NullBool{Valid: true, Bool: withStorageID})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Exists", d, success, strconv.FormatBool(withStorageID))
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) GetRange(d time.Duration, size int, success, withStorageID bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "GetRange", d, success, metrics_impl.NullBool{Valid: true, Bool: withStorageID})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "GetRange", d, success, strconv.FormatBool(withStorageID))
|
||||
if success {
|
||||
m.m.AddBlobobvnizcaTreeGet(m.shardID, m.path, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) Get(d time.Duration, size int, success, withStorageID bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Get", d, success, metrics_impl.NullBool{Valid: true, Bool: withStorageID})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Get", d, success, strconv.FormatBool(withStorageID))
|
||||
if success {
|
||||
m.m.AddBlobobvnizcaTreeGet(m.shardID, m.path, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) Iterate(d time.Duration, success bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Iterate", d, success, metrics_impl.NullBool{})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Iterate", d, success, "")
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) Put(d time.Duration, size int, success bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Put", d, success, metrics_impl.NullBool{})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "Put", d, success, "")
|
||||
if success {
|
||||
m.m.AddBlobobvnizcaTreePut(m.shardID, m.path, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobovniczaTreeMetrics) ObjectsCount(d time.Duration, success bool) {
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "ObjectsCount", d, success, metrics_impl.NullBool{})
|
||||
m.m.BlobobvnizcaTreeMethodDuration(m.shardID, m.path, "ObjectsCount", d, success, "")
|
||||
}
|
||||
|
||||
type blobovniczaMetrics struct {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
metrics_impl "git.frostfs.info/TrueCloudLab/frostfs-node/internal/metrics"
|
||||
|
@ -32,38 +33,38 @@ func (m *blobstoreMetrics) Close() {
|
|||
}
|
||||
|
||||
func (m *blobstoreMetrics) Delete(d time.Duration, success, withStorageID bool) {
|
||||
m.m.MethodDuration(m.shardID, "Delete", d, success, metrics_impl.NullBool{Bool: withStorageID, Valid: true})
|
||||
m.m.MethodDuration(m.shardID, "Delete", d, success, strconv.FormatBool(withStorageID))
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) Exists(d time.Duration, success, withStorageID bool) {
|
||||
m.m.MethodDuration(m.shardID, "Exists", d, success, metrics_impl.NullBool{Bool: withStorageID, Valid: true})
|
||||
m.m.MethodDuration(m.shardID, "Exists", d, success, strconv.FormatBool(withStorageID))
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) GetRange(d time.Duration, size int, success, withStorageID bool) {
|
||||
m.m.MethodDuration(m.shardID, "GetRange", d, success, metrics_impl.NullBool{Bool: withStorageID, Valid: true})
|
||||
m.m.MethodDuration(m.shardID, "GetRange", d, success, strconv.FormatBool(withStorageID))
|
||||
if success {
|
||||
m.m.AddGet(m.shardID, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) Get(d time.Duration, size int, success, withStorageID bool) {
|
||||
m.m.MethodDuration(m.shardID, "Get", d, success, metrics_impl.NullBool{Bool: withStorageID, Valid: true})
|
||||
m.m.MethodDuration(m.shardID, "Get", d, success, strconv.FormatBool(withStorageID))
|
||||
if success {
|
||||
m.m.AddGet(m.shardID, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) Iterate(d time.Duration, success bool) {
|
||||
m.m.MethodDuration(m.shardID, "Iterate", d, success, metrics_impl.NullBool{})
|
||||
m.m.MethodDuration(m.shardID, "Iterate", d, success, "")
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) Put(d time.Duration, size int, success bool) {
|
||||
m.m.MethodDuration(m.shardID, "Put", d, success, metrics_impl.NullBool{})
|
||||
m.m.MethodDuration(m.shardID, "Put", d, success, "")
|
||||
if success {
|
||||
m.m.AddPut(m.shardID, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *blobstoreMetrics) ObjectsCount(d time.Duration, success bool) {
|
||||
m.m.MethodDuration(m.shardID, "ObjectsCount", d, success, metrics_impl.NullBool{})
|
||||
m.m.MethodDuration(m.shardID, "ObjectsCount", d, success, "")
|
||||
}
|
||||
|
|
|
@ -1240,7 +1240,7 @@ func (t *boltForest) fillSortedChildren(b *bbolt.Bucket, nodeIDs MultiNode, h *f
|
|||
nodes = nil
|
||||
length = actualLength + 1
|
||||
count = 0
|
||||
c.Seek(append(prefix, byte(length), byte(length>>8)))
|
||||
c.Seek(binary.LittleEndian.AppendUint16(prefix, length))
|
||||
c.Prev() // c.Next() will be performed by for loop
|
||||
}
|
||||
}
|
||||
|
@ -1664,7 +1664,7 @@ func internalKeyPrefix(key []byte, k string) []byte {
|
|||
key = append(key, 'i')
|
||||
|
||||
l := len(k)
|
||||
key = append(key, byte(l), byte(l>>8))
|
||||
key = binary.LittleEndian.AppendUint16(key, uint16(l))
|
||||
key = append(key, k...)
|
||||
return key
|
||||
}
|
||||
|
@ -1679,14 +1679,10 @@ func internalKey(key []byte, k, v string, parent, node Node) []byte {
|
|||
key = internalKeyPrefix(key, k)
|
||||
|
||||
l := len(v)
|
||||
key = append(key, byte(l), byte(l>>8))
|
||||
key = binary.LittleEndian.AppendUint16(key, uint16(l))
|
||||
key = append(key, v...)
|
||||
|
||||
var raw [8]byte
|
||||
binary.LittleEndian.PutUint64(raw[:], parent)
|
||||
key = append(key, raw[:]...)
|
||||
|
||||
binary.LittleEndian.PutUint64(raw[:], node)
|
||||
key = append(key, raw[:]...)
|
||||
key = binary.LittleEndian.AppendUint64(key, parent)
|
||||
key = binary.LittleEndian.AppendUint64(key, node)
|
||||
return key
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ func wrapFrostFSError(err error) error {
|
|||
// Invoke invokes contract method by sending transaction into blockchain.
|
||||
// Returns valid until block value.
|
||||
// Supported args types: int64, string, util.Uint160, []byte and bool.
|
||||
func (c *Client) Invoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (uint32, error) {
|
||||
func (c *Client) Invoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (InvokeRes, error) {
|
||||
start := time.Now()
|
||||
success := false
|
||||
defer func() {
|
||||
|
@ -191,12 +191,12 @@ func (c *Client) Invoke(ctx context.Context, contract util.Uint160, fee fixedn.F
|
|||
defer c.switchLock.RUnlock()
|
||||
|
||||
if c.inactive {
|
||||
return 0, ErrConnectionLost
|
||||
return InvokeRes{}, ErrConnectionLost
|
||||
}
|
||||
|
||||
txHash, vub, err := c.rpcActor.SendTunedCall(contract, method, nil, addFeeCheckerModifier(int64(fee)), args...)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not invoke %s: %w", method, err)
|
||||
return InvokeRes{}, fmt.Errorf("could not invoke %s: %w", method, err)
|
||||
}
|
||||
|
||||
c.logger.Debug(ctx, logs.ClientNeoClientInvoke,
|
||||
|
@ -205,7 +205,7 @@ func (c *Client) Invoke(ctx context.Context, contract util.Uint160, fee fixedn.F
|
|||
zap.Stringer("tx_hash", txHash.Reverse()))
|
||||
|
||||
success = true
|
||||
return vub, nil
|
||||
return InvokeRes{Hash: txHash, VUB: vub}, nil
|
||||
}
|
||||
|
||||
// TestInvokeIterator invokes contract method returning an iterator and executes cb on each element.
|
||||
|
|
|
@ -58,9 +58,9 @@ func (c *Client) ForceRemovePeer(ctx context.Context, nodeInfo netmap.NodeInfo,
|
|||
prm.SetControlTX(true)
|
||||
prm.SetVUB(vub)
|
||||
|
||||
vub, err := c.UpdatePeerState(ctx, prm)
|
||||
res, err := c.UpdatePeerState(ctx, prm)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("updating peer state: %v", err)
|
||||
}
|
||||
return vub, nil
|
||||
return res.VUB, nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package netmap
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
|
@ -37,7 +36,7 @@ func (u *UpdatePeerPrm) SetMaintenance() {
|
|||
}
|
||||
|
||||
// UpdatePeerState changes peer status through Netmap contract call.
|
||||
func (c *Client) UpdatePeerState(ctx context.Context, p UpdatePeerPrm) (uint32, error) {
|
||||
func (c *Client) UpdatePeerState(ctx context.Context, p UpdatePeerPrm) (client.InvokeRes, error) {
|
||||
method := updateStateMethod
|
||||
|
||||
if c.client.WithNotary() && c.client.IsAlpha() {
|
||||
|
@ -56,9 +55,5 @@ func (c *Client) UpdatePeerState(ctx context.Context, p UpdatePeerPrm) (uint32,
|
|||
prm.SetArgs(int64(p.state), p.key)
|
||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||
|
||||
res, err := c.client.Invoke(ctx, prm)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not invoke smart contract: %w", err)
|
||||
}
|
||||
return res.VUB, nil
|
||||
return c.client.Invoke(ctx, prm)
|
||||
}
|
||||
|
|
|
@ -358,12 +358,12 @@ func (c *Client) UpdateNeoFSAlphabetList(ctx context.Context, prm UpdateAlphabet
|
|||
// Returns valid until block value.
|
||||
//
|
||||
// `nonce` and `vub` are used only if notary is enabled.
|
||||
func (c *Client) NotaryInvoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...any) (uint32, error) {
|
||||
func (c *Client) NotaryInvoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...any) (InvokeRes, error) {
|
||||
c.switchLock.RLock()
|
||||
defer c.switchLock.RUnlock()
|
||||
|
||||
if c.inactive {
|
||||
return 0, ErrConnectionLost
|
||||
return InvokeRes{}, ErrConnectionLost
|
||||
}
|
||||
|
||||
if c.notary == nil {
|
||||
|
@ -378,12 +378,12 @@ func (c *Client) NotaryInvoke(ctx context.Context, contract util.Uint160, fee fi
|
|||
// not expected to be signed by the current node.
|
||||
//
|
||||
// Considered to be used by non-IR nodes.
|
||||
func (c *Client) NotaryInvokeNotAlpha(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, vubP *uint32, method string, args ...any) (uint32, error) {
|
||||
func (c *Client) NotaryInvokeNotAlpha(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, vubP *uint32, method string, args ...any) (InvokeRes, error) {
|
||||
c.switchLock.RLock()
|
||||
defer c.switchLock.RUnlock()
|
||||
|
||||
if c.inactive {
|
||||
return 0, ErrConnectionLost
|
||||
return InvokeRes{}, ErrConnectionLost
|
||||
}
|
||||
|
||||
if c.notary == nil {
|
||||
|
@ -446,7 +446,7 @@ func (c *Client) notaryInvokeAsCommittee(ctx context.Context, method string, non
|
|||
return err
|
||||
}
|
||||
|
||||
func (c *Client) notaryInvoke(ctx context.Context, committee, invokedByAlpha bool, contract util.Uint160, nonce uint32, vub *uint32, method string, args ...any) (uint32, error) {
|
||||
func (c *Client) notaryInvoke(ctx context.Context, committee, invokedByAlpha bool, contract util.Uint160, nonce uint32, vub *uint32, method string, args ...any) (InvokeRes, error) {
|
||||
start := time.Now()
|
||||
success := false
|
||||
defer func() {
|
||||
|
@ -455,22 +455,22 @@ func (c *Client) notaryInvoke(ctx context.Context, committee, invokedByAlpha boo
|
|||
|
||||
alphabetList, err := c.notary.alphabetSource()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return InvokeRes{}, err
|
||||
}
|
||||
|
||||
until, err := c.getUntilValue(vub)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return InvokeRes{}, err
|
||||
}
|
||||
|
||||
cosigners, err := c.notaryCosigners(invokedByAlpha, alphabetList, committee)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return InvokeRes{}, err
|
||||
}
|
||||
|
||||
nAct, err := notary.NewActor(c.client, cosigners, c.acc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return InvokeRes{}, err
|
||||
}
|
||||
|
||||
mainH, fbH, untilActual, err := nAct.Notarize(nAct.MakeTunedCall(contract, method, nil, func(r *result.Invoke, t *transaction.Transaction) error {
|
||||
|
@ -485,7 +485,7 @@ func (c *Client) notaryInvoke(ctx context.Context, committee, invokedByAlpha boo
|
|||
}, args...))
|
||||
|
||||
if err != nil && !alreadyOnChainError(err) {
|
||||
return 0, err
|
||||
return InvokeRes{}, err
|
||||
}
|
||||
|
||||
c.logger.Debug(ctx, logs.ClientNotaryRequestInvoked,
|
||||
|
@ -495,7 +495,7 @@ func (c *Client) notaryInvoke(ctx context.Context, committee, invokedByAlpha boo
|
|||
zap.String("fallback_hash", fbH.StringLE()))
|
||||
|
||||
success = true
|
||||
return until, nil
|
||||
return InvokeRes{Hash: mainH, VUB: until}, nil
|
||||
}
|
||||
|
||||
func (c *Client) notaryCosignersFromTx(mainTx *transaction.Transaction, alphabetList keys.PublicKeys) ([]actor.SignerAccount, error) {
|
||||
|
|
|
@ -129,7 +129,8 @@ func (i *InvokePrmOptional) SetVUB(v uint32) {
|
|||
}
|
||||
|
||||
type InvokeRes struct {
|
||||
VUB uint32
|
||||
Hash util.Uint256
|
||||
VUB uint32
|
||||
}
|
||||
|
||||
// Invoke calls Invoke method of Client with static internal script hash and fee.
|
||||
|
@ -142,8 +143,6 @@ type InvokeRes struct {
|
|||
// If fee for the operation executed using specified method is customized, then StaticClient uses it.
|
||||
// Otherwise, default fee is used.
|
||||
func (s StaticClient) Invoke(ctx context.Context, prm InvokePrm) (InvokeRes, error) {
|
||||
var res InvokeRes
|
||||
var err error
|
||||
var vubP *uint32
|
||||
if s.tryNotary {
|
||||
if s.alpha {
|
||||
|
@ -170,26 +169,23 @@ func (s StaticClient) Invoke(ctx context.Context, prm InvokePrm) (InvokeRes, err
|
|||
vubP = &prm.vub
|
||||
}
|
||||
|
||||
res.VUB, err = s.client.NotaryInvoke(ctx, s.scScriptHash, s.fee, nonce, vubP, prm.method, prm.args...)
|
||||
return res, err
|
||||
return s.client.NotaryInvoke(ctx, s.scScriptHash, s.fee, nonce, vubP, prm.method, prm.args...)
|
||||
}
|
||||
|
||||
if prm.vub > 0 {
|
||||
vubP = &prm.vub
|
||||
}
|
||||
|
||||
res.VUB, err = s.client.NotaryInvokeNotAlpha(ctx, s.scScriptHash, s.fee, vubP, prm.method, prm.args...)
|
||||
return res, err
|
||||
return s.client.NotaryInvokeNotAlpha(ctx, s.scScriptHash, s.fee, vubP, prm.method, prm.args...)
|
||||
}
|
||||
|
||||
res.VUB, err = s.client.Invoke(
|
||||
return s.client.Invoke(
|
||||
ctx,
|
||||
s.scScriptHash,
|
||||
s.fee,
|
||||
prm.method,
|
||||
prm.args...,
|
||||
)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// TestInvokePrm groups parameters of the TestInvoke operation.
|
||||
|
|
51
pkg/morph/client/waiter.go
Normal file
51
pkg/morph/client/waiter.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
type waiterClient struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
func (w *waiterClient) Context() context.Context {
|
||||
return context.Background()
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) {
|
||||
return w.c.GetApplicationLog(hash, trig)
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetBlockCount() (uint32, error) {
|
||||
return w.c.BlockCount()
|
||||
}
|
||||
|
||||
func (w *waiterClient) GetVersion() (*result.Version, error) {
|
||||
return w.c.GetVersion()
|
||||
}
|
||||
|
||||
// WaitTxHalt waits until transaction with the specified hash persists on the blockchain.
|
||||
// It also checks execution result to finish in HALT state.
|
||||
func (c *Client) WaitTxHalt(ctx context.Context, p InvokeRes) error {
|
||||
w, err := waiter.NewPollingBased(&waiterClient{c: c})
|
||||
if err != nil {
|
||||
return fmt.Errorf("create tx waiter: %w", err)
|
||||
}
|
||||
|
||||
res, err := w.WaitAny(ctx, p.VUB, p.Hash)
|
||||
if err != nil {
|
||||
return fmt.Errorf("wait until tx persists: %w", err)
|
||||
}
|
||||
|
||||
if res.VMState.HasFlag(vmstate.Halt) {
|
||||
return nil
|
||||
}
|
||||
return wrapFrostFSError(¬HaltStateError{state: res.VMState.String(), exception: res.FaultException})
|
||||
}
|
|
@ -15,41 +15,19 @@ type BlockTickHandler func()
|
|||
// It can tick the blocks and perform certain actions
|
||||
// on block time intervals.
|
||||
type BlockTimer struct {
|
||||
rolledBack bool
|
||||
|
||||
mtx sync.Mutex
|
||||
|
||||
dur BlockMeter
|
||||
|
||||
baseDur uint32
|
||||
|
||||
mul, div uint32
|
||||
|
||||
cur, tgt uint32
|
||||
|
||||
last uint32
|
||||
|
||||
h BlockTickHandler
|
||||
|
||||
ps []BlockTimer
|
||||
|
||||
once bool
|
||||
|
||||
deltaCfg
|
||||
}
|
||||
|
||||
// DeltaOption is an option of delta-interval handler.
|
||||
type DeltaOption func(*deltaCfg)
|
||||
|
||||
type deltaCfg struct {
|
||||
pulse bool
|
||||
}
|
||||
|
||||
// WithPulse returns option to call delta-interval handler multiple times.
|
||||
func WithPulse() DeltaOption {
|
||||
return func(c *deltaCfg) {
|
||||
c.pulse = true
|
||||
}
|
||||
}
|
||||
|
||||
// StaticBlockMeter returns BlockMeters that always returns (d, nil).
|
||||
|
@ -65,52 +43,19 @@ func StaticBlockMeter(d uint32) BlockMeter {
|
|||
func NewBlockTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||
return &BlockTimer{
|
||||
dur: dur,
|
||||
mul: 1,
|
||||
div: 1,
|
||||
h: h,
|
||||
deltaCfg: deltaCfg{
|
||||
pulse: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewOneTickTimer creates a new BlockTimer that ticks only once.
|
||||
//
|
||||
// Do not use delta handlers with pulse in this timer.
|
||||
func NewOneTickTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||
return &BlockTimer{
|
||||
dur: dur,
|
||||
mul: 1,
|
||||
div: 1,
|
||||
h: h,
|
||||
once: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OnDelta registers handler which is executed on (mul / div * BlockMeter()) block
|
||||
// after basic interval reset.
|
||||
//
|
||||
// If WithPulse option is provided, handler is executed (mul / div * BlockMeter()) block
|
||||
// during base interval.
|
||||
func (t *BlockTimer) OnDelta(mul, div uint32, h BlockTickHandler, opts ...DeltaOption) {
|
||||
c := deltaCfg{
|
||||
pulse: false,
|
||||
}
|
||||
|
||||
for i := range opts {
|
||||
opts[i](&c)
|
||||
}
|
||||
|
||||
t.ps = append(t.ps, BlockTimer{
|
||||
mul: mul,
|
||||
div: div,
|
||||
h: h,
|
||||
once: t.once,
|
||||
|
||||
deltaCfg: c,
|
||||
})
|
||||
}
|
||||
|
||||
// Reset resets previous ticks of the BlockTimer.
|
||||
//
|
||||
// Returns BlockMeter's error upon occurrence.
|
||||
|
@ -124,29 +69,18 @@ func (t *BlockTimer) Reset() error {
|
|||
|
||||
t.resetWithBaseInterval(d)
|
||||
|
||||
for i := range t.ps {
|
||||
t.ps[i].resetWithBaseInterval(d)
|
||||
}
|
||||
|
||||
t.mtx.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *BlockTimer) resetWithBaseInterval(d uint32) {
|
||||
t.rolledBack = false
|
||||
t.baseDur = d
|
||||
t.reset()
|
||||
}
|
||||
|
||||
func (t *BlockTimer) reset() {
|
||||
mul, div := t.mul, t.div
|
||||
|
||||
if !t.pulse && t.rolledBack && mul < div {
|
||||
mul, div = 1, 1
|
||||
}
|
||||
|
||||
delta := mul * t.baseDur / div
|
||||
delta := t.baseDur
|
||||
if delta == 0 {
|
||||
delta = 1
|
||||
}
|
||||
|
@ -180,12 +114,7 @@ func (t *BlockTimer) tick(h uint32) {
|
|||
|
||||
if !t.once {
|
||||
t.cur = 0
|
||||
t.rolledBack = true
|
||||
t.reset()
|
||||
}
|
||||
}
|
||||
|
||||
for i := range t.ps {
|
||||
t.ps[i].tick(h)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package timer_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/timer"
|
||||
|
@ -17,7 +18,7 @@ func tickN(t *timer.BlockTimer, n uint32) {
|
|||
// "resetting" consists of ticking the current height as well and invoking `Reset`.
|
||||
func TestIRBlockTimer_Reset(t *testing.T) {
|
||||
var baseCounter [2]int
|
||||
blockDur := uint32(3)
|
||||
const blockDur = uint32(3)
|
||||
|
||||
bt1 := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return blockDur, nil },
|
||||
|
@ -48,8 +49,40 @@ func TestIRBlockTimer_Reset(t *testing.T) {
|
|||
require.Equal(t, baseCounter[0], baseCounter[1])
|
||||
}
|
||||
|
||||
func TestBlockTimer_ResetChangeDuration(t *testing.T) {
|
||||
var dur uint32 = 2
|
||||
var err error
|
||||
var counter int
|
||||
|
||||
bt := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return dur, err },
|
||||
func() { counter++ })
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 2)
|
||||
require.Equal(t, 1, counter)
|
||||
|
||||
t.Run("return error", func(t *testing.T) {
|
||||
dur = 5
|
||||
err = errors.New("my awesome error")
|
||||
require.ErrorIs(t, bt.Reset(), err)
|
||||
|
||||
tickN(bt, 2)
|
||||
require.Equal(t, 2, counter)
|
||||
})
|
||||
t.Run("change duration", func(t *testing.T) {
|
||||
dur = 5
|
||||
err = nil
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 5)
|
||||
require.Equal(t, 3, counter)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockTimer(t *testing.T) {
|
||||
blockDur := uint32(10)
|
||||
const blockDur = uint32(10)
|
||||
baseCallCounter := uint32(0)
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
|
@ -63,85 +96,6 @@ func TestBlockTimer(t *testing.T) {
|
|||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
|
||||
// add half-interval handler
|
||||
halfCallCounter := uint32(0)
|
||||
|
||||
bt.OnDelta(1, 2, func() {
|
||||
halfCallCounter++
|
||||
})
|
||||
|
||||
// add double interval handler
|
||||
doubleCallCounter := uint32(0)
|
||||
|
||||
bt.OnDelta(2, 1, func() {
|
||||
doubleCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
baseCallCounter = 0
|
||||
intervalNum = 20
|
||||
|
||||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(halfCallCounter))
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
require.Equal(t, intervalNum/2, uint32(doubleCallCounter))
|
||||
}
|
||||
|
||||
func TestDeltaPulse(t *testing.T) {
|
||||
blockDur := uint32(9)
|
||||
baseCallCounter := uint32(0)
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
deltaCallCounter := uint32(0)
|
||||
|
||||
div := uint32(3)
|
||||
|
||||
bt.OnDelta(1, div, func() {
|
||||
deltaCallCounter++
|
||||
}, timer.WithPulse())
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
intervalNum := uint32(7)
|
||||
|
||||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
require.Equal(t, intervalNum*div, uint32(deltaCallCounter))
|
||||
}
|
||||
|
||||
func TestDeltaReset(t *testing.T) {
|
||||
blockDur := uint32(6)
|
||||
baseCallCounter := 0
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
detlaCallCounter := 0
|
||||
|
||||
bt.OnDelta(1, 3, func() {
|
||||
detlaCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 6)
|
||||
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 3)
|
||||
|
||||
require.Equal(t, 2, detlaCallCounter)
|
||||
}
|
||||
|
||||
func TestNewOneTickTimer(t *testing.T) {
|
||||
|
@ -168,82 +122,51 @@ func TestNewOneTickTimer(t *testing.T) {
|
|||
tickN(bt, 10)
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
})
|
||||
|
||||
t.Run("delta without pulse", func(t *testing.T) {
|
||||
blockDur = uint32(10)
|
||||
baseCallCounter = 0
|
||||
|
||||
bt = timer.NewOneTickTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
detlaCallCounter := 0
|
||||
|
||||
bt.OnDelta(1, 10, func() {
|
||||
detlaCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 10)
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
|
||||
tickN(bt, 10) // 10 more ticks must not affect counters
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockTimer_TickSameHeight(t *testing.T) {
|
||||
var baseCounter, deltaCounter int
|
||||
var baseCounter int
|
||||
|
||||
blockDur := uint32(2)
|
||||
bt := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return blockDur, nil },
|
||||
func() { baseCounter++ })
|
||||
bt.OnDelta(2, 1, func() {
|
||||
deltaCounter++
|
||||
})
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
check := func(t *testing.T, h uint32, base, delta int) {
|
||||
check := func(t *testing.T, h uint32, base int) {
|
||||
for range 2 * int(blockDur) {
|
||||
bt.Tick(h)
|
||||
require.Equal(t, base, baseCounter)
|
||||
require.Equal(t, delta, deltaCounter)
|
||||
}
|
||||
}
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 1, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 1)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 2)
|
||||
|
||||
t.Run("works the same way after `Reset()`", func(t *testing.T) {
|
||||
t.Run("same block duration", func(t *testing.T) {
|
||||
require.NoError(t, bt.Reset())
|
||||
baseCounter = 0
|
||||
deltaCounter = 0
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 1, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 1)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 2)
|
||||
})
|
||||
t.Run("different block duration", func(t *testing.T) {
|
||||
blockDur = 3
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
baseCounter = 0
|
||||
deltaCounter = 0
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 0, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 1, 0)
|
||||
check(t, 5, 1, 0)
|
||||
check(t, 6, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 0)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 1)
|
||||
check(t, 5, 1)
|
||||
check(t, 6, 2)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
|
@ -104,14 +103,7 @@ func (c *checkerCoreImpl) CheckAPE(prm CheckPrm) error {
|
|||
if found && status == apechain.Allow {
|
||||
return nil
|
||||
}
|
||||
err = fmt.Errorf("access to operation %s is denied by access policy engine: %s", prm.Request.Operation(), status.String())
|
||||
return apeErr(err)
|
||||
}
|
||||
|
||||
func apeErr(err error) error {
|
||||
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
||||
errAccessDenied.WriteReason(err.Error())
|
||||
return errAccessDenied
|
||||
return fmt.Errorf("access to operation %s is denied by access policy engine: %s", prm.Request.Operation(), status.String())
|
||||
}
|
||||
|
||||
// isValidBearer checks whether bearer token was correctly signed by authorized
|
||||
|
|
|
@ -114,8 +114,9 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
|||
var unsortedVector []netmap.NodeInfo
|
||||
var regularVector []netmap.NodeInfo
|
||||
for i := range rem {
|
||||
unsortedVector = append(unsortedVector, ns[i][:rem[i]]...)
|
||||
regularVector = append(regularVector, ns[i][rem[i]:]...)
|
||||
pivot := min(len(ns[i]), rem[i])
|
||||
unsortedVector = append(unsortedVector, ns[i][:pivot]...)
|
||||
regularVector = append(regularVector, ns[i][pivot:]...)
|
||||
}
|
||||
rem = []int{-1, -1}
|
||||
|
||||
|
@ -201,7 +202,7 @@ func sortVector(cfg *cfg, unsortedVector []netmap.NodeInfo) ([]netmap.NodeInfo,
|
|||
metrics: m,
|
||||
}
|
||||
}
|
||||
slices.SortFunc(nm, func(a, b nodeMetrics) int {
|
||||
slices.SortStableFunc(nm, func(a, b nodeMetrics) int {
|
||||
return slices.Compare(a.metrics, b.metrics)
|
||||
})
|
||||
sortedVector := make([]netmap.NodeInfo, len(unsortedVector))
|
||||
|
|
|
@ -356,6 +356,52 @@ func TestTraverserPriorityMetrics(t *testing.T) {
|
|||
require.Nil(t, next)
|
||||
})
|
||||
|
||||
t.Run("one rep one metric fewer nodes", func(t *testing.T) {
|
||||
selectors := []int{2}
|
||||
replicas := []int{3}
|
||||
|
||||
nodes, cnr := testPlacement(selectors, replicas)
|
||||
|
||||
// Node_0, PK - ip4/0.0.0.0/tcp/0
|
||||
nodes[0][0].SetAttribute("ClusterName", "A")
|
||||
// Node_1, PK - ip4/0.0.0.0/tcp/1
|
||||
nodes[0][1].SetAttribute("ClusterName", "B")
|
||||
|
||||
sdkNode := testNode(5)
|
||||
sdkNode.SetAttribute("ClusterName", "B")
|
||||
|
||||
nodesCopy := copyVectors(nodes)
|
||||
|
||||
m := []Metric{NewAttributeMetric("ClusterName")}
|
||||
|
||||
tr, err := NewTraverser(
|
||||
ForContainer(cnr),
|
||||
UseBuilder(&testBuilder{
|
||||
vectors: nodesCopy,
|
||||
}),
|
||||
WithoutSuccessTracking(),
|
||||
WithPriorityMetrics(m),
|
||||
WithNodeState(&nodeState{
|
||||
node: &sdkNode,
|
||||
}),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Without priority metric `ClusterName` the order will be:
|
||||
// [ {Node_0 A}, {Node_1 A} ]
|
||||
// With priority metric `ClusterName` and current node in cluster B
|
||||
// the order should be:
|
||||
// [ {Node_1 B}, {Node_0 A} ]
|
||||
next := tr.Next()
|
||||
require.NotNil(t, next)
|
||||
require.Equal(t, 2, len(next))
|
||||
require.Equal(t, "/ip4/0.0.0.0/tcp/1", string(next[0].PublicKey()))
|
||||
require.Equal(t, "/ip4/0.0.0.0/tcp/0", string(next[1].PublicKey()))
|
||||
|
||||
next = tr.Next()
|
||||
require.Nil(t, next)
|
||||
})
|
||||
|
||||
t.Run("two reps two metrics", func(t *testing.T) {
|
||||
selectors := []int{3, 3}
|
||||
replicas := []int{2, 2}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||
|
@ -62,7 +63,16 @@ func (s *Service) verifyClient(ctx context.Context, req message, cid cidSDK.ID,
|
|||
return fmt.Errorf("can't get request role: %w", err)
|
||||
}
|
||||
|
||||
return s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey)
|
||||
if err = s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey); err != nil {
|
||||
return apeErr(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func apeErr(err error) error {
|
||||
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
||||
errAccessDenied.WriteReason(err.Error())
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
// Returns true iff the operation is read-only and request was signed
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
package util
|
||||
package ape
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||
"github.com/flynn-archive/go-shlex"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -27,38 +25,6 @@ var (
|
|||
errFailedToParseAllAny = errors.New("any/all is not parsed")
|
||||
)
|
||||
|
||||
// PrintHumanReadableAPEChain print APE chain rules.
|
||||
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
||||
cmd.Println("Chain ID: " + string(chain.ID))
|
||||
cmd.Printf(" HEX: %x\n", chain.ID)
|
||||
cmd.Println("Rules:")
|
||||
for _, rule := range chain.Rules {
|
||||
cmd.Println("\n\tStatus: " + rule.Status.String())
|
||||
cmd.Println("\tAny: " + strconv.FormatBool(rule.Any))
|
||||
cmd.Println("\tConditions:")
|
||||
for _, c := range rule.Condition {
|
||||
var ot string
|
||||
switch c.Kind {
|
||||
case apechain.KindResource:
|
||||
ot = "Resource"
|
||||
case apechain.KindRequest:
|
||||
ot = "Request"
|
||||
default:
|
||||
panic("unknown object type")
|
||||
}
|
||||
cmd.Println(fmt.Sprintf("\t\t%s %s %s %s", ot, c.Key, c.Op, c.Value))
|
||||
}
|
||||
cmd.Println("\tActions:\tInverted:" + strconv.FormatBool(rule.Actions.Inverted))
|
||||
for _, name := range rule.Actions.Names {
|
||||
cmd.Println("\t\t" + name)
|
||||
}
|
||||
cmd.Println("\tResources:\tInverted:" + strconv.FormatBool(rule.Resources.Inverted))
|
||||
for _, name := range rule.Resources.Names {
|
||||
cmd.Println("\t\t" + name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ParseAPEChainBinaryOrJSON(chain *apechain.Chain, path string) error {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
|
@ -1,4 +1,4 @@
|
|||
package util
|
||||
package ape
|
||||
|
||||
import (
|
||||
"fmt"
|
Loading…
Reference in a new issue