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