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