forked from linode/linodego
-
Notifications
You must be signed in to change notification settings - Fork 0
/
volumes.go
238 lines (201 loc) · 7.03 KB
/
volumes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package linodego
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/go-resty/resty/v2"
"github.com/linode/linodego/internal/parseabletime"
)
// VolumeStatus indicates the status of the Volume
type VolumeStatus string
const (
// VolumeCreating indicates the Volume is being created and is not yet available for use
VolumeCreating VolumeStatus = "creating"
// VolumeActive indicates the Volume is online and available for use
VolumeActive VolumeStatus = "active"
// VolumeResizing indicates the Volume is in the process of upgrading its current capacity
VolumeResizing VolumeStatus = "resizing"
// VolumeContactSupport indicates there is a problem with the Volume. A support ticket must be opened to resolve the issue
VolumeContactSupport VolumeStatus = "contact_support"
)
// Volume represents a linode volume object
type Volume struct {
ID int `json:"id"`
Label string `json:"label"`
Status VolumeStatus `json:"status"`
Region string `json:"region"`
Size int `json:"size"`
LinodeID *int `json:"linode_id"`
FilesystemPath string `json:"filesystem_path"`
Tags []string `json:"tags"`
Created *time.Time `json:"-"`
Updated *time.Time `json:"-"`
}
// VolumeCreateOptions fields are those accepted by CreateVolume
type VolumeCreateOptions struct {
Label string `json:"label,omitempty"`
Region string `json:"region,omitempty"`
LinodeID int `json:"linode_id,omitempty"`
ConfigID int `json:"config_id,omitempty"`
// The Volume's size, in GiB. Minimum size is 10GiB, maximum size is 10240GiB. A "0" value will result in the default size.
Size int `json:"size,omitempty"`
// An array of tags applied to this object. Tags are for organizational purposes only.
Tags []string `json:"tags"`
PersistAcrossBoots *bool `json:"persist_across_boots,omitempty"`
}
// VolumeUpdateOptions fields are those accepted by UpdateVolume
type VolumeUpdateOptions struct {
Label string `json:"label,omitempty"`
Tags *[]string `json:"tags,omitempty"`
}
// VolumeAttachOptions fields are those accepted by AttachVolume
type VolumeAttachOptions struct {
LinodeID int `json:"linode_id"`
ConfigID int `json:"config_id,omitempty"`
PersistAcrossBoots *bool `json:"persist_across_boots,omitempty"`
}
// VolumesPagedResponse represents a linode API response for listing of volumes
type VolumesPagedResponse struct {
*PageOptions
Data []Volume `json:"data"`
}
// UnmarshalJSON implements the json.Unmarshaler interface
func (v *Volume) UnmarshalJSON(b []byte) error {
type Mask Volume
p := struct {
*Mask
Created *parseabletime.ParseableTime `json:"created"`
Updated *parseabletime.ParseableTime `json:"updated"`
}{
Mask: (*Mask)(v),
}
if err := json.Unmarshal(b, &p); err != nil {
return err
}
v.Created = (*time.Time)(p.Created)
v.Updated = (*time.Time)(p.Updated)
return nil
}
// GetUpdateOptions converts a Volume to VolumeUpdateOptions for use in UpdateVolume
func (v Volume) GetUpdateOptions() (updateOpts VolumeUpdateOptions) {
updateOpts.Label = v.Label
updateOpts.Tags = &v.Tags
return
}
// GetCreateOptions converts a Volume to VolumeCreateOptions for use in CreateVolume
func (v Volume) GetCreateOptions() (createOpts VolumeCreateOptions) {
createOpts.Label = v.Label
createOpts.Tags = v.Tags
createOpts.Region = v.Region
createOpts.Size = v.Size
if v.LinodeID != nil && *v.LinodeID > 0 {
createOpts.LinodeID = *v.LinodeID
}
return
}
// endpoint gets the endpoint URL for Volume
func (VolumesPagedResponse) endpoint(_ ...any) string {
return "volumes"
}
func (resp *VolumesPagedResponse) castResult(r *resty.Request, e string) (int, int, error) {
res, err := coupleAPIErrors(r.SetResult(VolumesPagedResponse{}).Get(e))
if err != nil {
return 0, 0, err
}
castedRes := res.Result().(*VolumesPagedResponse)
resp.Data = append(resp.Data, castedRes.Data...)
return castedRes.Pages, castedRes.Results, nil
}
// ListVolumes lists Volumes
func (c *Client) ListVolumes(ctx context.Context, opts *ListOptions) ([]Volume, error) {
response := VolumesPagedResponse{}
err := c.listHelper(ctx, &response, opts)
if err != nil {
return nil, err
}
return response.Data, nil
}
// GetVolume gets the template with the provided ID
func (c *Client) GetVolume(ctx context.Context, volumeID int) (*Volume, error) {
e := fmt.Sprintf("volumes/%d", volumeID)
req := c.R(ctx).SetResult(&Volume{})
r, err := coupleAPIErrors(req.Get(e))
if err != nil {
return nil, err
}
return r.Result().(*Volume), nil
}
// AttachVolume attaches a volume to a Linode instance
func (c *Client) AttachVolume(ctx context.Context, volumeID int, opts *VolumeAttachOptions) (*Volume, error) {
body, err := json.Marshal(opts)
if err != nil {
return nil, err
}
e := fmt.Sprintf("volumes/%d/attach", volumeID)
req := c.R(ctx).SetResult(&Volume{}).SetBody(string(body))
resp, err := coupleAPIErrors(req.Post(e))
if err != nil {
return nil, err
}
return resp.Result().(*Volume), nil
}
// CreateVolume creates a Linode Volume
func (c *Client) CreateVolume(ctx context.Context, opts VolumeCreateOptions) (*Volume, error) {
body, err := json.Marshal(opts)
if err != nil {
return nil, err
}
e := "volumes"
req := c.R(ctx).SetResult(&Volume{}).SetBody(string(body))
resp, err := coupleAPIErrors(req.Post(e))
if err != nil {
return nil, err
}
return resp.Result().(*Volume), nil
}
// UpdateVolume updates the Volume with the specified id
func (c *Client) UpdateVolume(ctx context.Context, volumeID int, opts VolumeUpdateOptions) (*Volume, error) {
body, err := json.Marshal(opts)
if err != nil {
return nil, NewError(err)
}
e := fmt.Sprintf("volumes/%d", volumeID)
req := c.R(ctx).SetResult(&Volume{}).SetBody(string(body))
r, err := coupleAPIErrors(req.Put(e))
if err != nil {
return nil, err
}
return r.Result().(*Volume), nil
}
// CloneVolume clones a Linode volume
func (c *Client) CloneVolume(ctx context.Context, volumeID int, label string) (*Volume, error) {
body := fmt.Sprintf("{\"label\":\"%s\"}", label)
e := fmt.Sprintf("volumes/%d/clone", volumeID)
req := c.R(ctx).SetResult(&Volume{}).SetBody(body)
resp, err := coupleAPIErrors(req.Post(e))
if err != nil {
return nil, err
}
return resp.Result().(*Volume), nil
}
// DetachVolume detaches a Linode volume
func (c *Client) DetachVolume(ctx context.Context, volumeID int) error {
body := ""
e := fmt.Sprintf("volumes/%d/detach", volumeID)
_, err := coupleAPIErrors(c.R(ctx).SetBody(body).Post(e))
return err
}
// ResizeVolume resizes an instance to new Linode type
func (c *Client) ResizeVolume(ctx context.Context, volumeID int, size int) error {
body := fmt.Sprintf("{\"size\": %d}", size)
e := fmt.Sprintf("volumes/%d/resize", volumeID)
_, err := coupleAPIErrors(c.R(ctx).SetBody(body).Post(e))
return err
}
// DeleteVolume deletes the Volume with the specified id
func (c *Client) DeleteVolume(ctx context.Context, volumeID int) error {
e := fmt.Sprintf("volumes/%d", volumeID)
_, err := coupleAPIErrors(c.R(ctx).Delete(e))
return err
}