2018-04-30 15:47:39 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
)
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// Volume represents a Volume
|
|
|
|
type Volume struct {
|
2018-04-30 15:47:39 +00:00
|
|
|
// Identifier is a unique identifier for the volume
|
|
|
|
Identifier string `json:"id,omitempty"`
|
|
|
|
|
|
|
|
// Size is the allocated size of the volume
|
|
|
|
Size uint64 `json:"size,omitempty"`
|
|
|
|
|
|
|
|
// CreationDate is the creation date of the volume
|
|
|
|
CreationDate string `json:"creation_date,omitempty"`
|
|
|
|
|
|
|
|
// ModificationDate is the date of the last modification of the volume
|
|
|
|
ModificationDate string `json:"modification_date,omitempty"`
|
|
|
|
|
|
|
|
// Organization is the organization owning the volume
|
|
|
|
Organization string `json:"organization,omitempty"`
|
|
|
|
|
|
|
|
// Name is the name of the volume
|
|
|
|
Name string `json:"name,omitempty"`
|
|
|
|
|
|
|
|
// Server is the server using this image
|
|
|
|
Server *struct {
|
|
|
|
Identifier string `json:"id,omitempty"`
|
|
|
|
Name string `json:"name,omitempty"`
|
|
|
|
} `json:"server,omitempty"`
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// VolumeType is a identifier for the kind of volume (default: l_ssd)
|
2018-04-30 15:47:39 +00:00
|
|
|
VolumeType string `json:"volume_type,omitempty"`
|
|
|
|
|
|
|
|
// ExportURI represents the url used by initrd/scripts to attach the volume
|
|
|
|
ExportURI string `json:"export_uri,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type volumeResponse struct {
|
2019-12-02 20:37:43 +00:00
|
|
|
Volume Volume `json:"volume,omitempty"`
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// VolumeDefinition represents a volume definition
|
|
|
|
type VolumeDefinition struct {
|
2018-04-30 15:47:39 +00:00
|
|
|
// Name is the user-defined name of the volume
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
|
|
|
// Image is the image used by the volume
|
|
|
|
Size uint64 `json:"size"`
|
|
|
|
|
|
|
|
// Bootscript is the bootscript used by the volume
|
|
|
|
Type string `json:"volume_type"`
|
|
|
|
|
|
|
|
// Organization is the owner of the volume
|
|
|
|
Organization string `json:"organization"`
|
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// VolumePutDefinition represents a volume with nullable fields (for PUT)
|
|
|
|
type VolumePutDefinition struct {
|
2018-04-30 15:47:39 +00:00
|
|
|
Identifier *string `json:"id,omitempty"`
|
|
|
|
Size *uint64 `json:"size,omitempty"`
|
|
|
|
CreationDate *string `json:"creation_date,omitempty"`
|
|
|
|
ModificationDate *string `json:"modification_date,omitempty"`
|
|
|
|
Organization *string `json:"organization,omitempty"`
|
|
|
|
Name *string `json:"name,omitempty"`
|
|
|
|
Server struct {
|
|
|
|
Identifier *string `json:"id,omitempty"`
|
|
|
|
Name *string `json:"name,omitempty"`
|
|
|
|
} `json:"server,omitempty"`
|
|
|
|
VolumeType *string `json:"volume_type,omitempty"`
|
|
|
|
ExportURI *string `json:"export_uri,omitempty"`
|
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// CreateVolume creates a new volume
|
|
|
|
func (s *API) CreateVolume(definition VolumeDefinition) (*Volume, error) {
|
2018-04-30 15:47:39 +00:00
|
|
|
definition.Organization = s.Organization
|
|
|
|
if definition.Type == "" {
|
|
|
|
definition.Type = "l_ssd"
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := s.PostResponse(s.computeAPI, "volumes", definition)
|
|
|
|
if err != nil {
|
2019-12-02 20:37:43 +00:00
|
|
|
return nil, err
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
body, err := s.handleHTTPError([]int{http.StatusCreated}, resp)
|
|
|
|
if err != nil {
|
2019-12-02 20:37:43 +00:00
|
|
|
return nil, err
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
var volume volumeResponse
|
|
|
|
|
|
|
|
if err = json.Unmarshal(body, &volume); err != nil {
|
2019-12-02 20:37:43 +00:00
|
|
|
return nil, err
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
2019-12-02 20:37:43 +00:00
|
|
|
return &volume.Volume, nil
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// UpdateVolume updates a volume
|
|
|
|
func (s *API) UpdateVolume(volumeID string, definition VolumePutDefinition) (*Volume, error) {
|
2018-04-30 15:47:39 +00:00
|
|
|
resp, err := s.PutResponse(s.computeAPI, fmt.Sprintf("volumes/%s", volumeID), definition)
|
|
|
|
if err != nil {
|
2019-12-02 20:37:43 +00:00
|
|
|
return nil, err
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var volume volumeResponse
|
|
|
|
|
|
|
|
if err = json.Unmarshal(body, &volume); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &volume.Volume, nil
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteVolume deletes a volume
|
2019-12-02 20:37:43 +00:00
|
|
|
func (s *API) DeleteVolume(volumeID string) error {
|
2018-04-30 15:47:39 +00:00
|
|
|
resp, err := s.DeleteResponse(s.computeAPI, fmt.Sprintf("volumes/%s", volumeID))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
if _, err := s.handleHTTPError([]int{http.StatusNoContent}, resp); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type volumesResponse struct {
|
2019-12-02 20:37:43 +00:00
|
|
|
Volumes []Volume `json:"volumes,omitempty"`
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// GetVolumes gets the list of volumes from the API
|
|
|
|
func (s *API) GetVolumes() (*[]Volume, error) {
|
2018-04-30 15:47:39 +00:00
|
|
|
query := url.Values{}
|
|
|
|
|
|
|
|
resp, err := s.GetResponsePaginate(s.computeAPI, "volumes", query)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var volumes volumesResponse
|
|
|
|
|
|
|
|
if err = json.Unmarshal(body, &volumes); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &volumes.Volumes, nil
|
|
|
|
}
|
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
// GetVolume gets a volume from the API
|
|
|
|
func (s *API) GetVolume(volumeID string) (*Volume, error) {
|
2018-04-30 15:47:39 +00:00
|
|
|
resp, err := s.GetResponsePaginate(s.computeAPI, "volumes/"+volumeID, url.Values{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
body, err := s.handleHTTPError([]int{http.StatusOK}, resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-12-02 20:37:43 +00:00
|
|
|
var volume volumeResponse
|
2018-04-30 15:47:39 +00:00
|
|
|
|
2019-12-02 20:37:43 +00:00
|
|
|
if err = json.Unmarshal(body, &volume); err != nil {
|
2018-04-30 15:47:39 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// FIXME region, arch, owner, title
|
2019-12-02 20:37:43 +00:00
|
|
|
return &volume.Volume, nil
|
2018-04-30 15:47:39 +00:00
|
|
|
}
|