github.com/gophercloud/gophercloud@v1.11.0/openstack/imageservice/v2/images/requests.go (about) 1 package images 2 3 import ( 4 "fmt" 5 "net/url" 6 "time" 7 8 "github.com/gophercloud/gophercloud" 9 "github.com/gophercloud/gophercloud/pagination" 10 ) 11 12 // ListOptsBuilder allows extensions to add additional parameters to the 13 // List request. 14 type ListOptsBuilder interface { 15 ToImageListQuery() (string, error) 16 } 17 18 // ListOpts allows the filtering and sorting of paginated collections through 19 // the API. Filtering is achieved by passing in struct field values that map to 20 // the server attributes you want to see returned. Marker and Limit are used 21 // for pagination. 22 // 23 // http://developer.openstack.org/api-ref-image-v2.html 24 type ListOpts struct { 25 // ID is the ID of the image. 26 // Multiple IDs can be specified by constructing a string 27 // such as "in:uuid1,uuid2,uuid3". 28 ID string `q:"id"` 29 30 // Integer value for the limit of values to return. 31 Limit int `q:"limit"` 32 33 // UUID of the server at which you want to set a marker. 34 Marker string `q:"marker"` 35 36 // Name filters on the name of the image. 37 // Multiple names can be specified by constructing a string 38 // such as "in:name1,name2,name3". 39 Name string `q:"name"` 40 41 // Visibility filters on the visibility of the image. 42 Visibility ImageVisibility `q:"visibility"` 43 44 // Hidden filters on the hidden status of the image. 45 Hidden bool `q:"os_hidden"` 46 47 // MemberStatus filters on the member status of the image. 48 MemberStatus ImageMemberStatus `q:"member_status"` 49 50 // Owner filters on the project ID of the image. 51 Owner string `q:"owner"` 52 53 // Status filters on the status of the image. 54 // Multiple statuses can be specified by constructing a string 55 // such as "in:saving,queued". 56 Status ImageStatus `q:"status"` 57 58 // SizeMin filters on the size_min image property. 59 SizeMin int64 `q:"size_min"` 60 61 // SizeMax filters on the size_max image property. 62 SizeMax int64 `q:"size_max"` 63 64 // Sort sorts the results using the new style of sorting. See the OpenStack 65 // Image API reference for the exact syntax. 66 // 67 // Sort cannot be used with the classic sort options (sort_key and sort_dir). 68 Sort string `q:"sort"` 69 70 // SortKey will sort the results based on a specified image property. 71 SortKey string `q:"sort_key"` 72 73 // SortDir will sort the list results either ascending or decending. 74 SortDir string `q:"sort_dir"` 75 76 // Tags filters on specific image tags. 77 Tags []string `q:"tag"` 78 79 // CreatedAtQuery filters images based on their creation date. 80 CreatedAtQuery *ImageDateQuery 81 82 // UpdatedAtQuery filters images based on their updated date. 83 UpdatedAtQuery *ImageDateQuery 84 85 // ContainerFormat filters images based on the container_format. 86 // Multiple container formats can be specified by constructing a 87 // string such as "in:bare,ami". 88 ContainerFormat string `q:"container_format"` 89 90 // DiskFormat filters images based on the disk_format. 91 // Multiple disk formats can be specified by constructing a string 92 // such as "in:qcow2,iso". 93 DiskFormat string `q:"disk_format"` 94 } 95 96 // ToImageListQuery formats a ListOpts into a query string. 97 func (opts ListOpts) ToImageListQuery() (string, error) { 98 q, err := gophercloud.BuildQueryString(opts) 99 params := q.Query() 100 101 if opts.CreatedAtQuery != nil { 102 createdAt := opts.CreatedAtQuery.Date.Format(time.RFC3339) 103 if v := opts.CreatedAtQuery.Filter; v != "" { 104 createdAt = fmt.Sprintf("%s:%s", v, createdAt) 105 } 106 107 params.Add("created_at", createdAt) 108 } 109 110 if opts.UpdatedAtQuery != nil { 111 updatedAt := opts.UpdatedAtQuery.Date.Format(time.RFC3339) 112 if v := opts.UpdatedAtQuery.Filter; v != "" { 113 updatedAt = fmt.Sprintf("%s:%s", v, updatedAt) 114 } 115 116 params.Add("updated_at", updatedAt) 117 } 118 119 q = &url.URL{RawQuery: params.Encode()} 120 121 return q.String(), err 122 } 123 124 // List implements image list request. 125 func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { 126 url := listURL(c) 127 if opts != nil { 128 query, err := opts.ToImageListQuery() 129 if err != nil { 130 return pagination.Pager{Err: err} 131 } 132 url += query 133 } 134 return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { 135 imagePage := ImagePage{ 136 serviceURL: c.ServiceURL(), 137 LinkedPageBase: pagination.LinkedPageBase{PageResult: r}, 138 } 139 140 return imagePage 141 }) 142 } 143 144 // CreateOptsBuilder allows extensions to add parameters to the Create request. 145 type CreateOptsBuilder interface { 146 // Returns value that can be passed to json.Marshal 147 ToImageCreateMap() (map[string]interface{}, error) 148 } 149 150 // CreateOpts represents options used to create an image. 151 type CreateOpts struct { 152 // Name is the name of the new image. 153 Name string `json:"name" required:"true"` 154 155 // Id is the the image ID. 156 ID string `json:"id,omitempty"` 157 158 // Visibility defines who can see/use the image. 159 Visibility *ImageVisibility `json:"visibility,omitempty"` 160 161 // Hidden is whether the image is listed in default image list or not. 162 Hidden *bool `json:"os_hidden,omitempty"` 163 164 // Tags is a set of image tags. 165 Tags []string `json:"tags,omitempty"` 166 167 // ContainerFormat is the format of the 168 // container. Valid values are ami, ari, aki, bare, and ovf. 169 ContainerFormat string `json:"container_format,omitempty"` 170 171 // DiskFormat is the format of the disk. If set, 172 // valid values are ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, 173 // and iso. 174 DiskFormat string `json:"disk_format,omitempty"` 175 176 // MinDisk is the amount of disk space in 177 // GB that is required to boot the image. 178 MinDisk int `json:"min_disk,omitempty"` 179 180 // MinRAM is the amount of RAM in MB that 181 // is required to boot the image. 182 MinRAM int `json:"min_ram,omitempty"` 183 184 // protected is whether the image is not deletable. 185 Protected *bool `json:"protected,omitempty"` 186 187 // properties is a set of properties, if any, that 188 // are associated with the image. 189 Properties map[string]string `json:"-"` 190 } 191 192 // ToImageCreateMap assembles a request body based on the contents of 193 // a CreateOpts. 194 func (opts CreateOpts) ToImageCreateMap() (map[string]interface{}, error) { 195 b, err := gophercloud.BuildRequestBody(opts, "") 196 if err != nil { 197 return nil, err 198 } 199 200 if opts.Properties != nil { 201 for k, v := range opts.Properties { 202 b[k] = v 203 } 204 } 205 return b, nil 206 } 207 208 // Create implements create image request. 209 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { 210 b, err := opts.ToImageCreateMap() 211 if err != nil { 212 r.Err = err 213 return r 214 } 215 resp, err := client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{OkCodes: []int{201}}) 216 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 217 return 218 } 219 220 // Delete implements image delete request. 221 func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { 222 resp, err := client.Delete(deleteURL(client, id), nil) 223 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 224 return 225 } 226 227 // Get implements image get request. 228 func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { 229 resp, err := client.Get(getURL(client, id), &r.Body, nil) 230 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 231 return 232 } 233 234 // Update implements image updated request. 235 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { 236 b, err := opts.ToImageUpdateMap() 237 if err != nil { 238 r.Err = err 239 return r 240 } 241 resp, err := client.Patch(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 242 OkCodes: []int{200}, 243 MoreHeaders: map[string]string{"Content-Type": "application/openstack-images-v2.1-json-patch"}, 244 }) 245 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 246 return 247 } 248 249 // UpdateOptsBuilder allows extensions to add additional parameters to the 250 // Update request. 251 type UpdateOptsBuilder interface { 252 // returns value implementing json.Marshaler which when marshaled matches 253 // the patch schema: 254 // http://specs.openstack.org/openstack/glance-specs/specs/api/v2/http-patch-image-api-v2.html 255 ToImageUpdateMap() ([]interface{}, error) 256 } 257 258 // UpdateOpts implements UpdateOpts 259 type UpdateOpts []Patch 260 261 // ToImageUpdateMap assembles a request body based on the contents of 262 // UpdateOpts. 263 func (opts UpdateOpts) ToImageUpdateMap() ([]interface{}, error) { 264 m := make([]interface{}, len(opts)) 265 for i, patch := range opts { 266 patchJSON := patch.ToImagePatchMap() 267 m[i] = patchJSON 268 } 269 return m, nil 270 } 271 272 // Patch represents a single update to an existing image. Multiple updates 273 // to an image can be submitted at the same time. 274 type Patch interface { 275 ToImagePatchMap() map[string]interface{} 276 } 277 278 // UpdateVisibility represents an updated visibility property request. 279 type UpdateVisibility struct { 280 Visibility ImageVisibility 281 } 282 283 // ToImagePatchMap assembles a request body based on UpdateVisibility. 284 func (r UpdateVisibility) ToImagePatchMap() map[string]interface{} { 285 return map[string]interface{}{ 286 "op": "replace", 287 "path": "/visibility", 288 "value": r.Visibility, 289 } 290 } 291 292 // ReplaceImageHidden represents an updated os_hidden property request. 293 type ReplaceImageHidden struct { 294 NewHidden bool 295 } 296 297 // ToImagePatchMap assembles a request body based on ReplaceImageHidden. 298 func (r ReplaceImageHidden) ToImagePatchMap() map[string]interface{} { 299 return map[string]interface{}{ 300 "op": "replace", 301 "path": "/os_hidden", 302 "value": r.NewHidden, 303 } 304 } 305 306 // ReplaceImageName represents an updated image_name property request. 307 type ReplaceImageName struct { 308 NewName string 309 } 310 311 // ToImagePatchMap assembles a request body based on ReplaceImageName. 312 func (r ReplaceImageName) ToImagePatchMap() map[string]interface{} { 313 return map[string]interface{}{ 314 "op": "replace", 315 "path": "/name", 316 "value": r.NewName, 317 } 318 } 319 320 // ReplaceImageChecksum represents an updated checksum property request. 321 type ReplaceImageChecksum struct { 322 Checksum string 323 } 324 325 // ReplaceImageChecksum assembles a request body based on ReplaceImageChecksum. 326 func (r ReplaceImageChecksum) ToImagePatchMap() map[string]interface{} { 327 return map[string]interface{}{ 328 "op": "replace", 329 "path": "/checksum", 330 "value": r.Checksum, 331 } 332 } 333 334 // ReplaceImageTags represents an updated tags property request. 335 type ReplaceImageTags struct { 336 NewTags []string 337 } 338 339 // ToImagePatchMap assembles a request body based on ReplaceImageTags. 340 func (r ReplaceImageTags) ToImagePatchMap() map[string]interface{} { 341 return map[string]interface{}{ 342 "op": "replace", 343 "path": "/tags", 344 "value": r.NewTags, 345 } 346 } 347 348 // ReplaceImageMinDisk represents an updated min_disk property request. 349 type ReplaceImageMinDisk struct { 350 NewMinDisk int 351 } 352 353 // ToImagePatchMap assembles a request body based on ReplaceImageTags. 354 func (r ReplaceImageMinDisk) ToImagePatchMap() map[string]interface{} { 355 return map[string]interface{}{ 356 "op": "replace", 357 "path": "/min_disk", 358 "value": r.NewMinDisk, 359 } 360 } 361 362 // ReplaceImageMinRam represents an updated min_ram property request. 363 type ReplaceImageMinRam struct { 364 NewMinRam int 365 } 366 367 // ToImagePatchMap assembles a request body based on ReplaceImageTags. 368 func (r ReplaceImageMinRam) ToImagePatchMap() map[string]interface{} { 369 return map[string]interface{}{ 370 "op": "replace", 371 "path": "/min_ram", 372 "value": r.NewMinRam, 373 } 374 } 375 376 // ReplaceImageProtected represents an updated protected property request. 377 type ReplaceImageProtected struct { 378 NewProtected bool 379 } 380 381 // ToImagePatchMap assembles a request body based on ReplaceImageProtected 382 func (r ReplaceImageProtected) ToImagePatchMap() map[string]interface{} { 383 return map[string]interface{}{ 384 "op": "replace", 385 "path": "/protected", 386 "value": r.NewProtected, 387 } 388 } 389 390 // UpdateOp represents a valid update operation. 391 type UpdateOp string 392 393 const ( 394 AddOp UpdateOp = "add" 395 ReplaceOp UpdateOp = "replace" 396 RemoveOp UpdateOp = "remove" 397 ) 398 399 // UpdateImageProperty represents an update property request. 400 type UpdateImageProperty struct { 401 Op UpdateOp 402 Name string 403 Value string 404 } 405 406 // ToImagePatchMap assembles a request body based on UpdateImageProperty. 407 func (r UpdateImageProperty) ToImagePatchMap() map[string]interface{} { 408 updateMap := map[string]interface{}{ 409 "op": r.Op, 410 "path": fmt.Sprintf("/%s", r.Name), 411 } 412 413 if r.Op != RemoveOp { 414 updateMap["value"] = r.Value 415 } 416 417 return updateMap 418 }