open-nomad/plugins/csi/fake/client.go
Tim Gross 6ffd36c4e5
csi: add grpc retries to client controller RPCs (#7549)
The CSI Specification defines various gRPC Errors and how they may be retried. After auditing all our CSI RPC calls in #6863, this changeset:

* adds retries and backoffs to the where they were needed but not implemented
* annotates those CSI RPCs that do not need retries so that we don't wonder whether it's been left off accidentally
* added a timeout and cancellation context to the `Probe` call, which didn't have one.
2020-03-30 16:26:03 -04:00

279 lines
8.4 KiB
Go

// fake is a package that includes fake implementations of public interfaces
// from the CSI package for testing.
package fake
import (
"context"
"errors"
"fmt"
"sync"
"github.com/hashicorp/nomad/plugins/base"
"github.com/hashicorp/nomad/plugins/csi"
"github.com/hashicorp/nomad/plugins/shared/hclspec"
"google.golang.org/grpc"
)
var _ csi.CSIPlugin = &Client{}
// Client is a mock implementation of the csi.CSIPlugin interface for use in testing
// external components
type Client struct {
Mu sync.RWMutex
NextPluginInfoResponse *base.PluginInfoResponse
NextPluginInfoErr error
PluginInfoCallCount int64
NextPluginProbeResponse bool
NextPluginProbeErr error
PluginProbeCallCount int64
NextPluginGetInfoNameResponse string
NextPluginGetInfoVersionResponse string
NextPluginGetInfoErr error
PluginGetInfoCallCount int64
NextPluginGetCapabilitiesResponse *csi.PluginCapabilitySet
NextPluginGetCapabilitiesErr error
PluginGetCapabilitiesCallCount int64
NextControllerGetCapabilitiesResponse *csi.ControllerCapabilitySet
NextControllerGetCapabilitiesErr error
ControllerGetCapabilitiesCallCount int64
NextControllerPublishVolumeResponse *csi.ControllerPublishVolumeResponse
NextControllerPublishVolumeErr error
ControllerPublishVolumeCallCount int64
NextControllerUnpublishVolumeResponse *csi.ControllerUnpublishVolumeResponse
NextControllerUnpublishVolumeErr error
ControllerUnpublishVolumeCallCount int64
NextControllerValidateVolumeErr error
ControllerValidateVolumeCallCount int64
NextNodeGetCapabilitiesResponse *csi.NodeCapabilitySet
NextNodeGetCapabilitiesErr error
NodeGetCapabilitiesCallCount int64
NextNodeGetInfoResponse *csi.NodeGetInfoResponse
NextNodeGetInfoErr error
NodeGetInfoCallCount int64
NextNodeStageVolumeErr error
NodeStageVolumeCallCount int64
NextNodeUnstageVolumeErr error
NodeUnstageVolumeCallCount int64
PrevVolumeCapability *csi.VolumeCapability
NextNodePublishVolumeErr error
NodePublishVolumeCallCount int64
NextNodeUnpublishVolumeErr error
NodeUnpublishVolumeCallCount int64
}
// PluginInfo describes the type and version of a plugin.
func (c *Client) PluginInfo() (*base.PluginInfoResponse, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.PluginInfoCallCount++
return c.NextPluginInfoResponse, c.NextPluginInfoErr
}
// ConfigSchema returns the schema for parsing the plugins configuration.
func (c *Client) ConfigSchema() (*hclspec.Spec, error) {
return nil, errors.New("Unsupported")
}
// SetConfig is used to set the configuration by passing a MessagePack
// encoding of it.
func (c *Client) SetConfig(a *base.Config) error {
return errors.New("Unsupported")
}
// PluginProbe is used to verify that the plugin is in a healthy state
func (c *Client) PluginProbe(ctx context.Context) (bool, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.PluginProbeCallCount++
return c.NextPluginProbeResponse, c.NextPluginProbeErr
}
// PluginGetInfo is used to return semantic data about the plugin.
// Response:
// - string: name, the name of the plugin in domain notation format.
func (c *Client) PluginGetInfo(ctx context.Context) (string, string, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.PluginGetInfoCallCount++
return c.NextPluginGetInfoNameResponse, c.NextPluginGetInfoVersionResponse, c.NextPluginGetInfoErr
}
// PluginGetCapabilities is used to return the available capabilities from the
// identity service. This currently only looks for the CONTROLLER_SERVICE and
// Accessible Topology Support
func (c *Client) PluginGetCapabilities(ctx context.Context) (*csi.PluginCapabilitySet, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.PluginGetCapabilitiesCallCount++
return c.NextPluginGetCapabilitiesResponse, c.NextPluginGetCapabilitiesErr
}
func (c *Client) ControllerGetCapabilities(ctx context.Context) (*csi.ControllerCapabilitySet, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.ControllerGetCapabilitiesCallCount++
return c.NextControllerGetCapabilitiesResponse, c.NextControllerGetCapabilitiesErr
}
// ControllerPublishVolume is used to attach a remote volume to a node
func (c *Client) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest, opts ...grpc.CallOption) (*csi.ControllerPublishVolumeResponse, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.ControllerPublishVolumeCallCount++
return c.NextControllerPublishVolumeResponse, c.NextControllerPublishVolumeErr
}
// ControllerUnpublishVolume is used to attach a remote volume to a node
func (c *Client) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest, opts ...grpc.CallOption) (*csi.ControllerUnpublishVolumeResponse, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.ControllerUnpublishVolumeCallCount++
return c.NextControllerUnpublishVolumeResponse, c.NextControllerUnpublishVolumeErr
}
func (c *Client) ControllerValidateCapabilities(ctx context.Context, volumeID string, capabilities *csi.VolumeCapability, opts ...grpc.CallOption) error {
c.Mu.Lock()
defer c.Mu.Unlock()
c.ControllerValidateVolumeCallCount++
return c.NextControllerValidateVolumeErr
}
func (c *Client) NodeGetCapabilities(ctx context.Context) (*csi.NodeCapabilitySet, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.NodeGetCapabilitiesCallCount++
return c.NextNodeGetCapabilitiesResponse, c.NextNodeGetCapabilitiesErr
}
// NodeGetInfo is used to return semantic data about the current node in
// respect to the SP.
func (c *Client) NodeGetInfo(ctx context.Context) (*csi.NodeGetInfoResponse, error) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.NodeGetInfoCallCount++
return c.NextNodeGetInfoResponse, c.NextNodeGetInfoErr
}
// NodeStageVolume is used when a plugin has the STAGE_UNSTAGE volume capability
// to prepare a volume for usage on a host. If err == nil, the response should
// be assumed to be successful.
func (c *Client) NodeStageVolume(ctx context.Context, volumeID string, publishContext map[string]string, stagingTargetPath string, capabilities *csi.VolumeCapability, opts ...grpc.CallOption) error {
c.Mu.Lock()
defer c.Mu.Unlock()
c.NodeStageVolumeCallCount++
return c.NextNodeStageVolumeErr
}
// NodeUnstageVolume is used when a plugin has the STAGE_UNSTAGE volume capability
// to undo the work performed by NodeStageVolume. If a volume has been staged,
// this RPC must be called before freeing the volume.
//
// If err == nil, the response should be assumed to be successful.
func (c *Client) NodeUnstageVolume(ctx context.Context, volumeID string, stagingTargetPath string, opts ...grpc.CallOption) error {
c.Mu.Lock()
defer c.Mu.Unlock()
c.NodeUnstageVolumeCallCount++
return c.NextNodeUnstageVolumeErr
}
func (c *Client) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest, opts ...grpc.CallOption) error {
c.Mu.Lock()
defer c.Mu.Unlock()
c.PrevVolumeCapability = req.VolumeCapability
c.NodePublishVolumeCallCount++
return c.NextNodePublishVolumeErr
}
func (c *Client) NodeUnpublishVolume(ctx context.Context, volumeID, targetPath string, opts ...grpc.CallOption) error {
c.Mu.Lock()
defer c.Mu.Unlock()
c.NodeUnpublishVolumeCallCount++
return c.NextNodeUnpublishVolumeErr
}
// Shutdown the client and ensure any connections are cleaned up.
func (c *Client) Close() error {
c.NextPluginInfoResponse = nil
c.NextPluginInfoErr = fmt.Errorf("closed client")
c.NextPluginProbeResponse = false
c.NextPluginProbeErr = fmt.Errorf("closed client")
c.NextPluginGetInfoNameResponse = ""
c.NextPluginGetInfoVersionResponse = ""
c.NextPluginGetInfoErr = fmt.Errorf("closed client")
c.NextPluginGetCapabilitiesResponse = nil
c.NextPluginGetCapabilitiesErr = fmt.Errorf("closed client")
c.NextControllerGetCapabilitiesResponse = nil
c.NextControllerGetCapabilitiesErr = fmt.Errorf("closed client")
c.NextControllerPublishVolumeResponse = nil
c.NextControllerPublishVolumeErr = fmt.Errorf("closed client")
c.NextControllerUnpublishVolumeResponse = nil
c.NextControllerUnpublishVolumeErr = fmt.Errorf("closed client")
c.NextControllerValidateVolumeErr = fmt.Errorf("closed client")
c.NextNodeGetCapabilitiesResponse = nil
c.NextNodeGetCapabilitiesErr = fmt.Errorf("closed client")
c.NextNodeGetInfoResponse = nil
c.NextNodeGetInfoErr = fmt.Errorf("closed client")
c.NextNodeStageVolumeErr = fmt.Errorf("closed client")
c.NextNodeUnstageVolumeErr = fmt.Errorf("closed client")
c.NextNodePublishVolumeErr = fmt.Errorf("closed client")
c.NextNodeUnpublishVolumeErr = fmt.Errorf("closed client")
return nil
}