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 }