CSI: listing from plugins can return EOF

The AWS EBS CSI plugin was observed to return a EOF when we get to the end of
the paging for `ListSnapshots`, counter to specification. Handle this case
gracefully, including for `ListVolumes` (which EBS doesn't support but has
similar semantics).

Also fixes a timestamp formatting bug on `ListSnapshots`
This commit is contained in:
Tim Gross
2021-04-08 11:13:36 -04:00
committed by Tim Gross
parent 45f0a3a532
commit a24cf6bfd1
3 changed files with 31 additions and 21 deletions

View File

@@ -2,12 +2,14 @@ package command
import (
"fmt"
"io"
"sort"
"strings"
humanize "github.com/dustin/go-humanize"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/api/contexts"
"github.com/pkg/errors"
"github.com/posener/complete"
)
@@ -120,15 +122,18 @@ func (c *VolumeSnapshotListCommand) Run(args []string) int {
for {
resp, _, err := client.CSIVolumes().ListSnapshots(pluginID, q)
if err != nil {
if err != nil && !errors.Is(err, io.EOF) {
c.Ui.Error(fmt.Sprintf(
"Error querying CSI external snapshots for plugin %q: %s", pluginID, err))
return 1
}
if len(resp.Snapshots) > 0 {
c.Ui.Output(csiFormatSnapshots(resp.Snapshots, verbose))
if resp == nil || len(resp.Snapshots) == 0 {
// several plugins return EOF once you hit the end of the page,
// rather than an empty list
break
}
c.Ui.Output(csiFormatSnapshots(resp.Snapshots, verbose))
q.NextToken = resp.NextToken
if q.NextToken == "" {
break

View File

@@ -1,7 +1,9 @@
package command
import (
"errors"
"fmt"
"io"
"sort"
"strings"
@@ -103,7 +105,7 @@ NEXT_PLUGIN:
}
for {
externalList, _, err := client.CSIVolumes().ListExternal(plugin.ID, q)
if err != nil {
if err != nil && !errors.Is(err, io.EOF) {
c.Ui.Error(fmt.Sprintf(
"Error querying CSI external volumes for plugin %q: %s", plugin.ID, err))
// we'll stop querying this plugin, but there may be more to
@@ -112,23 +114,26 @@ NEXT_PLUGIN:
code = 1
continue NEXT_PLUGIN
}
rows := []string{}
if len(externalList.Volumes) > 0 {
rows[0] = "External ID|Condition|Nodes"
for i, v := range externalList.Volumes {
condition := "OK"
if v.IsAbnormal {
condition = fmt.Sprintf("Abnormal (%v)", v.Status)
}
rows[i+1] = fmt.Sprintf("%s|%s|%s",
limit(v.ExternalID, c.length),
limit(condition, 20),
strings.Join(v.PublishedExternalNodeIDs, ","),
)
}
c.Ui.Output(formatList(rows))
if externalList == nil || len(externalList.Volumes) == 0 {
// several plugins return EOF once you hit the end of the page,
// rather than an empty list
continue NEXT_PLUGIN
}
rows := []string{}
rows[0] = "External ID|Condition|Nodes"
for i, v := range externalList.Volumes {
condition := "OK"
if v.IsAbnormal {
condition = fmt.Sprintf("Abnormal (%v)", v.Status)
}
rows[i+1] = fmt.Sprintf("%s|%s|%s",
limit(v.ExternalID, c.length),
limit(condition, 20),
strings.Join(v.PublishedExternalNodeIDs, ","),
)
}
c.Ui.Output(formatList(rows))
q.NextToken = externalList.NextToken
if q.NextToken == "" {

View File

@@ -782,7 +782,7 @@ func NewListSnapshotsResponse(resp *csipbv1.ListSnapshotsResponse) *ControllerLi
SizeBytes: snap.GetSizeBytes(),
ID: snap.GetSnapshotId(),
SourceVolumeID: snap.GetSourceVolumeId(),
CreateTime: snap.GetCreationTime().GetSeconds(),
CreateTime: int64(snap.GetCreationTime().GetNanos()),
IsReady: snap.GetReadyToUse(),
},
})