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  }