diff --git a/CHANGELOG.md b/CHANGELOG.md index 530b34fb..8c208cd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Changelog for NeoFS Node - `neofs-node -check` command to check the configuration file (#1805) - `flush-cache` control service command to flush write-cache (#1806) - `wallet-address` flag in `neofs-adm morph refill-gas` command (#1820) +- Validate policy before container creation (#1704) ### Changed @@ -35,6 +36,7 @@ Changelog for NeoFS Node 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 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 (풍도, 楓島) diff --git a/cmd/neofs-cli/internal/commonflags/flags.go b/cmd/neofs-cli/internal/commonflags/flags.go index 5c6ad12b..7c3c50f8 100644 --- a/cmd/neofs-cli/internal/commonflags/flags.go +++ b/cmd/neofs-cli/internal/commonflags/flags.go @@ -31,6 +31,9 @@ const ( Verbose = "verbose" VerboseShorthand = "v" VerboseUsage = "verbose output" + + ForceFlag = "force" + ForceFlagShorthand = "f" ) // Init adds common flags to the command: diff --git a/cmd/neofs-cli/modules/container/create.go b/cmd/neofs-cli/modules/container/create.go index 73f69581..8f79e0f6 100644 --- a/cmd/neofs-cli/modules/container/create.go +++ b/cmd/neofs-cli/modules/container/create.go @@ -28,6 +28,7 @@ var ( containerName string containerNoTimestamp bool containerSubnet string + force bool ) var createContainerCmd = &cobra.Command{ @@ -39,6 +40,22 @@ It will be stored in sidechain when inner ring will accepts it.`, placementPolicy, err := parseContainerPolicy(containerPolicy) 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 != "" { var subnetID subnetid.ID @@ -57,8 +74,6 @@ It will be stored in sidechain when inner ring will accepts it.`, var basicACL acl.Basic common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL)) - key := key.GetOrGenerate(cmd) - var tok *session.Container 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.SetBasicACL(basicACL) - cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC) - var syncContainerPrm internalclient.SyncContainerPrm syncContainerPrm.SetClient(cli) syncContainerPrm.SetContainer(&cnr) @@ -138,6 +151,8 @@ func initContainerCreateCmd() { flags.StringVar(&containerName, "name", "", "container name attribute") flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute") 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) { diff --git a/cmd/neofs-cli/modules/container/delete.go b/cmd/neofs-cli/modules/container/delete.go index 8625931f..f5abd6c8 100644 --- a/cmd/neofs-cli/modules/container/delete.go +++ b/cmd/neofs-cli/modules/container/delete.go @@ -13,8 +13,6 @@ import ( "github.com/spf13/cobra" ) -const forceFlag = "force" - var deleteContainerCmd = &cobra.Command{ Use: "delete", Short: "Delete existing container", @@ -34,7 +32,7 @@ Only owner of the container has a permission to remove container.`, pk := key.Get(cmd) 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.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 { common.ExitOnErr(cmd, "", 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.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") }