volumes.go raw

   1  package linodego
   2  
   3  import (
   4  	"context"
   5  	"encoding/json"
   6  	"time"
   7  
   8  	"github.com/linode/linodego/internal/parseabletime"
   9  )
  10  
  11  // VolumeStatus indicates the status of the Volume
  12  type VolumeStatus string
  13  
  14  const (
  15  	// VolumeCreating indicates the Volume is being created and is not yet available for use
  16  	VolumeCreating VolumeStatus = "creating"
  17  
  18  	// VolumeActive indicates the Volume is online and available for use
  19  	VolumeActive VolumeStatus = "active"
  20  
  21  	// VolumeResizing indicates the Volume is in the process of upgrading its current capacity
  22  	VolumeResizing VolumeStatus = "resizing"
  23  
  24  	// VolumeContactSupport indicates there is a problem with the Volume. A support ticket must be opened to resolve the issue
  25  	VolumeContactSupport VolumeStatus = "contact_support"
  26  )
  27  
  28  // Volume represents a linode volume object
  29  type Volume struct {
  30  	ID             int          `json:"id"`
  31  	Label          string       `json:"label"`
  32  	Status         VolumeStatus `json:"status"`
  33  	Region         string       `json:"region"`
  34  	Size           int          `json:"size"`
  35  	LinodeID       *int         `json:"linode_id"`
  36  	FilesystemPath string       `json:"filesystem_path"`
  37  	Tags           []string     `json:"tags"`
  38  	HardwareType   string       `json:"hardware_type"`
  39  	LinodeLabel    string       `json:"linode_label"`
  40  	IOReady        bool         `json:"io_ready"`
  41  	Created        *time.Time   `json:"-"`
  42  	Updated        *time.Time   `json:"-"`
  43  
  44  	// Note: Block Storage Disk Encryption is not currently available to all users.
  45  	Encryption string `json:"encryption"`
  46  }
  47  
  48  // VolumeCreateOptions fields are those accepted by CreateVolume
  49  type VolumeCreateOptions struct {
  50  	Label    string `json:"label,omitempty"`
  51  	Region   string `json:"region,omitempty"`
  52  	LinodeID int    `json:"linode_id,omitempty"`
  53  	ConfigID int    `json:"config_id,omitempty"`
  54  	// The Volume's size, in GiB. Minimum size is 10GiB, maximum size is 10240GiB. A "0" value will result in the default size.
  55  	Size int `json:"size,omitempty"`
  56  	// An array of tags applied to this object. Tags are for organizational purposes only.
  57  	Tags               []string `json:"tags"`
  58  	PersistAcrossBoots *bool    `json:"persist_across_boots,omitempty"`
  59  	Encryption         string   `json:"encryption,omitempty"`
  60  }
  61  
  62  // VolumeUpdateOptions fields are those accepted by UpdateVolume
  63  type VolumeUpdateOptions struct {
  64  	Label string    `json:"label,omitempty"`
  65  	Tags  *[]string `json:"tags,omitempty"`
  66  }
  67  
  68  // VolumeAttachOptions fields are those accepted by AttachVolume
  69  type VolumeAttachOptions struct {
  70  	LinodeID           int   `json:"linode_id"`
  71  	ConfigID           int   `json:"config_id,omitempty"`
  72  	PersistAcrossBoots *bool `json:"persist_across_boots,omitempty"`
  73  }
  74  
  75  // UnmarshalJSON implements the json.Unmarshaler interface
  76  func (v *Volume) UnmarshalJSON(b []byte) error {
  77  	type Mask Volume
  78  
  79  	p := struct {
  80  		*Mask
  81  
  82  		Created *parseabletime.ParseableTime `json:"created"`
  83  		Updated *parseabletime.ParseableTime `json:"updated"`
  84  	}{
  85  		Mask: (*Mask)(v),
  86  	}
  87  
  88  	if err := json.Unmarshal(b, &p); err != nil {
  89  		return err
  90  	}
  91  
  92  	v.Created = (*time.Time)(p.Created)
  93  	v.Updated = (*time.Time)(p.Updated)
  94  
  95  	return nil
  96  }
  97  
  98  // GetUpdateOptions converts a Volume to VolumeUpdateOptions for use in UpdateVolume
  99  func (v Volume) GetUpdateOptions() (updateOpts VolumeUpdateOptions) {
 100  	updateOpts.Label = v.Label
 101  	updateOpts.Tags = &v.Tags
 102  
 103  	return updateOpts
 104  }
 105  
 106  // GetCreateOptions converts a Volume to VolumeCreateOptions for use in CreateVolume
 107  func (v Volume) GetCreateOptions() (createOpts VolumeCreateOptions) {
 108  	createOpts.Label = v.Label
 109  	createOpts.Tags = v.Tags
 110  	createOpts.Region = v.Region
 111  
 112  	createOpts.Size = v.Size
 113  	if v.LinodeID != nil && *v.LinodeID > 0 {
 114  		createOpts.LinodeID = *v.LinodeID
 115  	}
 116  
 117  	return createOpts
 118  }
 119  
 120  // ListVolumes lists Volumes
 121  func (c *Client) ListVolumes(ctx context.Context, opts *ListOptions) ([]Volume, error) {
 122  	return getPaginatedResults[Volume](ctx, c, "volumes", opts)
 123  }
 124  
 125  // GetVolume gets the template with the provided ID
 126  func (c *Client) GetVolume(ctx context.Context, volumeID int) (*Volume, error) {
 127  	e := formatAPIPath("volumes/%d", volumeID)
 128  	return doGETRequest[Volume](ctx, c, e)
 129  }
 130  
 131  // AttachVolume attaches a volume to a Linode instance
 132  func (c *Client) AttachVolume(ctx context.Context, volumeID int, opts *VolumeAttachOptions) (*Volume, error) {
 133  	e := formatAPIPath("volumes/%d/attach", volumeID)
 134  	return doPOSTRequest[Volume](ctx, c, e, opts)
 135  }
 136  
 137  // CreateVolume creates a Linode Volume
 138  func (c *Client) CreateVolume(ctx context.Context, opts VolumeCreateOptions) (*Volume, error) {
 139  	return doPOSTRequest[Volume](ctx, c, "volumes", opts)
 140  }
 141  
 142  // UpdateVolume updates the Volume with the specified id
 143  func (c *Client) UpdateVolume(ctx context.Context, volumeID int, opts VolumeUpdateOptions) (*Volume, error) {
 144  	e := formatAPIPath("volumes/%d", volumeID)
 145  	return doPUTRequest[Volume](ctx, c, e, opts)
 146  }
 147  
 148  // CloneVolume clones a Linode volume
 149  func (c *Client) CloneVolume(ctx context.Context, volumeID int, label string) (*Volume, error) {
 150  	opts := map[string]any{
 151  		"label": label,
 152  	}
 153  
 154  	e := formatAPIPath("volumes/%d/clone", volumeID)
 155  
 156  	return doPOSTRequest[Volume](ctx, c, e, opts)
 157  }
 158  
 159  // DetachVolume detaches a Linode volume
 160  func (c *Client) DetachVolume(ctx context.Context, volumeID int) error {
 161  	e := formatAPIPath("volumes/%d/detach", volumeID)
 162  	return doPOSTRequestNoRequestResponseBody(ctx, c, e)
 163  }
 164  
 165  // ResizeVolume resizes an instance to new Linode type
 166  func (c *Client) ResizeVolume(ctx context.Context, volumeID int, size int) error {
 167  	opts := map[string]int{
 168  		"size": size,
 169  	}
 170  
 171  	e := formatAPIPath("volumes/%d/resize", volumeID)
 172  
 173  	return doPOSTRequestNoResponseBody(ctx, c, e, opts)
 174  }
 175  
 176  // DeleteVolume deletes the Volume with the specified id
 177  func (c *Client) DeleteVolume(ctx context.Context, volumeID int) error {
 178  	e := formatAPIPath("volumes/%d", volumeID)
 179  	return doDELETERequest(ctx, c, e)
 180  }
 181