mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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 == "" {
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user