From ff1bed38cd2c46cc9fcc53319881538b4b45bd06 Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Thu, 24 Mar 2022 10:29:50 -0400 Subject: [PATCH] csi: add `-secret` and `-parameter` flag to `volume snapshot create` (#12360) Pass-through the `-secret` and `-parameter` flags to allow setting parameters for the snapshot and overriding the secrets we've stored on the CSI volume in the state store. --- .changelog/12360.txt | 3 ++ api/csi.go | 4 ++ command/volume_snapshot_create.go | 39 +++++++++++++++++++ command/volume_snapshot_delete.go | 5 ++- command/volume_snapshot_list.go | 17 +++++--- nomad/csi_endpoint.go | 8 +++- .../docs/commands/volume/snapshot-create.mdx | 11 ++++++ .../docs/commands/volume/snapshot-list.mdx | 5 ++- 8 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 .changelog/12360.txt diff --git a/.changelog/12360.txt b/.changelog/12360.txt new file mode 100644 index 000000000..8422c38cd --- /dev/null +++ b/.changelog/12360.txt @@ -0,0 +1,3 @@ +```release-note:improvement +csi: Added `-secret` and `-parameter` flags to `volume snapshot create` command +``` diff --git a/api/csi.go b/api/csi.go index 25cddc50b..829e3a251 100644 --- a/api/csi.go +++ b/api/csi.go @@ -120,6 +120,10 @@ func (v *CSIVolumes) CreateSnapshot(snap *CSISnapshot, w *WriteOptions) (*CSISna req := &CSISnapshotCreateRequest{ Snapshots: []*CSISnapshot{snap}, } + if w == nil { + w = &WriteOptions{} + } + w.SetHeadersFromCSISecrets(snap.Secrets) resp := &CSISnapshotCreateResponse{} meta, err := v.client.write("/v1/volumes/snapshot", req, resp, w) return resp, meta, err diff --git a/command/volume_snapshot_create.go b/command/volume_snapshot_create.go index 4fcfdcd73..013b285c0 100644 --- a/command/volume_snapshot_create.go +++ b/command/volume_snapshot_create.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/api/contexts" + flaghelper "github.com/hashicorp/nomad/helper/flags" "github.com/posener/complete" ) @@ -34,7 +35,20 @@ General Options: ` + generalOptionsUsage(usageOptsDefault) + ` +Snapshot Create Options: + + -parameter + Parameters to pass to the plugin to create a snapshot. Accepts multiple + flags in the form -parameter key=value + + -secret + Secrets to pass to the plugin to create snapshot. Accepts multiple + flags in the form -secret key=value + + -verbose + Display full information for the resulting snapshot. ` + return strings.TrimSpace(helpText) } @@ -70,7 +84,11 @@ func (c *VolumeSnapshotCreateCommand) Run(args []string) int { flags.Usage = func() { c.Ui.Output(c.Help()) } var verbose bool + var parametersArgs flaghelper.StringFlag + var secretsArgs flaghelper.StringFlag flags.BoolVar(&verbose, "verbose", false, "") + flags.Var(¶metersArgs, "parameter", "parameters for snapshot, ex. -parameter key=value") + flags.Var(&secretsArgs, "secret", "secrets for snapshot, ex. -secret key=value") if err := flags.Parse(args); err != nil { c.Ui.Error(fmt.Sprintf("Error parsing arguments %s", err)) @@ -97,9 +115,30 @@ func (c *VolumeSnapshotCreateCommand) Run(args []string) int { return 1 } + secrets := api.CSISecrets{} + for _, kv := range secretsArgs { + s := strings.Split(kv, "=") + if len(s) == 2 { + secrets[s[0]] = s[1] + } else { + c.Ui.Error("Secret must be in the format: -secret key=value") + return 1 + } + } + + params := map[string]string{} + for _, kv := range parametersArgs { + p := strings.Split(kv, "=") + if len(p) == 2 { + params[p[0]] = p[1] + } + } + snaps, _, err := client.CSIVolumes().CreateSnapshot(&api.CSISnapshot{ SourceVolumeID: volID, Name: snapshotName, + Secrets: secrets, + Parameters: params, }, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error snapshotting volume: %s", err)) diff --git a/command/volume_snapshot_delete.go b/command/volume_snapshot_delete.go index a2ac23c7b..d6eaccc1c 100644 --- a/command/volume_snapshot_delete.go +++ b/command/volume_snapshot_delete.go @@ -77,7 +77,7 @@ func (c *VolumeSnapshotDeleteCommand) Run(args []string) int { } // Check that we get exactly two arguments args = flags.Args() - if l := len(args); l != 2 { + if l := len(args); l < 2 { c.Ui.Error("This command takes two arguments: ") c.Ui.Error(commandErrorText(c)) return 1 @@ -97,6 +97,9 @@ func (c *VolumeSnapshotDeleteCommand) Run(args []string) int { s := strings.Split(kv, "=") if len(s) == 2 { secrets[s[0]] = s[1] + } else { + c.Ui.Error("Secret must be in the format: -secret key=value") + return 1 } } diff --git a/command/volume_snapshot_list.go b/command/volume_snapshot_list.go index a27e71bfa..df0f925e9 100644 --- a/command/volume_snapshot_list.go +++ b/command/volume_snapshot_list.go @@ -36,6 +36,12 @@ General Options: List Options: + -page-token + Where to start pagination. + + -per-page + How many results to show per page. Defaults to 30. + -plugin: Display only snapshots managed by a particular plugin. This parameter is required. @@ -43,12 +49,10 @@ List Options: Secrets to pass to the plugin to list snapshots. Accepts multiple flags in the form -secret key=value - -per-page - How many results to show per page. Defaults to 30. - - -page-token - Where to start pagination. + -verbose + Display full information for snapshots. ` + return strings.TrimSpace(helpText) } @@ -139,6 +143,9 @@ func (c *VolumeSnapshotListCommand) Run(args []string) int { s := strings.Split(kv, "=") if len(s) == 2 { secrets[s[0]] = s[1] + } else { + c.Ui.Error("Secret must be in the format: -secret key=value") + return 1 } } diff --git a/nomad/csi_endpoint.go b/nomad/csi_endpoint.go index add9c3cd8..4043955cc 100644 --- a/nomad/csi_endpoint.go +++ b/nomad/csi_endpoint.go @@ -1195,10 +1195,16 @@ func (v *CSIVolume) CreateSnapshot(args *structs.CSISnapshotCreateRequest, reply continue } + secrets := vol.Secrets + for k, v := range snap.Secrets { + // merge request secrets onto volume secrets + secrets[k] = v + } + cReq := &cstructs.ClientCSIControllerCreateSnapshotRequest{ ExternalSourceVolumeID: vol.ExternalID, Name: snap.Name, - Secrets: vol.Secrets, + Secrets: secrets, Parameters: snap.Parameters, } cReq.PluginID = pluginID diff --git a/website/content/docs/commands/volume/snapshot-create.mdx b/website/content/docs/commands/volume/snapshot-create.mdx index 241e18e0e..24b5b9556 100644 --- a/website/content/docs/commands/volume/snapshot-create.mdx +++ b/website/content/docs/commands/volume/snapshot-create.mdx @@ -1,5 +1,6 @@ --- layout: docs + page_title: 'Commands: volume snapshot create' description: | Create external volume snapshots. @@ -35,6 +36,16 @@ When ACLs are enabled, this command requires a token with the @include 'general_options.mdx' +## Snapshot Create Options + +- `-parameter`: Parameters to pass to the plugin to create a + snapshot. Accepts multiple flags in the form `-parameter key=value` + +- `-secret`: Secrets to pass to the plugin to create a snapshot. Accepts + multiple flags in the form `-secret key=value` + +- `-verbose`: Display full information for the resulting snapshot. + ## Examples Snapshot a volume: diff --git a/website/content/docs/commands/volume/snapshot-list.mdx b/website/content/docs/commands/volume/snapshot-list.mdx index 747de707f..2e2c66493 100644 --- a/website/content/docs/commands/volume/snapshot-list.mdx +++ b/website/content/docs/commands/volume/snapshot-list.mdx @@ -29,6 +29,8 @@ Nomad. ## Snapshot List Options +- `-page-token`: Where to start pagination. +- `-per-page`: How many results to show per page. - `-plugin`: Display only snapshots managed by a particular [CSI plugin][csi_plugin]. This flag is required and accepts a plugin ID or prefix. If there is an exact match based on the provided plugin, @@ -36,8 +38,7 @@ Nomad. matching plugins will be displayed. - `-secret`: Secrets to pass to the plugin to list snapshots. Accepts multiple flags in the form `-secret key=value` -- `-per-page`: How many results to show per page. -- `-page-token`: Where to start pagination. +- `-verbose`: Display full information for the resulting snapshot. When ACLs are enabled, this command requires a token with the `csi-list-volumes` capability for the plugin's namespace.