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 }