[#364] Support placement policy overriding

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-03-03 15:43:56 +03:00 committed by LeL
parent 4454821285
commit 6a4fba4d09
2 changed files with 54 additions and 69 deletions

View file

@ -54,8 +54,7 @@ type (
// IssueSecretOptions contains options for passing to Agent.IssueSecret method. // IssueSecretOptions contains options for passing to Agent.IssueSecret method.
IssueSecretOptions struct { IssueSecretOptions struct {
ContainerID *cid.ID Container ContainerOptions
ContainerFriendlyName string
NeoFSKey *keys.PrivateKey NeoFSKey *keys.PrivateKey
GatesPublicKeys []*keys.PublicKey GatesPublicKeys []*keys.PublicKey
EACLRules []byte EACLRules []byte
@ -65,6 +64,13 @@ type (
ContainerPolicies ContainerPolicies ContainerPolicies ContainerPolicies
} }
// ContainerOptions groups parameters of auth container to put the secret into.
ContainerOptions struct {
ID *cid.ID
FriendlyName string
PlacementPolicy string
}
// ObtainSecretOptions contains options for passing to Agent.ObtainSecret method. // ObtainSecretOptions contains options for passing to Agent.ObtainSecret method.
ObtainSecretOptions struct { ObtainSecretOptions struct {
SecretAddress string SecretAddress string
@ -98,14 +104,14 @@ type (
} }
) )
func (a *Agent) checkContainer(ctx context.Context, cid *cid.ID, friendlyName string) (*cid.ID, error) { func (a *Agent) checkContainer(ctx context.Context, opts ContainerOptions) (*cid.ID, error) {
if cid != nil { if opts.ID != nil {
// check that container exists // check that container exists
_, err := a.pool.GetContainer(ctx, cid) _, err := a.pool.GetContainer(ctx, opts.ID)
return cid, err return opts.ID, err
} }
pp, err := buildPlacementPolicy("") pp, err := policy.Parse(opts.PlacementPolicy)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to build placement policy: %w", err) return nil, fmt.Errorf("failed to build placement policy: %w", err)
} }
@ -115,24 +121,24 @@ func (a *Agent) checkContainer(ctx context.Context, cid *cid.ID, friendlyName st
container.WithCustomBasicACL(defaultAuthContainerBasicACL), container.WithCustomBasicACL(defaultAuthContainerBasicACL),
container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)), container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(time.Now().Unix(), 10)),
} }
if friendlyName != "" { if opts.FriendlyName != "" {
cnrOptions = append(cnrOptions, container.WithAttribute(container.AttributeName, friendlyName)) cnrOptions = append(cnrOptions, container.WithAttribute(container.AttributeName, opts.FriendlyName))
} }
cnr := container.New(cnrOptions...) cnr := container.New(cnrOptions...)
if friendlyName != "" { if opts.FriendlyName != "" {
container.SetNativeName(cnr, friendlyName) container.SetNativeName(cnr, opts.FriendlyName)
} }
cid, err = a.pool.PutContainer(ctx, cnr) cnrID, err := a.pool.PutContainer(ctx, cnr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := a.pool.WaitForContainerPresence(ctx, cid, pool.DefaultPollingParams()); err != nil { if err := a.pool.WaitForContainerPresence(ctx, cnrID, pool.DefaultPollingParams()); err != nil {
return nil, err return nil, err
} }
return cid, nil return cnrID, nil
} }
func (a *Agent) getEpochDurations(ctx context.Context) (*epochDurations, error) { func (a *Agent) getEpochDurations(ctx context.Context) (*epochDurations, error) {
@ -235,8 +241,10 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
lifetime.Exp = lifetime.Iat + epochLifetime lifetime.Exp = lifetime.Iat + epochLifetime
} }
a.log.Info("check container", zap.Stringer("cid", options.ContainerID)) a.log.Info("check container or create", zap.Stringer("cid", options.Container.ID),
if cid, err = a.checkContainer(ctx, options.ContainerID, options.ContainerFriendlyName); err != nil { zap.String("friendly_name", options.Container.FriendlyName),
zap.String("placement_policy", options.Container.PlacementPolicy))
if cid, err = a.checkContainer(ctx, options.Container); err != nil {
return err return err
} }
@ -321,40 +329,6 @@ func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSe
return enc.Encode(or) return enc.Encode(or)
} }
func buildPlacementPolicy(placementRules string) (*netmap.PlacementPolicy, error) {
if len(placementRules) != 0 {
return policy.Parse(placementRules)
}
/*
REP 2 IN X // place two copies of object
CBF 3
SELECT 2 From * AS X // in container of two nodes
*/
pp := new(netmap.PlacementPolicy)
pp.SetContainerBackupFactor(3)
pp.SetReplicas([]*netmap.Replica{newReplica("X", 2)}...)
pp.SetSelectors([]*netmap.Selector{newSimpleSelector("X", 2)}...)
return pp, nil
}
// selects <count> nodes in container without any additional attributes.
func newSimpleSelector(name string, count uint32) (s *netmap.Selector) {
s = new(netmap.Selector)
s.SetCount(count)
s.SetFilter("*")
s.SetName(name)
return
}
func newReplica(name string, count uint32) (r *netmap.Replica) {
r = new(netmap.Replica)
r.SetCount(count)
r.SetSelector(name)
return
}
func buildEACLTable(cid *cid.ID, eaclTable []byte) (*eacl.Table, error) { func buildEACLTable(cid *cid.ID, eaclTable []byte) (*eacl.Table, error) {
table := eacl.NewTable() table := eacl.NewTable()
if len(eaclTable) != 0 { if len(eaclTable) != 0 {

View file

@ -32,23 +32,24 @@ const (
) )
var ( var (
walletPathFlag string walletPathFlag string
accountAddressFlag string accountAddressFlag string
peerAddressFlag string peerAddressFlag string
eaclRulesFlag string eaclRulesFlag string
gateWalletPathFlag string gateWalletPathFlag string
gateAccountAddressFlag string gateAccountAddressFlag string
accessKeyIDFlag string accessKeyIDFlag string
containerIDFlag string containerIDFlag string
containerFriendlyName string containerFriendlyName string
gatesPublicKeysFlag cli.StringSlice containerPlacementPolicy string
logEnabledFlag bool gatesPublicKeysFlag cli.StringSlice
logDebugEnabledFlag bool logEnabledFlag bool
sessionTokenFlag string logDebugEnabledFlag bool
lifetimeFlag time.Duration sessionTokenFlag string
containerPolicies string lifetimeFlag time.Duration
awcCliCredFile string containerPolicies string
timeoutFlag time.Duration awcCliCredFile string
timeoutFlag time.Duration
) )
const ( const (
@ -191,6 +192,13 @@ func issueSecret() *cli.Command {
Required: false, Required: false,
Destination: &containerFriendlyName, Destination: &containerFriendlyName,
}, },
&cli.StringFlag{
Name: "container-placement-policy",
Usage: "placement policy of auth container to put the secret into",
Required: false,
Destination: &containerPlacementPolicy,
Value: "REP 2 IN X CBF 3 SELECT 2 FROM * AS X",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "session-token", Name: "session-token",
Usage: "create session token with rules, if the rules are set as 'none', no session tokens will be created", Usage: "create session token with rules, if the rules are set as 'none', no session tokens will be created",
@ -264,8 +272,11 @@ It will be ceil rounded to the nearest amount of epoch.`,
} }
issueSecretOptions := &authmate.IssueSecretOptions{ issueSecretOptions := &authmate.IssueSecretOptions{
ContainerID: containerID, Container: authmate.ContainerOptions{
ContainerFriendlyName: containerFriendlyName, ID: containerID,
FriendlyName: containerFriendlyName,
PlacementPolicy: containerPlacementPolicy,
},
NeoFSKey: key, NeoFSKey: key,
GatesPublicKeys: gatesPublicKeys, GatesPublicKeys: gatesPublicKeys,
EACLRules: getJSONRules(eaclRulesFlag), EACLRules: getJSONRules(eaclRulesFlag),