From c7f632f98b1d2746c4a52c3be1efb1cbcbaec42f Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Tue, 22 Jan 2019 00:34:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=EF=BC=9A=E8=8E=B7=E5=8F=96az?= =?UTF-8?q?ure=E5=AE=98=E6=96=B9=E9=95=9C=E5=83=8F=EF=BC=8C=20=E8=BF=98?= =?UTF-8?q?=E7=BC=BA=E5=B0=91=E4=BD=BF=E7=94=A8azure=E5=AE=98=E6=96=B9?= =?UTF-8?q?=E9=95=9C=E5=83=8F=E5=88=9B=E5=BB=BA=E4=B8=BB=E6=9C=BA=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/aws/image.go | 14 ++ pkg/util/aws/storagecache.go | 2 + pkg/util/azure/azure.go | 11 +- pkg/util/azure/disk.go | 4 +- pkg/util/azure/host.go | 4 +- pkg/util/azure/image.go | 264 ++++++++++++++++++++++--- pkg/util/azure/instance.go | 4 +- pkg/util/azure/publisher.go | 198 +++++++++++++++++++ pkg/util/azure/shell/image.go | 40 +++- pkg/util/azure/shell/storageaccount.go | 77 +++++++- pkg/util/azure/storageaccount.go | 19 +- pkg/util/azure/storagecache.go | 8 +- pkg/util/qcloud/storagecache.go | 4 +- 13 files changed, 602 insertions(+), 47 deletions(-) create mode 100644 pkg/util/azure/publisher.go diff --git a/pkg/util/aws/image.go b/pkg/util/aws/image.go index 5023b577bc..3372f950af 100644 --- a/pkg/util/aws/image.go +++ b/pkg/util/aws/image.go @@ -375,3 +375,17 @@ func (self *SRegion) DeleteImage(imageId string) error { _, err := self.ec2Client.DeregisterImage(params) return err } + +func (self *SRegion) addTags(resId string, key string, value string) error { + input := &ec2.CreateTagsInput{} + input.SetResources([]*string{&resId}) + tag := ec2.Tag{} + tag.Key = &key + tag.Value = &value + input.SetTags([]*ec2.Tag{&tag}) + _, err := self.ec2Client.CreateTags(input) + if err != nil { + return err + } + return nil +} \ No newline at end of file diff --git a/pkg/util/aws/storagecache.go b/pkg/util/aws/storagecache.go index 2442580cc8..23e0581dbc 100644 --- a/pkg/util/aws/storagecache.go +++ b/pkg/util/aws/storagecache.go @@ -250,6 +250,8 @@ func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.To log.Debugf("DescribeImportImage Task %s", ret.String()) for _, item := range ret.ImportImageTasks { if *item.Status == "completed" { + // add name tag + self.region.addTags(*item.ImageId, "Name", imageId) return *item.ImageId, nil } } diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index 13215b8aa1..89353eefe5 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -68,6 +68,7 @@ var DEFAULT_API_VERSION = map[string]string{ "Microsoft.ClassicNetwork/reservedIps": "2016-04-01", //2014-01-01,2014-06-01,2015-06-01,2015-12-01,2016-04-01,2016-11-01 "Microsoft.ClassicNetwork/networkSecurityGroups": "2016-11-01", //2015-06-01,2015-12-01,2016-04-01,2016-11-01 "Microsoft.ClassicCompute/domainNames": "2015-12-01", //2014-01-01, 2014-06-01, 2015-06-01, 2015-10-01, 2015-12-01, 2016-04-01, 2016-11-01, 2017-11-01, 2017-11-15 + "Microsoft.Compute/locations": "2018-06-01", } func NewAzureClient(providerId string, providerName string, accessKey string, secret string, envName string) (*SAzureClient, error) { @@ -140,6 +141,7 @@ func (self *SAzureClient) Get(resourceId string, params []string, retVal interfa if err != nil { return err } + fmt.Println(body) err = body.Unmarshal(retVal) if err != nil { return err @@ -172,6 +174,10 @@ func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) { } func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error { + return self.ListResources(resourceType, retVal, []string{"value"}) +} + +func (self *SAzureClient) ListResources(resourceType string, retVal interface{}, keys []string) error { cli, err := self.getDefaultClient() if err != nil { return err @@ -183,14 +189,13 @@ func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error if len(resourceType) > 0 { url += fmt.Sprintf("/providers/%s", resourceType) } - url += "?api-version=2018-06-01" body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "") if err != nil { return err } - fmt.Printf("%s", body) + // fmt.Printf("%s: %s\n", resourceType, body) if retVal != nil { - body.Unmarshal(retVal, "value") + return body.Unmarshal(retVal, keys...) } return nil } diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go index 9eec81b073..a8410ccd59 100644 --- a/pkg/util/azure/disk.go +++ b/pkg/util/azure/disk.go @@ -71,7 +71,9 @@ func (self *SRegion) CreateDisk(storageType string, name string, sizeGb int32, d Type: "Microsoft.Compute/disks", } if len(imageId) > 0 { - image, err := self.GetImage(imageId) + // TODO: need to fix scenarios where image is a public image + // XXX Qiu Jian + image, err := self.getPrivateImage(imageId) if err != nil { return nil, err } diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go index 2ffd102ccc..559fe15f6c 100644 --- a/pkg/util/azure/host.go +++ b/pkg/util/azure/host.go @@ -131,7 +131,9 @@ func (self *SHost) CreateVM2(name string, imgId string, sysDiskSize int, instanc } func (self *SHost) _createVM(name string, imgId string, sysDiskSize int32, cpu int, memMB int, instanceType string, nicId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string, userData string) (string, error) { - image, err := self.zone.region.GetImage(imgId) + // TODO: need to fix scenarios where image is a public image + // XXX Qiu Jian + image, err := self.zone.region.GetImageById(imgId) if err != nil { log.Errorf("Get Image %s fail %s", imgId, err) return "", err diff --git a/pkg/util/azure/image.go b/pkg/util/azure/image.go index 2f4655bdc0..02ecccd12f 100644 --- a/pkg/util/azure/image.go +++ b/pkg/util/azure/image.go @@ -2,13 +2,14 @@ package azure import ( "context" + "fmt" "strings" + "time" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" - "fmt" - "time" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -31,8 +32,9 @@ type ImageOSDisk struct { ManagedDisk *SubResource BlobURI string `json:"blobUri,omitempty"` Caching string `json:"caching,omitempty"` - DiskSizeGB int32 `json:"diskSizeGB,omitempty"` + DiskSizeGB int32 `json:"diskSizeGB,omitzero"` StorageAccountType string `json:"storageAccountType,omitempty"` + OperatingSystem string `json:"operatingSystem,omitempty"` } type ImageDataDisk struct { @@ -41,16 +43,18 @@ type ImageDataDisk struct { ManagedDisk SubResource BlobURI string Caching string - DiskSizeGB int32 + DiskSizeGB int32 `json:"diskSizeGB,omitzero"` StorageAccountType string } -type DataDisks []ImageDataDisk - type ImageStorageProfile struct { - OsDisk ImageOSDisk `json:"osDisk,omitempty"` - DataDisks *DataDisks - ZoneResilient *bool + OsDisk ImageOSDisk `json:"osDisk,omitempty"` + DataDisks []ImageDataDisk `json:"dataDisks,omitempty"` + ZoneResilient bool `json:"zoneResilient,omitfalse"` +} + +type SAutomaticOSUpgradeProperties struct { + AutomaticOSUpgradeSupported bool } type ImageProperties struct { @@ -63,10 +67,17 @@ type SImage struct { storageCache *SStoragecache Properties ImageProperties `json:"properties,omitempty"` - ID string + ID string `json:"id,omitempty"` Name string - Type string `` + Type string Location string + + Publisher string + Offer string + Sku string + Version string + + ImageType string } func (self *SImage) GetMetadata() *jsonutils.JSONDict { @@ -119,7 +130,7 @@ func (self *SImage) GetImageStatus() string { } func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.Name) + new, err := self.storageCache.region.GetImageById(self.ID) if err != nil { return err } @@ -127,7 +138,7 @@ func (self *SImage) Refresh() error { } func (self *SImage) GetImageType() string { - return "" + return self.ImageType } func (self *SImage) GetSize() int64 { @@ -135,19 +146,36 @@ func (self *SImage) GetSize() int64 { } func (self *SImage) isPublic() bool { + if self.ImageType == cloudprovider.CachedImageTypeCustomized { + return false + } return true } +func (self *SImage) GetOsType() string { + osType := self.Properties.StorageProfile.OsDisk.OsType + if len(osType) == 0 { + osType = publisherGetOsType(self.Publisher) + } + return osType +} + func (self *SImage) GetOsArch() string { - return "x86_64" + if self.ImageType == cloudprovider.CachedImageTypeCustomized { + return "x86_64" + } + return publisherGetOsArch(self.Publisher, self.Offer, self.Sku, self.Version) } func (self *SImage) GetOsDist() string { - return "CentOS" + if self.ImageType == cloudprovider.CachedImageTypeCustomized { + return "" + } + return publisherGetOsDist(self.Publisher, self.Offer, self.Sku, self.Version) } func (self *SImage) GetOsVersion() string { - return "" + return publisherGetOsVersion(self.Publisher, self.Offer, self.Sku, self.Version) } func (self *SImage) GetMinOsDiskSizeGb() int { @@ -167,19 +195,31 @@ func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { } func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { - if image, err := self.GetImage(imageId); err != nil { + if image, err := self.GetImageById(imageId); err != nil { return "", err } else { return image.Properties.ProvisioningState, nil } } -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - image := SImage{} - return &image, self.client.Get(imageId, []string{}, &image) +func (self *SRegion) GetImageById(imageId string) (SImage, error) { + if strings.HasPrefix(strings.ToLower(imageId), "/subscriptions/") { + return self.getPrivateImage(imageId) + } else { + return self.getOfferedImage(imageId) + } } -func (self *SRegion) GetImageByName(name string) (*SImage, error) { +func (self *SRegion) getPrivateImage(imageId string) (SImage, error) { + image := SImage{} + err := self.client.Get(imageId, []string{}, &image) + if err != nil { + return image, err + } + return image, nil +} + +/* func (self *SRegion) GetImageByName(name string) (*SImage, error) { images := []SImage{} err := self.client.ListAll("Microsoft.Compute/images", &images) if err != nil { @@ -205,7 +245,7 @@ func (self *SRegion) GetImageById(idstr string) (*SImage, error) { } } return nil, cloudprovider.ErrNotFound -} +}*/ func (self *SRegion) CreateImageByBlob(imageName, osType, blobURI string, diskSizeGB int32) (*SImage, error) { if diskSizeGB < 1 || diskSizeGB > 4095 { @@ -249,28 +289,109 @@ func (self *SRegion) CreateImage(snapshotId, imageName, osType, imageDesc string return &image, self.client.Create(jsonutils.Marshal(image), &image) } -func (self *SRegion) GetImages() ([]SImage, error) { +func (self *SRegion) getOfferedImages(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, imageType string, latestVer bool) ([]SImage, error) { + images := make([]SImage, 0) + idList, err := self.GetOfferedImageIDs(publishersFilter, offersFilter, skusFilter, verFilter, latestVer) + if err != nil { + return nil, err + } + for _, id := range idList { + image, err := self.getOfferedImage(id) + image.ImageType = imageType + if err == nil { + images = append(images, image) + } + } + return images, nil +} + +func (self *SRegion) GetOfferedImageIDs(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, latestVer bool) ([]string, error) { + idList := make([]string, 0) + publishers, err := self.GetImagePublishers(toLowerStringArray(publishersFilter)) + if err != nil { + return nil, err + } + for _, publisher := range publishers { + offers, err := self.getImageOffers(publisher, toLowerStringArray(offersFilter)) + if err != nil { + return nil, err + } + for _, offer := range offers { + skus, err := self.getImageSkus(publisher, offer, toLowerStringArray(skusFilter)) + if err != nil { + return nil, err + } + for _, sku := range skus { + verFilter = toLowerStringArray(verFilter) + vers, err := self.getImageVersions(publisher, offer, sku, verFilter) + if err != nil { + return nil, err + } + if latestVer && len(vers) > 0 { + vers = []string{vers[len(vers)-1]} + } + for _, ver := range vers { + idStr := strings.Join([]string{publisher, offer, sku, ver}, "/") + idList = append(idList, idStr) + } + } + } + } + return idList, nil +} + +func (self *SRegion) getPrivateImages() ([]SImage, error) { result := []SImage{} images := []SImage{} err := self.client.ListAll("Microsoft.Compute/images", &images) if err != nil { return nil, err } - fmt.Printf("%s", images) for i := 0; i < len(images); i++ { if images[i].Location == self.Name { + images[i].ImageType = cloudprovider.CachedImageTypeCustomized result = append(result, images[i]) } } return result, nil } +func toLowerStringArray(input []string) []string { + output := make([]string, len(input)) + for i := range input { + output[i] = strings.ToLower(input[i]) + } + return output +} + +func (self *SRegion) GetImages(imageType string) ([]SImage, error) { + images := make([]SImage, 0) + if len(imageType) == 0 { + ret, _ := self.getPrivateImages() + if len(ret) > 0 { + images = append(images, ret...) + } + ret, _ = self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.CachedImageTypeSystem, true) + if len(ret) > 0 { + images = append(images, ret...) + } + return images, nil + } + switch imageType { + case cloudprovider.CachedImageTypeCustomized: + return self.getPrivateImages() + case cloudprovider.CachedImageTypeSystem: + return self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.CachedImageTypeSystem, true) + default: + return self.getOfferedImages(nil, nil, nil, nil, cloudprovider.CachedImageTypeMarket, true) + } +} + func (self *SRegion) DeleteImage(imageId string) error { return self.client.Delete(imageId) } func (self *SImage) GetBlobUri() string { - return self.Properties.StorageProfile.OsDisk.BlobURI } @@ -278,6 +399,95 @@ func (self *SImage) Delete(ctx context.Context) error { return self.storageCache.region.DeleteImage(self.ID) } -func (self *SImage) GetOsType() string { - return string(self.Properties.StorageProfile.OsDisk.OsType) +type SAzureImageResource struct { + Id string + Name string + Location string +} + +func (region *SRegion) GetImagePublishers(filter []string) ([]string, error) { + publishers := make([]SAzureImageResource, 0) + err := region.client.ListResources(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers", region.Name), &publishers, nil) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range publishers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(publishers[i].Name), filter) { + ret = append(ret, publishers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageOffers(publisher string, filter []string) ([]string, error) { + offsers := make([]SAzureImageResource, 0) + err := region.client.ListResources(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers", region.Name, publisher), &offsers, nil) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range offsers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(offsers[i].Name), filter) { + ret = append(ret, offsers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageSkus(publisher string, offser string, filter []string) ([]string, error) { + skus := make([]SAzureImageResource, 0) + err := region.client.ListResources(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus", region.Name, publisher, offser), &skus, nil) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range skus { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(skus[i].Name), filter) { + ret = append(ret, skus[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageVersions(publisher string, offer string, sku string, filter []string) ([]string, error) { + vers := make([]SAzureImageResource, 0) + err := region.client.ListResources(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions", region.Name, publisher, offer, sku), &vers, nil) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range vers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(vers[i].Name), filter) { + ret = append(ret, vers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getOfferedImage(offerId string) (SImage, error) { + image := SImage{} + + parts := strings.Split(offerId, "/") + if len(parts) < 4 { + return image, fmt.Errorf("invalid image ID %s", offerId) + } + publisher := parts[0] + offer := parts[1] + sku := parts[2] + version := parts[3] + //err := region.client.Get(fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions/%s", region.client.subscriptionId, region.Name, publisher, offer, sku, version), nil, &image) + //if err != nil { + // return image, err + //} + image.ID = offerId + image.Location = region.Name + image.Type = "Microsoft.Compute/vmimage" + image.Name = publisherGetName(publisher, offer, sku, version) + image.Publisher = publisher + image.Offer = offer + image.Sku = sku + image.Version = version + image.Properties.ProvisioningState = ImageStatusAvailable + return image, nil } diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index bbb935fef6..62f0a2d14d 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -696,7 +696,9 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey if err != nil { return "", err } - image, err := region.GetImage(imageId) + // TODO: need to fix scenarios where image is a public image + // XXX Qiu Jian + image, err := region.getPrivateImage(imageId) if err != nil { return "", err } diff --git a/pkg/util/azure/publisher.go b/pkg/util/azure/publisher.go new file mode 100644 index 0000000000..e428dd4c15 --- /dev/null +++ b/pkg/util/azure/publisher.go @@ -0,0 +1,198 @@ +package azure + +import ( + "fmt" + "strings" +) + +type SPublisherDriver struct { + OsType string + GetOsDist func(offser, sku, version string) string + GetOsVersion func(offser, sku, version string) string + GetOsArch func(offser, sku, version string) string + GetName func(offser, sku, version string) string +} + +var publisherDrivers = map[string]SPublisherDriver{ + // Microsoft Windows Server + "MicrosoftWindowsServer": { + OsType: "Windows", + GetOsDist: func(offer, sku, version string) string { + parts := strings.Split(sku, "-") + return fmt.Sprintf("Windows Server %s", strings.Join(parts, " ")) + }, + GetOsVersion: func(offer, sku, version string) string { + parts := strings.Split(sku, "-") + return parts[0] + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s-%s", offer, sku, version) + }, + }, + // RHEL + "RedHat": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "RHEL" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s", offer, version) + }, + }, + // Ubuntu + "Canonical": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "Ubuntu" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s", offer, version) + }, + }, + // CentOS + "OpenLogic": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "CentOS" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s", offer, version) + }, + }, + // SUSE + "SUSE": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "SUSE" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s-%s", offer, sku, version) + }, + }, + // CoreOS + "CoreOS": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "CoreOS" + }, + GetOsVersion: func(offer, sku, version string) string { + return version + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s-%s", offer, sku, version) + }, + }, + // Debian + "credativ": { + OsType: "Linux", + GetOsDist: func(offer, sku, version string) string { + return "Debian" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s", offer, version) + }, + }, + // FreeBSD + "MicrosoftOSTC": { + OsType: "FreeBSD", + GetOsDist: func(offer, sku, version string) string { + return "FreeBSD" + }, + GetOsVersion: func(offer, sku, version string) string { + return sku + }, + GetOsArch: func(offer, sku, version string) string { + return "x86_64" + }, + GetName: func(offer, sku, version string) string { + return fmt.Sprintf("%s-%s", offer, version) + }, + }, +} + +var knownPublishers []string + +func init() { + knownPublishers = make([]string, len(publisherDrivers)) + i := 0 + for k := range publisherDrivers { + knownPublishers[i] = strings.ToLower(k) + i += 1 + } +} + +func publisherGetName(publisher, offer, sku, version string) string { + driver, ok := publisherDrivers[publisher] + if ok { + return driver.GetName(offer, sku, version) + } + return fmt.Sprintf("%s-%s-%s", offer, sku, version) +} + +func publisherGetOsType(publisher string) string { + driver, ok := publisherDrivers[publisher] + if ok { + return driver.OsType + } + return "Linux" +} + +func publisherGetOsDist(publisher, offer, sku, version string) string { + driver, ok := publisherDrivers[publisher] + if ok { + return driver.GetOsDist(offer, sku, version) + } + return offer +} + +func publisherGetOsVersion(publisher, offer, sku, version string) string { + driver, ok := publisherDrivers[publisher] + if ok { + return driver.GetOsVersion(offer, sku, version) + } + return sku +} + +func publisherGetOsArch(publisher, offer, sku, version string) string { + driver, ok := publisherDrivers[publisher] + if ok { + return driver.GetOsArch(offer, sku, version) + } + return "x86_64" +} diff --git a/pkg/util/azure/shell/image.go b/pkg/util/azure/shell/image.go index 9dbf4302a7..54abeb4ce0 100644 --- a/pkg/util/azure/shell/image.go +++ b/pkg/util/azure/shell/image.go @@ -1,24 +1,56 @@ package shell import ( + "fmt" + "sort" "yunion.io/x/onecloud/pkg/util/azure" "yunion.io/x/onecloud/pkg/util/shellutils" ) func init() { type ImageListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` + ImageType string `help:"image type" choices:"customized|system|shared|market"` } shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *azure.SRegion, args *ImageListOptions) error { - if images, err := cli.GetImages(); err != nil { + if images, err := cli.GetImages(args.ImageType); err != nil { return err } else { - printList(images, len(images), args.Offset, args.Limit, []string{}) + printList(images, len(images), 0, 0, []string{}) return nil } }) + type ImagePublishersOptions struct { + } + shellutils.R(&ImagePublishersOptions{}, "image-publisher-list", "List image providers", func(cli *azure.SRegion, args *ImagePublishersOptions) error { + providers, err := cli.GetImagePublishers(nil) + if err != nil { + return err + } + sort.Strings(providers) + fmt.Println(providers) + return nil + }) + + type ImageOfferedIDOptions struct { + Publisher []string `help:"publisher candidates"` + Offer []string `help:"offer candidates"` + Sku []string `help:"sku candidates"` + Version []string `help:"version candidates"` + Latest bool `help:"show latest version only"` + } + shellutils.R(&ImageOfferedIDOptions{}, "public-image-id-list", "List image providers", func(cli *azure.SRegion, args *ImageOfferedIDOptions) error { + idList, err := cli.GetOfferedImageIDs(args.Publisher, args.Offer, args.Sku, args.Version, args.Latest) + if err != nil { + return err + } + sort.Strings(idList) + for _, id := range idList { + fmt.Println(id) + } + return nil + }) + type ImageCreateOptions struct { NAME string `helo:"Image name"` OSTYPE string `helo:"Operation system" choices:"Linux|Windows"` diff --git a/pkg/util/azure/shell/storageaccount.go b/pkg/util/azure/shell/storageaccount.go index 3d3bbf167b..c48895c479 100644 --- a/pkg/util/azure/shell/storageaccount.go +++ b/pkg/util/azure/shell/storageaccount.go @@ -30,12 +30,12 @@ func init() { }) shellutils.R(&StorageAccountOptions{}, "storage-account-show", "Show storage account detail", func(cli *azure.SRegion, args *StorageAccountOptions) error { - if account, err := cli.GetStorageAccountDetail(args.ID); err != nil { + account, err := cli.GetStorageAccountDetail(args.ID) + if err != nil { return err - } else { - printObject(account) - return nil } + printObject(account) + return nil }) shellutils.R(&StorageAccountOptions{}, "storage-account-key", "Get storage account key", func(cli *azure.SRegion, args *StorageAccountOptions) error { @@ -47,6 +47,75 @@ func init() { } }) + shellutils.R(&StorageAccountOptions{}, "storage-container-list", "Get list of containers of a storage account", func(cli *azure.SRegion, args *StorageAccountOptions) error { + account, err := cli.GetStorageAccountDetail(args.ID) + if err != nil { + return err + } + containers, err := account.GetContainers() + if err != nil { + return err + } + printList(containers, len(containers), 0, 0, nil) + return nil + }) + + type StorageAccountCreateContainerOptions struct { + ACCOUNT string `help:"storage account ID"` + CONTAINER string `help:"name of container to create"` + } + shellutils.R(&StorageAccountCreateContainerOptions{}, "storage-container-create", "Create a container in a storage account", func(cli *azure.SRegion, args *StorageAccountCreateContainerOptions) error { + account, err := cli.GetStorageAccountDetail(args.ACCOUNT) + if err != nil { + return err + } + container, err := account.CreateContainer(args.CONTAINER) + if err != nil { + return err + } + printObject(container) + return nil + }) + + shellutils.R(&StorageAccountCreateContainerOptions{}, "storage-container-list-objects", "Create a container in a storage account", func(cli *azure.SRegion, args *StorageAccountCreateContainerOptions) error { + account, err := cli.GetStorageAccountDetail(args.ACCOUNT) + if err != nil { + return err + } + container, err := account.GetContainer(args.CONTAINER) + if err != nil { + return err + } + blobs, err := container.ListFiles() + if err != nil { + return err + } + printList(blobs, len(blobs), 0, 0, nil) + return nil + }) + + type StorageAccountUploadOptions struct { + ACCOUNT string `help:"storage account ID"` + CONTAINER string `help:"name of container to create"` + FILE string `help:"local file to upload"` + } + shellutils.R(&StorageAccountUploadOptions{}, "storage-container-upload", "Upload a container in a storage account", func(cli *azure.SRegion, args *StorageAccountUploadOptions) error { + account, err := cli.GetStorageAccountDetail(args.ACCOUNT) + if err != nil { + return err + } + container, err := account.GetContainer(args.CONTAINER) + if err != nil { + return err + } + url, err := container.UploadFile(args.FILE) + if err != nil { + return err + } + fmt.Println(url) + return nil + }) + type StorageAccountCreateOptions struct { NAME string `help:"StorageAccount NAME"` } diff --git a/pkg/util/azure/storageaccount.go b/pkg/util/azure/storageaccount.go index 8b146f0fcb..26ff8a5ffb 100644 --- a/pkg/util/azure/storageaccount.go +++ b/pkg/util/azure/storageaccount.go @@ -156,7 +156,11 @@ func (self *SRegion) getStorageAccountID(storageAccount string) (*SStorageAccoun func (self *SRegion) GetStorageAccountDetail(accountId string) (*SStorageAccount, error) { account := SStorageAccount{region: self} - return &account, self.client.Get(accountId, []string{}, &account) + err := self.client.Get(accountId, []string{}, &account) + if err != nil { + return nil, err + } + return &account, nil } type AccountKeys struct { @@ -269,6 +273,19 @@ func (self *SStorageAccount) GetContainers() ([]SContainer, error) { return containers, nil } +func (self *SStorageAccount) GetContainer(name string) (*SContainer, error) { + containers, err := self.GetContainers() + if err != nil { + return nil, err + } + for i := range containers { + if containers[i].Name == name { + return &containers[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + func (self *SContainer) ListFiles() ([]storage.Blob, error) { storageaccount := self.storageaccount client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env) diff --git a/pkg/util/azure/storagecache.go b/pkg/util/azure/storagecache.go index 080c748d37..46e80447f9 100644 --- a/pkg/util/azure/storagecache.go +++ b/pkg/util/azure/storagecache.go @@ -66,7 +66,7 @@ func (self *SStoragecache) GetManagerId() string { } func (self *SStoragecache) fetchImages() error { - if images, err := self.region.GetImages(); err != nil { + if images, err := self.region.GetImages(""); err != nil { return err } else { self.iimages = make([]cloudprovider.ICloudImage, len(images)) @@ -93,7 +93,7 @@ func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImag return nil, err } img.storageCache = self - return img, nil + return &img, nil } func (self *SStoragecache) GetPath() string { @@ -227,7 +227,9 @@ func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imag } func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - if image, err := self.region.GetImage(extId); err != nil { + // TODO: need to fix scenarios where image is a public image + // XXX Qiu Jian + if image, err := self.region.getPrivateImage(extId); err != nil { return nil, err } else if snapshotId := image.Properties.StorageProfile.OsDisk.Snapshot.ID; len(snapshotId) == 0 { return nil, cloudprovider.ErrNotFound diff --git a/pkg/util/qcloud/storagecache.go b/pkg/util/qcloud/storagecache.go index 580633375b..120c6c694e 100644 --- a/pkg/util/qcloud/storagecache.go +++ b/pkg/util/qcloud/storagecache.go @@ -84,7 +84,7 @@ func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imag func (self *SStoragecache) fetchImages() error { images := make([]SImage, 0) for { - parts, total, err := self.region.GetImages("", "PRIVATE_IMAGE", nil, "", len(images), 50) + parts, total, err := self.region.GetImages("", "", nil, "", len(images), 50) if err != nil { return err } @@ -112,7 +112,7 @@ func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { } func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - parts, _, err := self.region.GetImages("", "PRIVATE_IMAGE", []string{extId}, "", 0, 1) + parts, _, err := self.region.GetImages("", "", []string{extId}, "", 0, 1) if err != nil { return nil, err }