2019-12-18 18:14:42 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2020-07-01 16:17:51 +00:00
|
|
|
"fmt"
|
|
|
|
"net/url"
|
2019-12-18 18:14:42 +00:00
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// CSIVolumes is used to query the top level csi volumes
|
|
|
|
type CSIVolumes struct {
|
|
|
|
client *Client
|
|
|
|
}
|
|
|
|
|
2020-01-28 15:28:34 +00:00
|
|
|
// CSIVolumes returns a handle on the CSIVolumes endpoint
|
2019-12-18 18:14:42 +00:00
|
|
|
func (c *Client) CSIVolumes() *CSIVolumes {
|
|
|
|
return &CSIVolumes{client: c}
|
|
|
|
}
|
|
|
|
|
2020-01-28 15:28:34 +00:00
|
|
|
// List returns all CSI volumes
|
2019-12-18 18:14:42 +00:00
|
|
|
func (v *CSIVolumes) List(q *QueryOptions) ([]*CSIVolumeListStub, *QueryMeta, error) {
|
|
|
|
var resp []*CSIVolumeListStub
|
2020-03-12 18:20:40 +00:00
|
|
|
qm, err := v.client.query("/v1/volumes?type=csi", &resp, q)
|
2019-12-18 18:14:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
sort.Sort(CSIVolumeIndexSort(resp))
|
|
|
|
return resp, qm, nil
|
|
|
|
}
|
|
|
|
|
2020-01-28 15:28:34 +00:00
|
|
|
// PluginList returns all CSI volumes for the specified plugin id
|
|
|
|
func (v *CSIVolumes) PluginList(pluginID string) ([]*CSIVolumeListStub, *QueryMeta, error) {
|
|
|
|
return v.List(&QueryOptions{Prefix: pluginID})
|
2019-12-18 18:14:42 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 15:28:34 +00:00
|
|
|
// Info is used to retrieve a single CSIVolume
|
2019-12-18 18:14:42 +00:00
|
|
|
func (v *CSIVolumes) Info(id string, q *QueryOptions) (*CSIVolume, *QueryMeta, error) {
|
|
|
|
var resp CSIVolume
|
2020-03-12 18:20:40 +00:00
|
|
|
qm, err := v.client.query("/v1/volume/csi/"+id, &resp, q)
|
2019-12-18 18:14:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-03-06 15:09:10 +00:00
|
|
|
|
|
|
|
// Cleanup allocation representation for the ui
|
|
|
|
resp.allocs()
|
|
|
|
|
2019-12-18 18:14:42 +00:00
|
|
|
return &resp, qm, nil
|
|
|
|
}
|
|
|
|
|
2020-01-28 15:28:34 +00:00
|
|
|
func (v *CSIVolumes) Register(vol *CSIVolume, w *WriteOptions) (*WriteMeta, error) {
|
2019-12-18 18:14:42 +00:00
|
|
|
req := CSIVolumeRegisterRequest{
|
|
|
|
Volumes: []*CSIVolume{vol},
|
|
|
|
}
|
2020-03-12 18:20:40 +00:00
|
|
|
meta, err := v.client.write("/v1/volume/csi/"+vol.ID, req, nil, w)
|
2020-01-28 15:28:34 +00:00
|
|
|
return meta, err
|
2019-12-18 18:14:42 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 16:17:51 +00:00
|
|
|
func (v *CSIVolumes) Deregister(id string, force bool, w *WriteOptions) error {
|
|
|
|
_, err := v.client.delete(fmt.Sprintf("/v1/volume/csi/%v?purge=%t", url.PathEscape(id), force), nil, w)
|
2019-12-18 18:14:42 +00:00
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
2020-03-23 17:55:26 +00:00
|
|
|
type CSIMountOptions struct {
|
|
|
|
FSType string `hcl:"fs_type"`
|
|
|
|
MountFlags []string `hcl:"mount_flags"`
|
|
|
|
ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"` // report unexpected keys
|
|
|
|
}
|
|
|
|
|
2020-05-11 21:12:51 +00:00
|
|
|
type CSISecrets map[string]string
|
|
|
|
|
2019-12-18 18:14:42 +00:00
|
|
|
// CSIVolume is used for serialization, see also nomad/structs/csi.go
|
|
|
|
type CSIVolume struct {
|
2020-03-23 17:55:26 +00:00
|
|
|
ID string
|
|
|
|
Name string
|
|
|
|
ExternalID string `hcl:"external_id"`
|
|
|
|
Namespace string
|
|
|
|
Topologies []*CSITopology
|
2020-03-06 15:09:10 +00:00
|
|
|
AccessMode CSIVolumeAccessMode `hcl:"access_mode"`
|
|
|
|
AttachmentMode CSIVolumeAttachmentMode `hcl:"attachment_mode"`
|
2020-03-23 17:55:26 +00:00
|
|
|
MountOptions *CSIMountOptions `hcl:"mount_options"`
|
2020-05-11 21:12:51 +00:00
|
|
|
Secrets CSISecrets `hcl:"secrets"`
|
2020-05-15 12:16:01 +00:00
|
|
|
Parameters map[string]string `hcl:"parameters"`
|
|
|
|
Context map[string]string `hcl:"context"`
|
2020-03-06 15:09:10 +00:00
|
|
|
|
|
|
|
// Allocations, tracking claim status
|
|
|
|
ReadAllocs map[string]*Allocation
|
|
|
|
WriteAllocs map[string]*Allocation
|
|
|
|
|
|
|
|
// Combine structs.{Read,Write}Allocs
|
2019-12-18 18:14:42 +00:00
|
|
|
Allocations []*AllocationListStub
|
|
|
|
|
2020-03-06 15:09:10 +00:00
|
|
|
// Schedulable is true if all the denormalized plugin health fields are true
|
2020-03-03 15:59:58 +00:00
|
|
|
Schedulable bool
|
2020-03-06 15:09:10 +00:00
|
|
|
PluginID string `hcl:"plugin_id"`
|
2020-03-09 13:57:59 +00:00
|
|
|
Provider string
|
|
|
|
ProviderVersion string
|
2020-03-03 15:59:58 +00:00
|
|
|
ControllerRequired bool
|
2020-01-28 15:28:34 +00:00
|
|
|
ControllersHealthy int
|
|
|
|
ControllersExpected int
|
|
|
|
NodesHealthy int
|
|
|
|
NodesExpected int
|
|
|
|
ResourceExhausted time.Time
|
|
|
|
|
|
|
|
CreateIndex uint64
|
|
|
|
ModifyIndex uint64
|
2020-03-06 15:09:10 +00:00
|
|
|
|
|
|
|
// ExtraKeysHCL is used by the hcl parser to report unexpected keys
|
|
|
|
ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// allocs is called after we query the volume (creating this CSIVolume struct) to collapse
|
|
|
|
// allocations for the UI
|
|
|
|
func (v *CSIVolume) allocs() {
|
|
|
|
for _, a := range v.WriteAllocs {
|
2020-03-25 13:45:51 +00:00
|
|
|
if a != nil {
|
|
|
|
v.Allocations = append(v.Allocations, a.Stub())
|
|
|
|
}
|
2020-03-06 15:09:10 +00:00
|
|
|
}
|
|
|
|
for _, a := range v.ReadAllocs {
|
2020-03-25 13:45:51 +00:00
|
|
|
if a != nil {
|
|
|
|
v.Allocations = append(v.Allocations, a.Stub())
|
|
|
|
}
|
2020-03-06 15:09:10 +00:00
|
|
|
}
|
2019-12-18 18:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CSIVolumeIndexSort []*CSIVolumeListStub
|
|
|
|
|
|
|
|
func (v CSIVolumeIndexSort) Len() int {
|
|
|
|
return len(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v CSIVolumeIndexSort) Less(i, j int) bool {
|
2020-01-28 15:28:34 +00:00
|
|
|
return v[i].CreateIndex > v[j].CreateIndex
|
2019-12-18 18:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2020-03-03 15:59:58 +00:00
|
|
|
ID string
|
|
|
|
Namespace string
|
|
|
|
Name string
|
|
|
|
ExternalID string
|
|
|
|
Topologies []*CSITopology
|
|
|
|
AccessMode CSIVolumeAccessMode
|
|
|
|
AttachmentMode CSIVolumeAttachmentMode
|
|
|
|
Schedulable bool
|
2020-01-28 15:28:34 +00:00
|
|
|
PluginID string
|
2020-03-09 13:57:59 +00:00
|
|
|
Provider string
|
2020-03-03 15:59:58 +00:00
|
|
|
ControllerRequired bool
|
2020-01-28 15:28:34 +00:00
|
|
|
ControllersHealthy int
|
|
|
|
ControllersExpected int
|
|
|
|
NodesHealthy int
|
|
|
|
NodesExpected int
|
|
|
|
ResourceExhausted time.Time
|
|
|
|
|
|
|
|
CreateIndex uint64
|
|
|
|
ModifyIndex uint64
|
2019-12-18 18:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CSIVolumeRegisterRequest struct {
|
|
|
|
Volumes []*CSIVolume
|
|
|
|
WriteRequest
|
|
|
|
}
|
|
|
|
|
|
|
|
type CSIVolumeDeregisterRequest struct {
|
|
|
|
VolumeIDs []string
|
|
|
|
WriteRequest
|
|
|
|
}
|
2020-01-28 15:28:34 +00:00
|
|
|
|
|
|
|
// CSI Plugins are jobs with plugin specific data
|
|
|
|
type CSIPlugins struct {
|
|
|
|
client *Client
|
|
|
|
}
|
|
|
|
|
|
|
|
type CSIPlugin struct {
|
2020-03-03 15:59:58 +00:00
|
|
|
ID string
|
2020-03-09 13:57:59 +00:00
|
|
|
Provider string
|
|
|
|
Version string
|
2020-03-03 15:59:58 +00:00
|
|
|
ControllerRequired bool
|
2020-02-21 19:48:16 +00:00
|
|
|
// Map Node.ID to CSIInfo fingerprint results
|
2020-05-07 16:37:51 +00:00
|
|
|
Controllers map[string]*CSIInfo
|
|
|
|
Nodes map[string]*CSIInfo
|
|
|
|
Allocations []*AllocationListStub
|
|
|
|
ControllersHealthy int
|
|
|
|
ControllersExpected int
|
|
|
|
NodesHealthy int
|
|
|
|
NodesExpected int
|
|
|
|
CreateIndex uint64
|
|
|
|
ModifyIndex uint64
|
2020-01-28 15:28:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CSIPluginListStub struct {
|
|
|
|
ID string
|
2020-03-09 13:57:59 +00:00
|
|
|
Provider string
|
2020-03-03 15:59:58 +00:00
|
|
|
ControllerRequired bool
|
2020-01-28 15:28:34 +00:00
|
|
|
ControllersHealthy int
|
|
|
|
ControllersExpected int
|
|
|
|
NodesHealthy int
|
|
|
|
NodesExpected int
|
|
|
|
CreateIndex uint64
|
|
|
|
ModifyIndex uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
type CSIPluginIndexSort []*CSIPluginListStub
|
|
|
|
|
|
|
|
func (v CSIPluginIndexSort) Len() int {
|
|
|
|
return len(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v CSIPluginIndexSort) Less(i, j int) bool {
|
|
|
|
return v[i].CreateIndex > v[j].CreateIndex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v CSIPluginIndexSort) Swap(i, j int) {
|
|
|
|
v[i], v[j] = v[j], v[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
// CSIPlugins returns a handle on the CSIPlugins endpoint
|
|
|
|
func (c *Client) CSIPlugins() *CSIPlugins {
|
|
|
|
return &CSIPlugins{client: c}
|
|
|
|
}
|
|
|
|
|
|
|
|
// List returns all CSI plugins
|
|
|
|
func (v *CSIPlugins) List(q *QueryOptions) ([]*CSIPluginListStub, *QueryMeta, error) {
|
|
|
|
var resp []*CSIPluginListStub
|
2020-03-12 18:20:40 +00:00
|
|
|
qm, err := v.client.query("/v1/plugins?type=csi", &resp, q)
|
2020-01-28 15:28:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
sort.Sort(CSIPluginIndexSort(resp))
|
|
|
|
return resp, qm, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Info is used to retrieve a single CSI Plugin Job
|
|
|
|
func (v *CSIPlugins) Info(id string, q *QueryOptions) (*CSIPlugin, *QueryMeta, error) {
|
|
|
|
var resp *CSIPlugin
|
2020-03-12 18:20:40 +00:00
|
|
|
qm, err := v.client.query("/v1/plugin/csi/"+id, &resp, q)
|
2020-01-28 15:28:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return resp, qm, nil
|
|
|
|
}
|