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