[#1704] cli: Add force option to the command `container create`

Validate policy before container creation

Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
remotes/fyrchik/neofs-adm-fix-commands
Anton Nikiforov 2022-09-27 09:49:45 +03:00 committed by fyrchik
parent 4eb0ed11f8
commit 8bf82d738b
4 changed files with 27 additions and 9 deletions

View File

@ -12,6 +12,7 @@ Changelog for NeoFS Node
- `neofs-node -check` command to check the configuration file (#1805) - `neofs-node -check` command to check the configuration file (#1805)
- `flush-cache` control service command to flush write-cache (#1806) - `flush-cache` control service command to flush write-cache (#1806)
- `wallet-address` flag in `neofs-adm morph refill-gas` command (#1820) - `wallet-address` flag in `neofs-adm morph refill-gas` command (#1820)
- Validate policy before container creation (#1704)
### Changed ### Changed
@ -35,6 +36,7 @@ Changelog for NeoFS Node
Replace using the `control netmap-snapshot` command with `netmap snapshot` one in NeoFS CLI. Replace using the `control netmap-snapshot` command with `netmap snapshot` one in NeoFS CLI.
Node can now specify additional addresses in `ExternalAddr` attribute. To allow a node to dial Node can now specify additional addresses in `ExternalAddr` attribute. To allow a node to dial
other nodes external address, use `apiclient.allow_external` config setting. other nodes external address, use `apiclient.allow_external` config setting.
Add `--force` option to skip placement validity check for container creation.
## [0.32.0] - 2022-09-14 - Pungdo (풍도, 楓島) ## [0.32.0] - 2022-09-14 - Pungdo (풍도, 楓島)

View File

@ -31,6 +31,9 @@ const (
Verbose = "verbose" Verbose = "verbose"
VerboseShorthand = "v" VerboseShorthand = "v"
VerboseUsage = "verbose output" VerboseUsage = "verbose output"
ForceFlag = "force"
ForceFlagShorthand = "f"
) )
// Init adds common flags to the command: // Init adds common flags to the command:

View File

@ -28,6 +28,7 @@ var (
containerName string containerName string
containerNoTimestamp bool containerNoTimestamp bool
containerSubnet string containerSubnet string
force bool
) )
var createContainerCmd = &cobra.Command{ var createContainerCmd = &cobra.Command{
@ -39,6 +40,22 @@ It will be stored in sidechain when inner ring will accepts it.`,
placementPolicy, err := parseContainerPolicy(containerPolicy) placementPolicy, err := parseContainerPolicy(containerPolicy)
common.ExitOnErr(cmd, "", err) common.ExitOnErr(cmd, "", err)
key := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
if !force {
var prm internalclient.NetMapSnapshotPrm
prm.SetClient(cli)
resmap, err := internalclient.NetMapSnapshot(prm)
common.ExitOnErr(cmd, "unable to get netmap snapshot to validate container placement, "+
"use --force option to skip this check: %w", err)
_, err = resmap.NetMap().ContainerNodes(*placementPolicy, nil)
common.ExitOnErr(cmd, "could not build container nodes based on given placement policy, "+
"use --force option to skip this check: %w", err)
}
if containerSubnet != "" { if containerSubnet != "" {
var subnetID subnetid.ID var subnetID subnetid.ID
@ -57,8 +74,6 @@ It will be stored in sidechain when inner ring will accepts it.`,
var basicACL acl.Basic var basicACL acl.Basic
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL)) common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
key := key.GetOrGenerate(cmd)
var tok *session.Container var tok *session.Container
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken) sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
@ -78,8 +93,6 @@ It will be stored in sidechain when inner ring will accepts it.`,
cnr.SetPlacementPolicy(*placementPolicy) cnr.SetPlacementPolicy(*placementPolicy)
cnr.SetBasicACL(basicACL) cnr.SetBasicACL(basicACL)
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
var syncContainerPrm internalclient.SyncContainerPrm var syncContainerPrm internalclient.SyncContainerPrm
syncContainerPrm.SetClient(cli) syncContainerPrm.SetClient(cli)
syncContainerPrm.SetContainer(&cnr) syncContainerPrm.SetContainer(&cnr)
@ -138,6 +151,8 @@ func initContainerCreateCmd() {
flags.StringVar(&containerName, "name", "", "container name attribute") flags.StringVar(&containerName, "name", "", "container name attribute")
flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute") flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute")
flags.StringVar(&containerSubnet, "subnet", "", "string representation of container subnetwork") flags.StringVar(&containerSubnet, "subnet", "", "string representation of container subnetwork")
flags.BoolVarP(&force, commonflags.ForceFlag, commonflags.ForceFlagShorthand, false,
"skip placement validity check")
} }
func parseContainerPolicy(policyString string) (*netmap.PlacementPolicy, error) { func parseContainerPolicy(policyString string) (*netmap.PlacementPolicy, error) {

View File

@ -13,8 +13,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const forceFlag = "force"
var deleteContainerCmd = &cobra.Command{ var deleteContainerCmd = &cobra.Command{
Use: "delete", Use: "delete",
Short: "Delete existing container", Short: "Delete existing container",
@ -34,7 +32,7 @@ Only owner of the container has a permission to remove container.`,
pk := key.Get(cmd) pk := key.Get(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
if force, _ := cmd.Flags().GetBool(forceFlag); !force { if force, _ := cmd.Flags().GetBool(commonflags.ForceFlag); !force {
fs := objectSDK.NewSearchFilters() fs := objectSDK.NewSearchFilters()
fs.AddTypeFilter(objectSDK.MatchStringEqual, objectSDK.TypeLock) fs.AddTypeFilter(objectSDK.MatchStringEqual, objectSDK.TypeLock)
@ -52,7 +50,7 @@ Only owner of the container has a permission to remove container.`,
if len(res.IDList()) != 0 { if len(res.IDList()) != 0 {
common.ExitOnErr(cmd, "", common.ExitOnErr(cmd, "",
fmt.Errorf("Container wasn't removed because LOCK objects were found.\n"+ fmt.Errorf("Container wasn't removed because LOCK objects were found.\n"+
"Use --%s flag to remove anyway.", forceFlag)) "Use --%s flag to remove anyway.", commonflags.ForceFlag))
} }
} }
@ -100,5 +98,5 @@ func initContainerDeleteCmd() {
flags.StringVar(&containerID, "cid", "", "container ID") flags.StringVar(&containerID, "cid", "", "container ID")
flags.BoolVar(&containerAwait, "await", false, "block execution until container is removed") flags.BoolVar(&containerAwait, "await", false, "block execution until container is removed")
flags.Bool(forceFlag, false, "do not check whether container contains locks and remove immediately") flags.BoolP(commonflags.ForceFlag, commonflags.ForceFlagShorthand, false, "do not check whether container contains locks and remove immediately")
} }