1package api
2
3import (
4	"encoding/json"
5	"fmt"
6	"net/http"
7	"net/url"
8)
9
10// Volume represents a  Volume
11type Volume struct {
12	// Identifier is a unique identifier for the volume
13	Identifier string `json:"id,omitempty"`
14
15	// Size is the allocated size of the volume
16	Size uint64 `json:"size,omitempty"`
17
18	// CreationDate is the creation date of the volume
19	CreationDate string `json:"creation_date,omitempty"`
20
21	// ModificationDate is the date of the last modification of the volume
22	ModificationDate string `json:"modification_date,omitempty"`
23
24	// Organization is the organization owning the volume
25	Organization string `json:"organization,omitempty"`
26
27	// Name is the name of the volume
28	Name string `json:"name,omitempty"`
29
30	// Server is the server using this image
31	Server *struct {
32		Identifier string `json:"id,omitempty"`
33		Name       string `json:"name,omitempty"`
34	} `json:"server,omitempty"`
35
36	// VolumeType is a  identifier for the kind of volume (default: l_ssd)
37	VolumeType string `json:"volume_type,omitempty"`
38
39	// ExportURI represents the url used by initrd/scripts to attach the volume
40	ExportURI string `json:"export_uri,omitempty"`
41}
42
43type volumeResponse struct {
44	Volume Volume `json:"volume,omitempty"`
45}
46
47// VolumeDefinition represents a  volume definition
48type VolumeDefinition struct {
49	// Name is the user-defined name of the volume
50	Name string `json:"name"`
51
52	// Image is the image used by the volume
53	Size uint64 `json:"size"`
54
55	// Bootscript is the bootscript used by the volume
56	Type string `json:"volume_type"`
57
58	// Organization is the owner of the volume
59	Organization string `json:"organization"`
60}
61
62// VolumePutDefinition represents a  volume with nullable fields (for PUT)
63type VolumePutDefinition struct {
64	Identifier       *string `json:"id,omitempty"`
65	Size             *uint64 `json:"size,omitempty"`
66	CreationDate     *string `json:"creation_date,omitempty"`
67	ModificationDate *string `json:"modification_date,omitempty"`
68	Organization     *string `json:"organization,omitempty"`
69	Name             *string `json:"name,omitempty"`
70	Server           struct {
71		Identifier *string `json:"id,omitempty"`
72		Name       *string `json:"name,omitempty"`
73	} `json:"server,omitempty"`
74	VolumeType *string `json:"volume_type,omitempty"`
75	ExportURI  *string `json:"export_uri,omitempty"`
76}
77
78// CreateVolume creates a new volume
79func (s *API) CreateVolume(definition VolumeDefinition) (*Volume, error) {
80	definition.Organization = s.Organization
81	if definition.Type == "" {
82		definition.Type = "l_ssd"
83	}
84
85	resp, err := s.PostResponse(s.computeAPI, "volumes", definition)
86	if err != nil {
87		return nil, err
88	}
89	defer resp.Body.Close()
90
91	body, err := s.handleHTTPError([]int{http.StatusCreated}, resp)
92	if err != nil {
93		return nil, err
94	}
95	var volume volumeResponse
96
97	if err = json.Unmarshal(body, &volume); err != nil {
98		return nil, err
99	}
100	return &volume.Volume, nil
101}
102
103// UpdateVolume updates a volume
104func (s *API) UpdateVolume(volumeID string, definition VolumePutDefinition) (*Volume, error) {
105	resp, err := s.PutResponse(s.computeAPI, fmt.Sprintf("volumes/%s", volumeID), definition)
106	if err != nil {
107		return nil, err
108	}
109	defer resp.Body.Close()
110
111	body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
112	if err != nil {
113		return nil, err
114	}
115	var volume volumeResponse
116
117	if err = json.Unmarshal(body, &volume); err != nil {
118		return nil, err
119	}
120	return &volume.Volume, nil
121}
122
123// DeleteVolume deletes a volume
124func (s *API) DeleteVolume(volumeID string) error {
125	resp, err := s.DeleteResponse(s.computeAPI, fmt.Sprintf("volumes/%s", volumeID))
126	if err != nil {
127		return err
128	}
129	defer resp.Body.Close()
130
131	if _, err := s.handleHTTPError([]int{http.StatusNoContent}, resp); err != nil {
132		return err
133	}
134	return nil
135}
136
137type volumesResponse struct {
138	Volumes []Volume `json:"volumes,omitempty"`
139}
140
141// GetVolumes gets the list of volumes from the API
142func (s *API) GetVolumes() (*[]Volume, error) {
143	query := url.Values{}
144
145	resp, err := s.GetResponsePaginate(s.computeAPI, "volumes", query)
146	if err != nil {
147		return nil, err
148	}
149	defer resp.Body.Close()
150
151	body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
152	if err != nil {
153		return nil, err
154	}
155
156	var volumes volumesResponse
157
158	if err = json.Unmarshal(body, &volumes); err != nil {
159		return nil, err
160	}
161	return &volumes.Volumes, nil
162}
163
164// GetVolume gets a volume from the API
165func (s *API) GetVolume(volumeID string) (*Volume, error) {
166	resp, err := s.GetResponsePaginate(s.computeAPI, "volumes/"+volumeID, url.Values{})
167	if err != nil {
168		return nil, err
169	}
170	defer resp.Body.Close()
171
172	body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
173	if err != nil {
174		return nil, err
175	}
176	var volume volumeResponse
177
178	if err = json.Unmarshal(body, &volume); err != nil {
179		return nil, err
180	}
181	// FIXME region, arch, owner, title
182	return &volume.Volume, nil
183}
184