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