diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index f44cb82cbf..9f137cad98 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -20,10 +20,9 @@ import ( "math" "time" - "github.com/pkg/errors" - "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -352,6 +351,20 @@ func (self *SManagedVirtualizedGuestDriver) RequestDeployGuestOnHost(ctx context switch action { case "create": + region := host.GetRegion() + if len(desc.InstanceType) == 0 && region != nil { + sku, err := models.ServerSkuManager.GetMatchedSku(region.GetId(), int64(desc.Cpu), int64(desc.MemoryMB)) + if err != nil { + return errors.Wrap(err, "ManagedVirtualizedGuestDriver.RequestDeployGuestOnHost.GetMatchedSku") + } + + if sku == nil { + return errors.Wrap(errors.ErrNotFound, "ManagedVirtualizedGuestDriver.RequestDeployGuestOnHost.GetMatchedSku") + } + + desc.InstanceType = sku.Name + } + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { return guest.GetDriver().RemoteDeployGuestForCreate(ctx, task.GetUserCred(), guest, host, desc) }) @@ -704,7 +717,8 @@ func (self *SManagedVirtualizedGuestDriver) DoGuestCreateDisksTask(ctx context.C } func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error { - ihost, err := guest.GetHost().GetIHost() + host := guest.GetHost() + ihost, err := host.GetIHost() if err != nil { return err } @@ -714,6 +728,19 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co return err } + if len(instanceType) == 0 { + sku, err := models.ServerSkuManager.GetMatchedSku(host.GetRegion().GetId(), vcpuCount, vmemSize) + if err != nil { + return errors.Wrap(err, "ManagedVirtualizedGuestDriver.RequestChangeVmConfig.GetMatchedSku") + } + + if sku == nil { + return errors.Wrap(errors.ErrNotFound, "ManagedVirtualizedGuestDriver.RequestChangeVmConfig.GetMatchedSku") + } + + instanceType = sku.Name + } + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { config := &cloudprovider.SManagedVMChangeConfig{ Cpu: int(vcpuCount), @@ -722,7 +749,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co } err := iVM.ChangeConfig(ctx, config) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GuestDriver.RequestChangeVmConfig.ChangeConfig") } err = cloudprovider.WaitCreated(time.Second*5, time.Minute*5, func() bool { @@ -745,7 +772,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co return false }) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GuestDriver.RequestChangeVmConfig.WaitCreated") } instanceType = iVM.GetInstanceType() @@ -755,7 +782,7 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co return nil }) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GuestDriver.RequestChangeVmConfig.Update") } } diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index bf364f323c..fd528f46aa 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -806,6 +806,19 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem return q, err } +func (manager *SServerSkuManager) GetMatchedSku(regionId string, cpu int64, memMB int64) (*SServerSku, error) { + ret := &SServerSku{} + + q := manager.Query() + q = q.Equals("cpu_core_count", cpu).Equals("memory_size_mb", memMB).Equals("cloudregion_id", regionId).Equals("postpaid_status", api.SkuStatusAvailable) + err := q.First(ret) + if err != nil { + return nil, errors.Wrap(err, "ServerSkuManager.GetMatchedSku") + } + + return ret, nil +} + func (manager *SServerSkuManager) FetchSkuByNameAndProvider(name string, provider string, checkConsistency bool) (*SServerSku, error) { q := manager.Query() q = q.Equals("name", name) diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index b30c60abd3..fc3873e402 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -86,9 +86,6 @@ type ComputeOptions struct { SyncSkusDay int `default:"1" help:"Days auto sync skus data, default 1 day"` SyncSkusHour int `default:"3" help:"What hour start sync skus, default 03:00"` - // aws instance type file - DefaultAwsInstanceTypeFile string `default:"/etc/yunion/aws_instance_types.json" help:"aws instance type json file"` - ConvertHypervisorDefaultTemplate string `help:"Kvm baremetal convert option"` ConvertEsxiDefaultTemplate string `help:"ESXI baremetal convert option"` ConvertKubeletDockerVolumeSize string `default:"256g" help:"Docker volume size"` diff --git a/pkg/multicloud/aws/host.go b/pkg/multicloud/aws/host.go index 208f5d1d48..925d17489b 100644 --- a/pkg/multicloud/aws/host.go +++ b/pkg/multicloud/aws/host.go @@ -173,7 +173,7 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { } func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData) + vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData) if err != nil { return nil, err } @@ -186,7 +186,7 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr return vm, err } -func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, cpu, memMB int, instanceType string, +func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, instanceType string, networkId, ipAddr, desc, passwd string, dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string) (string, error) { // 网络配置及安全组绑定 @@ -268,28 +268,7 @@ func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo } } - // 匹配实例类型 - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, 0, self.zone.ZoneId) - if err != nil { - return "", err - } - if len(instanceTypes) == 0 { - return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.InstanceTypeId - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, self.zone.ZoneId, desc, disks, ipAddr, keypair, userData) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("Failed to create, %s", err.Error()) + return "", fmt.Errorf("Failed to create, instance type should not be empty") } func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { diff --git a/pkg/multicloud/aws/instance.go b/pkg/multicloud/aws/instance.go index 4cf2ec4651..dbc8419ea2 100644 --- a/pkg/multicloud/aws/instance.go +++ b/pkg/multicloud/aws/instance.go @@ -467,7 +467,7 @@ func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.S if len(config.InstanceType) > 0 { return self.ChangeConfig2(ctx, config.InstanceType) } - return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, config.Cpu, config.MemoryMB, nil) + return errors.Wrap(errors.ErrClient, "Instance.ChangeConfig.InstanceTypeIsEmpty") } func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { @@ -1002,29 +1002,6 @@ func (self *SRegion) ReplaceSystemDisk(ctx context.Context, instanceId string, i return tempInstance.Disks[0], nil } -func (self *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error { - params := &ec2.ModifyInstanceAttributeInput{} - params.SetInstanceId(instanceId) - instanceTypes, err := self.GetMatchInstanceTypes(ncpu, vmem, 0, zoneId) - if err != nil { - return err - } - - for _, instancetype := range instanceTypes { - t := &ec2.AttributeValue{Value: &instancetype.InstanceTypeId} - params.SetInstanceType(t) - - _, err := self.ec2Client.ModifyInstanceAttribute(params) - if err != nil { - log.Errorf("Failed for %s: %s", instancetype.InstanceTypeId, err) - } else { - return nil - } - } - - return fmt.Errorf("Failed to change vm config, specification not supported") -} - func (self *SRegion) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error { params := &ec2.ModifyInstanceAttributeInput{} params.SetInstanceId(instanceId) diff --git a/pkg/multicloud/aws/instancetype.go b/pkg/multicloud/aws/instancetype.go deleted file mode 100644 index 3a80d35574..0000000000 --- a/pkg/multicloud/aws/instancetype.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019 Yunion -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package aws - -import ( - "encoding/json" - "fmt" - "io/ioutil" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/compute/options" -) - -type Cpu struct { - Cores int `json:"cores"` - Units string `json:"units"` -} - -type CpuCredits struct { - OptimizationSupported bool `json:"optimizationSupported"` -} - -type ProcessorFeatures struct { - AESNI bool `json:"AES-NI"` - AVX bool `json:"AVX"` - Turbo bool `json:"Turbo"` -} - -type SInstanceType struct { - Architectures []string `json:"architectures"` - Cpu Cpu `json:"cpu"` - CpuCredits CpuCredits `json:"cpuCredits"` - Description string `json:"description"` - EbsEncryptionSupported bool `json:"ebsEncryptionSupported"` - EbsOnly bool `json:"ebsOnly"` - Family string `json:"family"` - FreeTierEligible bool `json:"freeTierEligible"` - Ipv6Support bool `json:"ipv6Support"` - Memory float32 `json:"memory"` - NetworkPerformance string `json:"networkPerformance"` - PhysicalProcessor string `json:"physicalProcessor"` - ProcessorFeatures ProcessorFeatures `json:"processorFeatures"` - ProcessorSpeed float32 `json:"processorSpeed"` - SpotSupported bool `json:"spotSupported"` - InstanceTypeId string `json:"typeName"` - VirtualizationTypes []string `json:"virtualizationTypes"` - Vpc bool `json:"vpc"` - VpcOnly bool `json:"vpcOnly"` - Windows bool `json:"windows"` -} - -func (self *SInstanceType) memoryMB() int { - return int(self.Memory * 1024) -} - -func (self *SRegion) GetInstanceTypes() ([]SInstanceType, error) { - if self.instanceTypes == nil { - var GlobalInstanceTyes []SInstanceType - instanceTypes, err := ioutil.ReadFile(options.Options.DefaultAwsInstanceTypeFile) - if err != nil { - return nil, err - } - - err = json.Unmarshal([]byte(instanceTypes), &GlobalInstanceTyes) - if err != nil { - log.Errorf("GetInstanceTypes %s", err) - return nil, err - } - return GlobalInstanceTyes, err - } else { - return self.instanceTypes, nil - } -} - -func (self *SRegion) GetInstanceType(instanceTypeId string) (*SInstanceType, error) { - ret, err := self.GetInstanceTypes() - if err != nil { - return nil, err - } - - for _, item := range ret { - if item.InstanceTypeId == instanceTypeId { - return &item, nil - } - } - - return nil, fmt.Errorf("instancetype %s not found", instanceTypeId) -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { - types, err := self.GetInstanceTypes() - if err != nil { - return nil, err - } - - // 实例类型顺序: 微型实例 -> 通用型 -> 计算优化型 ... - // todo:部分实例类型 需要启用ena才能正常启动。需要过滤掉。 - // https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/enhanced-networking-ena.html - ret := []SInstanceType{} - for _, t := range types { - // cpu & mem & disk & ena 都匹配才行 - if t.Cpu.Cores == cpu && t.memoryMB() == memMB { - ret = append(ret, t) - } - } - - return ret, nil -} diff --git a/pkg/multicloud/aws/region.go b/pkg/multicloud/aws/region.go index ff96859833..c00537cd22 100644 --- a/pkg/multicloud/aws/region.go +++ b/pkg/multicloud/aws/region.go @@ -89,8 +89,7 @@ type SRegion struct { izones []cloudprovider.ICloudZone ivpcs []cloudprovider.ICloudVpc - storageCache *SStoragecache - instanceTypes []SInstanceType + storageCache *SStoragecache RegionEndpoint string RegionId string // 这里为保持一致沿用阿里云RegionId的叫法, 与AWS RegionName字段对应 diff --git a/pkg/multicloud/aws/shell/instancetype.go b/pkg/multicloud/aws/shell/instancetype.go deleted file mode 100644 index 4bf4bba935..0000000000 --- a/pkg/multicloud/aws/shell/instancetype.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceTypeListOptions struct { - } - shellutils.R(&InstanceTypeListOptions{}, "instance-type-list", "List intance types", func(cli *aws.SRegion, args *InstanceTypeListOptions) error { - instanceTypes, e := cli.GetInstanceTypes() - if e != nil { - return e - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) - - type InstanceMatchOptions struct { - CPU int `help:"CPU count"` - MEM int `help:"Memory in MB"` - GPU int `help:"GPU size"` - Zone string `help:"Test in zone"` - } - shellutils.R(&InstanceMatchOptions{}, "instance-type-select", "Select matching instance types", func(cli *aws.SRegion, args *InstanceMatchOptions) error { - instanceTypes, e := cli.GetMatchInstanceTypes(args.CPU, args.MEM, args.GPU, args.Zone) - if e != nil { - return e - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/instance.go b/pkg/multicloud/huawei/instance.go index 476550a047..913a193860 100644 --- a/pkg/multicloud/huawei/instance.go +++ b/pkg/multicloud/huawei/instance.go @@ -22,10 +22,9 @@ import ( "strings" "time" - "github.com/pkg/errors" - "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/utils" @@ -590,10 +589,15 @@ func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.S func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { err := self.host.zone.region.ChangeVMConfig2(self.OSEXTAZAvailabilityZone, self.GetId(), instanceType, nil) if err != nil { - return err + return errors.Wrap(err, "Instance.ChangeConfig2.ChangeVMConfig2") } - return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) + err = cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.ChangeConfig2.WaitStatusWithDelay") + } + + return nil } // todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节