yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/google/storagecache.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 google
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"unicode"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    26  	"yunion.io/x/pkg/utils"
    27  
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/onecloud/pkg/image/options"
    30  	"yunion.io/x/onecloud/pkg/mcclient"
    31  	"yunion.io/x/onecloud/pkg/mcclient/auth"
    32  	modules "yunion.io/x/onecloud/pkg/mcclient/modules/image"
    33  	"yunion.io/x/cloudmux/pkg/multicloud"
    34  	"yunion.io/x/onecloud/pkg/util/qemuimg"
    35  )
    36  
    37  type SStoragecache struct {
    38  	multicloud.SResourceBase
    39  	GoogleTags
    40  	region *SRegion
    41  
    42  	iimages []cloudprovider.ICloudImage
    43  }
    44  
    45  func (cache *SStoragecache) GetId() string {
    46  	return cache.region.client.cpcfg.Id
    47  }
    48  
    49  func (cache *SStoragecache) GetName() string {
    50  	return cache.region.client.cpcfg.Name
    51  }
    52  
    53  func (cache *SStoragecache) GetStatus() string {
    54  	return "available"
    55  }
    56  
    57  func (cache *SStoragecache) Refresh() error {
    58  	return nil
    59  }
    60  
    61  func (cache *SStoragecache) GetGlobalId() string {
    62  	return cache.region.client.cpcfg.Id
    63  }
    64  
    65  func (cache *SStoragecache) IsEmulated() bool {
    66  	return true
    67  }
    68  
    69  func (cache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) {
    70  	return nil, cloudprovider.ErrNotImplemented
    71  }
    72  
    73  func (cache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) {
    74  	images, err := cache.region.GetImages(cache.region.client.projectId, 1000, "")
    75  	if err != nil {
    76  		return nil, errors.Wrapf(err, "GetImages")
    77  	}
    78  	ret := []cloudprovider.ICloudImage{}
    79  	for i := range images {
    80  		images[i].storagecache = cache
    81  		ret = append(ret, &images[i])
    82  	}
    83  	return ret, nil
    84  }
    85  
    86  func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) {
    87  	image, err := cache.region.GetImage(extId)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return image, nil
    92  }
    93  
    94  func (cache *SStoragecache) GetPath() string {
    95  	return ""
    96  }
    97  
    98  func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) {
    99  	return cache.uploadImage(ctx, userCred, image, callback)
   100  }
   101  
   102  func (region *SRegion) checkAndCreateBucket(bucketName string) (*SBucket, error) {
   103  	bucket, err := region.GetBucket(bucketName)
   104  	if err != nil {
   105  		if errors.Cause(err) == cloudprovider.ErrNotFound {
   106  			bucket, err = region.CreateBucket(bucketName, "", cloudprovider.ACLPrivate)
   107  			if err != nil {
   108  				return nil, errors.Wrapf(err, "region.CreateBucket(%s)", bucketName)
   109  			}
   110  		} else {
   111  			return nil, errors.Wrapf(err, "region.StorageGet(%s)", bucketName)
   112  		}
   113  	}
   114  	return bucket, nil
   115  }
   116  
   117  func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) {
   118  	s := auth.GetAdminSession(ctx, options.Options.Region)
   119  
   120  	meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false)
   121  	if err != nil {
   122  		return "", err
   123  	}
   124  	log.Infof("meta data %s", meta)
   125  
   126  	info := struct {
   127  		Id          string
   128  		Name        string
   129  		Size        int64
   130  		Description string
   131  	}{}
   132  	meta.Unmarshal(&info)
   133  
   134  	bucketName := fmt.Sprintf("imagecache-%s", info.Id)
   135  	bucket, err := cache.region.checkAndCreateBucket(bucketName)
   136  	if err != nil {
   137  		return "", errors.Wrapf(err, "checkAndCreateBucket(%s)", bucketName)
   138  	}
   139  
   140  	defer cache.region.DeleteBucket(bucket.Name)
   141  
   142  	log.Debugf("To upload image to bucket %s ...", bucketName)
   143  	body := multicloud.NewProgress(sizeBytes, 80, reader, callback)
   144  	err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false)
   145  	if err != nil {
   146  		return "", errors.Wrap(err, "UploadObjectWithProgress")
   147  	}
   148  
   149  	images, err := cache.region.GetImages(cache.region.GetProjectId(), 0, "")
   150  	if err != nil {
   151  		return "", errors.Wrap(err, "region.GetImages")
   152  	}
   153  	imageNames := []string{}
   154  	for _, image := range images {
   155  		imageNames = append(imageNames, image.Name)
   156  	}
   157  
   158  	imageName := "img-"
   159  	for _, s := range strings.ToLower(info.Name) {
   160  		if unicode.IsDigit(s) || unicode.IsLetter(s) || s == '-' {
   161  			imageName = fmt.Sprintf("%s%c", imageName, s)
   162  		} else {
   163  			imageName = fmt.Sprintf("%s-", imageName)
   164  		}
   165  	}
   166  
   167  	baseName := imageName
   168  	for i := 0; i < 30; i++ {
   169  		if !utils.IsInStringArray(imageName, imageNames) {
   170  			break
   171  		}
   172  		imageName = fmt.Sprintf("%s-%d", baseName, i)
   173  	}
   174  
   175  	_image, err := cache.region.CreateImage(imageName, info.Description, bucketName, info.Name)
   176  	if err != nil {
   177  		return "", errors.Wrap(err, "region.CreateImage")
   178  	}
   179  
   180  	if callback != nil {
   181  		callback(100)
   182  	}
   183  
   184  	return _image.GetGlobalId(), nil
   185  }
   186  
   187  func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
   188  	return nil, cloudprovider.ErrNotImplemented
   189  }
   190  
   191  func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
   192  	return nil, cloudprovider.ErrNotImplemented
   193  }
   194  
   195  func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) {
   196  	cache := &SStoragecache{region: region}
   197  	return []cloudprovider.ICloudStoragecache{cache}, nil
   198  }
   199  
   200  func (region *SRegion) getStoragecache() *SStoragecache {
   201  	return &SStoragecache{region: region}
   202  }
   203  
   204  func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
   205  	cache := region.getStoragecache()
   206  	if id == cache.GetGlobalId() {
   207  		return cache, nil
   208  	}
   209  	return nil, cloudprovider.ErrNotFound
   210  }