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  }