diff --git a/Gopkg.lock b/Gopkg.lock index 7c93a500e3..574d951376 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -908,7 +908,7 @@ branch = "master" name = "yunion.io/x/structarg" packages = ["."] - revision = "adf929ce0f8bd62335ebe57d9b51f023c84e4d7a" + revision = "d5e5d87357b9bc2164215117763f6b15b2a3e75d" [solve-meta] analyzer-name = "dep" diff --git a/cmd/climc/climc.go b/cmd/climc/climc.go index d7a8da1372..6a19ea1144 100644 --- a/cmd/climc/climc.go +++ b/cmd/climc/climc.go @@ -169,6 +169,40 @@ func newClientSession(options *BaseOptions) (*mcclient.ClientSession, error) { return session, nil } +func enterInteractiveMode( + parser *structarg.ArgumentParser, + sessionFactory func() *mcclient.ClientSession, +) { + promputils.InitEnv(parser, sessionFactory()) + defer fmt.Println("Bye!") + p := prompt.New( + promputils.Executor, + promputils.Completer, + prompt.OptionPrefix("climc> "), + prompt.OptionTitle("Climc, a Command Line Interface to Manage Clouds"), + prompt.OptionMaxSuggestion(16), + ) + p.Run() +} + +func executeSubcommand( + subcmd *structarg.SubcommandArgument, + subparser *structarg.ArgumentParser, + options *BaseOptions, + sessionFactory func() *mcclient.ClientSession, +) { + var e error + suboptions := subparser.Options() + if options.SUBCOMMAND == "help" { + e = subcmd.Invoke(suboptions) + } else { + e = subcmd.Invoke(sessionFactory(), suboptions) + } + if e != nil { + showErrorAndExit(e) + } +} + func main() { parser, e := getSubcommandsParser() if e != nil { @@ -179,47 +213,39 @@ func main() { if options.Help { fmt.Print(parser.HelpString()) - } else if options.Version { - fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) - } else if len(os.Args) <= 1 || (options.ApiVersion == "v2" && len(os.Args) <= 3) { - session, e := newClientSession(options) - if e != nil { - showErrorAndExit(e) - } - promputils.InitEnv(parser, session) - defer fmt.Println("Bye!") - p := prompt.New( - promputils.Executor, - promputils.Completer, - prompt.OptionPrefix("climc> "), - prompt.OptionTitle("Climc, a Command Line Interface to Manage Clouds"), - prompt.OptionMaxSuggestion(16), - ) - p.Run() - } else { - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } else { - session, e := newClientSession(options) - if e != nil { - showErrorAndExit(e) - } - suboptions := subparser.Options() - if options.SUBCOMMAND == "help" { - e = subcmd.Invoke(suboptions) - } else { - e = subcmd.Invoke(session, suboptions) - } - if e != nil { - showErrorAndExit(e) - } - } + return } + + if options.Version { + fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) + return + } + + ensureSessionFactory := func() *mcclient.ClientSession { + session, err := newClientSession(options) + if err != nil { + showErrorAndExit(err) + } + return session + } + + // enter interactive mode when not enough argument and SUBCOMMAND is empty + if _, ok := e.(*structarg.NotEnoughArgumentsError); ok && options.SUBCOMMAND == "" { + enterInteractiveMode(parser, ensureSessionFactory) + return + } + + subcmd := parser.GetSubcommand() + subparser := subcmd.GetSubParser() + if e != nil { + if subparser != nil { + fmt.Print(subparser.Usage()) + } else { + fmt.Print(parser.Usage()) + } + showErrorAndExit(e) + } + + // execute subcommand in non-interactive mode + executeSubcommand(subcmd, subparser, options, ensureSessionFactory) } diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index edfb638d90..36c986ddf2 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -140,12 +140,12 @@ func init() { }) type CloudproviderSyncOptions struct { - ID string `help:"ID or Name of cloud provider"` - Force bool `help:"Force sync no matter what"` - FullSync bool `help:"Synchronize everything"` - Region []string `help:"region to sync"` - Zone []string `help:"region to sync"` - Host []string `help:"region to sync"` + ID string `help:"ID or Name of cloud provider"` + Force bool `help:"Force sync no matter what"` + FullSync bool `help:"Synchronize everything"` + Region []string `help:"region to sync"` + Zone []string `help:"region to sync"` + Host []string `help:"region to sync"` } R(&CloudproviderSyncOptions{}, "cloud-provider-sync", "Sync of a cloud provider account", func(s *mcclient.ClientSession, args *CloudproviderSyncOptions) error { params := jsonutils.NewDict() diff --git a/cmd/scheduler/app/server.go b/cmd/scheduler/app/server.go index 3dc1ce9a4f..e3a8f93be8 100644 --- a/cmd/scheduler/app/server.go +++ b/cmd/scheduler/app/server.go @@ -8,10 +8,10 @@ import ( "net/http" "strconv" + "gopkg.in/gin-gonic/gin.v1" "yunion.io/x/log" "yunion.io/x/pkg/util/prometheus" "yunion.io/x/pkg/utils" - "gopkg.in/gin-gonic/gin.v1" o "yunion.io/x/onecloud/cmd/scheduler/options" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index c659160fc4..e31fea81cf 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -27,6 +27,7 @@ const ( CLOUD_PROVIDER_VMWARE = "VMware" CLOUD_PROVIDER_ALIYUN = "Aliyun" + CLOUD_PROVIDER_AZURE = "Azure" ) type SCloudproviderManager struct { diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index e3c31efbba..44a1901655 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -145,9 +145,9 @@ func (manager *SCloudregionManager) SyncRegions(ctx context.Context, userCred mc _, err = removed[i].PerformDisable(ctx, userCred, nil, nil) } if err != nil { - syncResult.Delete() - } else { syncResult.DeleteError(err) + } else { + syncResult.Delete() } } } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index c5dec34277..60b0c3bbe8 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -110,6 +110,7 @@ const ( HYPERVISOR_ESXI = "esxi" HYPERVISOR_HYPERV = "hyperv" HYPERVISOR_ALIYUN = "aliyun" + HYPERVISOR_AZURE = "azure" // HYPERVISOR_DEFAULT = HYPERVISOR_KVM HYPERVISOR_DEFAULT = HYPERVISOR_ALIYUN diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 6b47c4e370..1ce0d72e9a 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -35,6 +35,7 @@ const ( HOST_TYPE_HYPERV = "hyperv" // # Microsoft Hyper-V HOST_TYPE_XEN = "xen" // # XenServer HOST_TYPE_ALIYUN = "aliyun" + HOST_TYPE_AZURE = "azure" HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index a2d86c4f5c..e941ae9627 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -826,7 +826,11 @@ func isValidMaskLen(maskLen int64) bool { } } -func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { +func (manager *SNetworkManager) AllowPerformCheckNet(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool { + return userCred.IsSystemAdmin() +} + +func (manager *SNetworkManager) PerformCheckNet(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { prefixStr, _ := data.GetString("guest_ip_prefix") var maskLen64 int64 var err error @@ -962,7 +966,13 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred if !vpcRange.ContainsRange(netRange) { return nil, httperrors.NewInputParameterError("Network not in range of VPC cidrblock %s", vpc.CidrBlock) } + return data, nil +} +func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + if _, err := manager.PerformCheckNet(ctx, userCred, query, data); err != nil { + return nil, err + } serverTypeStr, _ := data.GetString("server_type") if len(serverTypeStr) == 0 { serverTypeStr = SERVER_TYPE_GUEST diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 4ac8ea7587..580f7f2235 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -290,6 +290,7 @@ func (manager *SStorageManager) SyncStorages(ctx context.Context, userCred mccli added := make([]cloudprovider.ICloudStorage, 0) err = compare.CompareSets(dbStorages, storages, &removed, &commondb, &commonext, &added) + if err != nil { syncResult.Error(err) return nil, nil, syncResult diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index c873819ebd..a018a3e2f1 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -21,10 +21,10 @@ type ComputeOptions struct { DefaultDiskSize int `default:"30720" help:"Default disk size in MB if not specified, default to 30GiB"` - EnablePendingDelete bool `default:"true" help:"Turn on/off pending delete VM and disk, default is on"` - PendingDeleteCheckSeconds int `default:"3600" help:"How long to wait to scan pending delete VM or disks, default is 1 hour"` - PendingDeleteExpireSeconds int `default:"259200" help:"How long a pending delete VM/disks cleaned automatically, default 3 days"` - PendingDeleteMaxCleanBatchSize int `default:"50" help:"How many pending delete servers can be clean in a batch"` + EnablePendingDelete bool `default:"true" help:"Turn on/off pending delete VM and disk, default is on"` + PendingDeleteCheckSeconds int `default:"3600" help:"How long to wait to scan pending delete VM or disks, default is 1 hour"` + PendingDeleteExpireSeconds int `default:"259200" help:"How long a pending delete VM/disks cleaned automatically, default 3 days"` + PendingDeleteMaxCleanBatchSize int `default:"50" help:"How many pending delete servers can be clean in a batch"` ImageCacheStoragePolicy string `default:"least_used" choices:"best_fit|least_used" help:"Policy to choose storage for image cache, best_fit or least_used"` MetricsRetentionDays int32 `default:"30" help:"Retention days for monitoring metrics in influxdb"` diff --git a/pkg/compute/service/service.go b/pkg/compute/service/service.go index f8cac5dbae..5b80643503 100644 --- a/pkg/compute/service/service.go +++ b/pkg/compute/service/service.go @@ -12,6 +12,7 @@ import ( _ "yunion.io/x/onecloud/pkg/compute/hostdrivers" _ "yunion.io/x/onecloud/pkg/compute/tasks" _ "yunion.io/x/onecloud/pkg/util/aliyun/provider" + _ "yunion.io/x/onecloud/pkg/util/azure/provider" _ "yunion.io/x/onecloud/pkg/util/esxi/provider" "yunion.io/x/onecloud/pkg/cloudcommon" diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index db08f85c25..78efb6a653 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -9,9 +9,10 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/pkg/utils" ) type SRegion struct { @@ -564,4 +565,4 @@ func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { return self.updateInstance(instId, "", "", passwd, "") -} \ No newline at end of file +} diff --git a/pkg/util/aliyun/shell/instance.go b/pkg/util/aliyun/shell/instance.go index 9c86e47aa8..495e2949cf 100644 --- a/pkg/util/aliyun/shell/instance.go +++ b/pkg/util/aliyun/shell/instance.go @@ -2,6 +2,7 @@ package shell import ( "fmt" + "yunion.io/x/onecloud/pkg/util/aliyun" "yunion.io/x/onecloud/pkg/util/shellutils" ) @@ -82,7 +83,7 @@ func init() { }) type InstanceUpdatePasswordOptions struct { - ID string `help:"Instance ID"` + ID string `help:"Instance ID"` PASSWD string `help:"new password"` } shellutils.R(&InstanceUpdatePasswordOptions{}, "instance-update-password", "Update instance password", func(cli *aliyun.SRegion, args *InstanceUpdatePasswordOptions) error { diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go new file mode 100644 index 0000000000..e72fa3bdd1 --- /dev/null +++ b/pkg/util/azure/azure.go @@ -0,0 +1,208 @@ +package azure + +import ( + "context" + "strings" + + "github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/resources" + "github.com/Azure/azure-sdk-for-go/services/preview/subscription/mgmt/2018-03-01-preview/subscription" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure/auth" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" +) + +const ( + CLOUD_PROVIDER_AZURE = models.CLOUD_PROVIDER_AZURE + CLOUD_PROVIDER_AZURE_CN = "微软" + + AZURE_DEFAULT_ENVIRONMENT = "AzureChinaCloud" + AZURE_DEFAULT_APPLICATION = "Azure-Yunion-API" + + AZURE_API_VERSION = "2014-05-26" +) + +type SAzureClient struct { + providerId string + providerName string + subscriptionId string + tenantId string + clientId string + clientScret string + baseUrl string + secret string + resourceGroups map[string][]string + authorizer autorest.Authorizer + iregions []cloudprovider.ICloudRegion +} + +func NewAzureClient(providerId string, providerName string, accessKey string, secret string, url string) (*SAzureClient, error) { + url = strings.Replace(url, "login", "management", -1) + if clientInfo := strings.Split(secret, "/"); len(clientInfo) == 3 { + client := SAzureClient{providerId: providerId, providerName: providerName, tenantId: accessKey, secret: secret, baseUrl: url} + client.clientId, client.clientScret, client.subscriptionId = clientInfo[0], clientInfo[1], clientInfo[2] + if err := client.fetchAzureInof(); err != nil { + return nil, err + } else if err := client.fetchRegions(); err != nil { + return nil, err + } + return &client, nil + } else { + return nil, httperrors.NewUnauthorizedError("clientId、clientScret or subscriptId input error") + } +} + +func (self *SAzureClient) fetchAzureInof() error { + conf := auth.NewClientCredentialsConfig(self.clientId, self.clientScret, self.tenantId) + conf.Resource = self.baseUrl + conf.AADEndpoint = strings.Replace(self.baseUrl, "management", "login", -1) + if authorizer, err := conf.Authorizer(); err != nil { + return err + } else { + self.authorizer = authorizer + } + resourceClient := resources.NewClientWithBaseURI(self.baseUrl, self.subscriptionId) + resourceClient.Authorizer = self.authorizer + if resourceList, err := resourceClient.List(context.Background(), "", "", nil); err != nil { + return err + } else { + self.resourceGroups = make(map[string][]string, len(resourceList.Values())) + for _, resource := range resourceList.Values() { + if _, ok := self.resourceGroups[*resource.Type]; !ok { + self.resourceGroups[*resource.Type] = []string{} + } + self.resourceGroups[*resource.Type] = append(self.resourceGroups[*resource.Type], *resource.Name) + log.Errorf("find resource group: %s => %s", *resource.Type, *resource.Name) + } + } + + return nil +} + +func (self *SAzureClient) UpdateAccount(tenantId, secret string) error { + if self.tenantId != tenantId || self.secret != secret { + self.tenantId = tenantId + self.secret = secret + if clientInfo := strings.Split(secret, "/"); len(clientInfo) == 3 { + self.clientId, self.clientScret, self.subscriptionId = clientInfo[0], clientInfo[1], clientInfo[2] + conf := auth.NewClientCredentialsConfig(self.clientId, self.clientScret, self.tenantId) + conf.Resource = self.baseUrl + conf.AADEndpoint = strings.Replace(self.baseUrl, "management", "login", -1) + if authorizer, err := conf.Authorizer(); err != nil { + return err + } else { + self.authorizer = authorizer + } + } else { + return httperrors.NewUnauthorizedError("clientId、clientScret or subscriptId input error") + } + return self.fetchAzureInof() + } else { + return nil + } +} + +func (self *SAzureClient) fetchRegions() error { + locationClient := subscription.NewSubscriptionsClientWithBaseURI(self.baseUrl) + locationClient.Authorizer = self.authorizer + if locationList, err := locationClient.ListLocations(context.Background(), self.subscriptionId); err != nil { + return err + } else { + regions := make([]SRegion, len(*locationList.Value)) + self.iregions = make([]cloudprovider.ICloudRegion, len(regions)) + for i, location := range *locationList.Value { + region := SRegion{SubscriptionID: self.subscriptionId} + if err := jsonutils.Update(®ion, location); err != nil { + return err + } + region.client = self + self.iregions[i] = ®ion + log.Infof("find region: %s", jsonutils.Marshal(region).PrettyString()) + } + } + return nil +} + +func (self *SAzureClient) GetRegions() []SRegion { + regions := make([]SRegion, len(self.iregions)) + for i := 0; i < len(regions); i += 1 { + region := self.iregions[i].(*SRegion) + regions[i] = *region + } + return regions +} + +func (self *SAzureClient) GetIRegions() []cloudprovider.ICloudRegion { + return self.iregions +} + +func (self *SAzureClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + for i := 0; i < len(self.iregions); i += 1 { + if self.iregions[i].GetGlobalId() == id { + return self.iregions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SAzureClient) GetRegion(regionId string) *SRegion { + for i := 0; i < len(self.iregions); i += 1 { + if self.iregions[i].GetId() == regionId { + return self.iregions[i].(*SRegion) + } + } + return nil +} + +func (self *SAzureClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + for i := 0; i < len(self.iregions); i += 1 { + ihost, err := self.iregions[i].GetIHostById(id) + if err == nil { + return ihost, nil + } else if err != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SAzureClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + for i := 0; i < len(self.iregions); i += 1 { + ihost, err := self.iregions[i].GetIVpcById(id) + if err == nil { + return ihost, nil + } else if err != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SAzureClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + for i := 0; i < len(self.iregions); i += 1 { + ihost, err := self.iregions[i].GetIStorageById(id) + if err == nil { + return ihost, nil + } else if err != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SAzureClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + for i := 0; i < len(self.iregions); i += 1 { + ihost, err := self.iregions[i].GetIStoragecacheById(id) + if err == nil { + return ihost, nil + } else if err != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go new file mode 100644 index 0000000000..7a86dda326 --- /dev/null +++ b/pkg/util/azure/disk.go @@ -0,0 +1,180 @@ +package azure + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" +) + +type StorageAccountTypes string + +const ( + // StorageAccountTypesPremiumLRS ... + StorageAccountTypesPremiumLRS StorageAccountTypes = "Premium_LRS" + // StorageAccountTypesStandardLRS ... + StorageAccountTypesStandardLRS StorageAccountTypes = "Standard_LRS" + // StorageAccountTypesStandardSSDLRS ... + StorageAccountTypesStandardSSDLRS StorageAccountTypes = "StandardSSD_LRS" +) + +type DiskSku struct { + Name StorageAccountTypes + Tier string +} + +type SDisk struct { + storage *SStorage + + DiskName string + DiskId string + Size int32 + DeleteWithInstance bool + ImageId string + OsType string + Status string + resourceGroup string + + ManagedBy string + Sku DiskSku + Zones []string + ID string + Name string + Type string + Location string + + Tags map[string]string +} + +func (self *SRegion) GetDisk(resourceGroup string, diskName string) (*SDisk, error) { + disk := SDisk{} + computeClient := compute.NewDisksClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + computeClient.Authorizer = self.client.authorizer + if _disk, err := computeClient.Get(context.Background(), resourceGroup, diskName); err != nil { + return nil, err + } else if err := jsonutils.Update(&disk, _disk); err != nil { + return nil, err + } else { + return &disk, nil + } +} + +func (self *SRegion) GetDisks() ([]SDisk, error) { + disks := make([]SDisk, 0) + computeClient := compute.NewDisksClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + computeClient.Authorizer = self.client.authorizer + if diskList, err := computeClient.List(context.Background()); err != nil { + return nil, err + } else { + for _, _disk := range diskList.Values() { + disk := SDisk{} + if err := jsonutils.Update(&disk, _disk); err != nil { + return disks, err + } + disk.resourceGroup, _, _ = pareResourceGroupWithName(disk.ID) + disks = append(disks, disk) + } + } + return disks, nil +} + +func (self *SDisk) GetStatus() string { + // In_use Available Attaching Detaching Creating ReIniting All + switch self.Status { + case "Creating", "ReIniting": + return models.DISK_ALLOCATING + default: + return models.DISK_READY + } +} + +func (self *SDisk) GetId() string { + return self.DiskId +} + +func (self *SRegion) getDisk(resourceGroup string, diskName string) (*SDisk, error) { + return self.GetDisk(resourceGroup, diskName) +} + +func (self *SDisk) Refresh() error { + if disk, err := self.storage.zone.region.GetDisk(self.resourceGroup, self.Name); err != nil { + return err + } else { + return jsonutils.Update(self, disk) + } +} + +func (self *SDisk) Delete() error { + return nil + //return self.storage.zone.region.deleteDisk(self.DiskId) +} + +func (self *SDisk) Resize(size int64) error { + //return self.storage.zone.region.resizeDisk(self.DiskId, size) + return nil +} + +func (self *SDisk) GetName() string { + if len(self.DiskName) > 0 { + return self.DiskName + } + return self.DiskId +} + +func (self *SDisk) GetGlobalId() string { + return self.DiskId +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetIStorge() cloudprovider.ICloudStorage { + return self.storage +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + return "scsi" +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetMountpoint() string { + return "" +} + +func (self *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.Size) * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.DeleteWithInstance +} + +func (self *SDisk) GetTemplateId() string { + return self.ImageId +} + +func (self *SDisk) GetDiskType() string { + if len(self.OsType) > 0 { + return models.DISK_TYPE_SYS + } + return models.DISK_TYPE_DATA +} diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go new file mode 100644 index 0000000000..98e92d2d54 --- /dev/null +++ b/pkg/util/azure/host.go @@ -0,0 +1,130 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SHost struct { + zone *SZone +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.providerId, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.providerName, self.zone.region.Name) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.SubscriptionID) +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetStatus() string { + return models.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string) (cloudprovider.ICloudVM, error) { + return nil, nil +} + +func (self *SHost) GetAccessIp() string { + return "" +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetCpuCount() int8 { + return 0 +} + +func (self *SHost) GetCpuDesc() string { + return "" +} + +func (self *SHost) GetCpuMhz() int { + return 0 +} + +func (self *SHost) GetMemSizeMB() int { + return 0 +} +func (self *SHost) GetEnabled() bool { + return true +} + +func (self *SHost) GetHostStatus() string { + return models.HOST_ONLINE +} +func (self *SHost) GetNodeCount() int8 { + return 0 +} + +func (self *SHost) GetHostType() string { + return models.HOST_TYPE_AZURE +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorageById(id) +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_AZURE), "manufacture") + return info +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorages() +} + +func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { + return nil, nil +} + +func (self *SHost) GetStorageSizeMB() int { + return 0 +} + +func (self *SHost) GetStorageType() string { + return models.DISK_TYPE_HYBRID +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + if vms, err := self.zone.region.GetInstances(); 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] + } + return ivms, nil + } +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.zone.GetIWires() +} + +func (self *SHost) GetManagerId() string { + return self.zone.region.client.providerId +} diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go new file mode 100644 index 0000000000..8f8d20c71f --- /dev/null +++ b/pkg/util/azure/instance.go @@ -0,0 +1,449 @@ +package azure + +import ( + "context" + "fmt" + "regexp" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/util/secrules" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" +) + +type HardwareProfile struct { + VMSize string + MaxDataDiskCount int32 + MemoryInMB int32 + NumberOfCores int32 + Name string + OsDiskSizeInMB int32 + ResourceDiskSizeInMB int32 +} + +type ImageReference struct { + Publisher string + Offer string + Sku string + Version string + ID string +} + +type OperatingSystemTypes string + +const ( + // Linux ... + Linux OperatingSystemTypes = "Linux" + // Windows ... + Windows OperatingSystemTypes = "Windows" +) + +type OSDisk struct { + OsType OperatingSystemTypes + Name string + DiskSizeGB int32 + ManagedDisk ManagedDiskParameters +} + +type VirtualHardDisk struct { + URI string +} + +type CachingTypes string + +const ( + // CachingTypesNone ... + CachingTypesNone CachingTypes = "None" + // CachingTypesReadOnly ... + CachingTypesReadOnly CachingTypes = "ReadOnly" + // CachingTypesReadWrite ... + CachingTypesReadWrite CachingTypes = "ReadWrite" +) + +type ManagedDiskParameters struct { + StorageAccountType StorageAccountTypes + ID string +} + +type DataDisk struct { + Lun int32 + Name string + Vhd VirtualHardDisk + Caching CachingTypes + DiskSizeGB int32 + ManagedDisk ManagedDiskParameters +} + +type StorageProfile struct { + ImageReference ImageReference + OsDisk OSDisk + DataDisks []DataDisk +} + +type SSHPublicKey struct { + Path string + KeyData string +} + +type SSHConfiguration struct { + PublicKeys []SSHPublicKey +} + +type LinuxConfiguration struct { + DisablePasswordAuthentication bool + SSH SSHConfiguration +} + +type SubResource struct { + ID string +} + +type VaultCertificate struct { + CertificateURL string + CertificateStore string +} + +type VaultSecretGroup struct { + SourceVault SubResource + VaultCertificates []VaultCertificate +} + +type OsProfile struct { + ComputerName string + AdminUsername string + AdminPassword string + CustomData string + LinuxConfiguration LinuxConfiguration + Secrets []VaultSecretGroup +} + +type NetworkInterfaceReference struct { + ID string +} + +type NetworkProfile struct { + NetworkInterfaces []NetworkInterfaceReference +} + +type InstanceViewStatus struct { + Code string + Level string + DisplayStatus string + Message string + Time time.Time +} + +type VirtualMachineInstanceView struct { + ComputerName string + OsName string + OsVersion string + Statuses []InstanceViewStatus +} + +type VirtualMachineProperties struct { + HardwareProfile HardwareProfile + StorageProfile StorageProfile + OsProfile OsProfile + NetworkProfile NetworkProfile + InstanceView VirtualMachineInstanceView + VmId string +} + +type SInstance struct { + host *SHost + + idisks []cloudprovider.ICloudDisk + + CreationTime time.Time + ResourceGroup string + + Properties VirtualMachineProperties + ID string + Name string + Type string + Location string + Tags map[string]string +} + +func pareResourceGroupWithName(s string) (string, string, error) { + valid := regexp.MustCompile("resourceGroups/(.+)/providers/.+/(.+)$") + if resourceGroups := valid.FindStringSubmatch(s); len(resourceGroups) == 3 { + return resourceGroups[1], resourceGroups[2], nil + } + return "", "", cloudprovider.ErrNotFound +} + +func (self *SRegion) GetInstance(resourceGroup string, VMName string) (*SInstance, error) { + instance := SInstance{} + computeClient := compute.NewVirtualMachinesClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + computeClient.Authorizer = self.client.authorizer + if _instance, err := computeClient.Get(context.Background(), resourceGroup, VMName, "instanceView"); err != nil { + return nil, err + } else if err := jsonutils.Update(&instance, _instance); err != nil { + return nil, err + } else { + instance.ResourceGroup = resourceGroup + log.Infof("instance: %s", jsonutils.Marshal(instance).PrettyString()) + return &instance, nil + } +} + +func (self *SRegion) GetInstances() ([]SInstance, error) { + instances := make([]SInstance, 0) + computeClient := compute.NewVirtualMachinesClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + computeClient.Authorizer = self.client.authorizer + if instanceList, err := computeClient.ListAll(context.Background()); err != nil { + return instances, err + } else { + for _, _instance := range instanceList.Values() { + instance := SInstance{} + if *_instance.Location == self.Name { + if err := jsonutils.Update(&instance, _instance); err != nil { + return instances, err + } + if vmSize, err := self.getVMSize(instance.Properties.HardwareProfile.VMSize); err != nil { + return instances, err + } else if err := jsonutils.Update(&instance.Properties.HardwareProfile, vmSize); err != nil { + return instances, err + } + instance.ResourceGroup, _, _ = pareResourceGroupWithName(instance.ID) + log.Infof("GetInstances: %s", jsonutils.Marshal(&instance).PrettyString()) + instances = append(instances, instance) + } + } + } + return instances, nil +} + +func (self *SRegion) doDeleteVM(instanceId string) error { + //return self.instanceOperation(instanceId, "DeleteInstance", nil) + return nil +} + +func (self *SInstance) GetHypervisor() string { + return models.HYPERVISOR_AZURE +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) Refresh() error { + if instance, err := self.host.zone.region.GetInstance(self.ResourceGroup, self.Name); err != nil { + log.Errorf("Refresh Instance error: %v", err) + return err + } else if err := jsonutils.Update(self, instance); err != nil { + log.Errorf("Refresh Instance error: %v", err) + return err + } + return nil +} + +func (self *SInstance) GetStatus() string { + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + if len(self.Properties.InstanceView.Statuses) == 0 { + self.Refresh() + } + for _, statuses := range self.Properties.InstanceView.Statuses { + if code := strings.Split(statuses.Code, "/"); len(code) == 2 { + if code[0] == "PowerState" { + return code[1] + } + } + } + return models.VM_UNKNOWN +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetId() string { + return self.ID +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.host.zone.region.GetGlobalId(), self.Properties.VmId) +} + +func (self *SRegion) DeleteVM(instanceId string) error { + // status, err := self.GetInstanceStatus(instanceId) + // if status == InstanceStatusRunning { + // err = self.StopVM(instanceId, true) + // if err != nil { + // return err + // } + // } else if status != InstanceStatusStopped { + // return cloudprovider.ErrInvalidStatus + // } + return self.doDeleteVM(instanceId) +} + +func (self *SInstance) DeleteVM() error { + return nil + // err := self.host.zone.region.DeleteVM(self.InstanceId) + // if err != nil { + // return err + // } + // return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SInstance) getDiskWithStore(resourceGroup string, diskName string) (*SDisk, error) { + if disk, err := self.host.zone.region.GetDisk(resourceGroup, diskName); err != nil { + return nil, err + } else if store, err := self.host.zone.getStorageByTier(disk.Sku.Tier); err != nil { + return nil, err + } else { + disk.storage = store + return disk, nil + } +} + +func (self *SInstance) fetchDisks() error { + self.Refresh() + self.idisks = make([]cloudprovider.ICloudDisk, len(self.Properties.StorageProfile.DataDisks)+1) + if disk, err := self.getDiskWithStore(self.ResourceGroup, self.Properties.StorageProfile.OsDisk.Name); err != nil { + return err + } else { + self.idisks[0] = disk + } + for i, dataDisk := range self.Properties.StorageProfile.DataDisks { + if resourceGroup, diskName, err := pareResourceGroupWithName(dataDisk.ManagedDisk.ID); err != nil { + return err + } else if disk, err := self.getDiskWithStore(resourceGroup, diskName); err != nil { + return err + } else { + self.idisks[i+1] = disk + } + } + return nil +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + if self.idisks == nil { + if err := self.fetchDisks(); err != nil { + return nil, err + } + } + return self.idisks, nil +} + +func (self *SInstance) GetOSType() string { + return osprofile.NormalizeOSType(self.Properties.InstanceView.OsName) +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + for _, _nic := range self.Properties.NetworkProfile.NetworkInterfaces { + if resourceGroup, nicName, err := pareResourceGroupWithName(_nic.ID); err != nil { + return nics, err + } else if nic, err := self.host.zone.region.getNetworkInterface(resourceGroup, nicName); err != nil { + return nics, err + } else { + nic.instance = self + nics = append(nics, nic) + } + } + return nics, nil +} + +func (self *SInstance) GetOSName() string { + return self.Properties.StorageProfile.ImageReference.Offer +} + +func (self *SInstance) GetBios() string { + return "BIOS" +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) GetVcpuCount() int8 { + return int8(self.Properties.HardwareProfile.NumberOfCores) +} + +func (self *SInstance) GetVmemSizeMB() int { + return int(self.Properties.HardwareProfile.MemoryInMB) +} + +func (self *SInstance) GetCreateTime() time.Time { + return self.CreationTime +} + +func (self *SInstance) GetEIP() cloudprovider.ICloudEIP { + return nil + //return &self.EipAddress +} + +func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) { + + // url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) + // if err != nil { + // return nil, err + // } + // passwd := seclib.RandomPassword(6) + // err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd) + // if err != nil { + // return nil, err + // } + ret := jsonutils.NewDict() + // ret.Add(jsonutils.NewString(url), "url") + // ret.Add(jsonutils.NewString(passwd), "password") + // ret.Add(jsonutils.NewString("aliyun"), "protocol") + // ret.Add(jsonutils.NewString(self.InstanceId), "instance_id") + return ret, nil +} + +func (self *SRegion) StartVM(instanceId string) error { + // status, _ := self.GetInstanceStatus(instanceId) + // if status != InstanceStatusStopped { + // return cloudprovider.ErrInvalidStatus + // } + return nil +} + +func (self *SInstance) StartVM() error { + // err := self.host.zone.region.StartVM(self.InstanceId) + // if err != nil { + // return err + // } + return cloudprovider.WaitStatus(self, models.VM_RUNNING, 5*time.Second, 180*time.Second) // 3minutes +} + +func (self *SInstance) StopVM(isForce bool) error { + // err := self.host.zone.region.StopVM(self.InstanceId, isForce) + // if err != nil { + // return err + // } + return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { + return nil +} diff --git a/pkg/util/azure/instancenic.go b/pkg/util/azure/instancenic.go new file mode 100644 index 0000000000..2df9b7ee12 --- /dev/null +++ b/pkg/util/azure/instancenic.go @@ -0,0 +1,93 @@ +package azure + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-04-01/network" +) + +type PublicIPAddressPropertiesFormat struct { + PublicIPAddressVersion string + IPAddress string +} + +type PublicIPAddress struct { + ID string + Name string + Location string + Properties PublicIPAddressPropertiesFormat +} + +type InterfaceIPConfigurationPropertiesFormat struct { + PrivateIPAddress string + PrivateIPAddressVersion string + Subnet Subnet + Primary bool + PublicIPAddress PublicIPAddress +} + +type InterfaceIPConfiguration struct { + Properties InterfaceIPConfigurationPropertiesFormat + Name string + ID string +} + +type InterfacePropertiesFormat struct { + IPConfigurations []InterfaceIPConfiguration + MacAddress string + Primary bool +} + +type SInstanceNic struct { + instance *SInstance + ID string + Name string + Type string + Location string + Properties InterfacePropertiesFormat +} + +func (self *SRegion) getNetworkInterface(resourceGroup string, nicName string) (*SInstanceNic, error) { + nic := SInstanceNic{} + networkClient := network.NewInterfacesClientWithBaseURI(self.client.baseUrl, self.SubscriptionID) + networkClient.Authorizer = self.client.authorizer + if _nic, err := networkClient.Get(context.Background(), resourceGroup, nicName, ""); err != nil { + return nil, err + } else if err := jsonutils.Update(&nic, _nic); err != nil { + return nil, err + } else { + log.Infof("get nic: %s", jsonutils.Marshal(_nic).PrettyString()) + } + return &nic, nil +} + +func (self *SInstanceNic) GetIP() string { + return self.Properties.IPConfigurations[0].Properties.PrivateIPAddress +} + +func (self *SInstanceNic) GetMAC() string { + return self.Properties.MacAddress +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { + if wires, err := self.instance.host.GetIWires(); err != nil { + log.Errorf("GetINetwork error: %v", err) + return nil + } else { + for i := 0; i < len(wires); i++ { + wire := wires[i].(*SWire) + if net := wire.getNetworkById(self.Properties.IPConfigurations[0].Properties.Subnet.ID); net != nil { + return net + } + } + } + return nil +} diff --git a/pkg/util/azure/network.go b/pkg/util/azure/network.go new file mode 100644 index 0000000000..86ccbe14b1 --- /dev/null +++ b/pkg/util/azure/network.go @@ -0,0 +1,109 @@ +package azure + +import ( + "fmt" + "strings" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/pkg/util/netutils" +) + +// {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"} + +const ( + VSwitchPending = "Pending" + VSwitchAvailable = "Available" +) + +type SNetwork struct { + wire *SWire + + AvailableIpAddressCount int + ID string + Name string + Properties SubnetPropertiesFormat + + Status string +} + +func (self *SNetwork) GetId() string { + return fmt.Sprintf("%s/%s/%s", self.wire.zone.region.GetGlobalId(), self.wire.zone.region.SubscriptionID, self.Name) +} + +func (self *SNetwork) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SNetwork) GetGlobalId() string { + return self.GetId() +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetStatus() string { + if strings.ToLower(self.Status) == "succeeded" { + return "avaliable" + } + return "disabled" +} + +func (self *SNetwork) Delete() error { + return nil +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + endIp = endIp.StepDown() // 253 + endIp = endIp.StepDown() // 252 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + return pref.MaskLen +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetIsPublic() bool { + // return self.IsDefault + return true +} + +func (self *SNetwork) GetServerType() string { + return models.SERVER_TYPE_GUEST +} + +func (self *SNetwork) Refresh() error { + // log.Debugf("vsiwtch refresh %s", self.VSwitchId) + // new, err := self.wire.zone.region.getVSwitch(self.VSwitchId) + // if err != nil { + // return err + // } + // return jsonutils.Update(self, new) + return nil +} diff --git a/pkg/util/azure/provider/provider.go b/pkg/util/azure/provider/provider.go new file mode 100644 index 0000000000..6ba0376018 --- /dev/null +++ b/pkg/util/azure/provider/provider.go @@ -0,0 +1,89 @@ +package provider + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/azure" + // "yunion.io/x/log" +) + +type SAzureProviderFactory struct { + providerTable map[string]*SAzureProvider +} + +func (self *SAzureProviderFactory) GetId() string { + return azure.CLOUD_PROVIDER_AZURE +} + +func (self *SAzureProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { + provider, ok := self.providerTable[providerId] + if ok { + err := provider.client.UpdateAccount(account, secret) + if err != nil { + return nil, err + } else { + return provider, nil + } + } + client, err := azure.NewAzureClient(providerId, providerName, account, secret, url) + if err != nil { + return nil, err + } + self.providerTable[providerId] = &SAzureProvider{client: client} + return self.providerTable[providerId], nil +} + +func init() { + factory := SAzureProviderFactory{ + providerTable: make(map[string]*SAzureProvider), + } + cloudprovider.RegisterFactory(&factory) +} + +type SAzureProvider struct { + client *azure.SAzureClient +} + +func (self *SAzureProvider) IsPublicCloud() bool { + return true +} + +func (self *SAzureProvider) GetId() string { + return azure.CLOUD_PROVIDER_AZURE +} + +func (self *SAzureProvider) GetName() string { + return azure.CLOUD_PROVIDER_AZURE_CN +} + +func (self *SAzureProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(azure.AZURE_API_VERSION), "api_version") + return info, nil +} + +func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SAzureProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + return self.client.GetIHostById(id) +} + +func (self *SAzureProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + return self.client.GetIVpcById(id) +} + +func (self *SAzureProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.client.GetIStorageById(id) +} + +func (self *SAzureProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + return self.client.GetIStoragecacheById(id) +} diff --git a/pkg/util/azure/region.go b/pkg/util/azure/region.go new file mode 100644 index 0000000000..6842870fa9 --- /dev/null +++ b/pkg/util/azure/region.go @@ -0,0 +1,240 @@ +package azure + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-06-01/compute" + "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 VMSize struct { + MaxDataDiskCount int32 + MemoryInMB int32 + NumberOfCores int32 + Name string + OsDiskSizeInMB int32 + ResourceDiskSizeInMB int32 +} + +type SRegion struct { + client *SAzureClient + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + + storageCache *SStoragecache + + vmSize map[string]VMSize + ID string + SubscriptionID string + Name string + DisplayName string + Latitude string + Longitude string +} + +///////////////////////////////////////////////////////////////////////////// +func (self *SRegion) Refresh() error { + // do nothing + return nil +} + +func (self *SRegion) fetchVMSize() error { + computeClient := compute.NewVirtualMachineSizesClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + computeClient.Authorizer = self.client.authorizer + if vmSizeList, err := computeClient.List(context.Background(), self.Name); err != nil { + return err + } else { + self.vmSize = make(map[string]VMSize, len(*vmSizeList.Value)) + for _, _vmSize := range *vmSizeList.Value { + vmSize := VMSize{} + jsonutils.Update(&vmSize, _vmSize) + self.vmSize[*_vmSize.Name] = vmSize + } + } + return nil +} + +func (self *SRegion) getVMSize(size string) (*VMSize, error) { + if self.vmSize == nil || len(self.vmSize) == 0 { + if err := self.fetchVMSize(); err != nil { + return nil, err + } + } + if vmSize, ok := self.vmSize[size]; !ok { + return nil, cloudprovider.ErrNotFound + } else { + return &vmSize, nil + } +} + +func (self *SRegion) GetId() string { + return self.ID +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AZURE_CN, self.DisplayName) +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_AZURE, self.Name) +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_AZURE +} + +func (self *SRegion) GetLatitude() float32 { + return 0.0 +} + +func (self *SRegion) GetLongitude() float32 { + return 0.0 +} + +func (self *SRegion) GetStatus() string { + return models.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) { + return nil, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + return nil, nil +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return nil, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + return nil, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + return nil, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + return nil, nil +} + +func (self *SRegion) getZoneById(id string) (*SZone, error) { + return nil, nil +} + +func (self *SRegion) fetchZones() error { + if self.izones == nil { + self.izones = make([]cloudprovider.ICloudZone, 1) + zone := SZone{region: self, Name: self.Name} + self.izones[0] = &zone + } + return nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + if err := self.fetchInfrastructure(); err != nil { + return nil, err + } + } + return self.izones, nil +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + 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 { + for _, _storage := range *storageList.Value { + if *_storage.Location == self.Name { + storage := SStorage{ + StorageId: *_storage.ID, + storageType: string(_storage.Kind), + Name: *_storage.Name, + Status: string(_storage.StatusOfPrimary), + Tier: string(_storage.Sku.Tier), + } + storages = append(storages, storage) + } + } + } + return storages, nil +} + +func (self *SRegion) getVpcs() ([]SVpc, error) { + vpcs := make([]SVpc, 0) + networkClient := network.NewVirtualNetworksClientWithBaseURI(self.client.baseUrl, self.client.subscriptionId) + networkClient.Authorizer = self.client.authorizer + if vpcList, err := networkClient.ListAll(context.Background()); err != nil { + return nil, err + } else if err := jsonutils.Update(&vpcs, vpcList.Values()); err != nil { + return nil, err + } + return vpcs, nil +} + +func (self *SRegion) fetchIVpc() error { + if vpcs, err := self.getVpcs(); err != nil { + return err + } else { + self.ivpcs = make([]cloudprovider.ICloudVpc, 0) + for i := 0; i < len(vpcs); i++ { + if vpcs[i].Location == self.Name { + vpcs[i].region = self + self.ivpcs = append(self.ivpcs, &vpcs[i]) + log.Infof("find region %s vpcs: %s", self.Name, jsonutils.Marshal(&vpcs[i]).PrettyString()) + } + } + } + return nil +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if self.ivpcs == nil { + if err := self.fetchInfrastructure(); err != nil { + return nil, err + } + } + return self.ivpcs, nil +} + +func (self *SRegion) fetchInfrastructure() error { + if err := self.fetchZones(); err != nil { + return err + } + if err := self.fetchIVpc(); err != nil { + return err + } + for i := 0; i < len(self.ivpcs); i++ { + for j := 0; j < len(self.izones); j++ { + zone := self.izones[j].(*SZone) + vpc := self.ivpcs[i].(*SVpc) + wire := SWire{zone: zone, vpc: vpc} + zone.addWire(&wire) + vpc.addWire(&wire) + } + } + return nil +} diff --git a/pkg/util/azure/storage.go b/pkg/util/azure/storage.go new file mode 100644 index 0000000000..c88b2afa24 --- /dev/null +++ b/pkg/util/azure/storage.go @@ -0,0 +1,119 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SStorage struct { + zone *SZone + StorageId string + storageType string + Name string + Status string + Tier string +} + +func (self *SStorage) GetId() string { + return self.StorageId +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.providerName, self.Name) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId, self.Name) +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetCapacityMB() int { + return 0 // unlimited +} + +func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) { + // diskId, err := self.zone.region.createDisk(self.zone.ZoneId, self.storageType, name, sizeGb, desc) + // if err != nil { + // log.Errorf("createDisk fail %s", err) + // return nil, err + // } + // disk, err := self.zone.region.getDisk(diskId) + // if err != nil { + // log.Errorf("getDisk fail %s", err) + // return nil, err + // } + // disk.storage = self + // return disk, nil + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) { + // if disk, err := self.zone.region.getDisk(idStr); err != nil { + // return nil, err + // } else { + // disk.storage = self + // return disk, nil + // } + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + if disks, err := self.zone.region.GetDisks(); err != nil { + return nil, err + } else { + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := 0; i < len(disks); i += 1 { + disks[i].storage = self + idisks[i] = &disks[i] + } + return idisks, nil + } +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) GetManagerId() string { + return self.zone.region.client.providerId +} + +func (self *SStorage) GetMediumType() string { + if self.Tier == "Premium" { + return models.DISK_TYPE_SSD + } + return models.DISK_TYPE_ROTATE +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetStatus() string { + return models.STORAGE_ONLINE +} + +func (self *SStorage) GetStorageType() string { + //return models.STORAGE_PUBLIC_CLOUD + return self.storageType +} + +func (self *SStorage) Refresh() error { + // do nothing + return nil +} diff --git a/pkg/util/azure/storagecache.go b/pkg/util/azure/storagecache.go new file mode 100644 index 0000000000..0f6528747d --- /dev/null +++ b/pkg/util/azure/storagecache.go @@ -0,0 +1,57 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" +) + +type SStoragecache struct { + region *SRegion + + iimages []cloudprovider.ICloudImage +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.providerName, self.region.GetId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) Refresh() error { + return nil +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetGlobalId()) +} + +func (self *SStoragecache) IsEmulated() bool { + return false +} + +func (self *SStoragecache) GetManagerId() string { + return self.region.client.providerId +} + +func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) { + // if self.iimages == nil { + // err := self.fetchImages() + // if err != nil { + // return nil, err + // } + // } + return self.iimages, nil +} + +func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, extId string, isForce bool) (string, error) { + + return "", nil +} diff --git a/pkg/util/azure/vpc.go b/pkg/util/azure/vpc.go new file mode 100644 index 0000000000..e02141f598 --- /dev/null +++ b/pkg/util/azure/vpc.go @@ -0,0 +1,158 @@ +package azure + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type AddressSpace struct { + AddressPrefixes []string +} + +type SubnetPropertiesFormat struct { + AddressPrefix string +} + +type Subnet struct { + Properties SubnetPropertiesFormat + Name string + ID string +} + +type VirtualNetworkPropertiesFormat struct { + AddressSpace AddressSpace + Subnets []Subnet +} + +type SVpc struct { + region *SRegion + + iwires []cloudprovider.ICloudWire + + // subnets []SSubnet + secgroups []cloudprovider.ICloudSecurityGroup + + // CidrBlock string + // Description string + IsDefault bool + // RegionId string + Status string + // VpcId string + // VpcName string + + ID string + Name string + Type string + Location string + Tags map[string]string + Properties VirtualNetworkPropertiesFormat +} + +func (self *SVpc) GetId() string { + return self.ID +} + +func (self *SVpc) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SVpc) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", self.region.GetGlobalId(), self.region.SubscriptionID, self.Name) +} + +func (self *SVpc) IsEmulated() bool { + return false +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetCidrBlock() string { + return self.Properties.AddressSpace.AddressPrefixes[0] +} + +func (self *SVpc) Delete() error { + return nil + //return self.region.DeleteVpc(self.VpcId) +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + // if self.secgroups == nil { + // err := self.fetchSecurityGroups() + // if err != nil { + // return nil, err + // } + // } + return self.secgroups, nil +} + +func (self *SVpc) fetchWires() error { + self.iwires = make([]cloudprovider.ICloudWire, 0) + networks := make([]cloudprovider.ICloudNetwork, len(self.Properties.Subnets)) + wire := SWire{zone: self.region.izones[0].(*SZone), vpc: self, inetworks: networks} + for i, _network := range self.Properties.Subnets { + network := SNetwork{wire: &wire} + if err := jsonutils.Update(&network, _network); err != nil { + return err + } + networks[i] = &network + } + self.iwires = append(self.iwires, &wire) + return nil +} + +func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + if self.iwires == nil { + if err := self.fetchWires(); err != nil { + return nil, err + } + } + for i := 0; i < len(self.iwires); i++ { + if self.iwires[i].GetGlobalId() == wireId { + return self.iwires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + if err := self.fetchWires(); err != nil { + return nil, err + } + } + return self.iwires, nil +} + +func (self *SVpc) GetManagerId() string { + return self.region.client.providerId +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + if strings.ToLower(self.Status) == "succeeded" { + return "avaliable" + } + return "disabled" +} + +func (self *SVpc) Refresh() error { + return nil +} + +func (self *SVpc) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} diff --git a/pkg/util/azure/wire.go b/pkg/util/azure/wire.go new file mode 100644 index 0000000000..7da3714ea3 --- /dev/null +++ b/pkg/util/azure/wire.go @@ -0,0 +1,111 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SWire struct { + zone *SZone + vpc *SVpc + name string + id string + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.providerId, self.zone.region.GetId()) +} +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId) +} + +func (self *SWire) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.providerName, self.zone.region.Name) +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetStatus() string { + return "available" +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) { + // vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, name, cidr, desc) + // if err != nil { + // log.Errorf("createVSwitch error %s", err) + // return nil, err + // } + // self.inetworks = nil + // vswitch := self.getNetworkById(vswitchId) + // if vswitch == nil { + // log.Errorf("cannot find vswitch after create????") + // return nil, cloudprovider.ErrNotFound + // } + // return vswitch, nil + return nil, nil +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, err + } + for i := 0; i < len(networks); i += 1 { + if networks[i].GetGlobalId() == netid { + return networks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if self.inetworks == nil { + self.inetworks = make([]cloudprovider.ICloudNetwork, len(self.vpc.Properties.Subnets)) + for i, _netwrok := range self.vpc.Properties.Subnets { + network := SNetwork{wire: self} + if err := jsonutils.Update(&network, _netwrok); err != nil { + return nil, err + } + self.inetworks[i] = &network + } + } + return self.inetworks, nil +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SWire) getNetworkById(networkId string) *SNetwork { + if networks, err := self.GetINetworks(); err != nil { + log.Errorf("getNetworkById error: %v", err) + return nil + } else { + log.Debugf("search for networks %d", len(networks)) + for i := 0; i < len(networks); i++ { + network := networks[i].(*SNetwork) + if network.ID == networkId { + return network + } + } + } + return nil +} diff --git a/pkg/util/azure/zone.go b/pkg/util/azure/zone.go new file mode 100644 index 0000000000..4d92e924b4 --- /dev/null +++ b/pkg/util/azure/zone.go @@ -0,0 +1,122 @@ +package azure + +import ( + "fmt" + + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SZone struct { + region *SRegion + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + + host *SHost + Name string +} + +func (self *SZone) GetId() string { + return self.region.client.providerId +} + +func (self *SZone) GetName() string { + return self.region.GetName() +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.region.client.subscriptionId) +} + +func (self *SZone) IsEmulated() bool { + return true +} + +func (self *SZone) GetStatus() string { + return "enable" +} + +func (self *SZone) Refresh() error { + // do nothing + return nil +} + +func (self *SZone) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self} + } + return self.host +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) fetchStorages() error { + if storages, err := self.region.getStorage(); err != nil { + return err + } else { + self.istorages = make([]cloudprovider.ICloudStorage, len(storages)) + for i := 0; i < len(storages); i++ { + storages[i].zone = self + self.istorages[i] = &storages[i] + } + } + return nil +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if err := self.fetchStorages(); err != nil { + return nil, err + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + self.fetchStorages() + } + for i := 0; i < len(self.istorages); i += 1 { + if self.istorages[i].GetGlobalId() == id { + return self.istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) getStorageByTier(tier string) (*SStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(storages); i += 1 { + storage := storages[i].(*SStorage) + if storage.Tier == tier { + return storage, nil + } + } + return nil, fmt.Errorf("No such storage %s", tier) +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host := self.getHost() + if host.GetGlobalId() == id { + return host, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return []cloudprovider.ICloudHost{self.getHost()}, nil +} + +func (self *SZone) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} diff --git a/pkg/util/esxi/manager.go b/pkg/util/esxi/manager.go index 0c0698bfcd..ed1dd5d76d 100644 --- a/pkg/util/esxi/manager.go +++ b/pkg/util/esxi/manager.go @@ -5,10 +5,12 @@ import ( "fmt" "net/url" "reflect" + "strings" "github.com/vmware/govmomi" "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/session" "github.com/vmware/govmomi/view" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" @@ -16,10 +18,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "github.com/vmware/govmomi/session" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "strings" ) const ( diff --git a/pkg/util/esxi/mobase.go b/pkg/util/esxi/mobase.go index 23f6aa9c61..c60498ebc5 100644 --- a/pkg/util/esxi/mobase.go +++ b/pkg/util/esxi/mobase.go @@ -1,10 +1,13 @@ package esxi import ( - "github.com/vmware/govmomi/vim25/mo" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudprovider" "reflect" + + "github.com/vmware/govmomi/vim25/mo" + + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudprovider" ) type SManagedObject struct { diff --git a/pkg/util/seclib2/seclib.go b/pkg/util/seclib2/seclib.go index 86cee26422..d3fd831df3 100644 --- a/pkg/util/seclib2/seclib.go +++ b/pkg/util/seclib2/seclib.go @@ -1,10 +1,10 @@ package seclib2 import ( - "fmt" - "strings" "bytes" + "fmt" "math/rand" + "strings" ) const ( @@ -39,7 +39,7 @@ func RandomPassword2(width int) string { } buf.WriteByte(ch) } - if digitsCnt > 1 && letterCnt > 1 && upperCnt > 1 && puncCnt >=1 && puncCnt <= 2 { + if digitsCnt > 1 && letterCnt > 1 && upperCnt > 1 && puncCnt >= 1 && puncCnt <= 2 { return buf.String() } } diff --git a/vendor/yunion.io/x/structarg/errors.go b/vendor/yunion.io/x/structarg/errors.go new file mode 100644 index 0000000000..3aeeac0b81 --- /dev/null +++ b/vendor/yunion.io/x/structarg/errors.go @@ -0,0 +1,13 @@ +package structarg + +import ( + "fmt" +) + +type NotEnoughArgumentsError struct { + argument Argument +} + +func (e *NotEnoughArgumentsError) Error() string { + return fmt.Sprintf("Not enough arguments, missing %s", e.argument) +} diff --git a/vendor/yunion.io/x/structarg/structarg.go b/vendor/yunion.io/x/structarg/structarg.go index 7e4c9193d5..9eb223f272 100644 --- a/vendor/yunion.io/x/structarg/structarg.go +++ b/vendor/yunion.io/x/structarg/structarg.go @@ -854,7 +854,7 @@ func (this *ArgumentParser) ParseArgs(args []string, ignore_unknown bool) error } } if err == nil && pos_idx < len(this.posArgs) { - err = fmt.Errorf("Not enough arguments, missing %s", this.posArgs[pos_idx]) + err = &NotEnoughArgumentsError{argument: this.posArgs[pos_idx]} } if err == nil { err = this.Validate()