From f63ee0b716a396f8de9db933a837032f199d80fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Wed, 24 Oct 2018 11:09:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=8F=E5=B0=91API=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/disks.go | 20 +- pkg/compute/models/guests.go | 6 +- pkg/compute/models/wires.go | 4 +- pkg/util/azure/azure.go | 286 ++++++++++++------------ pkg/util/azure/classic_disk.go | 118 ++++++---- pkg/util/azure/classic_host.go | 8 +- pkg/util/azure/classic_instance.go | 128 ++++++----- pkg/util/azure/classic_network.go | 3 +- pkg/util/azure/classic_secruitygroup.go | 6 +- pkg/util/azure/classic_snapshot.go | 74 ++++++ pkg/util/azure/classic_storage.go | 34 +-- pkg/util/azure/disk.go | 107 +++++---- pkg/util/azure/eip.go | 6 +- pkg/util/azure/host.go | 29 ++- pkg/util/azure/instance.go | 236 +++++++++++-------- pkg/util/azure/instancenic.go | 3 +- pkg/util/azure/network.go | 12 +- pkg/util/azure/networkinterface.go | 17 +- pkg/util/azure/region.go | 47 +--- pkg/util/azure/securitygroup.go | 6 +- pkg/util/azure/shell/instance.go | 14 +- pkg/util/azure/snapshot.go | 57 ++++- pkg/util/azure/storage.go | 45 ++-- pkg/util/azure/storageaccount.go | 144 ++++++++++-- pkg/util/azure/storagecache.go | 47 +++- pkg/util/azure/vpc.go | 25 +-- pkg/util/azure/wire.go | 21 +- pkg/util/azure/zone.go | 81 ++++--- 28 files changed, 971 insertions(+), 613 deletions(-) create mode 100644 pkg/util/azure/classic_snapshot.go diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 9165c8f407..700869341a 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -651,7 +651,7 @@ func (manager *SDiskManager) getDisksByStorage(storage *SStorage) ([]SDisk, erro return disks, nil } -func (manager *SDiskManager) syncCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, vdisk cloudprovider.ICloudDisk) (*SDisk, error) { +func (manager *SDiskManager) syncCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, vdisk cloudprovider.ICloudDisk, index int) (*SDisk, error) { diskObj, err := manager.FetchByExternalId(vdisk.GetGlobalId()) if err != nil { if err == sql.ErrNoRows { @@ -662,13 +662,13 @@ func (manager *SDiskManager) syncCloudDisk(ctx context.Context, userCred mcclien return nil, err } storage := storageObj.(*SStorage) - return manager.newFromCloudDisk(ctx, userCred, vdisk, storage) + return manager.newFromCloudDisk(ctx, userCred, vdisk, storage, index) } else { return nil, err } } else { disk := diskObj.(*SDisk) - err = disk.syncWithCloudDisk(ctx, userCred, vdisk) + err = disk.syncWithCloudDisk(ctx, userCred, vdisk, index) if err != nil { return nil, err } @@ -708,7 +708,7 @@ func (manager *SDiskManager) SyncDisks(ctx context.Context, userCred mcclient.To } for i := 0; i < len(commondb); i += 1 { - err = commondb[i].syncWithCloudDisk(ctx, userCred, commonext[i]) + err = commondb[i].syncWithCloudDisk(ctx, userCred, commonext[i], -1) if err != nil { syncResult.UpdateError(err) } else { @@ -719,7 +719,7 @@ func (manager *SDiskManager) SyncDisks(ctx context.Context, userCred mcclient.To } for i := 0; i < len(added); i += 1 { - new, err := manager.newFromCloudDisk(ctx, userCred, added[i], storage) + new, err := manager.newFromCloudDisk(ctx, userCred, added[i], storage, -1) if err != nil { syncResult.AddError(err) } else { @@ -732,7 +732,7 @@ func (manager *SDiskManager) SyncDisks(ctx context.Context, userCred mcclient.To return localDisks, remoteDisks, syncResult } -func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, extDisk cloudprovider.ICloudDisk) error { +func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, extDisk cloudprovider.ICloudDisk, index int) error { _, err := self.GetModelManager().TableSpec().Update(self, func() error { extDisk.Refresh() self.Name = extDisk.GetName() @@ -742,6 +742,9 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke self.AutoDelete = extDisk.GetIsAutoDelete() // self.TemplateId = extDisk.GetTemplateId() no sync template ID self.DiskType = extDisk.GetDiskType() + if index == 0 { + self.DiskType = DISK_TYPE_SYS + } // self.FsFormat = extDisk.GetFsFormat() self.Nonpersistent = extDisk.GetIsNonPersistent() @@ -775,7 +778,7 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke return nil } -func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, extDisk cloudprovider.ICloudDisk, storage *SStorage) (*SDisk, error) { +func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mcclient.TokenCredential, extDisk cloudprovider.ICloudDisk, storage *SStorage, index int) (*SDisk, error) { disk := SDisk{} disk.SetModelManager(manager) @@ -789,6 +792,9 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl disk.DiskSize = extDisk.GetDiskSizeMB() disk.AutoDelete = extDisk.GetIsAutoDelete() disk.DiskType = extDisk.GetDiskType() + if index == 0 { + disk.DiskType = DISK_TYPE_SYS + } disk.Nonpersistent = extDisk.GetIsNonPersistent() disk.IsEmulated = extDisk.IsEmulated() diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 999bfa112b..3b8603ad0b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1883,8 +1883,9 @@ func (self *SGuest) SyncVMDisks(ctx context.Context, userCred mcclient.TokenCred if len(vdisks[i].GetGlobalId()) == 0 { continue } - disk, err := DiskManager.syncCloudDisk(ctx, userCred, vdisks[i]) + disk, err := DiskManager.syncCloudDisk(ctx, userCred, vdisks[i], i) if err != nil { + log.Errorf("syncCloudDisk error: %v", err) result.Error(err) return result } @@ -1934,6 +1935,7 @@ func (self *SGuest) SyncVMDisks(ctx context.Context, userCred mcclient.TokenCred vdisk := needAdds[i].vdisk err := self.attach2Disk(needAdds[i].disk, userCred, vdisk.GetDriver(), vdisk.GetCacheMode(), vdisk.GetMountpoint()) if err != nil { + log.Errorf("attach2Disk error: %v", err) result.AddError(err) } else { result.Add() @@ -4257,10 +4259,12 @@ func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCreden // add neip, err := ElasticipManager.getEipByExtEip(userCred, extEip, self.getRegion()) if err != nil { + log.Errorf("getEipByExtEip error %v", err) result.AddError(err) } else { err = neip.AssociateVM(userCred, self) if err != nil { + log.Errorf("AssociateVM error %v", err) result.AddError(err) } else { result.Add() diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 345de3fd12..fc89f879a1 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -233,7 +233,7 @@ func (manager *SWireManager) newFromCloudWire(extWire cloudprovider.ICloudWire, wire.VpcId = vpc.Id zoneObj, err := ZoneManager.FetchByExternalId(extWire.GetIZone().GetGlobalId()) if err != nil { - log.Errorf("cannot find zone for wire %s", err) + log.Errorf("cannot find zone %s for wire %s", extWire.GetIZone().GetGlobalId(), err) return nil, err } wire.ZoneId = zoneObj.(*SZone).Id @@ -605,4 +605,4 @@ func (self *SWire) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict } } return extra -} \ No newline at end of file +} diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index a7f67f7a2d..e444dd2f43 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -29,24 +29,28 @@ const ( ) type SAzureClient struct { - client autorest.Client - providerId string - providerName string - subscriptionId string - tenantId string - clientId string - clientScret string - domain string - baseUrl string - secret string - envName string - subscriptionName string - env azureenv.Environment - authorizer autorest.Authorizer - iregions []cloudprovider.ICloudRegion + client autorest.Client + providerId string + providerName string + subscriptionId string + tenantId string + clientId string + clientScret string + domain string + baseUrl string + secret string + envName string + ressourceGroups []SResourceGroup + fetchResourceGroups bool + subscriptionName string + env azureenv.Environment + authorizer autorest.Authorizer + iregions []cloudprovider.ICloudRegion } var DEFAULT_API_VERSION = map[string]string{ + "vmSizes": "2018-06-01", //2015-05-01-preview,2015-06-15,2016-03-30,2016-04-30-preview,2016-08-30,2017-03-30,2017-12-01,2018-04-01,2018-06-01,2018-10-01 + "Microsoft.Compute/virtualMachineScaleSets": "2017-12-01", "Microsoft.Compute/virtualMachines": "2018-04-01", "Microsoft.ClassicCompute/virtualMachines": "2017-04-01", "Microsoft.Compute/operations": "2018-10-01", @@ -111,13 +115,7 @@ func (self *SAzureClient) jsonRequest(method, url string, body string) (jsonutil if err != nil { return nil, err } - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(strings.ToLower(url), strings.ToLower(resourceType)) > 0 { - version = _version - } - } - return jsonRequest(cli, method, version, self.domain, url, body) + return jsonRequest(cli, method, self.domain, url, body) } func (self *SAzureClient) Get(resourceId string, retVal interface{}) error { @@ -125,13 +123,7 @@ func (self *SAzureClient) Get(resourceId string, retVal interface{}) error { if err != nil { return err } - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(strings.ToLower(resourceId), strings.ToLower(resourceType)) > 0 { - version = _version - } - } - body, err := jsonRequest(cli, "GET", version, self.domain, resourceId, "") + body, err := jsonRequest(cli, "GET", self.domain, resourceId, "") if err != nil { return err } @@ -151,7 +143,7 @@ func (self *SAzureClient) ListVmSizes(location string) (jsonutils.JSONObject, er return nil, fmt.Errorf("need subscription id") } url := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/vmSizes", self.subscriptionId, location) - return jsonRequest(cli, "GET", "2018-06-01", self.domain, url, "") + return jsonRequest(cli, "GET", self.domain, url, "") } func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) { @@ -163,7 +155,7 @@ func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) { return nil, fmt.Errorf("need subscription id") } url := fmt.Sprintf("/subscriptions/%s/services/disks", self.subscriptionId) - return jsonRequest(cli, "GET", "2018-06-01", self.domain, url, "") + return jsonRequest(cli, "GET", self.domain, url, "") } func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error { @@ -175,18 +167,17 @@ func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error if len(self.subscriptionId) > 0 { url += fmt.Sprintf("/%s", self.subscriptionId) } - version := AZURE_API_VERSION if len(resourceType) > 0 { url += fmt.Sprintf("/providers/%s", resourceType) - if _version, ok := DEFAULT_API_VERSION[resourceType]; ok { - version = _version - } } - body, err := jsonRequest(cli, "GET", version, self.domain, url, "") + body, err := jsonRequest(cli, "GET", self.domain, url, "") if err != nil { return err } - return body.Unmarshal(retVal, "value") + if retVal != nil { + body.Unmarshal(retVal, "value") + } + return nil } func (self *SAzureClient) ListSubscriptions() (jsonutils.JSONObject, error) { @@ -194,7 +185,7 @@ func (self *SAzureClient) ListSubscriptions() (jsonutils.JSONObject, error) { if err != nil { return nil, err } - return jsonRequest(cli, "GET", AZURE_API_VERSION, self.domain, "/subscriptions", "") + return jsonRequest(cli, "GET", self.domain, "/subscriptions", "") } func (self *SAzureClient) List(golbalResource string, retVal interface{}) error { @@ -209,14 +200,14 @@ func (self *SAzureClient) List(golbalResource string, retVal interface{}) error if len(self.subscriptionId) > 0 && len(golbalResource) > 0 { url += fmt.Sprintf("/%s", golbalResource) } - body, err := jsonRequest(cli, "GET", AZURE_API_VERSION, self.domain, url, "") + body, err := jsonRequest(cli, "GET", self.domain, url, "") if err != nil { return err } return body.Unmarshal(retVal, "value") } -func (self *SAzureClient) ListByType(Type string, retVal interface{}) error { +func (self *SAzureClient) ListByTypeWithResourceGroup(resourceGroupName string, Type string, retVal interface{}) error { cli, err := self.getDefaultClient() if err != nil { return err @@ -224,17 +215,8 @@ func (self *SAzureClient) ListByType(Type string, retVal interface{}) error { if len(self.subscriptionId) == 0 { return fmt.Errorf("Missing subscription Info") } - resourceGroupName, ok := defaultResourceGroups[Type] - if !ok { - return fmt.Errorf("Not find default resourceGroup for %s", Type) - } - version := AZURE_API_VERSION - if _version, ok := DEFAULT_API_VERSION[Type]; ok { - version = _version - } - url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s", self.subscriptionId, resourceGroupName, Type) - body, err := jsonRequest(cli, "GET", version, self.domain, url, "") + body, err := jsonRequest(cli, "GET", self.domain, url, "") if err != nil { return err } @@ -246,13 +228,7 @@ func (self *SAzureClient) Delete(resourceId string) error { if err != nil { return err } - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(resourceId, resourceType) > 0 { - version = _version - } - } - _, err = jsonRequest(cli, "DELETE", version, self.domain, resourceId, "") + _, err = jsonRequest(cli, "DELETE", self.domain, resourceId, "") return err } @@ -261,14 +237,41 @@ func (self *SAzureClient) PerformAction(resourceId string, action string) (jsonu if err != nil { return nil, err } - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(resourceId, resourceType) > 0 { - version = _version - } - } url := fmt.Sprintf("%s/%s", resourceId, action) - return jsonRequest(cli, "POST", version, self.domain, url, "") + return jsonRequest(cli, "POST", self.domain, url, "") +} + +func (self *SAzureClient) fetchResourceGroup(cli *autorest.Client, location string) error { + if !self.fetchResourceGroups { + err := self.List("resourcegroups", &self.ressourceGroups) + if err != nil { + log.Errorf("failed to list resourceGroups: %v", err) + return err + } + self.fetchResourceGroups = true + } + if len(self.ressourceGroups) == 0 { + //Create Default resourceGroup + _url := fmt.Sprintf("/subscriptions/%s/resourcegroups/Default", self.subscriptionId) + body, err := jsonRequest(cli, "PUT", self.domain, _url, fmt.Sprintf(`{"name": "Default", "location": "%s"}`, location)) + if err != nil { + return err + } + return body.Unmarshal(&self.ressourceGroups, "value") + } + return nil +} + +func (self *SAzureClient) checkParams(body jsonutils.JSONObject, params []string) (map[string]string, error) { + result := map[string]string{} + for i := 0; i < len(params); i++ { + data, err := body.GetString(params[i]) + if err != nil { + return nil, fmt.Errorf("Missing %s params") + } + result[params[i]] = data + } + return result, nil } func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) error { @@ -276,34 +279,22 @@ func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) if err != nil { return err } - url := "/subscriptions" if len(self.subscriptionId) == 0 { return fmt.Errorf("Missing subscription info") } - url += fmt.Sprintf("/%s", self.subscriptionId) - Type, err := body.GetString("type") + params, err := self.checkParams(body, []string{"type", "name", "location"}) + if err != nil { + return fmt.Errorf("Azure create resource failed: %s", err.Error()) + } + err = self.fetchResourceGroup(cli, params["location"]) if err != nil { return err } - if resourceGroupName, ok := defaultResourceGroups[Type]; ok { - url += fmt.Sprintf("/resourceGroups/%s/providers/%s", resourceGroupName, Type) - } else { - msg := fmt.Sprintf("Create %s Missing resourceGroupName", Type) - return fmt.Errorf(msg) + if len(self.ressourceGroups) == 0 { + return fmt.Errorf("Create Default resourceGroup error?") } - - version := AZURE_API_VERSION - if _version, ok := DEFAULT_API_VERSION[Type]; ok { - version = _version - } - name, err := body.GetString("name") - if err != nil { - log.Errorf("Create %s error: Missing name params", Type) - return err - } - url += fmt.Sprintf("/%s", name) - - result, err := jsonRequest(cli, "PUT", version, self.domain, url, body.String()) + url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s", self.subscriptionId, self.ressourceGroups[0].Name, params["type"], params["name"]) + result, err := jsonRequest(cli, "PUT", self.domain, url, body.String()) if err != nil { return err } @@ -319,66 +310,30 @@ func (self *SAzureClient) CheckNameAvailability(Type string, body string) (jsonu return nil, fmt.Errorf("Missing subscription ID") } url := fmt.Sprintf("/subscriptions/%s/providers/%s/checkNameAvailability", self.subscriptionId, Type) - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(url, resourceType) > 0 { - version = _version - } - } - return jsonRequest(cli, "POST", version, self.domain, url, body) + return jsonRequest(cli, "POST", self.domain, url, body) } -func (self *SAzureClient) Update(body jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{}) error { cli, err := self.getDefaultClient() if err != nil { - return nil, err + return err } url, err := body.GetString("id") - version := AZURE_API_VERSION - for resourceType, _version := range DEFAULT_API_VERSION { - if strings.Index(url, resourceType) > 0 { - version = _version - } - } - return jsonRequest(cli, "PUT", version, self.domain, url, body.String()) -} - -func jsonRequest(client *autorest.Client, method, version, domain, baseUrl string, body string) (jsonutils.JSONObject, error) { - return _jsonRequest(client, method, version, domain, baseUrl, body) -} - -func _jsonRequest(client *autorest.Client, method, version, domain, baseUrl string, body string) (result jsonutils.JSONObject, err error) { - url := fmt.Sprintf("%s%s?api-version=%s", domain, baseUrl, version) - if strings.Index(baseUrl, "?") > 0 { - url = fmt.Sprintf("%s%s&api-version=%s", domain, baseUrl, version) - } - req := &http.Request{} - if len(body) != 0 { - req, err = http.NewRequest(method, url, strings.NewReader(body)) - if err != nil { - return nil, err - } - } else { - req, err = http.NewRequest(method, url, nil) - if err != nil { - return nil, err - } - } - req.Header.Add("Content-Type", "application/json; charset=utf-8") - resp, err := client.Do(req) + result, err := jsonRequest(cli, "PUT", self.domain, url, body.String()) if err != nil { - return nil, err + return err } - - if resp.StatusCode == 404 { - data := []byte{} - if resp.ContentLength != 0 { - data, _ = ioutil.ReadAll(resp.Body) - } - log.Errorf("failed find %s error: %s", url, string(data)) - return nil, cloudprovider.ErrNotFound + if retVal != nil { + return result.Unmarshal(retVal) } + return nil +} +func jsonRequest(client *autorest.Client, method, domain, baseUrl string, body string) (jsonutils.JSONObject, error) { + return _jsonRequest(client, method, domain, baseUrl, body) +} + +func waitForComplatetion(client *autorest.Client, req *http.Request, resp *http.Response) (jsonutils.JSONObject, error) { location := resp.Header.Get("Location") asyncoperation := resp.Header.Get("Azure-Asyncoperation") if len(location) > 0 || (len(asyncoperation) > 0 && resp.StatusCode != 200) { @@ -399,7 +354,7 @@ func _jsonRequest(client *autorest.Client, method, version, domain, baseUrl stri continue } if asyncResp.ContentLength == 0 { - return jsonutils.NewDict(), nil + return nil, nil } data, err := ioutil.ReadAll(asyncResp.Body) if err != nil { @@ -412,17 +367,71 @@ func _jsonRequest(client *autorest.Client, method, version, domain, baseUrl stri if len(asyncoperation) > 0 && asyncData.Contains("status") { status, _ := asyncData.GetString("status") if status == "InProgress" { + log.Debugf("process %s %s InProgress", req.Method, req.URL.String()) + time.Sleep(time.Second * 5) continue } if status == "Succeeded" { - break + log.Debugf("process %s %s Succeeded", req.Method, req.URL.String()) + return nil, nil } - return nil, fmt.Errorf("Create %s failed: %s", body, data) + return nil, fmt.Errorf("Create failed: %s", data) } + log.Debugf("process %s %s return: %s", req.Method, req.URL.String(), data) return asyncData, nil } } + return nil, nil +} +func _jsonRequest(client *autorest.Client, method, domain, baseURL, body string) (result jsonutils.JSONObject, err error) { + version := AZURE_API_VERSION + for resourceType, _version := range DEFAULT_API_VERSION { + if strings.Index(strings.ToLower(baseURL), strings.ToLower(resourceType)) > 0 { + version = _version + } + } + url := fmt.Sprintf("%s%s?api-version=%s", domain, baseURL, version) + if strings.Index(baseURL, "?") > 0 { + url = fmt.Sprintf("%s%s&api-version=%s", domain, baseURL, version) + } + req := &http.Request{} + if len(body) != 0 { + req, err = http.NewRequest(method, url, strings.NewReader(body)) + if err != nil { + log.Errorf("Azure %s new request: %s body: %s error: %v", method, url, body, err) + return nil, err + } + } else { + req, err = http.NewRequest(method, url, nil) + if err != nil { + log.Errorf("Azure %s new request: %s error: %v", method, url, err) + return nil, err + } + } + req.Header.Add("Content-Type", "application/json; charset=utf-8") + resp, err := client.Do(req) + if err != nil { + log.Errorf("Azure %s request: %s \nbody: %s error: %v", req.Method, req.URL.String(), body, err) + return nil, err + } + + if resp.StatusCode == 404 { + data := []byte{} + if resp.ContentLength != 0 { + data, _ = ioutil.ReadAll(resp.Body) + } + log.Errorf("failed find %s error: %s", url, string(data)) + return nil, cloudprovider.ErrNotFound + } + + asyncData, err := waitForComplatetion(client, req, resp) + if err != nil { + return nil, err + } + if asyncData != nil { + return asyncData, nil + } if resp.ContentLength == 0 { return jsonutils.NewDict(), nil } @@ -436,6 +445,7 @@ func _jsonRequest(client *autorest.Client, method, version, domain, baseUrl stri return nil, err } if result.Contains("error") { + log.Errorf("Azure %s request: %s \nbody: %s error: %v", req.Method, req.URL.String(), body, err) return nil, fmt.Errorf(result.String()) } return result, nil diff --git a/pkg/util/azure/classic_disk.go b/pkg/util/azure/classic_disk.go index 0cc05c1427..8946493c8e 100644 --- a/pkg/util/azure/classic_disk.go +++ b/pkg/util/azure/classic_disk.go @@ -1,11 +1,11 @@ package azure import ( - "fmt" "strings" "time" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -18,51 +18,84 @@ type SClassicDisk struct { OperatingSystem string IoType string DiskSizeGB int32 + DiskSize int32 + diskSizeMB int32 CreatedTime string SourceImageName string VhdUri string + diskType string StorageAccount SubResource } +func (self *SRegion) GetStorageAccountsDisksWithSnapshots(storageaccounts ...SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) { + disks, snapshots := []SClassicDisk{}, []SClassicSnapshot{} + for i := 0; i < len(storageaccounts); i++ { + _disks, _snapshots, err := self.GetStorageAccountDisksWithSnapshots(storageaccounts[i]) + if err != nil { + return nil, nil, err + } + disks = append(disks, _disks...) + snapshots = append(snapshots, _snapshots...) + } + return disks, snapshots, nil +} + +func (self *SRegion) GetStorageAccountDisksWithSnapshots(storageaccount SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) { + disks, snapshots := []SClassicDisk{}, []SClassicSnapshot{} + containers, err := storageaccount.GetContainers() + if err != nil { + return nil, nil, err + } + for _, container := range containers { + if container.Name == "vhds" { + files, err := container.ListFiles() + if err != nil { + log.Errorf("List storage %s container %s files error: %v", storageaccount.Name, container.Name, err) + return nil, nil, err + } + + for _, file := range files { + if strings.HasSuffix(file.Name, ".vhd") { + diskType := models.DISK_TYPE_DATA + if _diskType, ok := file.Metadata["microsoftazurecompute_disktype"]; ok && _diskType == "OSDisk" { + diskType = models.DISK_TYPE_SYS + } + diskName := file.Name + if _diskName, ok := file.Metadata["microsoftazurecompute_diskname"]; ok { + diskName = _diskName + } + if file.Snapshot.IsZero() { + disks = append(disks, SClassicDisk{ + DiskName: diskName, + diskType: diskType, + DiskSizeGB: int32(file.Properties.ContentLength / 1024 / 1024 / 1024), + diskSizeMB: int32(file.Properties.ContentLength / 1024 / 1024), + VhdUri: file.GetURL(), + }) + } else { + snapshots = append(snapshots, SClassicSnapshot{ + region: self, + Name: file.Snapshot.String(), + sizeMB: int32(file.Properties.ContentLength / 1024 / 1024), + diskID: file.GetURL(), + diskName: diskName, + }) + } + } + } + } + } + return disks, snapshots, nil +} + func (self *SRegion) GetClassicDisks() ([]SClassicDisk, error) { storageaccounts, err := self.GetClassicStorageAccounts() if err != nil { return nil, err } - disks := []SClassicDisk{} - for _, storageaccount := range storageaccounts { - containers, err := storageaccount.GetContainers() - if err != nil { - return nil, err - } - baseUrl := storageaccount.GetBlobBaseUrl() - if len(baseUrl) == 0 { - return nil, fmt.Errorf("failed to find storageaccount %s blob endpoint", storageaccount.Name) - } - storage := SClassicStorage{ - Name: storageaccount.Name, - ID: storageaccount.ID, - Location: storageaccount.Location, - Type: storageaccount.Type, - } - for _, container := range containers { - if container.Name == "vhds" { - files, err := container.ListFiles() - if err != nil { - return nil, err - } - for _, file := range files { - if strings.HasSuffix(file.Name, ".vhd") { - disks = append(disks, SClassicDisk{ - storage: &storage, - DiskName: file.Name, - DiskSizeGB: int32(file.Properties.ContentLength / 1024 / 1024 / 1024), - VhdUri: baseUrl + file.Name, - }) - } - } - } - } + disks, _, err := self.GetStorageAccountsDisksWithSnapshots(storageaccounts...) + if err != nil { + return nil, err } return disks, nil } @@ -108,7 +141,10 @@ func (self *SClassicDisk) GetDiskFormat() string { } func (self *SClassicDisk) GetDiskSizeMB() int { - return int(self.DiskSizeGB * 1024) + if self.DiskSizeGB > 0 { + return int(self.DiskSizeGB * 1024) + } + return int(self.diskSizeMB) } func (self *SClassicDisk) GetIsAutoDelete() bool { @@ -120,10 +156,7 @@ func (self *SClassicDisk) GetTemplateId() string { } func (self *SClassicDisk) GetDiskType() string { - if len(self.OperatingSystem) > 0 { - return models.DISK_TYPE_SYS - } - return models.DISK_TYPE_DATA + return self.diskType } func (self *SClassicDisk) GetExpiredAt() time.Time { @@ -142,6 +175,11 @@ func (self *SClassicDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudS return nil, cloudprovider.ErrNotSupported } +func (region *SRegion) GetClassicSnapShots(diskId string) ([]SClassicSnapshot, error) { + result := []SClassicSnapshot{} + return result, nil +} + func (self *SClassicDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { return nil, cloudprovider.ErrNotSupported } diff --git a/pkg/util/azure/classic_host.go b/pkg/util/azure/classic_host.go index 834e351362..64075ace69 100644 --- a/pkg/util/azure/classic_host.go +++ b/pkg/util/azure/classic_host.go @@ -130,12 +130,12 @@ func (self *SClassicHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) } func (self *SClassicHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { - if instance, err := self.zone.region.GetClassicInstance(instanceId); err != nil { + instance, err := self.zone.region.GetClassicInstance(instanceId) + if err != nil { return nil, err - } else { - instance.host = self - return instance, nil } + instance.host = self + return instance, nil } func (self *SClassicHost) GetStorageSizeMB() int { diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index 172d269a5b..f6219233e9 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -34,7 +34,8 @@ type SubResource struct { Type string } -type OperatingSystemDisk struct { +type ClassicDisk struct { + Lun int32 DiskName string Caching string OperatingSystem string @@ -42,24 +43,13 @@ type OperatingSystemDisk struct { CreatedTime string SourceImageName string VhdUri string - StorageAccount SubResource -} - -type ClassicDataDisk struct { - Lun int32 - DiskName string - Caching string - OperatingSystem string - IoType string - CreatedTime string - VhdUri string DiskSize int32 `json:"diskSize,omitempty"` StorageAccount SubResource } type ClassicStorageProfile struct { - OperatingSystemDisk OperatingSystemDisk `json:"operatingSystemDisk,omitempty"` - DataDisks *[]ClassicDataDisk `json:"aataDisks,omitempty"` + OperatingSystemDisk ClassicDisk `json:"operatingSystemDisk,omitempty"` + DataDisks *[]ClassicDisk `json:"aataDisks,omitempty"` } type ClassicHardwareProfile struct { @@ -158,46 +148,44 @@ func (self *SRegion) GetClassicInstance(instanceId string) (*SClassicInstance, e return &instance, self.client.Get(fmt.Sprintf("%s?$expand=instanceView", instanceId), &instance) } +type ClassicInstanceDiskProperties struct { + DiskName string + Caching string + OperatingSystem string + IoType string + DiskSize int32 + SourceImageName string + VhdUri string +} + +type ClassicInstanceDisk struct { + Properties ClassicInstanceDiskProperties + ID string + Name string + Type string +} + func (self *SClassicInstance) getDisks() ([]SClassicDisk, error) { disks := []SClassicDisk{} - osDisk := self.Properties.StorageProfile.OperatingSystemDisk - store, err := self.host.zone.region.GetStorageAccountDetail(osDisk.StorageAccount.ID) + body, err := self.host.zone.region.client.jsonRequest("GET", fmt.Sprintf("%s/disks", self.ID), "") if err != nil { return nil, err } - storage := SClassicStorage{zone: self.host.zone, Name: store.Name, Location: store.Location, ID: store.ID, Type: store.Type} - disks = append(disks, SClassicDisk{ - storage: &storage, - DiskName: osDisk.DiskName, - Caching: osDisk.Caching, - OperatingSystem: osDisk.OperatingSystem, - IoType: osDisk.IoType, - CreatedTime: osDisk.CreatedTime, - SourceImageName: osDisk.SourceImageName, - VhdUri: osDisk.VhdUri, - StorageAccount: osDisk.StorageAccount, - }) - if self.Properties.StorageProfile.DataDisks != nil { - for _, disk := range *self.Properties.StorageProfile.DataDisks { - store, err := self.host.zone.region.GetStorageAccountDetail(disk.StorageAccount.ID) - if err != nil { - return nil, err - } - storage := SClassicStorage{zone: self.host.zone, Name: store.Name, Location: store.Location, ID: store.ID, Type: store.Type} - disks = append(disks, SClassicDisk{ - storage: &storage, - DiskName: disk.DiskName, - DiskSizeGB: disk.DiskSize, - Caching: disk.Caching, - OperatingSystem: disk.OperatingSystem, - IoType: disk.IoType, - CreatedTime: disk.CreatedTime, - VhdUri: disk.VhdUri, - StorageAccount: osDisk.StorageAccount, - }) + _disks, err := body.GetArray("value") + if err != nil { + return nil, err + } + for i := 0; i < len(_disks); i++ { + disk := SClassicDisk{} + err = _disks[i].Unmarshal(&disk, "properties") + if err != nil { + return nil, err } + storage := SClassicStorage{zone: self.host.zone, Name: disk.StorageAccount.Name, ID: disk.StorageAccount.ID} + disk.DiskSizeGB = disk.DiskSize + disk.storage = &storage + disks = append(disks, disk) } - return disks, nil } @@ -232,28 +220,34 @@ func (self *SClassicInstance) getNics() ([]SClassicInstanceNic, error) { } func (self *SClassicInstance) Refresh() error { - if instance, err := self.host.zone.region.GetClassicInstance(self.ID); err != nil { + instance, err := self.host.zone.region.GetClassicInstance(self.ID) + if err != nil { return err - } else { - return jsonutils.Update(self, instance) } + return jsonutils.Update(self, instance) } func (self *SClassicInstance) GetStatus() string { - if self.Properties.InstanceView != nil { - switch self.Properties.InstanceView.Status { - case "StoppedDeallocated": - return models.VM_READY - case "ReadyRole": - return models.VM_RUNNING - case "Stopped": - return models.VM_READY - default: - log.Errorf("Unknow instance %s status %s", self.Name, self.Properties.InstanceView.Status) + if self.Properties.InstanceView == nil { + err := self.Refresh() + if err != nil { + log.Errorf("failed to get status for classic instance %s", self.Name) return models.VM_UNKNOWN } } - return models.VM_UNKNOWN + switch self.Properties.InstanceView.Status { + case "StoppedDeallocated": + return models.VM_READY + case "ReadyRole": + return models.VM_RUNNING + case "Stopped": + return models.VM_READY + case "RoleStateUnknown": + return models.VM_UNKNOWN + default: + log.Errorf("Unknow classic instance %s status %s", self.Name, self.Properties.InstanceView.Status) + return models.VM_UNKNOWN + } } func (self *SClassicInstance) GetIHost() cloudprovider.ICloudHost { @@ -407,12 +401,18 @@ func (self *SClassicInstance) StartVM() error { } func (self *SClassicInstance) StopVM(isForce bool) error { - if err := self.host.zone.region.StopVM(self.ID, isForce); err != nil { + err := self.host.zone.region.StopClassicVM(self.ID, isForce) + if err != nil { return err } return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) } +func (self *SRegion) StopClassicVM(instanceId string, isForce bool) error { + _, err := self.client.PerformAction(instanceId, "shutdown") + return err +} + func (self *SClassicInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { return cloudprovider.ErrNotSupported } @@ -423,6 +423,10 @@ func (self *SClassicInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { eip, err := self.host.zone.region.GetClassicEip(reserveIp.ID) if err == nil { eip.instanceId = self.ID + if eip.Properties.AttachedTo != nil && eip.Properties.AttachedTo.ID != self.ID { + //一般是此实例deallocate, eip被绑到其他机器上了. + return nil, nil + } return eip, nil } log.Errorf("failed find eip %s for classic instance %s", reserveIp.Name, self.Name) diff --git a/pkg/util/azure/classic_network.go b/pkg/util/azure/classic_network.go index d27612181f..6f328299f3 100644 --- a/pkg/util/azure/classic_network.go +++ b/pkg/util/azure/classic_network.go @@ -51,8 +51,7 @@ func (self *SClassicNetwork) Delete() error { } subnets = append(subnets, network) } - _, err := self.wire.vpc.region.client.Update(jsonutils.Marshal(vpc)) - return err + return self.wire.vpc.region.client.Update(jsonutils.Marshal(vpc), self.wire.vpc) } func (self *SClassicNetwork) GetGateway() string { diff --git a/pkg/util/azure/classic_secruitygroup.go b/pkg/util/azure/classic_secruitygroup.go index 62c4f574b6..3023094d41 100644 --- a/pkg/util/azure/classic_secruitygroup.go +++ b/pkg/util/azure/classic_secruitygroup.go @@ -228,8 +228,7 @@ func (region *SRegion) updateClassicSecurityGroupRules(secgroupId string, rules } secgroup.Properties.SecurityRules = &securityRules secgroup.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(secgroup)) - return secgroup.ID, err + return secgroup.ID, region.client.Update(jsonutils.Marshal(secgroup), nil) } func (region *SRegion) AssiginClassicSecurityGroup(instanceId, secgroupId string) error { @@ -246,8 +245,7 @@ func (region *SRegion) AssiginClassicSecurityGroup(instanceId, secgroupId string Name: secgroup.Name, Type: secgroup.Type, } - _, err = region.client.Update(jsonutils.Marshal(instance)) - return err + return region.client.Update(jsonutils.Marshal(instance), nil) } func (self *SRegion) syncClassicSecgroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) { diff --git a/pkg/util/azure/classic_snapshot.go b/pkg/util/azure/classic_snapshot.go new file mode 100644 index 0000000000..87a449fbfc --- /dev/null +++ b/pkg/util/azure/classic_snapshot.go @@ -0,0 +1,74 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SClassicSnapshot struct { + region *SRegion + + Name string + sizeMB int32 + diskID string + diskName string +} + +func (self *SClassicSnapshot) GetId() string { + return fmt.Sprintf("%s?snapshot=%s", self.diskID, self.Name) +} + +func (self *SClassicSnapshot) GetGlobalId() string { + return self.GetId() +} + +func (self *SClassicSnapshot) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SClassicSnapshot) GetName() string { + return fmt.Sprintf("%s-%s", self.diskName, self.Name) +} + +func (self *SClassicSnapshot) GetStatus() string { + return models.SNAPSHOT_READY +} + +func (self *SClassicSnapshot) IsEmulated() bool { + return false +} + +func (self *SRegion) CreateClassicSnapshot(diskId, snapName, desc string) (*SClassicSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SClassicSnapshot) Delete() error { + return self.region.DeleteClassicSnapshot(self.GetId()) +} + +func (self *SClassicSnapshot) GetSize() int32 { + return self.sizeMB +} + +func (self *SRegion) DeleteClassicSnapshot(snapshotId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SClassicSnapshot) Refresh() error { + return nil +} + +func (self *SClassicSnapshot) GetDiskId() string { + return self.diskID +} + +func (self *SClassicSnapshot) GetManagerId() string { + return self.region.client.providerId +} + +func (self *SClassicSnapshot) GetRegionId() string { + return self.region.GetId() +} diff --git a/pkg/util/azure/classic_storage.go b/pkg/util/azure/classic_storage.go index 7deb2848ff..be29365981 100644 --- a/pkg/util/azure/classic_storage.go +++ b/pkg/util/azure/classic_storage.go @@ -1,9 +1,7 @@ package azure import ( - "fmt" "strings" - "time" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -19,7 +17,7 @@ type ClassicStorageProperties struct { StatusOfPrimaryRegion string GeoSecondaryRegion string StatusOfSecondaryRegion string - CreationTime time.Time + //CreationTime time.Time } type SClassicStorage struct { @@ -83,34 +81,14 @@ func (self *SClassicStorage) GetIDisk(diskId string) (cloudprovider.ICloudDisk, func (self *SClassicStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { storageaccount, err := self.zone.region.GetStorageAccountDetail(self.ID) + disks, _, err := self.zone.region.GetStorageAccountDisksWithSnapshots(*storageaccount) if err != nil { return nil, err } - containers, err := storageaccount.GetContainers() - if err != nil { - return nil, err - } - baseUrl := storageaccount.GetBlobBaseUrl() - if len(baseUrl) == 0 { - return nil, fmt.Errorf("failed to find storageaccount %s blob endpoint", storageaccount.Name) - } - idisks := make([]cloudprovider.ICloudDisk, 0) - for _, container := range containers { - if container.Name == "vhds" { - files, err := container.ListFiles() - if err != nil { - return nil, err - } - for _, file := range files { - if strings.HasSuffix(file.Name, ".vhd") { - idisks = append(idisks, &SClassicDisk{ - storage: self, - DiskName: file.Name, - VhdUri: baseUrl + file.Name, - }) - } - } - } + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := 0; i < len(disks); i++ { + disks[i].storage = self + idisks[i] = &disks[i] } return idisks, nil } diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go index f60743252f..d361e3709d 100644 --- a/pkg/util/azure/disk.go +++ b/pkg/util/azure/disk.go @@ -101,22 +101,24 @@ func (self *SRegion) DeleteDisk(diskId string) error { } func (self *SRegion) deleteDisk(diskId string) error { - return self.client.Delete(diskId) + if !strings.HasPrefix(diskId, "https://") { + return self.client.Delete(diskId) + } + //TODO + return cloudprovider.ErrNotImplemented } func (self *SRegion) ResizeDisk(diskId string, sizeGb int32) error { - return self.resizeDisk(diskId, sizeGb) -} - -func (self *SRegion) resizeDisk(diskId string, sizeGb int32) error { - disk, err := self.GetDisk(diskId) - if err != nil { - return err + if !strings.HasPrefix(diskId, "https://") { + disk, err := self.GetDisk(diskId) + if err != nil { + return err + } + disk.Properties.DiskSizeGB = sizeGb + disk.Properties.ProvisioningState = "" + return self.client.Update(jsonutils.Marshal(disk), nil) } - disk.Properties.DiskSizeGB = sizeGb - disk.Properties.ProvisioningState = "" - _, err = self.client.Update(jsonutils.Marshal(disk)) - return err + return cloudprovider.ErrNotSupported } func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { @@ -126,7 +128,6 @@ func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { func (self *SRegion) GetDisks() ([]SDisk, error) { result := []SDisk{} - //self.client.ListClassicDisks() disks := []SDisk{} err := self.client.ListAll("Microsoft.Compute/disks", &disks) if err != nil { @@ -147,16 +148,19 @@ func (self *SDisk) GetMetadata() *jsonutils.JSONDict { } func (self *SDisk) GetStatus() string { - status := self.Properties.ProvisioningState - switch status { - case "Updating": - return models.DISK_ALLOCATING - case "Succeeded": - return models.DISK_READY - default: - log.Errorf("Unknow azure disk status: %s", status) - return models.DISK_UNKNOWN + if !strings.HasPrefix(self.ID, "https://") { + status := self.Properties.ProvisioningState + switch status { + case "Updating": + return models.DISK_ALLOCATING + case "Succeeded": + return models.DISK_READY + default: + log.Errorf("Unknow azure disk %s status: %s", self.ID, status) + return models.DISK_UNKNOWN + } } + return models.DISK_READY } func (self *SDisk) GetId() string { @@ -164,11 +168,14 @@ func (self *SDisk) GetId() string { } func (self *SDisk) Refresh() error { - if disk, err := self.storage.zone.region.GetDisk(self.ID); err != nil { - return cloudprovider.ErrNotFound - } else { + if !strings.HasPrefix(self.ID, "https://") { + disk, err := self.storage.zone.region.GetDisk(self.ID) + if err != nil { + return cloudprovider.ErrNotFound + } return jsonutils.Update(self, disk) } + return nil } func (self *SDisk) Delete() error { @@ -176,7 +183,7 @@ func (self *SDisk) Delete() error { } func (self *SDisk) Resize(size int64) error { - return self.storage.zone.region.resizeDisk(self.ID, int32(size)) + return self.storage.zone.region.ResizeDisk(self.ID, int32(size)) } func (self *SDisk) GetName() string { @@ -255,15 +262,18 @@ func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot } func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - if snapshots, err := self.storage.zone.region.GetSnapShots(self.ID); err != nil { - return nil, err - } else { - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + isnapshots := make([]cloudprovider.ICloudSnapshot, 0) + if !strings.HasPrefix(self.ID, "https://") { + snapshots, err := self.storage.zone.region.GetSnapShots(self.ID) + if err != nil { + return nil, err + } + for i := 0; i < len(snapshots); i++ { - isnapshots[i] = &snapshots[i] + isnapshots = append(isnapshots, &snapshots[i]) } - return isnapshots, nil } + return isnapshots, nil } func (self *SDisk) GetBillingType() string { @@ -275,13 +285,14 @@ func (self *SDisk) GetExpiredAt() time.Time { } func (self *SDisk) GetSnapshotDetail(snapshotId string) (*SSnapshot, error) { - if snapshot, err := self.storage.zone.region.GetSnapshotDetail(snapshotId); err != nil { + snapshot, err := self.storage.zone.region.GetSnapshotDetail(snapshotId) + if err != nil { return nil, err - } else if snapshot.Properties.CreationData.SourceResourceID != self.ID { - return nil, cloudprovider.ErrNotFound - } else { - return snapshot, nil } + if snapshot.Properties.CreationData.SourceResourceID != self.ID { + return nil, cloudprovider.ErrNotFound + } + return snapshot, nil } func (region *SRegion) GetSnapshotDetail(snapshotId string) (*SSnapshot, error) { @@ -291,16 +302,18 @@ func (region *SRegion) GetSnapshotDetail(snapshotId string) (*SSnapshot, error) func (region *SRegion) GetSnapShots(diskId string) ([]SSnapshot, error) { result := []SSnapshot{} - snapshots := []SSnapshot{} - err := region.client.ListAll("Microsoft.Compute/snapshots", &snapshots) - if err != nil { - return nil, err - } - for i := 0; i < len(snapshots); i++ { - if snapshots[i].Location == region.Name { - if len(diskId) == 0 || diskId == snapshots[i].Properties.CreationData.SourceResourceID { - snapshots[i].region = region - result = append(result, snapshots[i]) + if !strings.HasPrefix(diskId, "https://") { + snapshots := []SSnapshot{} + err := region.client.ListAll("Microsoft.Compute/snapshots", &snapshots) + if err != nil { + return nil, err + } + for i := 0; i < len(snapshots); i++ { + if snapshots[i].Location == region.Name { + if len(diskId) == 0 || diskId == snapshots[i].Properties.CreationData.SourceResourceID { + snapshots[i].region = region + result = append(result, snapshots[i]) + } } } } diff --git a/pkg/util/azure/eip.go b/pkg/util/azure/eip.go index ede1e9b328..e437eb4e0c 100644 --- a/pkg/util/azure/eip.go +++ b/pkg/util/azure/eip.go @@ -84,8 +84,7 @@ func (region *SRegion) AssociateEip(eipId string, instanceId string) error { return err } nic.Properties.IPConfigurations[0].Properties.PublicIPAddress.ID = eipId - _, err = region.client.Update(jsonutils.Marshal(nic)) - return err + return region.client.Update(jsonutils.Marshal(nic), nil) } func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { @@ -123,8 +122,7 @@ func (region *SRegion) DissociateEip(eipId string) error { return err } nic.Properties.IPConfigurations[0].Properties.PublicIPAddress.ID = "" - _, err = region.client.Update(jsonutils.Marshal(nic)) - return err + return region.client.Update(jsonutils.Marshal(nic), nil) } func (self *SEipAddress) GetAssociationExternalId() string { diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go index 3bc0eddf3d..6dc360be3c 100644 --- a/pkg/util/azure/host.go +++ b/pkg/util/azure/host.go @@ -146,7 +146,6 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int for _, profile := range self.zone.region.getHardwareProfile(cpu, memMB) { instance.Properties.HardwareProfile.VMSize = profile - log.Errorf("instance: %s", jsonutils.Marshal(instance).PrettyString()) log.Debugf("Try HardwareProfile : %s", profile) err := self.zone.region.client.Create(jsonutils.Marshal(instance), &instance) if err != nil { @@ -207,16 +206,16 @@ func (self *SHost) GetSysInfo() jsonutils.JSONObject { } func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return self.zone.GetIStorages() + return self.zone.istorages, nil } func (self *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { - if instance, err := self.zone.region.GetInstance(instanceId); err != nil { + instance, err := self.zone.region.GetInstance(instanceId) + if err != nil { return nil, err - } else { - instance.host = self - return instance, nil } + instance.host = self + return instance, nil } func (self *SHost) GetStorageSizeMB() int { @@ -232,17 +231,17 @@ func (self *SHost) GetSN() string { } func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - if vms, err := self.zone.region.GetInstances(); err != nil { + vms, err := self.zone.region.GetInstances() + if err != nil { return nil, err - } else { - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := 0; i < len(vms); i++ { - vms[i].host = self - ivms[i] = &vms[i] - log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName()) - } - return ivms, nil } + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := 0; i < len(vms); i++ { + vms[i].host = self + ivms[i] = &vms[i] + log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName()) + } + return ivms, nil } func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index 53150ceb6c..00675ec6a7 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -197,6 +197,11 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { return &instance, self.client.Get(fmt.Sprintf("%s?$expand=instanceView", instanceId), &instance) } +func (self *SRegion) GetInstanceScaleSets() ([]SInstance, error) { + instance := []SInstance{} + return instance, self.client.ListAll("Microsoft.Compute/virtualMachineScaleSets", &instance) +} + func (self *SRegion) GetInstances() ([]SInstance, error) { result := []SInstance{} instances := []SInstance{} @@ -261,18 +266,18 @@ func (self *SInstance) getOsDisk() (*SDisk, error) { } } -func (self *SInstance) getClassicStorageInfoByUri(uri string) (*SClassicStorage, error) { +func (self *SInstance) getStorageInfoByUri(uri string) (*SStorage, *SClassicStorage, error) { _storageName := strings.Split(strings.Replace(uri, "https://", "", -1), ".") storageName := "" if len(_storageName) > 0 { storageName = _storageName[0] } if len(storageName) == 0 { - return nil, fmt.Errorf("bad uri %s for search storageaccount", uri) + return nil, nil, fmt.Errorf("bad uri %s for search storageaccount", uri) } storageaccounts, err := self.host.zone.region.GetClassicStorageAccounts() if err != nil { - return nil, err + return nil, nil, err } for i := 0; i < len(storageaccounts); i++ { if storageaccounts[i].Name == storageName { @@ -283,27 +288,57 @@ func (self *SInstance) getClassicStorageInfoByUri(uri string) (*SClassicStorage, Type: storageaccounts[i].Type, Location: storageaccounts[i].Type, } - return &storage, nil + return nil, &storage, nil } } - return nil, fmt.Errorf("failed to found classic storageaccount for %s", uri) + storageaccounts, err = self.host.zone.region.GetStorageAccounts() + if err != nil { + return nil, nil, err + } + for i := 0; i < len(storageaccounts); i++ { + if storageaccounts[i].Name == storageName { + storage := SStorage{ + zone: self.host.zone, + Name: storageName, + storageType: storageaccounts[i].Sku.Name, + } + return &storage, nil, nil + } + } + return nil, nil, fmt.Errorf("failed to found classic storageaccount for %s", uri) } func (self *SInstance) getDisks() ([]SDisk, []SClassicDisk, error) { disks, classicDisk := []SDisk{}, []SClassicDisk{} if self.Properties.StorageProfile.OsDisk.Vhd != nil { disk := self.Properties.StorageProfile.OsDisk - storage, err := self.getClassicStorageInfoByUri(disk.Vhd.Uri) + storage, classicStorage, err := self.getStorageInfoByUri(disk.Vhd.Uri) if err != nil { return nil, nil, err } - classicDisk = append(classicDisk, SClassicDisk{ - storage: storage, - DiskName: disk.Name, - DiskSizeGB: disk.DiskSizeGB, - Caching: disk.Caching, - VhdUri: disk.Vhd.Uri, - }) + if classicStorage != nil { + classicDisk = append(classicDisk, SClassicDisk{ + storage: classicStorage, + DiskName: disk.Name, + DiskSizeGB: disk.DiskSizeGB, + Caching: disk.Caching, + VhdUri: disk.Vhd.Uri, + }) + } + if storage != nil { + disks = append(disks, SDisk{ + storage: storage, + ID: disk.Vhd.Uri, + Name: disk.Name, + Properties: DiskProperties{ + OsType: disk.OsType, + CreationData: CreationData{ + CreateOption: disk.CreateOption, + }, + DiskSizeGB: disk.DiskSizeGB, + }, + }) + } } else if self.Properties.StorageProfile.OsDisk.ManagedDisk != nil { disk, err := self.getDiskWithStore(self.Properties.StorageProfile.OsDisk.ManagedDisk.ID) if err != nil { @@ -314,21 +349,36 @@ func (self *SInstance) getDisks() ([]SDisk, []SClassicDisk, error) { } for _, _disk := range *self.Properties.StorageProfile.DataDisks { if _disk.Vhd != nil { - storage, err := self.getClassicStorageInfoByUri(_disk.Vhd.Uri) + storage, classicStorage, err := self.getStorageInfoByUri(_disk.Vhd.Uri) if err != nil { return nil, nil, err } - classicDisk = append(classicDisk, SClassicDisk{ - storage: storage, - DiskName: _disk.Name, - DiskSizeGB: _disk.DiskSizeGB, - Caching: _disk.Caching, - VhdUri: _disk.Vhd.Uri, - }) - } else if self.Properties.StorageProfile.OsDisk.ManagedDisk != nil { - disk, err := self.getDiskWithStore(self.Properties.StorageProfile.OsDisk.ManagedDisk.ID) + if classicStorage != nil { + classicDisk = append(classicDisk, SClassicDisk{ + storage: classicStorage, + DiskName: _disk.Name, + DiskSizeGB: _disk.DiskSizeGB, + Caching: _disk.Caching, + VhdUri: _disk.Vhd.Uri, + }) + } + if storage != nil { + disks = append(disks, SDisk{ + storage: storage, + ID: _disk.Vhd.Uri, + Name: _disk.Name, + Properties: DiskProperties{ + CreationData: CreationData{ + CreateOption: _disk.CreateOption, + }, + DiskSizeGB: _disk.DiskSizeGB, + }, + }) + } + } else if _disk.ManagedDisk != nil { + disk, err := self.getDiskWithStore(_disk.ManagedDisk.ID) if err != nil { - log.Errorf("Failed to find instance %s os disk: %s", self.Name, self.Properties.StorageProfile.OsDisk.ManagedDisk.ID) + log.Errorf("Failed to find instance %s os disk: %s", self.Name, _disk.ManagedDisk.ID) return nil, nil, err } disks = append(disks, *disk) @@ -352,40 +402,43 @@ func (self *SInstance) getNics() ([]SInstanceNic, error) { } func (self *SInstance) Refresh() error { - if instance, err := self.host.zone.region.GetInstance(self.ID); err != nil { + instance, err := self.host.zone.region.GetInstance(self.ID) + if err != nil { return err - } else { - return jsonutils.Update(self, instance) } + return jsonutils.Update(self, instance) } func (self *SInstance) GetStatus() string { - if self.Properties.InstanceView != nil { - for _, statuses := range self.Properties.InstanceView.Statuses { - if code := strings.Split(statuses.Code, "/"); len(code) == 2 { - if code[0] == "PowerState" { - switch code[1] { - case "stopped": - return models.VM_READY - case "deallocated": - return models.VM_DEALLOCATED - case "running": - return models.VM_RUNNING - case "stopping": - return models.VM_START_STOP - case "starting": - return models.VM_STARTING - case "deleting": - return models.VM_DELETING - default: - log.Errorf("Unknow instance status %s", code[1]) - return models.VM_UNKNOWN - } + if self.Properties.InstanceView == nil { + err := self.Refresh() + if err != nil { + log.Errorf("failed to get status for instance %s", self.Name) + return models.VM_UNKNOWN + } + } + for _, statuses := range self.Properties.InstanceView.Statuses { + if code := strings.Split(statuses.Code, "/"); len(code) == 2 { + if code[0] == "PowerState" { + switch code[1] { + case "stopped", "deallocated": + return models.VM_READY + case "running": + return models.VM_RUNNING + case "stopping": + return models.VM_START_STOP + case "starting": + return models.VM_STARTING + case "deleting": + return models.VM_DELETING + default: + log.Errorf("Unknow instance status %s", code[1]) + return models.VM_UNKNOWN } } - if statuses.Level == "Error" { - log.Errorf("Find error code: [%s] message: %s", statuses.Code, statuses.Message) - } + } + if statuses.Level == "Error" { + log.Errorf("Find error code: [%s] message: %s", statuses.Code, statuses.Message) } } return models.VM_UNKNOWN @@ -428,8 +481,7 @@ func (region *SRegion) AttachDisk(instanceId, diskId string) error { }, }) instance.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(instance)) - return err + return region.client.Update(jsonutils.Marshal(instance), nil) } func (self *SInstance) DetachDisk(diskId string) error { @@ -460,8 +512,7 @@ func (region *SRegion) DetachDisk(instanceId, diskId string) error { } } instance.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(instance)) - return err + return region.client.Update(jsonutils.Marshal(instance), nil) } func (self *SInstance) ChangeConfig(instanceId string, ncpu int, vmem int) error { @@ -469,7 +520,7 @@ func (self *SInstance) ChangeConfig(instanceId string, ncpu int, vmem int) error self.Properties.HardwareProfile.VMSize = vmSize self.Properties.ProvisioningState = "" log.Debugf("Try HardwareProfile : %s", vmSize) - _, err := self.host.zone.region.client.Update(jsonutils.Marshal(self)) + err := self.host.zone.region.client.Update(jsonutils.Marshal(self), nil) if err == nil { return cloudprovider.WaitStatus(self, self.GetStatus(), 10*time.Second, 300*time.Second) } @@ -535,19 +586,17 @@ func (region *SRegion) resetPassword(instanceId, username, password string) erro } func (region *SRegion) DeployVM(instanceId, name, password, publicKey string, deleteKeypair bool, description string) error { - if instance, err := region.GetInstance(instanceId); err != nil { + instance, err := region.GetInstance(instanceId) + if err != nil { return err - } else { - if deleteKeypair { - return nil - } - if len(publicKey) > 0 { - return region.resetPublicKey(instanceId, instance.Properties.OsProfile.AdminUsername, publicKey) - } else { - return region.resetPassword(instanceId, instance.Properties.OsProfile.AdminUsername, password) - } + } + if deleteKeypair { return nil } + if len(publicKey) > 0 { + return region.resetPublicKey(instanceId, instance.Properties.OsProfile.AdminUsername, publicKey) + } + return region.resetPassword(instanceId, instance.Properties.OsProfile.AdminUsername, password) } func (self *SInstance) RebuildRoot(imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) { @@ -564,7 +613,7 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey if err != nil { return "", err } - err = region.stopVM(instanceId) + err = region.StopVM(instanceId, true) if err != nil { return "", err } @@ -597,7 +646,7 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey } } instance.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(instance)) + err = region.client.Update(jsonutils.Marshal(instance), nil) if err != nil { return "", err } @@ -627,14 +676,6 @@ func (self *SInstance) GetGlobalId() string { return strings.ToLower(self.ID) } -func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { - instance, err := self.GetInstance(instanceId) - if err != nil { - return "", err - } - return instance.GetStatus(), nil -} - func (self *SRegion) DeleteVM(instanceId string) error { return self.doDeleteVM(instanceId) } @@ -679,8 +720,9 @@ func (self *SInstance) fetchDisks() error { self.idisks[i] = &disks[i] } for i := 0; i < len(classicDisks); i++ { - self.idisks[i] = &classicDisks[i] + self.idisks[len(disks)+i] = &classicDisks[i] } + return nil } @@ -707,7 +749,6 @@ func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { _nics[i].instance = self nics = append(nics, &_nics[i]) } - log.Errorf("get nic count %d for %s", len(nics), self.Name) return nics, nil } @@ -748,7 +789,7 @@ func (self *SInstance) GetVcpuCount() int8 { err := self.fetchVMSize() if err != nil { log.Errorf("fetchVMSize error: %v", err) - return 1 + return 0 } return int8(self.vmSize.NumberOfCores) } @@ -757,7 +798,7 @@ func (self *SInstance) GetVmemSizeMB() int { err := self.fetchVMSize() if err != nil { log.Errorf("fetchVMSize error: %v", err) - return 2048 + return 0 } return int(self.vmSize.MemoryInMB) } @@ -784,18 +825,15 @@ func (self *SInstance) StartVM() error { } func (self *SInstance) StopVM(isForce bool) error { - if err := self.host.zone.region.StopVM(self.ID, isForce); err != nil { + err := self.host.zone.region.StopVM(self.ID, isForce) + if err != nil { return err } return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) } func (self *SRegion) StopVM(instanceId string, isForce bool) error { - return self.stopVM(instanceId) -} - -func (self *SRegion) stopVM(instanceId string) error { - _, err := self.client.PerformAction(instanceId, "shutdown") + _, err := self.client.PerformAction(instanceId, "deallocate") return err } @@ -810,13 +848,15 @@ func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules [ return err } } - } else if extId, err := self.host.zone.region.syncSecurityGroup(secgroupId, name, rules); err != nil { + return nil + } + extId, err := self.host.zone.region.syncSecurityGroup(secgroupId, name, rules) + if err != nil { return err - } else { - for _, nic := range nics { - if err := nic.assignSecurityGroup(extId); err != nil { - return err - } + } + for _, nic := range nics { + if err := nic.assignSecurityGroup(extId); err != nil { + return err } } return nil @@ -829,12 +869,14 @@ func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { } for _, nic := range nics { for _, ip := range nic.Properties.IPConfigurations { - if len(ip.Properties.PublicIPAddress.ID) > 0 { - eip, err := self.host.zone.region.GetEip(ip.Properties.PublicIPAddress.ID) - if err == nil { - return eip, nil + if ip.Properties.PublicIPAddress != nil { + if len(ip.Properties.PublicIPAddress.ID) > 0 { + eip, err := self.host.zone.region.GetEip(ip.Properties.PublicIPAddress.ID) + if err == nil { + return eip, nil + } + log.Errorf("find eip for instance %s failed: %v", self.Name, err) } - log.Errorf("find eip for instance %s failed: %v", self.Name, err) } } } diff --git a/pkg/util/azure/instancenic.go b/pkg/util/azure/instancenic.go index 7606335103..621d54e81f 100644 --- a/pkg/util/azure/instancenic.go +++ b/pkg/util/azure/instancenic.go @@ -82,8 +82,7 @@ func (self *SInstanceNic) updateSecurityGroup(secgroupId string) error { if len(secgroupId) > 0 { self.Properties.NetworkSecurityGroup = &SSecurityGroup{ID: secgroupId} } - _, err := region.client.Update(jsonutils.Marshal(self)) - return err + return region.client.Update(jsonutils.Marshal(self), nil) } func (self *SInstanceNic) revokeSecurityGroup() error { diff --git a/pkg/util/azure/network.go b/pkg/util/azure/network.go index f90b9be85b..fb777e8f05 100644 --- a/pkg/util/azure/network.go +++ b/pkg/util/azure/network.go @@ -12,12 +12,11 @@ import ( type SNetwork struct { wire *SWire - AvailableIpAddressCount int + AvailableIpAddressCount *int `json:"availableIpAddressCount,omitempty"` ID string Name string Properties SubnetPropertiesFormat AddressPrefix string `json:"addressPrefix,omitempty"` - // Status string } func (self *SNetwork) GetMetadata() *jsonutils.JSONDict { @@ -41,10 +40,7 @@ func (self *SNetwork) IsEmulated() bool { } func (self *SNetwork) GetStatus() string { - if strings.ToLower(self.Properties.ProvisioningState) == "succeeded" || len(self.AddressPrefix) > 0 { - return "available" - } - return "disabled" + return "available" } func (self *SNetwork) Delete() error { @@ -58,8 +54,8 @@ func (self *SNetwork) Delete() error { subnets = append(subnets, (*vpc.Properties.Subnets)[i]) } vpc.Properties.Subnets = &subnets - _, err := self.wire.vpc.region.client.Update(jsonutils.Marshal(vpc)) - return err + vpc.Properties.ProvisioningState = "" + return self.wire.vpc.region.client.Update(jsonutils.Marshal(vpc), nil) } return nil } diff --git a/pkg/util/azure/networkinterface.go b/pkg/util/azure/networkinterface.go index cf7011a25f..d95444bd4e 100644 --- a/pkg/util/azure/networkinterface.go +++ b/pkg/util/azure/networkinterface.go @@ -2,6 +2,7 @@ package azure import ( "fmt" + "regexp" "yunion.io/x/jsonutils" ) @@ -26,9 +27,9 @@ func (self *SRegion) GetNetworkInterfaces() ([]SInstanceNic, error) { return result, nil } -func (self *SRegion) isNetworkInstanceNameAvaliable(nicName string) (bool, error) { +func (self *SRegion) isNetworkInstanceNameAvaliable(resourceGroupName, nicName string) (bool, error) { nics := []SInstanceNic{} - err := self.client.ListByType("Microsoft.Network/networkInterfaces", &nics) + err := self.client.ListByTypeWithResourceGroup(resourceGroupName, "Microsoft.Network/networkInterfaces", &nics) if err != nil { return false, err } @@ -40,6 +41,15 @@ func (self *SRegion) isNetworkInstanceNameAvaliable(nicName string) (bool, error return true, nil } +func getResourceGroupNameByID(id string) string { + reg := regexp.MustCompile("/resourceGroups/(.+)/providers/") + _resourceGroup := reg.FindStringSubmatch(id) + if len(_resourceGroup) == 2 { + return _resourceGroup[1] + } + return "" +} + func (self *SRegion) CreateNetworkInterface(nicName string, ipAddr string, subnetId string, secgrpId string) (*SInstanceNic, error) { secgroup, err := self.GetSecurityGroupDetails(secgrpId) if err != nil { @@ -47,9 +57,10 @@ func (self *SRegion) CreateNetworkInterface(nicName string, ipAddr string, subne } secgroup.Properties.ProvisioningState = "" + resourceGroupName := getResourceGroupNameByID(subnetId) nicNameBase := nicName for i := 0; i < 5; i++ { - ok, err := self.isNetworkInstanceNameAvaliable(nicName) + ok, err := self.isNetworkInstanceNameAvaliable(resourceGroupName, nicName) if err != nil { return nil, err } diff --git a/pkg/util/azure/region.go b/pkg/util/azure/region.go index 2e26bc2c46..00dfefb556 100644 --- a/pkg/util/azure/region.go +++ b/pkg/util/azure/region.go @@ -1,7 +1,6 @@ package azure import ( - "context" "fmt" "yunion.io/x/jsonutils" @@ -9,9 +8,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/seclib2" - - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-06-01/network" - "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage" ) type SVMSize struct { @@ -130,25 +126,18 @@ func (self *SRegion) GetStatus() string { } func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) { - vpcClient := network.NewVirtualNetworksClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) - vpcClient.Authorizer = self.client.authorizer - addressPrefixes := []string{cidr} - addressSpace := network.AddressSpace{AddressPrefixes: &addressPrefixes} - properties := network.VirtualNetworkPropertiesFormat{AddressSpace: &addressSpace} - parameters := network.VirtualNetwork{Name: &name, Location: &self.Name, VirtualNetworkPropertiesFormat: &properties} - vpcId, resourceGroup, vpcName := pareResourceGroupWithName(name, VPC_RESOURCE) - self.CreateResourceGroup(resourceGroup) - if result, err := vpcClient.CreateOrUpdate(context.Background(), resourceGroup, vpcName, parameters); err != nil { - return nil, err - } else if err := result.WaitForCompletion(context.Background(), vpcClient.Client); err != nil { - return nil, err - } else if err := self.fetchInfrastructure(); err != nil { - return nil, err - } else if vpc, err := self.GetIVpcById(vpcId); err != nil { - return nil, err - } else { - return vpc, nil + vpc := SVpc{ + region: self, + Name: name, + Location: self.Name, + Properties: VirtualNetworkPropertiesFormat{ + AddressSpace: AddressSpace{ + AddressPrefixes: []string{cidr}, + }, + }, + Type: "Microsoft.Network/virtualNetworks", } + return &vpc, self.client.Create(jsonutils.Marshal(vpc), &vpc) } func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { @@ -232,7 +221,7 @@ func (self *SRegion) getZoneById(id string) (*SZone, error) { } func (self *SRegion) fetchZones() error { - if self.izones == nil { + if self.izones == nil || len(self.izones) == 0 { self.izones = make([]cloudprovider.ICloudZone, 1) zone := SZone{region: self, Name: self.Name} self.izones[0] = &zone @@ -256,18 +245,6 @@ func (self *SRegion) getStoragecache() *SStoragecache { return self.storageCache } -func (self *SRegion) getStorage() ([]SStorage, error) { - storages := make([]SStorage, 0) - storageClient := storage.NewAccountsClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) - storageClient.Authorizer = self.client.authorizer - if storageList, err := storageClient.List(context.Background()); err != nil { - return nil, err - } else if err := jsonutils.Update(&storages, storageList.Value); err != nil { - return storages, err - } - return storages, nil -} - func (self *SRegion) getVpcs() ([]SVpc, error) { result := []SVpc{} vpcs := []SVpc{} diff --git a/pkg/util/azure/securitygroup.go b/pkg/util/azure/securitygroup.go index f6291aecea..78aef6e263 100644 --- a/pkg/util/azure/securitygroup.go +++ b/pkg/util/azure/securitygroup.go @@ -308,8 +308,7 @@ func (region *SRegion) updateSecurityGroupRules(secgroupId string, rules []secru } secgroup.Properties.SecurityRules = &securityRules secgroup.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(secgroup)) - return secgroup.ID, err + return secgroup.ID, region.client.Update(jsonutils.Marshal(secgroup), nil) } func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error { @@ -323,8 +322,7 @@ func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []st } secgroup.Properties.NetworkInterfaces = &interfaces secgroup.Properties.ProvisioningState = "" - _, err = region.client.Update(jsonutils.Marshal(secgroup)) - return err + return region.client.Update(jsonutils.Marshal(secgroup), nil) } func (region *SRegion) AssiginSecurityGroup(instanceId, secgroupId string) error { diff --git a/pkg/util/azure/shell/instance.go b/pkg/util/azure/shell/instance.go index 9a38c7cd00..a5e5f6987a 100644 --- a/pkg/util/azure/shell/instance.go +++ b/pkg/util/azure/shell/instance.go @@ -9,9 +9,10 @@ import ( func init() { type InstanceListOptions struct { - Classic bool `help:"List classic instance"` - Limit int `help:"page size"` - Offset int `help:"page offset"` + Classic bool `help:"List classic instance"` + ScaleSets bool `help:"List Scale Sets instance"` + Limit int `help:"page size"` + Offset int `help:"page offset"` } shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *azure.SRegion, args *InstanceListOptions) error { if args.Classic { @@ -21,6 +22,13 @@ func init() { } printList(instances, len(instances), args.Offset, args.Limit, []string{}) return nil + } else if args.ScaleSets { + instances, err := cli.GetInstanceScaleSets() + if err != nil { + return err + } + printList(instances, len(instances), args.Offset, args.Limit, []string{}) + return nil } instances, err := cli.GetInstances() if err != nil { diff --git a/pkg/util/azure/snapshot.go b/pkg/util/azure/snapshot.go index 60162f77fd..60d6497b22 100644 --- a/pkg/util/azure/snapshot.go +++ b/pkg/util/azure/snapshot.go @@ -8,7 +8,9 @@ import ( "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" ) type SnapshotSku struct { @@ -44,7 +46,13 @@ func (self *SSnapshot) GetName() string { } func (self *SSnapshot) GetStatus() string { - return "" + switch self.Properties.ProvisioningState { + case "Succeeded": + return models.SNAPSHOT_READY + default: + log.Errorf("Unknow azure snapshot %s status: %s", self.ID, self.Properties.ProvisioningState) + return models.SNAPSHOT_UNKNOWN + } } func (self *SSnapshot) IsEmulated() bool { @@ -104,28 +112,53 @@ func (self *SRegion) GrantAccessSnapshot(snapshotId string) (string, error) { } func (self *SSnapshot) Refresh() error { - if snapshot, err := self.region.GetSnapshotDetail(self.ID); err != nil { - return err - } else if err := jsonutils.Update(self, snapshot); err != nil { + snapshot, err := self.region.GetSnapshotDetail(self.ID) + if err != nil { return err } - return nil + return jsonutils.Update(self, snapshot) } func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + if strings.HasPrefix(snapshotId, "https://") { + //TODO + return nil, cloudprovider.ErrNotImplemented + } return self.GetSnapshotDetail(snapshotId) } func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - if snapshots, err := self.GetSnapShots(""); err != nil { + snapshots, err := self.GetSnapShots("") + if err != nil { return nil, err - } else { - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i++ { - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil } + classicSnapshots := []SClassicSnapshot{} + storages, err := self.GetStorageAccounts() + if err != nil { + return nil, err + } + _, _classicSnapshots, err := self.GetStorageAccountsDisksWithSnapshots(storages...) + if err != nil { + return nil, err + } + classicSnapshots = append(classicSnapshots, _classicSnapshots...) + classicStorages, err := self.GetClassicStorageAccounts() + if err != nil { + return nil, err + } + _, _classicSnapshots, err = self.GetStorageAccountsDisksWithSnapshots(classicStorages...) + if err != nil { + return nil, err + } + classicSnapshots = append(classicSnapshots, _classicSnapshots...) + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)+len(classicSnapshots)) + for i := 0; i < len(snapshots); i++ { + isnapshots[i] = &snapshots[i] + } + for i := 0; i < len(classicSnapshots); i++ { + isnapshots[len(snapshots)+i] = &classicSnapshots[i] + } + return isnapshots, nil } func (self *SSnapshot) GetDiskId() string { diff --git a/pkg/util/azure/storage.go b/pkg/util/azure/storage.go index 310ec1bcbe..d2f5dcce26 100644 --- a/pkg/util/azure/storage.go +++ b/pkg/util/azure/storage.go @@ -86,24 +86,43 @@ func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { idisks := make([]cloudprovider.ICloudDisk, 0) for i := 0; i < len(disks); i++ { storageType := strings.ToLower(string(disks[i].Sku.Name)) - if storageType == self.storageType { + if storageType == strings.ToLower(self.storageType) { disks[i].storage = self idisks = append(idisks, &disks[i]) log.Debugf("find disk %s for storage %s", disks[i].GetName(), self.GetName()) } } - // classicDisks, err := self.zone.region.GetClassicDisks() - // if err != nil { - // return nil, err - // } - // for i := 0; i < len(classicDisks); i++ { - // storageType := strings.ToLower(string(classicDisks[i].storage.storageType)) - // if storageType == self.storageType { - // disks[i].storage = self - // idisks = append(idisks, &disks[i]) - // log.Debugf("find disk %s for storage %s", disks[i].GetName(), self.GetName()) - // } - // } + storageaccounts, err := self.zone.region.GetStorageAccounts() + if err != nil { + log.Errorf("List storage account for get idisks error: %v", err) + return nil, err + } + for i := 0; i < len(storageaccounts); i++ { + storageType := strings.ToLower(storageaccounts[i].Sku.Name) + if strings.ToLower(self.storageType) != storageType { + continue + } + disks, _, err := self.zone.region.GetStorageAccountDisksWithSnapshots(storageaccounts[i]) + if err != nil { + return nil, err + } + for i := 0; i < len(disks); i++ { + disk := SDisk{ + storage: self, + Sku: DiskSku{ + Name: storageaccounts[i].Sku.Name, + Tier: storageaccounts[i].Sku.Tier, + }, + Properties: DiskProperties{ + DiskSizeGB: disks[i].DiskSizeGB, + OsType: disks[i].diskType, + }, + ID: disks[i].VhdUri, + Name: disks[i].DiskName, + } + idisks = append(idisks, &disk) + } + } return idisks, nil } diff --git a/pkg/util/azure/storageaccount.go b/pkg/util/azure/storageaccount.go index b9491f4d76..2e8fa28b07 100644 --- a/pkg/util/azure/storageaccount.go +++ b/pkg/util/azure/storageaccount.go @@ -3,10 +3,13 @@ package azure import ( "fmt" "math/rand" + "path" "strings" "time" "github.com/Azure/azure-sdk-for-go/storage" + "github.com/Microsoft/azure-vhd-utils/vhdcore/common" + "github.com/Microsoft/azure-vhd-utils/vhdcore/diskstream" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" ) @@ -24,19 +27,19 @@ type Identity struct { Type string } +type PrimaryEndpoints struct { + Blob string + Queue string + Table string + File string +} + type AccountProperties struct { //classic ClassicStorageProperties - // Status string - // Endpoints []string - // AccountType string - // GeoPrimaryRegion string - // StatusOfPrimaryRegion string - // GeoSecondaryRegion string - // StatusOfSecondaryRegion string - // CreationTime time.Time //normal + PrimaryEndpoints PrimaryEndpoints `json:"primaryEndpoints,omitempty"` ProvisioningState string PrimaryLocation string SecondaryLocation string @@ -63,17 +66,15 @@ type SStorageAccount struct { func (self *SRegion) GetStorageAccounts() ([]SStorageAccount, error) { result := []SStorageAccount{} - for _, resourceType := range []string{"Microsoft.ClassicStorage/storageAccounts", "Microsoft.Storage/storageAccounts"} { - accounts := []SStorageAccount{} - err := self.client.ListAll(resourceType, &accounts) - if err != nil { - return nil, err - } - for i := 0; i < len(accounts); i++ { - if accounts[i].Location == self.Name { - accounts[i].region = self - result = append(result, accounts[i]) - } + accounts := []SStorageAccount{} + err := self.client.ListAll("Microsoft.Storage/storageAccounts", &accounts) + if err != nil { + return nil, err + } + for i := 0; i < len(accounts); i++ { + if accounts[i].Location == self.Name { + accounts[i].region = self + result = append(result, accounts[i]) } } return result, nil @@ -207,6 +208,9 @@ func (self *SStorageAccount) GetAccountKey() (accountKey string, err error) { } func (self *SStorageAccount) GetBlobBaseUrl() string { + if self.Type == "Microsoft.Storage/storageAccounts" { + return self.Properties.PrimaryEndpoints.Blob + } for _, url := range self.Properties.Endpoints { if strings.Contains(url, ".blob.") { return url @@ -215,6 +219,25 @@ func (self *SStorageAccount) GetBlobBaseUrl() string { return "" } +func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer, error) { + accessKey, err := self.GetAccountKey() + if err != nil { + return nil, err + } + client, err := storage.NewBasicClientOnSovereignCloud(self.Name, accessKey, self.region.client.env) + if err != nil { + return nil, err + } + container := SContainer{storageaccount: self} + blobService := client.GetBlobService() + containerRef := blobService.GetContainerReference(containerName) + err = containerRef.Create(&storage.CreateContainerOptions{}) + if err != nil { + return nil, err + } + return &container, jsonutils.Update(&container, containerRef) +} + func (self *SStorageAccount) GetContainers() ([]SContainer, error) { accessKey, err := self.GetAccountKey() if err != nil { @@ -270,17 +293,92 @@ type SContainerFile struct { Metadata map[string]string } -func (self *SContainer) ListFiles() ([]SContainerFile, error) { - files := []SContainerFile{} +func (self *SContainer) ListFiles() ([]storage.Blob, error) { storageaccount := self.storageaccount client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env) if err != nil { return nil, err } blobService := client.GetBlobService() - result, err := blobService.GetContainerReference(self.Name).ListBlobs(storage.ListBlobsParameters{}) + result, err := blobService.GetContainerReference(self.Name).ListBlobs(storage.ListBlobsParameters{Include: &storage.IncludeBlobDataset{Snapshots: true, Metadata: true}}) if err != nil { return nil, err } - return files, jsonutils.Update(&files, result.Blobs) + return result.Blobs, nil +} + +func (self *SContainer) UploadFile(filePath string) (string, error) { + storageaccount := self.storageaccount + client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env) + if err != nil { + return "", err + } + blobService := client.GetBlobService() + containerRef := blobService.GetContainerReference(self.Name) + + err = ensureVHDSanity(filePath) + if err != nil { + return "", err + } + diskStream, err := diskstream.CreateNewDiskStream(filePath) + if err != nil { + return "", err + } + defer diskStream.Close() + blobName := path.Base(filePath) + blobRef := containerRef.GetBlobReference(blobName) + blobRef.Properties.ContentLength = diskStream.GetSize() + err = blobRef.PutPageBlob(&storage.PutBlobOptions{}) + if err != nil { + return "", err + } + var rangesToSkip []*common.IndexRange + uploadableRanges, err := LocateUploadableRanges(diskStream, rangesToSkip, DefaultReadBlockSize) + if err != nil { + return "", err + } + uploadableRanges, err = DetectEmptyRanges(diskStream, uploadableRanges) + if err != nil { + return "", err + } + + cxt := &DiskUploadContext{ + VhdStream: diskStream, + UploadableRanges: uploadableRanges, + AlreadyProcessedBytes: common.TotalRangeLength(rangesToSkip), + BlobServiceClient: blobService, + ContainerName: self.Name, + BlobName: blobName, + Parallelism: 3, + Resume: false, + MD5Hash: []byte(""), //localMetaData.FileMetaData.MD5Hash, + } + + if err := Upload(cxt); err != nil { + return "", err + } + return blobRef.GetURL(), nil +} + +func (self *SStorageAccount) UploadFile(containerName string, filePath string) (string, error) { + containers, err := self.GetContainers() + if err != nil { + return "", err + } + container := &SContainer{} + find := false + for i := 0; i < len(containers); i++ { + if containers[i].Name == containerName { + container = &containers[i] + find = true + break + } + } + if !find { + container, err = self.CreateContainer(containerName) + if err != nil { + return "", err + } + } + return container.UploadFile(filePath) } diff --git a/pkg/util/azure/storagecache.go b/pkg/util/azure/storagecache.go index 30cff5044a..54f49f6c78 100644 --- a/pkg/util/azure/storagecache.go +++ b/pkg/util/azure/storagecache.go @@ -100,9 +100,40 @@ func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageI return self.uploadImage(userCred, imageId, osArch, osType, osDist, isForce) } +func (self *SStoragecache) checkStorageAccount() (*SStorageAccount, error) { + storageaccount := &SStorageAccount{} + storageaccounts, err := self.region.GetStorageAccounts() + if err != nil { + return nil, err + } + if len(storageaccounts) == 0 { + storageaccount, err = self.region.CreateStorageAccount(self.region.Name) + if err != nil { + return nil, err + } + } else { + for i := 0; i < len(storageaccounts); i++ { + if id, ok := storageaccounts[i].Tags["id"]; ok && id == self.region.Name { + storageaccount = &storageaccounts[i] + break + } + } + if id, ok := storageaccount.Tags["id"]; !ok || id == self.region.Name { + if storageaccount.Tags == nil { + storageaccount.Tags = map[string]string{} + } + storageaccount.Tags["id"] = self.region.Name + err = self.region.client.Update(jsonutils.Marshal(storageaccount), nil) + if err != nil { + return nil, err + } + } + } + return storageaccount, nil +} + func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, isForce bool) (string, error) { s := auth.GetAdminSession(options.Options.Region, "") - if meta, reader, err := modules.Images.Download(s, imageId); err != nil { return "", err } else { @@ -123,27 +154,19 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI if _, err := io.Copy(f, reader); err != nil { return "", err } - storageAccount := fmt.Sprintf("%s%s", self.region.Name, DefaultStorageAccount) - log.Debugf("Create storageAccount: %s", storageAccount) - storage, err := self.region.CreateStorageAccount(storageAccount) + storageaccount, err := self.checkStorageAccount() if err != nil { return "", err } - log.Debugf("Create Container: %s", DefaultContainer) - if _, err := self.region.CreateContainer(storage, DefaultContainer); err != nil { + blobURI, err := storageaccount.UploadFile("image-cache", tmpFile) + if err != nil { return "", err } size, _ := meta.Int("size") - blobURI, err := self.region.UploadVHD(storage, DefaultContainer, tmpFile) - if err != nil { - log.Errorf("uploadContainerFileByPath error: %v", err) - return "", err - } - imageBaseName := imageId if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { imageBaseName = fmt.Sprintf("img%s", imageId) diff --git a/pkg/util/azure/vpc.go b/pkg/util/azure/vpc.go index a6e428e70d..a086f5e101 100644 --- a/pkg/util/azure/vpc.go +++ b/pkg/util/azure/vpc.go @@ -9,12 +9,12 @@ import ( ) type AddressSpace struct { - AddressPrefixes []string + AddressPrefixes []string `json:"addressPrefixes,omitempty"` } type SubnetPropertiesFormat struct { - AddressPrefix string - ProvisioningState string + AddressPrefix string `json:"addressPrefix,omitempty"` + //ProvisioningState string } type Subnet struct { @@ -27,9 +27,8 @@ type VirtualNetworkPropertiesFormat struct { ProvisioningState string Status string VirtualNetworkSiteName string - InUse bool - AddressSpace AddressSpace - Subnets *[]SNetwork + AddressSpace AddressSpace `json:"addressSpace,omitempty"` + Subnets *[]SNetwork `json:"subnets,omitempty"` } type SVpc struct { @@ -38,7 +37,7 @@ type SVpc struct { iwires []cloudprovider.ICloudWire secgroups []cloudprovider.ICloudSecurityGroup - IsDefault bool + isDefault bool ID string Name string @@ -46,7 +45,7 @@ type SVpc struct { Type string Location string Tags map[string]string - Properties VirtualNetworkPropertiesFormat + Properties VirtualNetworkPropertiesFormat `json:"properties,omitempty"` } func (self *SVpc) GetMetadata() *jsonutils.JSONDict { @@ -58,10 +57,7 @@ func (self *SVpc) GetId() string { } func (self *SVpc) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID + return self.Name } func (self *SVpc) GetGlobalId() string { @@ -73,7 +69,7 @@ func (self *SVpc) IsEmulated() bool { } func (self *SVpc) GetIsDefault() bool { - return self.IsDefault + return self.isDefault } func (self *SVpc) GetCidrBlock() string { @@ -150,6 +146,9 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err func (self *SVpc) fetchWires() error { networks := make([]cloudprovider.ICloudNetwork, len(*self.Properties.Subnets)) + if len(self.region.izones) == 0 { + self.region.fetchZones() + } wire := SWire{zone: self.region.izones[0].(*SZone), vpc: self, inetworks: networks} for i, _network := range *self.Properties.Subnets { network := SNetwork{wire: &wire} diff --git a/pkg/util/azure/wire.go b/pkg/util/azure/wire.go index 3ff9bf51ce..08830e8eeb 100644 --- a/pkg/util/azure/wire.go +++ b/pkg/util/azure/wire.go @@ -72,17 +72,26 @@ func (self *SRegion) createNetwork(vpc *SVpc, subnetName string, cidr string, de } else { *vpc.Properties.Subnets = append(*vpc.Properties.Subnets, subnet) } - _, err := self.client.Update(jsonutils.Marshal(vpc)) - return &subnet, err + vpc.Properties.ProvisioningState = "" + err := self.client.Update(jsonutils.Marshal(vpc), vpc) + if err != nil { + return nil, err + } + for i := 0; i < len(*vpc.Properties.Subnets); i++ { + if (*vpc.Properties.Subnets)[i].Name == subnetName { + subnet.ID = (*vpc.Properties.Subnets)[i].ID + } + } + return &subnet, nil } func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) { - if network, err := self.zone.region.createNetwork(self.vpc, name, cidr, desc); err != nil { + network, err := self.zone.region.createNetwork(self.vpc, name, cidr, desc) + if err != nil { return nil, err - } else { - network.wire = self - return network, nil } + network.wire = self + return network, nil } func (self *SWire) GetBandwidth() int { diff --git a/pkg/util/azure/zone.go b/pkg/util/azure/zone.go index 4f6ad14989..eba090104f 100644 --- a/pkg/util/azure/zone.go +++ b/pkg/util/azure/zone.go @@ -12,14 +12,16 @@ import ( type SZone struct { region *SRegion - iwires []cloudprovider.ICloudWire - iclassicWires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage + iwires []cloudprovider.ICloudWire + iclassicWires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + iclassicStorages []cloudprovider.ICloudStorage - storageTypes []string - Name string - host *SHost - classicHost *SClassicHost + storageTypes []string + classicStorageTypes []string + Name string + host *SHost + classicHost *SClassicHost } func (self *SZone) GetMetadata() *jsonutils.JSONDict { @@ -101,21 +103,12 @@ func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { return self.region } -func (self *SZone) fetchStorages() error { - if len(self.storageTypes) == 0 { - if err := self.getStorageTypes(); err != nil { - return err - } - } - self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes)) - for i, storageType := range self.storageTypes { - storage := SStorage{zone: self, storageType: storageType} - self.istorages[i] = &storage - } +func (self *SZone) fetchClassicStorages() error { storageaccounts, err := self.region.GetClassicStorageAccounts() if err != nil { return err } + self.iclassicStorages = make([]cloudprovider.ICloudStorage, len(storageaccounts)) for i := 0; i < len(storageaccounts); i++ { storage := SClassicStorage{ zone: self, @@ -125,16 +118,34 @@ func (self *SZone) fetchStorages() error { Location: storageaccounts[i].Location, Properties: storageaccounts[i].Properties.ClassicStorageProperties, } - self.istorages = append(self.istorages, &storage) + self.iclassicStorages[i] = &storage + } + return nil +} + +func (self *SZone) fetchStorages() error { + if len(self.storageTypes) == 0 { + err := self.getStorageTypes() + if err != nil { + return err + } + } + self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes)) + for i, storageType := range self.storageTypes { + storage := SStorage{zone: self, storageType: storageType} + self.istorages[i] = &storage } return nil } func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if err := self.fetchStorages(); err != nil { + err := self.fetchStorages() + if err != nil { return nil, err } - return self.istorages, nil + self.fetchClassicStorages() + istorages := append(self.istorages, self.iclassicStorages...) + return istorages, nil } func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { @@ -150,14 +161,28 @@ func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, erro } func (self *SZone) getStorageByType(storageType string) (*SStorage, error) { - if storages, err := self.GetIStorages(); err != nil { + _, err := self.GetIStorages() + if err != nil { return nil, err - } else { - for i := 0; i < len(storages); i += 1 { - _storage := storages[i].(*SStorage) - if strings.ToLower(_storage.storageType) == strings.ToLower(storageType) { - return _storage, nil - } + } + for i := 0; i < len(self.istorages); i += 1 { + storage := self.istorages[i].(*SStorage) + if strings.ToLower(storage.storageType) == strings.ToLower(storageType) { + return storage, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) getClassicStorageByType(storageType string) (*SClassicStorage, error) { + _, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(self.iclassicStorages); i += 1 { + storage := self.iclassicStorages[i].(*SClassicStorage) + if strings.ToLower(storage.Properties.AccountType) == strings.ToLower(storageType) { + return storage, nil } } return nil, cloudprovider.ErrNotFound