diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 36717c6852..5bb6012956 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1749,6 +1749,8 @@ func fillDiskConfigByImage(ctx context.Context, userCred mcclient.TokenCredentia } if strings.Contains(image.Properties["os_arch"], "aarch") { diskConfig.OsArch = api.OS_ARCH_AARCH64 + } else { + diskConfig.OsArch = image.Properties["os_arch"] } } return nil diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index dbf46ffd7f..beedfb5322 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1476,6 +1476,16 @@ func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.To if err != nil { return nil, err } + + // compare os arch + if len(self.InstanceType) > 0 { + provider := GetDriver(self.Hypervisor).GetProvider() + sku, _ := ServerSkuManager.FetchSkuByNameAndProvider(self.InstanceType, provider, true) + if sku != nil && len(sku.CpuArch) > 0 && len(img.Properties["os_arch"]) > 0 && !strings.Contains(img.Properties["os_arch"], sku.CpuArch) { + return nil, httperrors.NewConflictError("root disk image(%s) and sku(%s) architecture mismatch", img.Properties["os_arch"], sku.CpuArch) + } + } + diskCat := self.CategorizeDisks() if img.MinDiskMB == 0 || img.Status != imageapi.IMAGE_STATUS_ACTIVE { return nil, httperrors.NewInputParameterError("invlid image") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 8e7358ff6c..aa55f59564 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1323,7 +1323,7 @@ func (manager *SGuestManager) validateCreateData( input.Disks[0] = rootDiskConfig if sku != nil { if len(rootDiskConfig.OsArch) > 0 && len(sku.CpuArch) > 0 { - if strings.Contains(rootDiskConfig.OsArch, sku.CpuArch) { + if !strings.Contains(rootDiskConfig.OsArch, sku.CpuArch) { return nil, httperrors.NewConflictError("root disk image(%s) and sku(%s) architecture mismatch", rootDiskConfig.OsArch, sku.CpuArch) } } diff --git a/pkg/multicloud/aws/image.go b/pkg/multicloud/aws/image.go index 161a5c9bf4..710116137d 100644 --- a/pkg/multicloud/aws/image.go +++ b/pkg/multicloud/aws/image.go @@ -99,6 +99,8 @@ type SImage struct { // Usage string RootDevice RootDevice RootDeviceName string + // devices + BlockDevicesNames []string Public bool Hypervisor string @@ -512,12 +514,15 @@ func (self *SRegion) getImages(status ImageStatusType, owners []TImageOwnerType, } var rootDevice RootDevice + devicesName := []string{} for _, block := range image.BlockDeviceMappings { if len(*image.RootDeviceName) > 0 && *block.DeviceName == *image.RootDeviceName { rootDevice.SnapshotId = *block.Ebs.SnapshotId rootDevice.Category = *block.Ebs.VolumeType rootDevice.Size = int(*block.Ebs.VolumeSize) } + + devicesName = append(devicesName, *block.DeviceName) } osType := "" @@ -547,6 +552,7 @@ func (self *SRegion) getImages(status ImageStatusType, owners []TImageOwnerType, EnaSupport: *image.EnaSupport, Platform: *image.Platform, RootDeviceName: *image.RootDeviceName, + BlockDevicesNames: devicesName, Status: ImageStatusType(*image.State), CreationTime: createTime, SizeGB: size, diff --git a/pkg/multicloud/aws/instance.go b/pkg/multicloud/aws/instance.go index 33d5476922..6c50dc7923 100644 --- a/pkg/multicloud/aws/instance.go +++ b/pkg/multicloud/aws/instance.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -65,6 +66,7 @@ type SInstance struct { multicloud.SInstanceBase host *SHost + img *SImage RegionId string ZoneId string InstanceId string @@ -582,7 +584,33 @@ func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) { return nil, cloudprovider.ErrNotSupported } +func (self *SInstance) GetImage() (*SImage, error) { + if self.img != nil { + return self.img, nil + } + + img, err := self.host.zone.region.GetImage(self.ImageId) + if err != nil { + return nil, errors.Wrap(err, "GetImage") + } + + self.img = img + return self.img, nil +} + func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + img, err := self.GetImage() + if err != nil { + return errors.Wrap(err, "GetImage") + } + + // mix in image block device names + for i := range img.BlockDevicesNames { + if !utils.IsInStringArray(img.BlockDevicesNames[i], self.DeviceNames) { + self.DeviceNames = append(self.DeviceNames, img.BlockDevicesNames[i]) + } + } + name, err := NextDeviceName(self.DeviceNames) if err != nil { return err @@ -803,6 +831,7 @@ func (self *SRegion) CreateInstance(name string, image *SImage, instanceType str for i := range disks { var ebs ec2.EbsBlockDevice var deviceName string + var err error disk := disks[i] if i == 0 { @@ -832,9 +861,11 @@ func (self *SRegion) CreateInstance(name string, image *SImage, instanceType str VolumeSize: &size, VolumeType: &disk.Category, } - // todo: generator device name - // todo: 这里还需要测试预置硬盘的实例。deviceName是否会冲突。 - deviceName = fmt.Sprintf("/dev/sd%s", string(98+i)) + + deviceName, err = NextDeviceName(image.BlockDevicesNames) + if err != nil { + return "", errors.Wrap(err, "NextDeviceName") + } } // io1类型的卷需要指定IOPS参数。这里根据aws网站的建议值进行设置