From 209cff97f03fade298e14bb2554ea04df801a8cb Mon Sep 17 00:00:00 2001 From: Grant Griffiths Date: Fri, 2 Jul 2021 17:46:41 -0700 Subject: [PATCH] CSI ListSnapshots secrets implementation Signed-off-by: Grant Griffiths --- api/csi.go | 6 +++++- client/csi_endpoint_test.go | 4 ++++ client/structs/csi.go | 2 ++ command/agent/csi_endpoint.go | 8 ++++++++ command/volume_snapshot_list.go | 5 ++++- nomad/csi_endpoint.go | 1 + nomad/csi_endpoint_test.go | 3 +++ nomad/structs/csi.go | 1 + plugins/csi/plugin.go | 2 ++ 9 files changed, 30 insertions(+), 2 deletions(-) diff --git a/api/csi.go b/api/csi.go index 836d37d04e42..120c239fde8f 100644 --- a/api/csi.go +++ b/api/csi.go @@ -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{} @@ -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 { @@ -406,6 +409,7 @@ type CSISnapshotCreateResponse struct { // fields type CSISnapshotListRequest struct { PluginID string + Secrets CSISecrets QueryOptions } diff --git a/client/csi_endpoint_test.go b/client/csi_endpoint_test.go index f5bc07b44dc2..5e8382eb96e0 100644 --- a/client/csi_endpoint_test.go +++ b/client/csi_endpoint_test.go @@ -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, }, diff --git a/client/structs/csi.go b/client/structs/csi.go index d4846f7e95cc..ca7f88d41deb 100644 --- a/client/structs/csi.go +++ b/client/structs/csi.go @@ -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 } @@ -370,6 +371,7 @@ func (req *ClientCSIControllerListSnapshotsRequest) ToCSIRequest() *csi.Controll return &csi.ControllerListSnapshotsRequest{ MaxEntries: req.MaxEntries, StartingToken: req.StartingToken, + Secrets: req.Secrets, } } diff --git a/command/agent/csi_endpoint.go b/command/agent/csi_endpoint.go index 9184bfe0794e..fb8c1a6c0cbb 100644 --- a/command/agent/csi_endpoint.go +++ b/command/agent/csi_endpoint.go @@ -333,6 +333,14 @@ func (s *HTTPServer) csiSnapshotList(resp http.ResponseWriter, req *http.Request query := req.URL.Query() args.PluginID = query.Get("plugin_id") + secrets := query["secrets"] + 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 { diff --git a/command/volume_snapshot_list.go b/command/volume_snapshot_list.go index 65ea484ca279..b88bdd838adb 100644 --- a/command/volume_snapshot_list.go +++ b/command/volume_snapshot_list.go @@ -35,6 +35,7 @@ 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. ` return strings.TrimSpace(helpText) } @@ -68,11 +69,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)) @@ -121,7 +124,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)) diff --git a/nomad/csi_endpoint.go b/nomad/csi_endpoint.go index 30a223cc33a9..eb6954eed2f1 100644 --- a/nomad/csi_endpoint.go +++ b/nomad/csi_endpoint.go @@ -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{} diff --git a/nomad/csi_endpoint_test.go b/nomad/csi_endpoint_test.go index cbcd74695ce2..35cafb2696bd 100644 --- a/nomad/csi_endpoint_test.go +++ b/nomad/csi_endpoint_test.go @@ -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, diff --git a/nomad/structs/csi.go b/nomad/structs/csi.go index 1c7845c0a61e..e0f35aeaca36 100644 --- a/nomad/structs/csi.go +++ b/nomad/structs/csi.go @@ -897,6 +897,7 @@ type CSISnapshotDeleteResponse struct { // fields type CSISnapshotListRequest struct { PluginID string + Secrets CSISecrets QueryOptions } diff --git a/plugins/csi/plugin.go b/plugins/csi/plugin.go index 7019127c54e7..6c85db7a8e09 100644 --- a/plugins/csi/plugin.go +++ b/plugins/csi/plugin.go @@ -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, } }