yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/image.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package apsara 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 "time" 22 23 "yunion.io/x/jsonutils" 24 "yunion.io/x/log" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 "yunion.io/x/onecloud/pkg/util/imagetools" 30 ) 31 32 type ImageStatusType string 33 34 const ( 35 ImageStatusCreating ImageStatusType = "Creating" 36 ImageStatusAvailable ImageStatusType = "Available" 37 ImageStatusUnAvailable ImageStatusType = "UnAvailable" 38 ImageStatusCreateFailed ImageStatusType = "CreateFailed" 39 ) 40 41 type ImageOwnerType string 42 43 const ( 44 ImageOwnerSystem ImageOwnerType = "system" 45 ImageOwnerSelf ImageOwnerType = "self" 46 ImageOwnerOthers ImageOwnerType = "others" 47 ImageOwnerMarketplace ImageOwnerType = "marketplace" 48 ) 49 50 type ImageUsageType string 51 52 const ( 53 ImageUsageInstance ImageUsageType = "instance" 54 ImageUsageNone ImageUsageType = "none" 55 ) 56 57 type SImage struct { 58 multicloud.SImageBase 59 ApsaraTags 60 storageCache *SStoragecache 61 62 // normalized image info 63 imgInfo *imagetools.ImageInfo 64 65 Architecture string 66 CreationTime time.Time 67 Description string 68 ImageId string 69 ImageName string 70 OSName string 71 OSType string 72 ImageOwnerAlias ImageOwnerType 73 IsSupportCloudinit bool 74 IsSupportIoOptimized bool 75 Platform string 76 Size int 77 Status ImageStatusType 78 Usage string 79 } 80 81 func (self *SImage) GetMinRamSizeMb() int { 82 return 0 83 } 84 85 func (self *SImage) GetId() string { 86 return self.ImageId 87 } 88 89 func (self *SImage) GetName() string { 90 if self.ImageOwnerAlias == ImageOwnerSystem { 91 return self.OSName 92 } else { 93 return self.ImageName 94 } 95 } 96 97 func (self *SImage) IsEmulated() bool { 98 return false 99 } 100 101 func (self *SImage) Delete(ctx context.Context) error { 102 return self.storageCache.region.DeleteImage(self.ImageId) 103 } 104 105 func (self *SImage) GetGlobalId() string { 106 return self.ImageId 107 } 108 109 func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { 110 return self.storageCache 111 } 112 113 func (self *SImage) GetStatus() string { 114 switch self.Status { 115 case ImageStatusCreating: 116 return api.CACHED_IMAGE_STATUS_SAVING 117 case ImageStatusAvailable: 118 return api.CACHED_IMAGE_STATUS_ACTIVE 119 case ImageStatusUnAvailable: 120 return api.CACHED_IMAGE_STATUS_CACHE_FAILED 121 case ImageStatusCreateFailed: 122 return api.CACHED_IMAGE_STATUS_CACHE_FAILED 123 default: 124 return api.CACHED_IMAGE_STATUS_CACHE_FAILED 125 } 126 } 127 128 func (self *SImage) GetImageStatus() string { 129 switch self.Status { 130 case ImageStatusCreating: 131 return cloudprovider.IMAGE_STATUS_QUEUED 132 case ImageStatusAvailable: 133 return cloudprovider.IMAGE_STATUS_ACTIVE 134 case ImageStatusUnAvailable: 135 return cloudprovider.IMAGE_STATUS_DELETED 136 case ImageStatusCreateFailed: 137 return cloudprovider.IMAGE_STATUS_KILLED 138 default: 139 return cloudprovider.IMAGE_STATUS_KILLED 140 } 141 } 142 143 func (self *SImage) Refresh() error { 144 new, err := self.storageCache.region.GetImage(self.ImageId) 145 if err != nil { 146 return err 147 } 148 return jsonutils.Update(self, new) 149 } 150 151 func (self *SImage) GetImageType() cloudprovider.TImageType { 152 switch self.ImageOwnerAlias { 153 case ImageOwnerSystem: 154 return cloudprovider.ImageTypeSystem 155 case ImageOwnerSelf: 156 return cloudprovider.ImageTypeCustomized 157 case ImageOwnerMarketplace: 158 return cloudprovider.ImageTypeMarket 159 case ImageOwnerOthers: 160 return cloudprovider.ImageTypeShared 161 default: 162 return cloudprovider.ImageTypeCustomized 163 } 164 } 165 166 func (self *SImage) GetSizeByte() int64 { 167 return int64(self.Size) * 1024 * 1024 * 1024 168 } 169 170 func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { 171 if self.imgInfo == nil { 172 imgInfo := imagetools.NormalizeImageInfo(self.OSName, self.Architecture, self.OSType, self.Platform, "") 173 self.imgInfo = &imgInfo 174 } 175 176 return self.imgInfo 177 } 178 179 func (self *SImage) GetFullOsName() string { 180 return self.OSName 181 } 182 183 func (self *SImage) GetOsType() cloudprovider.TOsType { 184 return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) 185 } 186 187 func (self *SImage) GetOsDist() string { 188 return self.getNormalizedImageInfo().OsDistro 189 } 190 191 func (self *SImage) GetOsVersion() string { 192 return self.getNormalizedImageInfo().OsVersion 193 } 194 195 func (self *SImage) GetOsLang() string { 196 return self.getNormalizedImageInfo().OsLang 197 } 198 199 func (self *SImage) GetOsArch() string { 200 return self.getNormalizedImageInfo().OsArch 201 } 202 203 func (self *SImage) GetBios() cloudprovider.TBiosType { 204 return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) 205 } 206 207 func (self *SImage) GetMinOsDiskSizeGb() int { 208 return 40 209 } 210 211 func (self *SImage) GetImageFormat() string { 212 return "vhd" 213 } 214 215 func (self *SImage) GetCreatedAt() time.Time { 216 return self.CreationTime 217 } 218 219 type ImageExportTask struct { 220 ImageId string 221 RegionId string 222 // RequestId string 223 TaskId string 224 } 225 226 func (self *SRegion) ExportImage(imageId string, bucketName string) (*ImageExportTask, error) { 227 params := make(map[string]string) 228 params["RegionId"] = self.RegionId 229 params["ImageId"] = imageId 230 params["OssBucket"] = bucketName 231 params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) 232 233 if body, err := self.ecsRequest("ExportImage", params); err != nil { 234 return nil, err 235 } else { 236 result := ImageExportTask{} 237 if err := body.Unmarshal(&result); err != nil { 238 log.Errorf("unmarshal result error %s", err) 239 return nil, err 240 } 241 return &result, nil 242 } 243 } 244 245 // {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} 246 247 type ImageImportTask struct { 248 ImageId string 249 RegionId string 250 // RequestId string 251 TaskId string 252 } 253 254 func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, bucket string, key string) (*ImageImportTask, error) { 255 params := make(map[string]string) 256 params["RegionId"] = self.RegionId 257 params["ImageName"] = name 258 if osDist == "RHEL" { 259 osDist = "CentOS" 260 } 261 params["Platform"] = osDist // "Others Linux" 262 params["OSType"] = osType // "linux" 263 params["Architecture"] = osArch // "x86_64" 264 params["DiskDeviceMapping.1.OSSBucket"] = bucket 265 params["DiskDeviceMapping.1.OSSObject"] = key 266 267 log.Debugf("Upload image with params %#v", params) 268 269 body, err := self.ecsRequest("ImportImage", params) 270 if err != nil { 271 log.Errorf("ImportImage fail %s", err) 272 return nil, err 273 } 274 275 log.Infof("%s", body) 276 result := ImageImportTask{} 277 err = body.Unmarshal(&result) 278 if err != nil { 279 log.Errorf("unmarshal result error %s", err) 280 return nil, err 281 } 282 283 return &result, nil 284 } 285 286 func (self *SRegion) GetImage(imageId string) (*SImage, error) { 287 for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { 288 images, _, err := self.GetImages("", owner, []string{imageId}, "", 0, 1) 289 if err != nil { 290 return nil, err 291 } 292 if len(images) == 1 { 293 return &images[0], nil 294 } 295 } 296 return nil, cloudprovider.ErrNotFound 297 } 298 299 func (self *SRegion) GetImageByName(name string) (*SImage, error) { 300 for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { 301 images, _, err := self.GetImages("", owner, nil, name, 0, 1) 302 if err != nil { 303 return nil, err 304 } 305 if len(images) == 1 { 306 return &images[0], nil 307 } 308 } 309 return nil, cloudprovider.ErrNotFound 310 } 311 312 func (self *SRegion) GetImagesBySnapshot(snapshotId string, offset int, limit int) ([]SImage, int, error) { 313 if limit > 50 || limit <= 0 { 314 limit = 50 315 } 316 params := make(map[string]string) 317 params["RegionId"] = self.RegionId 318 params["PageSize"] = fmt.Sprintf("%d", limit) 319 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 320 params["SnapshotId"] = snapshotId 321 322 return self.getImages(params) 323 } 324 325 func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { 326 image, err := self.GetImage(imageId) 327 if err != nil { 328 return "", err 329 } 330 return image.Status, nil 331 } 332 333 func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) { 334 if limit > 50 || limit <= 0 { 335 limit = 50 336 } 337 params := make(map[string]string) 338 params["RegionId"] = self.RegionId 339 params["PageSize"] = fmt.Sprintf("%d", limit) 340 params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) 341 342 if len(status) > 0 { 343 params["Status"] = string(status) 344 } else { 345 params["Status"] = "Creating,Available,UnAvailable,CreateFailed" 346 } 347 if imageId != nil && len(imageId) > 0 { 348 params["ImageId"] = strings.Join(imageId, ",") 349 } 350 if len(owner) > 0 { 351 params["ImageOwnerAlias"] = string(owner) 352 } 353 354 if len(name) > 0 { 355 params["ImageName"] = name 356 } 357 358 return self.getImages(params) 359 } 360 361 func (self *SRegion) getImages(params map[string]string) ([]SImage, int, error) { 362 body, err := self.ecsRequest("DescribeImages", params) 363 if err != nil { 364 log.Errorf("DescribeImages fail %s", err) 365 return nil, 0, err 366 } 367 368 images := make([]SImage, 0) 369 err = body.Unmarshal(&images, "Images", "Image") 370 if err != nil { 371 log.Errorf("unmarshal images fail %s", err) 372 return nil, 0, nil 373 } 374 total, _ := body.Int("TotalCount") 375 return images, int(total), nil 376 } 377 378 func (self *SRegion) DeleteImage(imageId string) error { 379 params := make(map[string]string) 380 params["RegionId"] = self.RegionId 381 params["ImageId"] = imageId 382 params["Force"] = "true" 383 384 _, err := self.ecsRequest("DeleteImage", params) 385 if err != nil { 386 log.Errorf("DeleteImage fail %s", err) 387 return err 388 } 389 return nil 390 }