Skip to content

Commit

Permalink
node/placement: use predefined error for empty netmap (#2916)
Browse files Browse the repository at this point in the history
  • Loading branch information
cthulhu-rider committed Aug 21, 2024
2 parents 1a9784c + 6ad2ad6 commit 7baa16c
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 85 deletions.
14 changes: 7 additions & 7 deletions cmd/neofs-cli/internal/common/eacl.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
var errUnsupportedEACLFormat = errors.New("unsupported eACL format")

// ReadEACL reads extended ACL table from eaclPath.
func ReadEACL(cmd *cobra.Command, eaclPath string) *eacl.Table {
func ReadEACL(cmd *cobra.Command, eaclPath string) eacl.Table {
_, err := os.Stat(eaclPath) // check if `eaclPath` is an existing file
if err != nil {
ExitOnErr(cmd, "", errors.New("incorrect path to file with EACL"))
Expand All @@ -24,25 +24,25 @@ func ReadEACL(cmd *cobra.Command, eaclPath string) *eacl.Table {
data, err := os.ReadFile(eaclPath)
ExitOnErr(cmd, "can't read file with EACL: %w", err)

table := eacl.NewTable()

if err = table.UnmarshalJSON(data); err == nil {
table, err := eacl.UnmarshalJSON(data)
if err == nil {
validateAndFixEACLVersion(table)
PrintVerbose(cmd, "Parsed JSON encoded EACL table")
return table
}

if err = table.Unmarshal(data); err == nil {
table, err = eacl.Unmarshal(data)
if err == nil {
validateAndFixEACLVersion(table)
PrintVerbose(cmd, "Parsed binary encoded EACL table")
return table
}

ExitOnErr(cmd, "", errUnsupportedEACLFormat)
return nil
return eacl.Table{}
}

func validateAndFixEACLVersion(table *eacl.Table) {
func validateAndFixEACLVersion(table eacl.Table) {
if !version.IsValid(table.Version()) {
table.SetVersion(versionSDK.Current())
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/neofs-cli/modules/acl/extended/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ func createEACL(cmd *cobra.Command, _ []string) {
os.Exit(1)
}

tb := eacl.NewTable()
common.ExitOnErr(cmd, "unable to parse provided rules: %w", util.ParseEACLRules(tb, rules))
var tb eacl.Table
common.ExitOnErr(cmd, "unable to parse provided rules: %w", util.ParseEACLRules(&tb, rules))

err = util.ValidateEACLTable(tb)
common.ExitOnErr(cmd, "table validation: %w", err)
Expand Down
6 changes: 3 additions & 3 deletions cmd/neofs-cli/modules/bearer/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ func createToken(cmd *cobra.Command, _ []string) {

eaclPath, _ := cmd.Flags().GetString(eaclFlag)
if eaclPath != "" {
table := eaclSDK.NewTable()
raw, err := os.ReadFile(eaclPath)
common.ExitOnErr(cmd, "can't read extended ACL file: %w", err)
common.ExitOnErr(cmd, "can't parse extended ACL: %w", json.Unmarshal(raw, table))
b.SetEACLTable(*table)
table, err := eaclSDK.UnmarshalJSON(raw)
common.ExitOnErr(cmd, "can't parse extended ACL: %w", err)
b.SetEACLTable(table)
}

var data []byte
Expand Down
2 changes: 1 addition & 1 deletion cmd/neofs-cli/modules/container/set_eacl.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Container ID in EACL table will be substituted with ID from the CLI.`,

var setEACLPrm internalclient.SetEACLPrm
setEACLPrm.SetClient(cli)
setEACLPrm.SetTable(*eaclTable)
setEACLPrm.SetTable(eaclTable)
setEACLPrm.SetPrivateKey(*pk)

if tok != nil {
Expand Down
71 changes: 41 additions & 30 deletions cmd/neofs-cli/modules/util/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ func parseEACLTable(tb *eacl.Table, args []string) error {
return errors.New("at least 2 arguments must be provided")
}

var action eacl.Action
if !action.DecodeString(strings.ToUpper(args[0])) {
action, ok := eacl.ActionFromString(strings.ToUpper(args[0]))
if !ok {
return errors.New("invalid action (expected 'allow' or 'deny')")
}

Expand All @@ -226,81 +226,91 @@ func parseEACLTable(tb *eacl.Table, args []string) error {

r.SetAction(action)

records := make([]eacl.Record, 0, len(ops))

for _, op := range ops {
r := *r
r.SetOperation(op)
tb.AddRecord(&r)
var record eacl.Record
r.CopyTo(&record)

record.SetOperation(op)
records = append(records, record)
}

tb.SetRecords(records)

return nil
}

func parseEACLRecord(args []string) (*eacl.Record, error) {
r := new(eacl.Record)
func parseEACLRecord(args []string) (eacl.Record, error) {
var filters []eacl.Filter
var targets []eacl.Target

for i := range args {
ss := strings.SplitN(args[i], ":", 2)

switch prefix := strings.ToLower(ss[0]); prefix {
case "req", "obj": // filters
if len(ss) != 2 {
return nil, fmt.Errorf("invalid filter or target: %s", args[i])
return eacl.Record{}, fmt.Errorf("invalid filter or target: %s", args[i])
}

key, value, op, err := parseKVWithOp(ss[1])
if err != nil {
return nil, fmt.Errorf("invalid filter key-value pair %s: %w", ss[1], err)
return eacl.Record{}, fmt.Errorf("invalid filter key-value pair %s: %w", ss[1], err)
}

typ := eacl.HeaderFromRequest
if ss[0] == "obj" {
typ = eacl.HeaderFromObject
}

r.AddFilter(typ, op, key, value)
filters = append(filters, eacl.ConstructFilter(typ, key, op, value))
case "others", "system", "user", "pubkey": // targets
var err error

var pubs []ecdsa.PublicKey
var pubs []*ecdsa.PublicKey
if len(ss) == 2 {
pubs, err = parseKeyList(ss[1])
if err != nil {
return nil, err
return eacl.Record{}, err
}
}

var role eacl.Role
if prefix != "pubkey" {
role, err = eaclRoleFromString(prefix)
role, err := eaclRoleFromString(prefix)
if err != nil {
return nil, err
return eacl.Record{}, err
}

targets = append(targets, eacl.NewTargetByRole(role))
continue
}

eacl.AddFormedTarget(r, role, pubs...)
var target eacl.Target
eacl.SetTargetECDSAKeys(&target, pubs...)
targets = append(targets, target)
case "address": // targets
var (
err error
accounts []user.ID
)

if len(ss) != 2 {
return nil, fmt.Errorf("invalid address: %s", args[i])
return eacl.Record{}, fmt.Errorf("invalid address: %s", args[i])
}

accounts, err = parseAccountList(ss[1])
if err != nil {
return nil, err
return eacl.Record{}, err
}

t := eacl.NewTarget()
t.SetAccounts(accounts)
eacl.AddRecordTarget(r, t)
targets = append(targets, eacl.NewTargetByAccounts(accounts))
default:
return nil, fmt.Errorf("invalid prefix: %s", ss[0])
return eacl.Record{}, fmt.Errorf("invalid prefix: %s", ss[0])
}
}

return r, nil
return eacl.ConstructRecord(eacl.ActionUnspecified, eacl.OperationUnspecified, targets, filters...), nil
}

func parseKVWithOp(s string) (string, string, eacl.Match, error) {
Expand Down Expand Up @@ -356,26 +366,26 @@ func validateDecimal(s string) bool {

// eaclRoleFromString parses eacl.Role from string.
func eaclRoleFromString(s string) (eacl.Role, error) {
var r eacl.Role
if !r.DecodeString(strings.ToUpper(s)) {
r, ok := eacl.RoleFromString(strings.ToUpper(s))
if !ok {
return r, fmt.Errorf("unexpected role %s", s)
}

return r, nil
}

// parseKeyList parses list of hex-encoded public keys separated by comma.
func parseKeyList(s string) ([]ecdsa.PublicKey, error) {
func parseKeyList(s string) ([]*ecdsa.PublicKey, error) {
ss := strings.Split(s, ",")
pubs := make([]ecdsa.PublicKey, len(ss))
pubs := make([]*ecdsa.PublicKey, len(ss))
for i := range ss {
st := strings.TrimPrefix(ss[i], "0x")
pub, err := keys.NewPublicKeyFromString(st)
if err != nil {
return nil, fmt.Errorf("invalid public key '%s': %w", ss[i], err)
}

pubs[i] = ecdsa.PublicKey(*pub)
pubs[i] = (*ecdsa.PublicKey)(pub)
}

return pubs, nil
Expand All @@ -402,9 +412,10 @@ func parseAccountList(s string) ([]user.ID, error) {
func eaclOperationsFromString(s string) ([]eacl.Operation, error) {
ss := strings.Split(s, ",")
ops := make([]eacl.Operation, len(ss))
var ok bool

for i := range ss {
if !ops[i].DecodeString(strings.ToUpper(ss[i])) {
if ops[i], ok = eacl.OperationFromString(strings.ToUpper(ss[i])); !ok {
return nil, fmt.Errorf("invalid operation: %s", ss[i])
}
}
Expand All @@ -414,7 +425,7 @@ func eaclOperationsFromString(s string) ([]eacl.Operation, error) {

// ValidateEACLTable validates eACL table:
// - eACL table must not modify [eacl.RoleSystem] access.
func ValidateEACLTable(t *eacl.Table) error {
func ValidateEACLTable(t eacl.Table) error {
var b big.Int
for _, record := range t.Records() {
for _, target := range record.Targets() {
Expand Down
6 changes: 3 additions & 3 deletions cmd/neofs-cli/modules/util/acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ func TestValidateEACL(t *testing.T) {
tb := anyValidEACL()
tb.AddRecord(&r)

err := ValidateEACLTable(&tb)
err := ValidateEACLTable(tb)
require.ErrorContains(t, err, "non-empty value in absence filter")

r = eacl.Record{}
r.AddObjectAttributeFilter(eacl.MatchNotPresent, "any_key", "")
tb = anyValidEACL()
tb.AddRecord(&r)

err = ValidateEACLTable(&tb)
err = ValidateEACLTable(tb)
require.NoError(t, err)
})

Expand All @@ -124,7 +124,7 @@ func TestValidateEACL(t *testing.T) {
tb := anyValidEACL()
tb.AddRecord(&r)

err := ValidateEACLTable(&tb)
err := ValidateEACLTable(tb)
if tc.ok {
require.NoError(t, err, [2]any{m, tc})
} else {
Expand Down
4 changes: 1 addition & 3 deletions cmd/neofs-node/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
"errors"
"fmt"
"strings"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/nspcc-dev/neofs-api-go/v2/object"
Expand Down Expand Up @@ -750,8 +749,7 @@ func (n netmapSourceWithNodes) ServerInContainer(cID cid.ID) (bool, error) {
return true
})
if err != nil {
// https://github.com/nspcc-dev/neofs-sdk-go/pull/615
if strings.Contains(err.Error(), "not enough nodes to SELECT from") {
if errors.Is(err, netmapsdk.ErrNotEnoughNodes) {
return false, nil
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/nspcc-dev/neo-go v0.106.3
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4
github.com/nspcc-dev/neofs-contract v0.20.0
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b
github.com/nspcc-dev/tzhash v1.8.0
github.com/olekukonko/tablewriter v0.0.5
github.com/panjf2000/ants/v2 v2.9.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:ar
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
github.com/nspcc-dev/neofs-contract v0.20.0 h1:ARE/3mSN+P9qi/10NBsf7QyPiYrvnxeEgYUN13vHRlo=
github.com/nspcc-dev/neofs-contract v0.20.0/go.mod h1:YxtKYE/5cMNiqwWcQWzeizbB9jizauLni+p8wXxfhsQ=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc h1:WjVjs1vGILIVXC0lhJGWy2ek5FfT9S0HCOite/4tsks=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240807160341-3528eb5bb1cc/go.mod h1:ewV84r1NACvoBfbKQKzRLUun+Xn5+z9JVqsuCVgv9xI=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b h1:/7jXQP5pf+M0kRFC1gg5GEdTPkvotpMHxjSXIbMZaGQ=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20240809202351-256513c1b29b/go.mod h1:ewV84r1NACvoBfbKQKzRLUun+Xn5+z9JVqsuCVgv9xI=
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
github.com/nspcc-dev/tzhash v1.8.0 h1:pJvzME2mZzP/h5rcy/Wb6amT9FJBFeKbJ3HEnWEeUpY=
Expand Down
6 changes: 2 additions & 4 deletions pkg/innerring/processors/container/process_eacl.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error {
binTable := e.Table()

// unmarshal table
table := eacl.NewTable()

err := table.Unmarshal(binTable)
table, err := eacl.Unmarshal(binTable)
if err != nil {
return fmt.Errorf("invalid binary table: %w", err)
}
Expand Down Expand Up @@ -99,7 +97,7 @@ func (cp *Processor) approveSetEACL(e container.SetEACL) {
}
}

func validateEACL(t *eacl.Table) error {
func validateEACL(t eacl.Table) error {
var b big.Int
for _, record := range t.Records() {
for _, target := range record.Targets() {
Expand Down
6 changes: 3 additions & 3 deletions pkg/innerring/processors/container/process_eacl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ func TestValidateEACL(t *testing.T) {
tb := anyValidEACL()
tb.AddRecord(&r)

err := validateEACL(&tb)
err := validateEACL(tb)
require.ErrorContains(t, err, "non-empty value in absence filter")

r = eacl.Record{}
r.AddObjectAttributeFilter(eacl.MatchNotPresent, "any_key", "")
tb = anyValidEACL()
tb.AddRecord(&r)

err = validateEACL(&tb)
err = validateEACL(tb)
require.NoError(t, err)
})

Expand All @@ -54,7 +54,7 @@ func TestValidateEACL(t *testing.T) {
tb := anyValidEACL()
tb.AddRecord(&r)

err := validateEACL(&tb)
err := validateEACL(tb)
if tc.ok {
require.NoError(t, err, [2]any{m, tc})
} else {
Expand Down
Loading

0 comments on commit 7baa16c

Please sign in to comment.