fix(region): support query public cloud vm modification types (#24653)

This commit is contained in:
屈轩
2026-04-10 16:53:45 +08:00
committed by GitHub
parent 31e935ad89
commit 448bae5037
13 changed files with 174 additions and 4 deletions
+1
View File
@@ -138,6 +138,7 @@ func init() {
cmd.Perform("kickstart-complete", &options.ServerKickstartCompleteOptions{})
cmd.Get("kickstart", new(options.ServerIdOptions))
cmd.Get("vnc", new(options.ServerVncOptions))
cmd.Get("modification-types", new(options.ServerIdOptions))
cmd.Get("desc", new(options.ServerIdOptions))
cmd.Get("status", new(options.ServerIdOptions))
cmd.Get("iso", new(options.ServerIdOptions))
+1 -1
View File
@@ -108,7 +108,7 @@ require (
k8s.io/cri-api v0.28.15
k8s.io/klog/v2 v2.90.1
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409072734-6e765c0846d6
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409123844-2f5e06efeade
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005
yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
+2 -2
View File
@@ -1785,8 +1785,8 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409072734-6e765c0846d6 h1:1+DtEfMWn4AYP/GJMN3aatH2gyOzry0nb//ASMVS7WQ=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409072734-6e765c0846d6/go.mod h1:TbMuTWxcTdyL2Usn+WQdIw0jdlBYO66SzPRY8LZ3Wj0=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409123844-2f5e06efeade h1:8DBeLhYpDrOW7oP5s/mGlc458zAN0mZq8ZMbH5b+JTA=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409123844-2f5e06efeade/go.mod h1:TbMuTWxcTdyL2Usn+WQdIw0jdlBYO66SzPRY8LZ3Wj0=
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005 h1:3sWwcjGXGjG9mLBWa7AyLq+QSi0udTAx21pfVQRFMBE=
yunion.io/x/executor v0.0.0-20260312022053-f538abd2b005/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
+8
View File
@@ -1572,3 +1572,11 @@ type ServerPerformStatusInput struct {
apis.PerformStatusInput
Containers map[string]*ContainerPerformStatusInput `json:"containers"`
}
type ServerModificationType struct {
Name string `json:"name"`
}
type ServerModificationTypesOutput struct {
ModificationTypes []ServerModificationType `json:"modification_types"`
}
+23
View File
@@ -98,6 +98,29 @@ func (self *SGuest) GetDetailsVnc(ctx context.Context, userCred mcclient.TokenCr
return ret, nil
}
// 获取公有云可变更配置
// 目前支持: 阿里云,腾讯云,华为云
func (guest *SGuest) GetDetailsModificationTypes(ctx context.Context, userCred mcclient.TokenCredential, input jsonutils.JSONObject) (*api.ServerModificationTypesOutput, error) {
if len(guest.ExternalId) == 0 {
return nil, httperrors.NewNotFoundError("guest external id is empty")
}
vm, err := guest.GetIVM(ctx)
if err != nil {
return nil, errors.Wrapf(err, "GetIVM")
}
ret := &api.ServerModificationTypesOutput{}
ret.ModificationTypes = make([]api.ServerModificationType, 0)
modificationTypes, err := vm.GetModificationTypes()
if err != nil {
return nil, errors.Wrapf(err, "GetModificationTypes")
}
for _, modificationType := range modificationTypes {
ret.ModificationTypes = append(ret.ModificationTypes, api.ServerModificationType{Name: modificationType.InstanceType})
}
return ret, nil
}
func (self *SGuest) PreCheckPerformAction(
ctx context.Context, userCred mcclient.TokenCredential,
action string, query jsonutils.JSONObject, data jsonutils.JSONObject,
+1 -1
View File
@@ -2603,7 +2603,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.3.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409072734-6e765c0846d6
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20260409123844-2f5e06efeade
## explicit; go 1.24
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
+4
View File
@@ -388,3 +388,7 @@ type SInstanceDeployOptions struct {
DeleteKeypair bool
UserData string
}
type SInstanceModificationType struct {
InstanceType string
}
+2
View File
@@ -389,6 +389,8 @@ type ICloudVM interface {
DeployVM(ctx context.Context, opts *SInstanceDeployOptions) error
ChangeConfig(ctx context.Context, config *SManagedVMChangeConfig) error
// 获取实例可变更类型
GetModificationTypes() ([]SInstanceModificationType, error)
GetVNCInfo(input *ServerVncInput) (*ServerVncOutput, error)
// 若有跟随主机删除的选项,需要设置为True
+55
View File
@@ -522,6 +522,61 @@ func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.S
return fmt.Errorf("Failed to change vm config, specification not supported")
}
func (self *SInstance) GetModificationTypes() ([]cloudprovider.SInstanceModificationType, error) {
return self.host.zone.region.GetInstanceModificationTypes(self.InstanceId)
}
func (self *SRegion) GetInstanceModificationTypes(instanceId string) ([]cloudprovider.SInstanceModificationType, error) {
params := map[string]string{
"RegionId": self.RegionId,
"ResourceId": instanceId,
"DestinationResource": "InstanceType",
}
body, err := self.ecsRequest("DescribeResourcesModification", params)
if err != nil {
return nil, errors.Wrapf(err, "DescribeResourcesModification")
}
parsed := struct {
AvailableZones struct {
AvailableZone []struct {
AvailableResources struct {
AvailableResource []struct {
SupportedResources struct {
SupportedResource []struct {
Value string
Status string
StatusCategory string
}
}
}
}
}
}
}{}
if err := body.Unmarshal(&parsed); err != nil {
return nil, errors.Wrapf(err, "body.Unmarshal")
}
ret := make([]cloudprovider.SInstanceModificationType, 0)
seen := map[string]struct{}{}
for _, zone := range parsed.AvailableZones.AvailableZone {
for _, resource := range zone.AvailableResources.AvailableResource {
for _, supportedResource := range resource.SupportedResources.SupportedResource {
if len(supportedResource.Value) == 0 || len(supportedResource.Status) == 0 || strings.ToLower(supportedResource.Status) != "available" {
continue
}
if _, ok := seen[supportedResource.Value]; ok {
continue
}
seen[supportedResource.Value] = struct{}{}
ret = append(ret, cloudprovider.SInstanceModificationType{InstanceType: supportedResource.Value})
}
}
}
return ret, nil
}
func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
return self.host.zone.region.AttachDisk(self.InstanceId, diskId)
}
+25
View File
@@ -682,6 +682,31 @@ func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.S
return fmt.Errorf("Failed to change vm config, specification not supported")
}
func (self *SInstance) GetModificationTypes() ([]cloudprovider.SInstanceModificationType, error) {
return self.host.zone.region.GetInstanceModificationTypes(self.GetId())
}
// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListResizeFlavors
func (self *SRegion) GetInstanceModificationTypes(instanceId string) ([]cloudprovider.SInstanceModificationType, error) {
params := url.Values{}
params.Set("instance_uuid", instanceId)
resp, err := self.list(SERVICE_ECS, "cloudservers/resize_flavors", params)
if err != nil {
return nil, errors.Wrapf(err, "ListResizeFlavors(%s)", instanceId)
}
flavors := []SInstanceType{}
err = resp.Unmarshal(&flavors, "flavors")
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal(flavors)")
}
ret := make([]cloudprovider.SInstanceModificationType, 0, len(flavors))
for _, flavor := range flavors {
ret = append(ret, cloudprovider.SInstanceModificationType{InstanceType: flavor.ID})
}
return ret, nil
}
func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
return self.host.zone.region.GetInstanceVNCUrl(self.GetId())
}
+4
View File
@@ -106,3 +106,7 @@ func (instance *SInstanceBase) GetIsolateDeviceIds() ([]string, error) {
func (instance *SInstanceBase) GetContainers() ([]cloudprovider.ICloudContainer, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetContainers")
}
func (instance *SInstanceBase) GetModificationTypes() ([]cloudprovider.SInstanceModificationType, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetModificationTypes")
}
+44
View File
@@ -496,6 +496,50 @@ func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SMa
return self.host.zone.region.ChangeVMConfig(self.InstanceId, opts.InstanceType)
}
func (self *SInstance) GetModificationTypes() ([]cloudprovider.SInstanceModificationType, error) {
return self.host.zone.region.GetInstanceModificationTypes(self.InstanceId)
}
func (self *SRegion) GetInstanceModificationTypes(instanceId string) ([]cloudprovider.SInstanceModificationType, error) {
params := map[string]string{
"Region": self.Region,
"InstanceIds.0": instanceId,
}
body, err := self.cvmRequest("DescribeInstancesModification", params, true)
if err != nil {
return nil, errors.Wrapf(err, "DescribeInstancesModification")
}
resp := struct {
InstanceTypeConfigStatusSet []struct {
InstanceTypeConfig struct {
InstanceType string
Zone string
}
Status string
}
}{}
if err := body.Unmarshal(&resp); err != nil {
return nil, errors.Wrapf(err, "body.Unmarshal")
}
ret := make([]cloudprovider.SInstanceModificationType, 0)
seen := map[string]struct{}{}
for _, cfg := range resp.InstanceTypeConfigStatusSet {
if !strings.EqualFold(cfg.Status, "SELL") {
continue
}
if _, ok := seen[cfg.InstanceTypeConfig.InstanceType]; ok {
continue
}
seen[cfg.InstanceTypeConfig.InstanceType] = struct{}{}
ret = append(ret, cloudprovider.SInstanceModificationType{InstanceType: cfg.InstanceTypeConfig.InstanceType})
}
return ret, nil
}
func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
return self.host.zone.region.AttachDisk(self.InstanceId, diskId)
}
+4
View File
@@ -296,3 +296,7 @@ func (self *SInstance) GetIsolateDeviceIds() ([]string, error) {
func (self *SInstance) GetContainers() ([]cloudprovider.ICloudContainer, error) {
return nil, cloudprovider.ErrNotSupported
}
func (self *SInstance) GetModificationTypes() ([]cloudprovider.SInstanceModificationType, error) {
return nil, cloudprovider.ErrNotSupported
}