mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
api: csi
This commit is contained in:
152
api/csi.go
Normal file
152
api/csi.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CSIVolumes is used to query the top level csi volumes
|
||||
type CSIVolumes struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// CSIVolumes returns a handle on the allocs endpoints.
|
||||
func (c *Client) CSIVolumes() *CSIVolumes {
|
||||
return &CSIVolumes{client: c}
|
||||
}
|
||||
|
||||
// List returns all CSI volumes, ignoring driver
|
||||
func (v *CSIVolumes) List(q *QueryOptions) ([]*CSIVolumeListStub, *QueryMeta, error) {
|
||||
var resp []*CSIVolumeListStub
|
||||
qm, err := v.client.query("/v1/csi/volumes", &resp, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sort.Sort(CSIVolumeIndexSort(resp))
|
||||
return resp, qm, nil
|
||||
}
|
||||
|
||||
// DriverList returns all CSI volumes for the specified driver
|
||||
func (v *CSIVolumes) DriverList(driver string) ([]*CSIVolumeListStub, *QueryMeta, error) {
|
||||
return v.List(&QueryOptions{Prefix: driver})
|
||||
}
|
||||
|
||||
// Info is used to retrieve a single allocation.
|
||||
func (v *CSIVolumes) Info(id string, q *QueryOptions) (*CSIVolume, *QueryMeta, error) {
|
||||
var resp CSIVolume
|
||||
qm, err := v.client.query("/v1/csi/volume/"+id, &resp, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &resp, qm, nil
|
||||
}
|
||||
|
||||
func (v *CSIVolumes) Register(vol *CSIVolume, w *WriteOptions) error {
|
||||
req := CSIVolumeRegisterRequest{
|
||||
Volumes: []*CSIVolume{vol},
|
||||
}
|
||||
var resp struct{}
|
||||
_, err := v.client.write("/v1/csi/volume/"+vol.ID, req, &resp, w)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *CSIVolumes) Deregister(id string, w *WriteOptions) error {
|
||||
_, err := v.client.delete("/v1/csi/volume/"+id, nil, w)
|
||||
return err
|
||||
}
|
||||
|
||||
// CSIVolumeAttachmentMode duplicated in nomad/structs/csi.go
|
||||
type CSIVolumeAttachmentMode string
|
||||
|
||||
const (
|
||||
CSIVolumeAttachmentModeUnknown CSIVolumeAttachmentMode = ""
|
||||
CSIVolumeAttachmentModeBlockDevice CSIVolumeAttachmentMode = "block-device"
|
||||
CSIVolumeAttachmentModeFilesystem CSIVolumeAttachmentMode = "file-system"
|
||||
)
|
||||
|
||||
// CSIVolumeAccessMode duplicated in nomad/structs/csi.go
|
||||
type CSIVolumeAccessMode string
|
||||
|
||||
const (
|
||||
CSIVolumeAccessModeUnknown CSIVolumeAccessMode = ""
|
||||
|
||||
CSIVolumeAccessModeSingleNodeReader CSIVolumeAccessMode = "single-node-reader-only"
|
||||
CSIVolumeAccessModeSingleNodeWriter CSIVolumeAccessMode = "single-node-writer"
|
||||
|
||||
CSIVolumeAccessModeMultiNodeReader CSIVolumeAccessMode = "multi-node-reader-only"
|
||||
CSIVolumeAccessModeMultiNodeSingleWriter CSIVolumeAccessMode = "multi-node-single-writer"
|
||||
CSIVolumeAccessModeMultiNodeMultiWriter CSIVolumeAccessMode = "multi-node-multi-writer"
|
||||
)
|
||||
|
||||
// CSIVolume is used for serialization, see also nomad/structs/csi.go
|
||||
type CSIVolume struct {
|
||||
ID string
|
||||
Driver string
|
||||
Namespace string
|
||||
Topologies []*CSITopology
|
||||
AccessMode CSIVolumeAccessMode
|
||||
AttachmentMode CSIVolumeAttachmentMode
|
||||
|
||||
// Combine structs.{Read,Write,Past}Allocs
|
||||
Allocations []*AllocationListStub
|
||||
|
||||
// Healthy is true iff all the denormalized plugin health fields are true, and the
|
||||
// volume has not been marked for garbage collection
|
||||
Healthy bool
|
||||
VolumeGC time.Time
|
||||
ControllerName string
|
||||
ControllerHealthy bool
|
||||
NodeHealthy int
|
||||
NodeExpected int
|
||||
ResourceExhausted time.Time
|
||||
|
||||
CreatedIndex uint64
|
||||
ModifiedIndex uint64
|
||||
}
|
||||
|
||||
type CSIVolumeIndexSort []*CSIVolumeListStub
|
||||
|
||||
func (v CSIVolumeIndexSort) Len() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
func (v CSIVolumeIndexSort) Less(i, j int) bool {
|
||||
return v[i].CreatedIndex > v[j].CreatedIndex
|
||||
}
|
||||
|
||||
func (v CSIVolumeIndexSort) Swap(i, j int) {
|
||||
v[i], v[j] = v[j], v[i]
|
||||
}
|
||||
|
||||
// CSIVolumeListStub omits allocations. See also nomad/structs/csi.go
|
||||
type CSIVolumeListStub struct {
|
||||
ID string
|
||||
Driver string
|
||||
Namespace string
|
||||
Topologies []*CSITopology
|
||||
AccessMode CSIVolumeAccessMode
|
||||
AttachmentMode CSIVolumeAttachmentMode
|
||||
|
||||
// Healthy is true iff all the denormalized plugin health fields are true, and the
|
||||
// volume has not been marked for garbage collection
|
||||
Healthy bool
|
||||
VolumeGC time.Time
|
||||
ControllerName string
|
||||
ControllerHealthy bool
|
||||
NodeHealthy int
|
||||
NodeExpected int
|
||||
ResourceExhausted time.Time
|
||||
|
||||
CreatedIndex uint64
|
||||
ModifiedIndex uint64
|
||||
}
|
||||
|
||||
type CSIVolumeRegisterRequest struct {
|
||||
Volumes []*CSIVolume
|
||||
WriteRequest
|
||||
}
|
||||
|
||||
type CSIVolumeDeregisterRequest struct {
|
||||
VolumeIDs []string
|
||||
WriteRequest
|
||||
}
|
||||
69
api/csi_test.go
Normal file
69
api/csi_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCSIVolumes_CRUD(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, s, root := makeACLClient(t, nil, nil)
|
||||
defer s.Stop()
|
||||
v := c.CSIVolumes()
|
||||
|
||||
// Successful empty result
|
||||
vols, qm, err := v.List(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, qm.LastIndex)
|
||||
assert.Equal(t, 0, len(vols))
|
||||
|
||||
// Authorized QueryOpts. Use the root token to just bypass ACL details
|
||||
opts := &QueryOptions{
|
||||
Region: "global",
|
||||
Namespace: "default",
|
||||
AuthToken: root.SecretID,
|
||||
}
|
||||
|
||||
wpts := &WriteOptions{
|
||||
Region: "global",
|
||||
Namespace: "default",
|
||||
AuthToken: root.SecretID,
|
||||
}
|
||||
|
||||
// Register a volume
|
||||
v.Register(&CSIVolume{
|
||||
ID: "DEADBEEF-63C7-407F-AE82-C99FBEF78FEB",
|
||||
Driver: "minnie",
|
||||
Namespace: "default",
|
||||
AccessMode: CSIVolumeAccessModeMultiNodeSingleWriter,
|
||||
AttachmentMode: CSIVolumeAttachmentModeFilesystem,
|
||||
Topologies: []*CSITopology{{Segments: map[string]string{"foo": "bar"}}},
|
||||
}, wpts)
|
||||
|
||||
// Successful result with volumes
|
||||
vols, qm, err = v.List(opts)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, qm.LastIndex)
|
||||
assert.Equal(t, 1, len(vols))
|
||||
|
||||
// Successful info query
|
||||
vol, qm, err := v.Info("DEADBEEF-63C7-407F-AE82-C99FBEF78FEB", opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "minnie", vol.Driver)
|
||||
assert.Equal(t, "bar", vol.Topologies[0].Segments["foo"])
|
||||
|
||||
// Deregister the volume
|
||||
err = v.Deregister("DEADBEEF-63C7-407F-AE82-C99FBEF78FEB", wpts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Successful empty result
|
||||
vols, qm, err = v.List(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, qm.LastIndex)
|
||||
assert.Equal(t, 0, len(vols))
|
||||
|
||||
// Failed info query
|
||||
vol, qm, err = v.Info("DEADBEEF-63C7-407F-AE82-C99FBEF78FEB", opts)
|
||||
assert.Error(t, err, "missing")
|
||||
}
|
||||
Reference in New Issue
Block a user