[#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

@ -41,6 +41,7 @@ var (
accessKeyIDFlag string accessKeyIDFlag string
containerIDFlag string containerIDFlag string
containerFriendlyName string containerFriendlyName string
containerPlacementPolicy string
gatesPublicKeysFlag cli.StringSlice gatesPublicKeysFlag cli.StringSlice
logEnabledFlag bool logEnabledFlag bool
logDebugEnabledFlag bool logDebugEnabledFlag bool
@ -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),