Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSI Listsnapshot secrets support #10848

Merged
merged 1 commit into from
Aug 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/10848.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
csi: add flag for providing secrets as a set of key/value pairs to list snapshots
```
6 changes: 5 additions & 1 deletion api/csi.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (v *CSIVolumes) DeleteSnapshot(snap *CSISnapshot, w *WriteOptions) error {
}

// ListSnapshots lists external storage volume snapshots.
func (v *CSIVolumes) ListSnapshots(pluginID string, q *QueryOptions) (*CSISnapshotListResponse, *QueryMeta, error) {
func (v *CSIVolumes) ListSnapshots(pluginID string, secrets string, q *QueryOptions) (*CSISnapshotListResponse, *QueryMeta, error) {
var resp *CSISnapshotListResponse

qp := url.Values{}
Expand All @@ -150,6 +150,9 @@ func (v *CSIVolumes) ListSnapshots(pluginID string, q *QueryOptions) (*CSISnapsh
if q.PerPage != 0 {
qp.Set("per_page", fmt.Sprint(q.PerPage))
}
if secrets != "" {
qp.Set("secrets", secrets)
}

qm, err := v.client.query("/v1/volumes/snapshot?"+qp.Encode(), &resp, q)
if err != nil {
Expand Down Expand Up @@ -406,6 +409,7 @@ type CSISnapshotCreateResponse struct {
// fields
type CSISnapshotListRequest struct {
PluginID string
Secrets CSISecrets
QueryOptions
}

Expand Down
4 changes: 4 additions & 0 deletions client/csi_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,10 @@ func TestCSIController_ListSnapshots(t *testing.T) {
CSIControllerQuery: structs.CSIControllerQuery{
PluginID: fakePlugin.Name,
},
Secrets: map[string]string{
"secret-key-1": "secret-val-1",
"secret-key-2": "secret-val-2",
},
StartingToken: "1",
MaxEntries: 100,
},
Expand Down
2 changes: 2 additions & 0 deletions client/structs/csi.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ type ClientCSIControllerListSnapshotsRequest struct {
// not Nomad's own fields, for clarity when mapping between the two RPCs
MaxEntries int32
StartingToken string
Secrets structs.CSISecrets

CSIControllerQuery
}
Expand All @@ -370,6 +371,7 @@ func (req *ClientCSIControllerListSnapshotsRequest) ToCSIRequest() *csi.Controll
return &csi.ControllerListSnapshotsRequest{
MaxEntries: req.MaxEntries,
StartingToken: req.StartingToken,
Secrets: req.Secrets,
}
}

Expand Down
13 changes: 13 additions & 0 deletions command/agent/csi_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,19 @@ func (s *HTTPServer) csiSnapshotList(resp http.ResponseWriter, req *http.Request

query := req.URL.Query()
args.PluginID = query.Get("plugin_id")
querySecrets := query["secrets"]

// Parse comma separated secrets only when provided
if len(querySecrets) >= 1 {
secrets := strings.Split(querySecrets[0], ",")
args.Secrets = make(structs.CSISecrets)
for _, raw := range secrets {
secret := strings.Split(raw, "=")
if len(secret) == 2 {
args.Secrets[secret[0]] = secret[1]
}
}
}

var out structs.CSISnapshotListResponse
if err := s.agent.RPC("CSIVolume.ListSnapshots", &args, &out); err != nil {
Expand Down
6 changes: 5 additions & 1 deletion command/volume_snapshot_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ List Options:

-plugin: Display only snapshots managed by a particular plugin. By default
this command will query all plugins for their snapshots.

-secrets: A set of key/value secrets to be used when listing snapshots.
ggriffiths marked this conversation as resolved.
Show resolved Hide resolved
`
return strings.TrimSpace(helpText)
}
Expand Down Expand Up @@ -68,11 +70,13 @@ func (c *VolumeSnapshotListCommand) Name() string { return "volume snapshot list
func (c *VolumeSnapshotListCommand) Run(args []string) int {
var pluginID string
var verbose bool
var secrets string

flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.StringVar(&pluginID, "plugin", "", "")
flags.BoolVar(&verbose, "verbose", false, "")
flags.StringVar(&secrets, "secrets", "", "")

if err := flags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing arguments %s", err))
Expand Down Expand Up @@ -121,7 +125,7 @@ func (c *VolumeSnapshotListCommand) Run(args []string) int {
q := &api.QueryOptions{PerPage: 30} // TODO: tune page size

for {
resp, _, err := client.CSIVolumes().ListSnapshots(pluginID, q)
resp, _, err := client.CSIVolumes().ListSnapshots(pluginID, secrets, q)
if err != nil && !errors.Is(err, io.EOF) {
c.Ui.Error(fmt.Sprintf(
"Error querying CSI external snapshots for plugin %q: %s", pluginID, err))
Expand Down
1 change: 1 addition & 0 deletions nomad/csi_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ func (v *CSIVolume) ListSnapshots(args *structs.CSISnapshotListRequest, reply *s
cReq := &cstructs.ClientCSIControllerListSnapshotsRequest{
MaxEntries: args.PerPage,
StartingToken: args.NextToken,
Secrets: args.Secrets,
}
cReq.PluginID = plugin.ID
cResp := &cstructs.ClientCSIControllerListSnapshotsResponse{}
Expand Down
3 changes: 3 additions & 0 deletions nomad/csi_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,9 @@ func TestCSIVolumeEndpoint_ListSnapshots(t *testing.T) {
// List snapshots

req := &structs.CSISnapshotListRequest{
Secrets: structs.CSISecrets{
"secret-key-1": "secret-val-1",
},
QueryOptions: structs.QueryOptions{
Region: "global",
Namespace: structs.DefaultNamespace,
Expand Down
1 change: 1 addition & 0 deletions nomad/structs/csi.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ type CSISnapshotDeleteResponse struct {
// fields
type CSISnapshotListRequest struct {
PluginID string
Secrets CSISecrets
QueryOptions
}

Expand Down
2 changes: 2 additions & 0 deletions plugins/csi/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,12 +756,14 @@ func (r *ControllerDeleteSnapshotRequest) Validate() error {
type ControllerListSnapshotsRequest struct {
MaxEntries int32
StartingToken string
Secrets structs.CSISecrets
}

func (r *ControllerListSnapshotsRequest) ToCSIRepresentation() *csipbv1.ListSnapshotsRequest {
return &csipbv1.ListSnapshotsRequest{
MaxEntries: r.MaxEntries,
StartingToken: r.StartingToken,
Secrets: r.Secrets,
}
}

Expand Down
5 changes: 4 additions & 1 deletion website/content/api-docs/volumes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,15 @@ The table below shows this endpoint's support for
return for this request. The response will include a `NextToken` field that
can be passed to the next request to fetch additional pages.

- `secrets` `(string: "")` - Specifies a list of key/value secrets for listing snapshots.
These key/value pairs are comma-separated and are passed directly to the CSI plugin.

### Sample Request

```shell-session
$ curl \
https://localhost:4646/v1/volumes/snapshot?&plugin_id=plugin-id1&per_page=2
https://localhost:4646/v1/volumes/snapshot?plugin_id=plugin-id1&per_page=2& \
secrets=secret-key-1=secret-value-1,secret-key-2=secret-value-2
```

### Sample Response
Expand Down
15 changes: 12 additions & 3 deletions website/content/docs/commands/volume/snapshot-list.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ command.
## Usage

```plaintext
nomad volume snapshot list [-plugin plugin_id]
nomad volume snapshot list [-plugin plugin_id -secrets key=value]
```

The `volume snapshot list` command returns a list of snapshots along with their
Expand All @@ -27,14 +27,16 @@ Nomad.

@include 'general_options.mdx'

## Status Options
## List Options

- `-plugin`: Display only snapshots managed by a particular [CSI
plugin][csi_plugin]. By default the `snapshot list` command will query all
plugins for their snapshots. This flag accepts a plugin ID or prefix. If
there is an exact match based on the provided plugin, then that specific
plugin will be queried. Otherwise, a list of matching plugins will be
displayed.
- `-secrets`: A list of comma separated secret key/value pairs to be passed
to the CSI driver.

When ACLs are enabled, this command requires a token with the
`csi-list-volumes` capability for the plugin's namespace.
Expand All @@ -50,7 +52,14 @@ snap-12345 vol-abcdef 50GiB 2021-01-03T12:15:02Z true
snap-67890 vol-fedcba 50GiB 2021-01-04T15:45:00Z true
```

List volume snapshots with two secret key/value pairs:
```shell-session
$ nomad volume snapshot list -secrets key1=value1,key2=val2
Snapshot ID External ID Size Creation Time Ready?
snap-12345 vol-abcdef 50GiB 2021-01-03T12:15:02Z true
```

[csi]: https://github.com/container-storage-interface/spec
[csi_plugin]: /docs/job-specification/csi_plugin
[registered]: /docs/commands/volume/register
[csi_plugins_internals]: /docs/internals/plugins/csi#csi-plugins
[csi_plugins_internals]: /docs/internals/plugins/csi#csi-plugins