github.com/gophercloud/gophercloud@v1.11.0/openstack/imageservice/v2/images/results.go (about)

     1  package images
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/gophercloud/gophercloud"
    11  	"github.com/gophercloud/gophercloud/pagination"
    12  )
    13  
    14  // Image represents an image found in the OpenStack Image service.
    15  type Image struct {
    16  	// ID is the image UUID.
    17  	ID string `json:"id"`
    18  
    19  	// Name is the human-readable display name for the image.
    20  	Name string `json:"name"`
    21  
    22  	// Status is the image status. It can be "queued" or "active"
    23  	// See imageservice/v2/images/type.go
    24  	Status ImageStatus `json:"status"`
    25  
    26  	// Tags is a list of image tags. Tags are arbitrarily defined strings
    27  	// attached to an image.
    28  	Tags []string `json:"tags"`
    29  
    30  	// ContainerFormat is the format of the container.
    31  	// Valid values are ami, ari, aki, bare, and ovf.
    32  	ContainerFormat string `json:"container_format"`
    33  
    34  	// DiskFormat is the format of the disk.
    35  	// If set, valid values are ami, ari, aki, vhd, vmdk, raw, qcow2, vdi,
    36  	// and iso.
    37  	DiskFormat string `json:"disk_format"`
    38  
    39  	// MinDiskGigabytes is the amount of disk space in GB that is required to
    40  	// boot the image.
    41  	MinDiskGigabytes int `json:"min_disk"`
    42  
    43  	// MinRAMMegabytes [optional] is the amount of RAM in MB that is required to
    44  	// boot the image.
    45  	MinRAMMegabytes int `json:"min_ram"`
    46  
    47  	// Owner is the tenant ID the image belongs to.
    48  	Owner string `json:"owner"`
    49  
    50  	// Protected is whether the image is deletable or not.
    51  	Protected bool `json:"protected"`
    52  
    53  	// Visibility defines who can see/use the image.
    54  	Visibility ImageVisibility `json:"visibility"`
    55  
    56  	// Hidden is whether the image is listed in default image list or not.
    57  	Hidden bool `json:"os_hidden"`
    58  
    59  	// Checksum is the checksum of the data that's associated with the image.
    60  	Checksum string `json:"checksum"`
    61  
    62  	// SizeBytes is the size of the data that's associated with the image.
    63  	SizeBytes int64 `json:"-"`
    64  
    65  	// Metadata is a set of metadata associated with the image.
    66  	// Image metadata allow for meaningfully define the image properties
    67  	// and tags.
    68  	// See http://docs.openstack.org/developer/glance/metadefs-concepts.html.
    69  	Metadata map[string]string `json:"metadata"`
    70  
    71  	// Properties is a set of key-value pairs, if any, that are associated with
    72  	// the image.
    73  	Properties map[string]interface{}
    74  
    75  	// CreatedAt is the date when the image has been created.
    76  	CreatedAt time.Time `json:"created_at"`
    77  
    78  	// UpdatedAt is the date when the last change has been made to the image or
    79  	// its properties.
    80  	UpdatedAt time.Time `json:"updated_at"`
    81  
    82  	// File is the trailing path after the glance endpoint that represent the
    83  	// location of the image or the path to retrieve it.
    84  	File string `json:"file"`
    85  
    86  	// Schema is the path to the JSON-schema that represent the image or image
    87  	// entity.
    88  	Schema string `json:"schema"`
    89  
    90  	// VirtualSize is the virtual size of the image
    91  	VirtualSize int64 `json:"virtual_size"`
    92  
    93  	// OpenStackImageImportMethods is a slice listing the types of import
    94  	// methods available in the cloud.
    95  	OpenStackImageImportMethods []string `json:"-"`
    96  	// OpenStackImageStoreIDs is a slice listing the store IDs available in
    97  	// the cloud.
    98  	OpenStackImageStoreIDs []string `json:"-"`
    99  }
   100  
   101  func (r *Image) UnmarshalJSON(b []byte) error {
   102  	type tmp Image
   103  	var s struct {
   104  		tmp
   105  		SizeBytes                   interface{} `json:"size"`
   106  		OpenStackImageImportMethods string      `json:"openstack-image-import-methods"`
   107  		OpenStackImageStoreIDs      string      `json:"openstack-image-store-ids"`
   108  	}
   109  	err := json.Unmarshal(b, &s)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	*r = Image(s.tmp)
   114  
   115  	switch t := s.SizeBytes.(type) {
   116  	case nil:
   117  		r.SizeBytes = 0
   118  	case float32:
   119  		r.SizeBytes = int64(t)
   120  	case float64:
   121  		r.SizeBytes = int64(t)
   122  	default:
   123  		return fmt.Errorf("Unknown type for SizeBytes: %v (value: %v)", reflect.TypeOf(t), t)
   124  	}
   125  
   126  	// Bundle all other fields into Properties
   127  	var result interface{}
   128  	err = json.Unmarshal(b, &result)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	if resultMap, ok := result.(map[string]interface{}); ok {
   133  		delete(resultMap, "self")
   134  		delete(resultMap, "size")
   135  		delete(resultMap, "openstack-image-import-methods")
   136  		delete(resultMap, "openstack-image-store-ids")
   137  		r.Properties = gophercloud.RemainingKeys(Image{}, resultMap)
   138  	}
   139  
   140  	if v := strings.FieldsFunc(strings.TrimSpace(s.OpenStackImageImportMethods), splitFunc); len(v) > 0 {
   141  		r.OpenStackImageImportMethods = v
   142  	}
   143  	if v := strings.FieldsFunc(strings.TrimSpace(s.OpenStackImageStoreIDs), splitFunc); len(v) > 0 {
   144  		r.OpenStackImageStoreIDs = v
   145  	}
   146  
   147  	return err
   148  }
   149  
   150  type commonResult struct {
   151  	gophercloud.Result
   152  }
   153  
   154  // Extract interprets any commonResult as an Image.
   155  func (r commonResult) Extract() (*Image, error) {
   156  	var s *Image
   157  	if v, ok := r.Body.(map[string]interface{}); ok {
   158  		for k, h := range r.Header {
   159  			if strings.ToLower(k) == "openstack-image-import-methods" {
   160  				for _, s := range h {
   161  					v["openstack-image-import-methods"] = s
   162  				}
   163  			}
   164  			if strings.ToLower(k) == "openstack-image-store-ids" {
   165  				for _, s := range h {
   166  					v["openstack-image-store-ids"] = s
   167  				}
   168  			}
   169  		}
   170  	}
   171  	err := r.ExtractInto(&s)
   172  	return s, err
   173  }
   174  
   175  // CreateResult represents the result of a Create operation. Call its Extract
   176  // method to interpret it as an Image.
   177  type CreateResult struct {
   178  	commonResult
   179  }
   180  
   181  // UpdateResult represents the result of an Update operation. Call its Extract
   182  // method to interpret it as an Image.
   183  type UpdateResult struct {
   184  	commonResult
   185  }
   186  
   187  // GetResult represents the result of a Get operation. Call its Extract
   188  // method to interpret it as an Image.
   189  type GetResult struct {
   190  	commonResult
   191  }
   192  
   193  // DeleteResult represents the result of a Delete operation. Call its
   194  // ExtractErr method to interpret it as an Image.
   195  type DeleteResult struct {
   196  	gophercloud.ErrResult
   197  }
   198  
   199  // ImagePage represents the results of a List request.
   200  type ImagePage struct {
   201  	serviceURL string
   202  	pagination.LinkedPageBase
   203  }
   204  
   205  // IsEmpty returns true if an ImagePage contains no Images results.
   206  func (r ImagePage) IsEmpty() (bool, error) {
   207  	if r.StatusCode == 204 {
   208  		return true, nil
   209  	}
   210  
   211  	images, err := ExtractImages(r)
   212  	return len(images) == 0, err
   213  }
   214  
   215  // NextPageURL uses the response's embedded link reference to navigate to
   216  // the next page of results.
   217  func (r ImagePage) NextPageURL() (string, error) {
   218  	var s struct {
   219  		Next string `json:"next"`
   220  	}
   221  	err := r.ExtractInto(&s)
   222  	if err != nil {
   223  		return "", err
   224  	}
   225  
   226  	if s.Next == "" {
   227  		return "", nil
   228  	}
   229  
   230  	return nextPageURL(r.serviceURL, s.Next)
   231  }
   232  
   233  // ExtractImages interprets the results of a single page from a List() call,
   234  // producing a slice of Image entities.
   235  func ExtractImages(r pagination.Page) ([]Image, error) {
   236  	var s struct {
   237  		Images []Image `json:"images"`
   238  	}
   239  	err := (r.(ImagePage)).ExtractInto(&s)
   240  	return s.Images, err
   241  }
   242  
   243  // splitFunc is a helper function used to avoid a slice of empty strings.
   244  func splitFunc(c rune) bool {
   245  	return c == ','
   246  }