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