Files
nomad/api/host_volumes.go
Daniel Bennett 5826e92671 dynamic host volumes: delete by single volume ID (#24606)
string instead of []string
2024-12-19 09:25:54 -05:00

249 lines
8.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package api
import "net/url"
// HostVolume represents a Dynamic Host Volume: a volume associated with a
// specific Nomad client agent but created via API.
type HostVolume struct {
// Namespace is the Nomad namespace for the host volume, which constrains
// which jobs can mount it.
Namespace string `mapstructure:"namespace" hcl:"namespace"`
// ID is a UUID-like string generated by the server.
ID string `mapstructure:"id" hcl:"id"`
// Name is the name that group.volume will use to identify the volume
// source. Not expected to be unique.
Name string `mapstructure:"name" hcl:"name"`
// PluginID is the name of the host volume plugin on the client that will be
// used for creating the volume. If omitted, the client will use its default
// built-in plugin.
PluginID string `mapstructure:"plugin_id" hcl:"plugin_id"`
// NodePool is the node pool of the node where the volume is placed. If the
// user doesn't provide a node ID, a node will be selected using the
// NodePool and Constraints. If the user provides both NodePool and NodeID,
// NodePool will be used to validate the request. If omitted, the server
// will populate this value in before writing the volume to Raft.
NodePool string `mapstructure:"node_pool" hcl:"node_pool"`
// NodeID is the node where the volume is placed. If the user doesn't
// provide a NodeID, one will be selected using the NodePool and
// Constraints. If omitted, this field will then be populated by the server
// before writing the volume to Raft.
NodeID string `mapstructure:"node_id" hcl:"node_id"`
// Constraints are optional. If the NodeID is not provided, the NodePool and
// Constraints are used to select a node. If the NodeID is provided,
// Constraints are used to validate that the node meets those constraints at
// the time of volume creation.
Constraints []*Constraint `json:",omitempty" hcl:"constraint"`
// Because storage may allow only specific intervals of size, we accept a
// min and max and return the actual capacity when the volume is created or
// updated on the client
RequestedCapacityMinBytes int64 `mapstructure:"capacity_min" hcl:"capacity_min"`
RequestedCapacityMaxBytes int64 `mapstructure:"capacity_max" hcl:"capacity_max"`
CapacityBytes int64
// RequestedCapabilities defines the options available to group.volume
// blocks. The scheduler checks against the listed capability blocks and
// selects a node for placement if *any* capability block works.
RequestedCapabilities []*HostVolumeCapability `hcl:"capability"`
// Parameters are an opaque map of parameters for the host volume plugin.
Parameters map[string]string `json:",omitempty"`
// HostPath is the path on disk where the volume's mount point was
// created. We record this to make debugging easier.
HostPath string `mapstructure:"host_path" hcl:"host_path"`
// State represents the overall state of the volume. One of pending, ready,
// deleted.
State HostVolumeState
CreateIndex uint64
CreateTime int64
ModifyIndex uint64
ModifyTime int64
// Allocations is the list of non-client-terminal allocations with claims on
// this host volume. They are denormalized on read and this field will be
// never written to Raft
Allocations []*AllocationListStub `json:",omitempty" mapstructure:"-" hcl:"-"`
}
// HostVolume state reports the current status of the host volume
type HostVolumeState string
const (
HostVolumeStatePending HostVolumeState = "pending"
HostVolumeStateReady HostVolumeState = "ready"
HostVolumeStateDeleted HostVolumeState = "deleted"
)
// HostVolumeCapability is the requested attachment and access mode for a volume
type HostVolumeCapability struct {
AttachmentMode HostVolumeAttachmentMode `mapstructure:"attachment_mode" hcl:"attachment_mode"`
AccessMode HostVolumeAccessMode `mapstructure:"access_mode" hcl:"access_mode"`
}
// HostVolumeAttachmentMode chooses the type of storage API that will be used to
// interact with the device.
type HostVolumeAttachmentMode string
const (
HostVolumeAttachmentModeUnknown HostVolumeAttachmentMode = ""
HostVolumeAttachmentModeBlockDevice HostVolumeAttachmentMode = "block-device"
HostVolumeAttachmentModeFilesystem HostVolumeAttachmentMode = "file-system"
)
// HostVolumeAccessMode indicates how Nomad should make the volume available to
// concurrent allocations.
type HostVolumeAccessMode string
const (
HostVolumeAccessModeUnknown HostVolumeAccessMode = ""
HostVolumeAccessModeSingleNodeReader HostVolumeAccessMode = "single-node-reader-only"
HostVolumeAccessModeSingleNodeWriter HostVolumeAccessMode = "single-node-writer"
HostVolumeAccessModeMultiNodeReader HostVolumeAccessMode = "multi-node-reader-only"
HostVolumeAccessModeMultiNodeSingleWriter HostVolumeAccessMode = "multi-node-single-writer"
HostVolumeAccessModeMultiNodeMultiWriter HostVolumeAccessMode = "multi-node-multi-writer"
)
// HostVolumeStub is used for responses for the List Volumes endpoint
type HostVolumeStub struct {
Namespace string
ID string
Name string
PluginID string
NodePool string
NodeID string
CapacityBytes int64
State HostVolumeState
CreateIndex uint64
CreateTime int64
ModifyIndex uint64
ModifyTime int64
}
// HostVolumes is used to access the host volumes API.
type HostVolumes struct {
client *Client
}
// HostVolumes returns a new handle on the host volumes API.
func (c *Client) HostVolumes() *HostVolumes {
return &HostVolumes{client: c}
}
type HostVolumeCreateRequest struct {
Volume *HostVolume
// PolicyOverride overrides Sentinel soft-mandatory policy enforcement
PolicyOverride bool
}
type HostVolumeRegisterRequest struct {
Volume *HostVolume
// PolicyOverride overrides Sentinel soft-mandatory policy enforcement
PolicyOverride bool
}
type HostVolumeCreateResponse struct {
Volume *HostVolume
Warnings string
}
type HostVolumeRegisterResponse struct {
Volume *HostVolume
Warnings string
}
type HostVolumeListRequest struct {
NodeID string
NodePool string
}
type HostVolumeDeleteRequest struct {
ID string
}
// Create forwards to client agents so a host volume can be created on those
// hosts, and registers the volume with Nomad servers.
func (hv *HostVolumes) Create(req *HostVolumeCreateRequest, opts *WriteOptions) (*HostVolumeCreateResponse, *WriteMeta, error) {
var out *HostVolumeCreateResponse
wm, err := hv.client.put("/v1/volume/host/create", req, &out, opts)
if err != nil {
return nil, wm, err
}
return out, wm, nil
}
// Register registers a host volume that was created out-of-band with the Nomad
// servers.
func (hv *HostVolumes) Register(req *HostVolumeRegisterRequest, opts *WriteOptions) (*HostVolumeRegisterResponse, *WriteMeta, error) {
var out *HostVolumeRegisterResponse
wm, err := hv.client.put("/v1/volume/host/register", req, &out, opts)
if err != nil {
return nil, wm, err
}
return out, wm, nil
}
// Get queries for a single host volume, by ID
func (hv *HostVolumes) Get(id string, opts *QueryOptions) (*HostVolume, *QueryMeta, error) {
var out *HostVolume
path, err := url.JoinPath("/v1/volume/host/", url.PathEscape(id))
if err != nil {
return nil, nil, err
}
qm, err := hv.client.query(path, &out, opts)
if err != nil {
return nil, qm, err
}
return out, qm, nil
}
// List queries for a set of host volumes, by namespace, node, node pool, or
// name prefix.
func (hv *HostVolumes) List(req *HostVolumeListRequest, opts *QueryOptions) ([]*HostVolumeStub, *QueryMeta, error) {
var out []*HostVolumeStub
qv := url.Values{}
qv.Set("type", "host")
if req != nil {
if req.NodeID != "" {
qv.Set("node_id", req.NodeID)
}
if req.NodePool != "" {
qv.Set("node_pool", req.NodePool)
}
}
qm, err := hv.client.query("/v1/volumes?"+qv.Encode(), &out, opts)
if err != nil {
return nil, qm, err
}
return out, qm, nil
}
// Delete deletes a host volume
func (hv *HostVolumes) Delete(req *HostVolumeDeleteRequest, opts *WriteOptions) (*WriteMeta, error) {
path, err := url.JoinPath("/v1/volume/host/", url.PathEscape(req.ID))
if err != nil {
return nil, err
}
wm, err := hv.client.delete(path, nil, nil, opts)
return wm, err
}