github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/blockstorage/v2/volumes/requests.go (about) 1 package volumes 2 3 import ( 4 "context" 5 "maps" 6 "regexp" 7 8 "github.com/vnpaycloud-console/gophercloud/v2" 9 "github.com/vnpaycloud-console/gophercloud/v2/pagination" 10 ) 11 12 // SchedulerHintOptsBuilder builds the scheduler hints into a serializable format. 13 type SchedulerHintOptsBuilder interface { 14 ToSchedulerHintsMap() (map[string]any, error) 15 } 16 17 // SchedulerHintOpts contains options for providing scheduler hints 18 // when creating a Volume. This object is passed to the volumes.Create function. 19 // For more information about these parameters, see the Volume object. 20 type SchedulerHintOpts struct { 21 // DifferentHost will place the volume on a different back-end that does not 22 // host the given volumes. 23 DifferentHost []string 24 25 // SameHost will place the volume on a back-end that hosts the given volumes. 26 SameHost []string 27 28 // LocalToInstance will place volume on same host on a given instance 29 LocalToInstance string 30 31 // Query is a conditional statement that results in back-ends able to 32 // host the volume. 33 Query string 34 35 // AdditionalProperies are arbitrary key/values that are not validated by nova. 36 AdditionalProperties map[string]any 37 } 38 39 // ToSchedulerHintsMap assembles a request body for scheduler hints 40 func (opts SchedulerHintOpts) ToSchedulerHintsMap() (map[string]any, error) { 41 sh := make(map[string]any) 42 43 uuidRegex, _ := regexp.Compile("^[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$") 44 45 if len(opts.DifferentHost) > 0 { 46 for _, diffHost := range opts.DifferentHost { 47 if !uuidRegex.MatchString(diffHost) { 48 err := gophercloud.ErrInvalidInput{} 49 err.Argument = "volumes.SchedulerHintOpts.DifferentHost" 50 err.Value = opts.DifferentHost 51 err.Info = "The hosts must be in UUID format." 52 return nil, err 53 } 54 } 55 sh["different_host"] = opts.DifferentHost 56 } 57 58 if len(opts.SameHost) > 0 { 59 for _, sameHost := range opts.SameHost { 60 if !uuidRegex.MatchString(sameHost) { 61 err := gophercloud.ErrInvalidInput{} 62 err.Argument = "volumes.SchedulerHintOpts.SameHost" 63 err.Value = opts.SameHost 64 err.Info = "The hosts must be in UUID format." 65 return nil, err 66 } 67 } 68 sh["same_host"] = opts.SameHost 69 } 70 71 if opts.LocalToInstance != "" { 72 if !uuidRegex.MatchString(opts.LocalToInstance) { 73 err := gophercloud.ErrInvalidInput{} 74 err.Argument = "volumes.SchedulerHintOpts.LocalToInstance" 75 err.Value = opts.LocalToInstance 76 err.Info = "The instance must be in UUID format." 77 return nil, err 78 } 79 sh["local_to_instance"] = opts.LocalToInstance 80 } 81 82 if opts.Query != "" { 83 sh["query"] = opts.Query 84 } 85 86 if opts.AdditionalProperties != nil { 87 for k, v := range opts.AdditionalProperties { 88 sh[k] = v 89 } 90 } 91 92 if len(sh) == 0 { 93 return sh, nil 94 } 95 96 return map[string]any{"OS-SCH-HNT:scheduler_hints": sh}, nil 97 } 98 99 // CreateOptsBuilder allows extensions to add additional parameters to the 100 // Create request. 101 type CreateOptsBuilder interface { 102 ToVolumeCreateMap() (map[string]any, error) 103 } 104 105 // CreateOpts contains options for creating a Volume. This object is passed to 106 // the volumes.Create function. For more information about these parameters, 107 // see the Volume object. 108 type CreateOpts struct { 109 // The size of the volume, in GB 110 Size int `json:"size" required:"true"` 111 // The availability zone 112 AvailabilityZone string `json:"availability_zone,omitempty"` 113 // ConsistencyGroupID is the ID of a consistency group 114 ConsistencyGroupID string `json:"consistencygroup_id,omitempty"` 115 // The volume description 116 Description string `json:"description,omitempty"` 117 // One or more metadata key and value pairs to associate with the volume 118 Metadata map[string]string `json:"metadata,omitempty"` 119 // The volume name 120 Name string `json:"name,omitempty"` 121 // the ID of the existing volume snapshot 122 SnapshotID string `json:"snapshot_id,omitempty"` 123 // SourceReplica is a UUID of an existing volume to replicate with 124 SourceReplica string `json:"source_replica,omitempty"` 125 // the ID of the existing volume 126 SourceVolID string `json:"source_volid,omitempty"` 127 // The ID of the image from which you want to create the volume. 128 // Required to create a bootable volume. 129 ImageID string `json:"imageRef,omitempty"` 130 // The associated volume type 131 VolumeType string `json:"volume_type,omitempty"` 132 } 133 134 // ToVolumeCreateMap assembles a request body based on the contents of a 135 // CreateOpts. 136 func (opts CreateOpts) ToVolumeCreateMap() (map[string]any, error) { 137 return gophercloud.BuildRequestBody(opts, "volume") 138 } 139 140 // Create will create a new Volume based on the values in CreateOpts. To extract 141 // the Volume object from the response, call the Extract method on the 142 // CreateResult. 143 func Create(ctx context.Context, client *gophercloud.ServiceClient, opts CreateOptsBuilder, hintOpts SchedulerHintOptsBuilder) (r CreateResult) { 144 b, err := opts.ToVolumeCreateMap() 145 if err != nil { 146 r.Err = err 147 return 148 } 149 150 if hintOpts != nil { 151 sh, err := hintOpts.ToSchedulerHintsMap() 152 if err != nil { 153 r.Err = err 154 return 155 } 156 maps.Copy(b, sh) 157 } 158 159 resp, err := client.Post(ctx, createURL(client), b, &r.Body, &gophercloud.RequestOpts{ 160 OkCodes: []int{202}, 161 }) 162 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 163 return 164 } 165 166 // DeleteOptsBuilder allows extensions to add additional parameters to the 167 // Delete request. 168 type DeleteOptsBuilder interface { 169 ToVolumeDeleteQuery() (string, error) 170 } 171 172 // DeleteOpts contains options for deleting a Volume. This object is passed to 173 // the volumes.Delete function. 174 type DeleteOpts struct { 175 // Delete all snapshots of this volume as well. 176 Cascade bool `q:"cascade"` 177 } 178 179 // ToLoadBalancerDeleteQuery formats a DeleteOpts into a query string. 180 func (opts DeleteOpts) ToVolumeDeleteQuery() (string, error) { 181 q, err := gophercloud.BuildQueryString(opts) 182 return q.String(), err 183 } 184 185 // Delete will delete the existing Volume with the provided ID. 186 func Delete(ctx context.Context, client *gophercloud.ServiceClient, id string, opts DeleteOptsBuilder) (r DeleteResult) { 187 url := deleteURL(client, id) 188 if opts != nil { 189 query, err := opts.ToVolumeDeleteQuery() 190 if err != nil { 191 r.Err = err 192 return 193 } 194 url += query 195 } 196 resp, err := client.Delete(ctx, url, nil) 197 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 198 return 199 } 200 201 // Get retrieves the Volume with the provided ID. To extract the Volume object 202 // from the response, call the Extract method on the GetResult. 203 func Get(ctx context.Context, client *gophercloud.ServiceClient, id string) (r GetResult) { 204 resp, err := client.Get(ctx, getURL(client, id), &r.Body, nil) 205 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 206 return 207 } 208 209 // ListOptsBuilder allows extensions to add additional parameters to the List 210 // request. 211 type ListOptsBuilder interface { 212 ToVolumeListQuery() (string, error) 213 } 214 215 // ListOpts holds options for listing Volumes. It is passed to the volumes.List 216 // function. 217 type ListOpts struct { 218 // AllTenants will retrieve volumes of all tenants/projects. 219 AllTenants bool `q:"all_tenants"` 220 221 // Metadata will filter results based on specified metadata. 222 Metadata map[string]string `q:"metadata"` 223 224 // Name will filter by the specified volume name. 225 Name string `q:"name"` 226 227 // Status will filter by the specified status. 228 Status string `q:"status"` 229 230 // TenantID will filter by a specific tenant/project ID. 231 // Setting AllTenants is required for this. 232 TenantID string `q:"project_id"` 233 234 // Comma-separated list of sort keys and optional sort directions in the 235 // form of <key>[:<direction>]. 236 Sort string `q:"sort"` 237 238 // Requests a page size of items. 239 Limit int `q:"limit"` 240 241 // Used in conjunction with limit to return a slice of items. 242 Offset int `q:"offset"` 243 244 // The ID of the last-seen item. 245 Marker string `q:"marker"` 246 } 247 248 // ToVolumeListQuery formats a ListOpts into a query string. 249 func (opts ListOpts) ToVolumeListQuery() (string, error) { 250 q, err := gophercloud.BuildQueryString(opts) 251 return q.String(), err 252 } 253 254 // List returns Volumes optionally limited by the conditions provided in ListOpts. 255 func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { 256 url := listURL(client) 257 if opts != nil { 258 query, err := opts.ToVolumeListQuery() 259 if err != nil { 260 return pagination.Pager{Err: err} 261 } 262 url += query 263 } 264 265 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { 266 return VolumePage{pagination.LinkedPageBase{PageResult: r}} 267 }) 268 } 269 270 // UpdateOptsBuilder allows extensions to add additional parameters to the 271 // Update request. 272 type UpdateOptsBuilder interface { 273 ToVolumeUpdateMap() (map[string]any, error) 274 } 275 276 // UpdateOpts contain options for updating an existing Volume. This object is passed 277 // to the volumes.Update function. For more information about the parameters, see 278 // the Volume object. 279 type UpdateOpts struct { 280 Name *string `json:"name,omitempty"` 281 Description *string `json:"description,omitempty"` 282 Metadata map[string]string `json:"metadata,omitempty"` 283 } 284 285 // ToVolumeUpdateMap assembles a request body based on the contents of an 286 // UpdateOpts. 287 func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]any, error) { 288 return gophercloud.BuildRequestBody(opts, "volume") 289 } 290 291 // Update will update the Volume with provided information. To extract the updated 292 // Volume from the response, call the Extract method on the UpdateResult. 293 func Update(ctx context.Context, client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { 294 b, err := opts.ToVolumeUpdateMap() 295 if err != nil { 296 r.Err = err 297 return 298 } 299 resp, err := client.Put(ctx, updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 300 OkCodes: []int{200}, 301 }) 302 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 303 return 304 } 305 306 // AttachOptsBuilder allows extensions to add additional parameters to the 307 // Attach request. 308 type AttachOptsBuilder interface { 309 ToVolumeAttachMap() (map[string]any, error) 310 } 311 312 // AttachMode describes the attachment mode for volumes. 313 type AttachMode string 314 315 // These constants determine how a volume is attached. 316 const ( 317 ReadOnly AttachMode = "ro" 318 ReadWrite AttachMode = "rw" 319 ) 320 321 // AttachOpts contains options for attaching a Volume. 322 type AttachOpts struct { 323 // The mountpoint of this volume. 324 MountPoint string `json:"mountpoint,omitempty"` 325 326 // The nova instance ID, can't set simultaneously with HostName. 327 InstanceUUID string `json:"instance_uuid,omitempty"` 328 329 // The hostname of baremetal host, can't set simultaneously with InstanceUUID. 330 HostName string `json:"host_name,omitempty"` 331 332 // Mount mode of this volume. 333 Mode AttachMode `json:"mode,omitempty"` 334 } 335 336 // ToVolumeAttachMap assembles a request body based on the contents of a 337 // AttachOpts. 338 func (opts AttachOpts) ToVolumeAttachMap() (map[string]any, error) { 339 return gophercloud.BuildRequestBody(opts, "os-attach") 340 } 341 342 // Attach will attach a volume based on the values in AttachOpts. 343 func Attach(ctx context.Context, client *gophercloud.ServiceClient, id string, opts AttachOptsBuilder) (r AttachResult) { 344 b, err := opts.ToVolumeAttachMap() 345 if err != nil { 346 r.Err = err 347 return 348 } 349 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 350 OkCodes: []int{202}, 351 }) 352 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 353 return 354 } 355 356 // BeginDetaching will mark the volume as detaching. 357 func BeginDetaching(ctx context.Context, client *gophercloud.ServiceClient, id string) (r BeginDetachingResult) { 358 b := map[string]any{"os-begin_detaching": make(map[string]any)} 359 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 360 OkCodes: []int{202}, 361 }) 362 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 363 return 364 } 365 366 // DetachOptsBuilder allows extensions to add additional parameters to the 367 // Detach request. 368 type DetachOptsBuilder interface { 369 ToVolumeDetachMap() (map[string]any, error) 370 } 371 372 // DetachOpts contains options for detaching a Volume. 373 type DetachOpts struct { 374 // AttachmentID is the ID of the attachment between a volume and instance. 375 AttachmentID string `json:"attachment_id,omitempty"` 376 } 377 378 // ToVolumeDetachMap assembles a request body based on the contents of a 379 // DetachOpts. 380 func (opts DetachOpts) ToVolumeDetachMap() (map[string]any, error) { 381 return gophercloud.BuildRequestBody(opts, "os-detach") 382 } 383 384 // Detach will detach a volume based on volume ID. 385 func Detach(ctx context.Context, client *gophercloud.ServiceClient, id string, opts DetachOptsBuilder) (r DetachResult) { 386 b, err := opts.ToVolumeDetachMap() 387 if err != nil { 388 r.Err = err 389 return 390 } 391 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 392 OkCodes: []int{202}, 393 }) 394 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 395 return 396 } 397 398 // Reserve will reserve a volume based on volume ID. 399 func Reserve(ctx context.Context, client *gophercloud.ServiceClient, id string) (r ReserveResult) { 400 b := map[string]any{"os-reserve": make(map[string]any)} 401 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 402 OkCodes: []int{200, 201, 202}, 403 }) 404 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 405 return 406 } 407 408 // Unreserve will unreserve a volume based on volume ID. 409 func Unreserve(ctx context.Context, client *gophercloud.ServiceClient, id string) (r UnreserveResult) { 410 b := map[string]any{"os-unreserve": make(map[string]any)} 411 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 412 OkCodes: []int{200, 201, 202}, 413 }) 414 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 415 return 416 } 417 418 // InitializeConnectionOptsBuilder allows extensions to add additional parameters to the 419 // InitializeConnection request. 420 type InitializeConnectionOptsBuilder interface { 421 ToVolumeInitializeConnectionMap() (map[string]any, error) 422 } 423 424 // InitializeConnectionOpts hosts options for InitializeConnection. 425 // The fields are specific to the storage driver in use and the destination 426 // attachment. 427 type InitializeConnectionOpts struct { 428 IP string `json:"ip,omitempty"` 429 Host string `json:"host,omitempty"` 430 Initiator string `json:"initiator,omitempty"` 431 Wwpns []string `json:"wwpns,omitempty"` 432 Wwnns string `json:"wwnns,omitempty"` 433 Multipath *bool `json:"multipath,omitempty"` 434 Platform string `json:"platform,omitempty"` 435 OSType string `json:"os_type,omitempty"` 436 } 437 438 // ToVolumeInitializeConnectionMap assembles a request body based on the contents of a 439 // InitializeConnectionOpts. 440 func (opts InitializeConnectionOpts) ToVolumeInitializeConnectionMap() (map[string]any, error) { 441 b, err := gophercloud.BuildRequestBody(opts, "connector") 442 return map[string]any{"os-initialize_connection": b}, err 443 } 444 445 // InitializeConnection initializes an iSCSI connection by volume ID. 446 func InitializeConnection(ctx context.Context, client *gophercloud.ServiceClient, id string, opts InitializeConnectionOptsBuilder) (r InitializeConnectionResult) { 447 b, err := opts.ToVolumeInitializeConnectionMap() 448 if err != nil { 449 r.Err = err 450 return 451 } 452 resp, err := client.Post(ctx, actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 453 OkCodes: []int{200, 201, 202}, 454 }) 455 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 456 return 457 } 458 459 // TerminateConnectionOptsBuilder allows extensions to add additional parameters to the 460 // TerminateConnection request. 461 type TerminateConnectionOptsBuilder interface { 462 ToVolumeTerminateConnectionMap() (map[string]any, error) 463 } 464 465 // TerminateConnectionOpts hosts options for TerminateConnection. 466 type TerminateConnectionOpts struct { 467 IP string `json:"ip,omitempty"` 468 Host string `json:"host,omitempty"` 469 Initiator string `json:"initiator,omitempty"` 470 Wwpns []string `json:"wwpns,omitempty"` 471 Wwnns string `json:"wwnns,omitempty"` 472 Multipath *bool `json:"multipath,omitempty"` 473 Platform string `json:"platform,omitempty"` 474 OSType string `json:"os_type,omitempty"` 475 } 476 477 // ToVolumeTerminateConnectionMap assembles a request body based on the contents of a 478 // TerminateConnectionOpts. 479 func (opts TerminateConnectionOpts) ToVolumeTerminateConnectionMap() (map[string]any, error) { 480 b, err := gophercloud.BuildRequestBody(opts, "connector") 481 return map[string]any{"os-terminate_connection": b}, err 482 } 483 484 // TerminateConnection terminates an iSCSI connection by volume ID. 485 func TerminateConnection(ctx context.Context, client *gophercloud.ServiceClient, id string, opts TerminateConnectionOptsBuilder) (r TerminateConnectionResult) { 486 b, err := opts.ToVolumeTerminateConnectionMap() 487 if err != nil { 488 r.Err = err 489 return 490 } 491 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 492 OkCodes: []int{202}, 493 }) 494 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 495 return 496 } 497 498 // ExtendSizeOptsBuilder allows extensions to add additional parameters to the 499 // ExtendSize request. 500 type ExtendSizeOptsBuilder interface { 501 ToVolumeExtendSizeMap() (map[string]any, error) 502 } 503 504 // ExtendSizeOpts contains options for extending the size of an existing Volume. 505 // This object is passed to the volumes.ExtendSize function. 506 type ExtendSizeOpts struct { 507 // NewSize is the new size of the volume, in GB. 508 NewSize int `json:"new_size" required:"true"` 509 } 510 511 // ToVolumeExtendSizeMap assembles a request body based on the contents of an 512 // ExtendSizeOpts. 513 func (opts ExtendSizeOpts) ToVolumeExtendSizeMap() (map[string]any, error) { 514 return gophercloud.BuildRequestBody(opts, "os-extend") 515 } 516 517 // ExtendSize will extend the size of the volume based on the provided information. 518 // This operation does not return a response body. 519 func ExtendSize(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ExtendSizeOptsBuilder) (r ExtendSizeResult) { 520 b, err := opts.ToVolumeExtendSizeMap() 521 if err != nil { 522 r.Err = err 523 return 524 } 525 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 526 OkCodes: []int{202}, 527 }) 528 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 529 return 530 } 531 532 // UploadImageOptsBuilder allows extensions to add additional parameters to the 533 // UploadImage request. 534 type UploadImageOptsBuilder interface { 535 ToVolumeUploadImageMap() (map[string]any, error) 536 } 537 538 // UploadImageOpts contains options for uploading a Volume to image storage. 539 type UploadImageOpts struct { 540 // Container format, may be bare, ofv, ova, etc. 541 ContainerFormat string `json:"container_format,omitempty"` 542 543 // Disk format, may be raw, qcow2, vhd, vdi, vmdk, etc. 544 DiskFormat string `json:"disk_format,omitempty"` 545 546 // The name of image that will be stored in glance. 547 ImageName string `json:"image_name,omitempty"` 548 549 // Force image creation, usable if volume attached to instance. 550 Force bool `json:"force,omitempty"` 551 552 // Visibility defines who can see/use the image. 553 // supported since 3.1 microversion 554 Visibility string `json:"visibility,omitempty"` 555 556 // whether the image is not deletable. 557 // supported since 3.1 microversion 558 Protected bool `json:"protected,omitempty"` 559 } 560 561 // ToVolumeUploadImageMap assembles a request body based on the contents of a 562 // UploadImageOpts. 563 func (opts UploadImageOpts) ToVolumeUploadImageMap() (map[string]any, error) { 564 return gophercloud.BuildRequestBody(opts, "os-volume_upload_image") 565 } 566 567 // UploadImage will upload an image based on the values in UploadImageOptsBuilder. 568 func UploadImage(ctx context.Context, client *gophercloud.ServiceClient, id string, opts UploadImageOptsBuilder) (r UploadImageResult) { 569 b, err := opts.ToVolumeUploadImageMap() 570 if err != nil { 571 r.Err = err 572 return 573 } 574 resp, err := client.Post(ctx, actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 575 OkCodes: []int{202}, 576 }) 577 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 578 return 579 } 580 581 // ForceDelete will delete the volume regardless of state. 582 func ForceDelete(ctx context.Context, client *gophercloud.ServiceClient, id string) (r ForceDeleteResult) { 583 resp, err := client.Post(ctx, actionURL(client, id), map[string]any{"os-force_delete": ""}, nil, nil) 584 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 585 return 586 } 587 588 // ImageMetadataOptsBuilder allows extensions to add additional parameters to the 589 // ImageMetadataRequest request. 590 type ImageMetadataOptsBuilder interface { 591 ToImageMetadataMap() (map[string]any, error) 592 } 593 594 // ImageMetadataOpts contains options for setting image metadata to a volume. 595 type ImageMetadataOpts struct { 596 // The image metadata to add to the volume as a set of metadata key and value pairs. 597 Metadata map[string]string `json:"metadata"` 598 } 599 600 // ToImageMetadataMap assembles a request body based on the contents of a 601 // ImageMetadataOpts. 602 func (opts ImageMetadataOpts) ToImageMetadataMap() (map[string]any, error) { 603 return gophercloud.BuildRequestBody(opts, "os-set_image_metadata") 604 } 605 606 // SetImageMetadata will set image metadata on a volume based on the values in ImageMetadataOptsBuilder. 607 func SetImageMetadata(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ImageMetadataOptsBuilder) (r SetImageMetadataResult) { 608 b, err := opts.ToImageMetadataMap() 609 if err != nil { 610 r.Err = err 611 return 612 } 613 resp, err := client.Post(ctx, actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ 614 OkCodes: []int{200}, 615 }) 616 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 617 return 618 } 619 620 // BootableOpts contains options for setting bootable status to a volume. 621 type BootableOpts struct { 622 // Enables or disables the bootable attribute. You can boot an instance from a bootable volume. 623 Bootable bool `json:"bootable"` 624 } 625 626 // ToBootableMap assembles a request body based on the contents of a 627 // BootableOpts. 628 func (opts BootableOpts) ToBootableMap() (map[string]any, error) { 629 return gophercloud.BuildRequestBody(opts, "os-set_bootable") 630 } 631 632 // SetBootable will set bootable status on a volume based on the values in BootableOpts 633 func SetBootable(ctx context.Context, client *gophercloud.ServiceClient, id string, opts BootableOpts) (r SetBootableResult) { 634 b, err := opts.ToBootableMap() 635 if err != nil { 636 r.Err = err 637 return 638 } 639 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 640 OkCodes: []int{200}, 641 }) 642 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 643 return 644 } 645 646 // MigrationPolicy type represents a migration_policy when changing types. 647 type MigrationPolicy string 648 649 // Supported attributes for MigrationPolicy attribute for changeType operations. 650 const ( 651 MigrationPolicyNever MigrationPolicy = "never" 652 MigrationPolicyOnDemand MigrationPolicy = "on-demand" 653 ) 654 655 // ChangeTypeOptsBuilder allows extensions to add additional parameters to the 656 // ChangeType request. 657 type ChangeTypeOptsBuilder interface { 658 ToVolumeChangeTypeMap() (map[string]any, error) 659 } 660 661 // ChangeTypeOpts contains options for changing the type of an existing Volume. 662 // This object is passed to the volumes.ChangeType function. 663 type ChangeTypeOpts struct { 664 // NewType is the name of the new volume type of the volume. 665 NewType string `json:"new_type" required:"true"` 666 667 // MigrationPolicy specifies if the volume should be migrated when it is 668 // re-typed. Possible values are "on-demand" or "never". If not specified, 669 // the default is "never". 670 MigrationPolicy MigrationPolicy `json:"migration_policy,omitempty"` 671 } 672 673 // ToVolumeChangeTypeMap assembles a request body based on the contents of an 674 // ChangeTypeOpts. 675 func (opts ChangeTypeOpts) ToVolumeChangeTypeMap() (map[string]any, error) { 676 return gophercloud.BuildRequestBody(opts, "os-retype") 677 } 678 679 // ChangeType will change the volume type of the volume based on the provided information. 680 // This operation does not return a response body. 681 func ChangeType(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ChangeTypeOptsBuilder) (r ChangeTypeResult) { 682 b, err := opts.ToVolumeChangeTypeMap() 683 if err != nil { 684 r.Err = err 685 return 686 } 687 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 688 OkCodes: []int{202}, 689 }) 690 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 691 return 692 } 693 694 // ReImageOpts contains options for Re-image a volume. 695 type ReImageOpts struct { 696 // New image id 697 ImageID string `json:"image_id"` 698 // set true to re-image volumes in reserved state 699 ReImageReserved bool `json:"reimage_reserved"` 700 } 701 702 // ToReImageMap assembles a request body based on the contents of a ReImageOpts. 703 func (opts ReImageOpts) ToReImageMap() (map[string]any, error) { 704 return gophercloud.BuildRequestBody(opts, "os-reimage") 705 } 706 707 // ReImage will re-image a volume based on the values in ReImageOpts 708 func ReImage(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ReImageOpts) (r ReImageResult) { 709 b, err := opts.ToReImageMap() 710 if err != nil { 711 r.Err = err 712 return 713 } 714 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 715 OkCodes: []int{202}, 716 }) 717 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 718 return 719 } 720 721 // ResetStatusOptsBuilder allows extensions to add additional parameters to the 722 // ResetStatus request. 723 type ResetStatusOptsBuilder interface { 724 ToResetStatusMap() (map[string]any, error) 725 } 726 727 // ResetStatusOpts contains options for resetting a Volume status. 728 // For more information about these parameters, please, refer to the Block Storage API V3, 729 // Volume Actions, ResetStatus volume documentation. 730 type ResetStatusOpts struct { 731 // Status is a volume status to reset to. 732 Status string `json:"status"` 733 // MigrationStatus is a volume migration status to reset to. 734 MigrationStatus string `json:"migration_status,omitempty"` 735 // AttachStatus is a volume attach status to reset to. 736 AttachStatus string `json:"attach_status,omitempty"` 737 } 738 739 // ToResetStatusMap assembles a request body based on the contents of a 740 // ResetStatusOpts. 741 func (opts ResetStatusOpts) ToResetStatusMap() (map[string]any, error) { 742 return gophercloud.BuildRequestBody(opts, "os-reset_status") 743 } 744 745 // ResetStatus will reset the existing volume status. ResetStatusResult contains only the error. 746 // To extract it, call the ExtractErr method on the ResetStatusResult. 747 func ResetStatus(ctx context.Context, client *gophercloud.ServiceClient, id string, opts ResetStatusOptsBuilder) (r ResetStatusResult) { 748 b, err := opts.ToResetStatusMap() 749 if err != nil { 750 r.Err = err 751 return 752 } 753 754 resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ 755 OkCodes: []int{202}, 756 }) 757 _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) 758 return 759 }