From 7d94c4e46f2e5fa06cc0d83a81ead3d2440f15b2 Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Mon, 24 Aug 2020 17:22:40 +0800 Subject: [PATCH] support create arm virtual machine --- pkg/apis/compute/api.go | 6 ++++++ pkg/apis/compute/guest_const.go | 5 +++++ pkg/apis/compute/host_const.go | 4 ++++ pkg/apis/compute/snapshot.go | 2 ++ pkg/apis/scheduler/api.go | 1 + pkg/compute/guestdrivers/kvm.go | 3 ++- pkg/compute/models/disks.go | 8 ++++++++ pkg/compute/models/guest_actions.go | 19 ++++++++++++++++++- pkg/compute/models/guests.go | 8 ++++++++ pkg/compute/models/hosts.go | 4 ++++ pkg/compute/models/instance_snapshots.go | 3 +++ pkg/compute/models/snapshots.go | 2 ++ pkg/hostman/guestfs/fsdriver/drivers.go | 17 ++++++++++++++++- pkg/hostman/guestfs/fsdriver/linux.go | 14 +++++++++++--- pkg/hostman/guestfs/fsdriver/windows.go | 2 +- .../hostdeployer/deployserver/deployserver.go | 4 +++- pkg/image/models/image_guest.go | 2 ++ pkg/image/models/images.go | 2 ++ pkg/scheduler/algorithm/predicates/error.go | 1 + .../predicates/guest/cpu_predicate.go | 8 ++++++++ pkg/util/winutils/winutils.go | 14 +++++++++++--- 21 files changed, 118 insertions(+), 11 deletions(-) diff --git a/pkg/apis/compute/api.go b/pkg/apis/compute/api.go index 24a7a3242f..cdeb497a16 100644 --- a/pkg/apis/compute/api.go +++ b/pkg/apis/compute/api.go @@ -141,6 +141,10 @@ type DiskConfig struct { // requried: false Mountpoint string `json:"mountpoint"` + // 操作系统CPU架构 + // required: false + OsArch string `json:"os_arch"` + //后端存储类型,若指定了存储ID,此参数会根据存储设置,若不指定,则作为调度的一个参考 // // @@ -472,6 +476,8 @@ type ServerCreateInput struct { // swagger:ignore OsType string `json:"os_type"` // swagger:ignore + OsArch string `json:"os_arch"` + // swagger:ignore DisableUsbKbd bool `json:"disable_usb_kbd"` // swagger:ignore OsProfile jsonutils.JSONObject `json:"__os_profile__"` diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index 30d6ac920a..bdcb44955f 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -170,6 +170,11 @@ const ( CPU_MODE_HOST = "host" ) +const ( + CPU_ARCH_X86 = "x86" + CPU_ARCH_ARM = "arm" +) + var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL} var VM_CREATING_STATUS = []string{VM_CREATE_NETWORK, VM_CREATE_DISK, VM_START_DEPLOY, VM_DEPLOYING} diff --git a/pkg/apis/compute/host_const.go b/pkg/apis/compute/host_const.go index 5c74da65f7..5db120eb99 100644 --- a/pkg/apis/compute/host_const.go +++ b/pkg/apis/compute/host_const.go @@ -129,3 +129,7 @@ const ( HOST_HEALTH_STATUS_RUNNING = "running" HOST_HEALTH_LOCK_PREFIX = "host-health" ) + +const ( + CPU_ARCH_AARCH64 = "aarch64" +) diff --git a/pkg/apis/compute/snapshot.go b/pkg/apis/compute/snapshot.go index cf82cf89d4..4b94357ce9 100644 --- a/pkg/apis/compute/snapshot.go +++ b/pkg/apis/compute/snapshot.go @@ -41,6 +41,8 @@ type SnapshotCreateInput struct { OutOfChain bool `json:"out_of_chain"` // swagger:ignore ManagerId string `json:"manager_id"` + // swagger:ignore + OsArch string `json:"os_arch"` } type SSnapshotPolicyCreateInput struct { diff --git a/pkg/apis/scheduler/api.go b/pkg/apis/scheduler/api.go index 984a557e3f..3bef82fdfc 100644 --- a/pkg/apis/scheduler/api.go +++ b/pkg/apis/scheduler/api.go @@ -78,6 +78,7 @@ type ScheduleInput struct { CpuDesc string `json:"cpu_desc"` CpuMicrocode string `json:"cpu_microcode"` CpuMode string `json:"cpu_mode"` + OsArch string `json:"os_arch"` PendingUsages []jsonutils.JSONObject } diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 414a309757..47a9bc063e 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -361,7 +361,8 @@ func (self *SKVMGuestDriver) RequestAssociateEip(ctx context.Context, userCred m func (self *SKVMGuestDriver) NeedStopForChangeSpec(guest *models.SGuest, cpuChanged, memChanged bool) bool { return guest.GetMetadata("hotplug_cpu_mem", nil) != "enable" || - (memChanged && guest.GetMetadata("__hugepage", nil) == "native") + (memChanged && guest.GetMetadata("__hugepage", nil) == "native") || + guest.OsArch == api.CPU_ARCH_ARM } func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error { diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index a499c08958..60df5182b9 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -115,6 +115,9 @@ type SDisk struct { // example: sys DiskType string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"admin" json:"disk_type"` + // cpu架构 + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // # is persistent Nonpersistent bool `default:"false" list:"user" json:"nonpersistent"` } @@ -1688,6 +1691,7 @@ func fillDiskConfigBySnapshot(userCred mcclient.TokenCredential, diskConfig *api diskConfig.Backend = storage.StorageType diskConfig.Fs = "" diskConfig.Mountpoint = "" + diskConfig.OsArch = snapshot.OsArch } return nil } @@ -1716,6 +1720,9 @@ func fillDiskConfigByImage(ctx context.Context, userCred mcclient.TokenCredentia if diskConfig.SizeMb != api.DISK_SIZE_AUTOEXTEND && diskConfig.SizeMb < image.MinDiskMB { diskConfig.SizeMb = image.MinDiskMB // MB } + if strings.Contains(image.Properties["os_arch"], "aarch") { + diskConfig.OsArch = api.CPU_ARCH_ARM + } } return nil } @@ -1766,6 +1773,7 @@ func (self *SDisk) fetchDiskInfo(diskConfig *api.DiskConfig) { } self.DiskFormat = diskConfig.Format self.DiskSize = diskConfig.SizeMb + self.OsArch = diskConfig.OsArch } type DiskInfo struct { diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 5aa76f69fc..b05fdaa18b 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -195,6 +195,15 @@ func (self *SGuest) PerformSaveImage(ctx context.Context, userCred mcclient.Toke osType = "Linux" } properties.Add(jsonutils.NewString(osType), "os_type") + if self.OsArch == api.CPU_ARCH_ARM { + var osArch string + if osArch = self.GetMetadata("os_arch", nil); len(osArch) == 0 { + host := self.GetHost() + osArch = host.CpuArchitecture + } + properties.Add(jsonutils.NewString(osArch), "os_arch") + kwargs.Set("os_arch", jsonutils.NewString(self.OsArch)) + } kwargs.Add(properties, "properties") kwargs.Add(jsonutils.NewBool(restart), "restart") @@ -261,8 +270,16 @@ func (self *SGuest) PerformSaveGuestImage(ctx context.Context, userCred mcclient osType = "Linux" } properties.Add(jsonutils.NewString(osType), "os_type") + if self.OsArch == api.CPU_ARCH_ARM { + var osArch string + if osArch = self.GetMetadata("os_arch", nil); len(osArch) == 0 { + host := self.GetHost() + osArch = host.CpuArchitecture + } + properties.Add(jsonutils.NewString(osArch), "os_arch") + kwargs.Set("os_arch", jsonutils.NewString(self.OsArch)) + } kwargs.Add(properties, "properties") - kwargs.Add(images, "images") s := auth.GetSession(ctx, userCred, options.Options.Region, "") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 918b2179ef..2873973a72 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -146,6 +146,9 @@ type SGuest struct { // 虚拟化技术 // example: kvm Hypervisor string `width:"16" charset:"ascii" nullable:"false" default:"kvm" list:"user" create:"required"` + // 虚拟机CPU架构 + // example: x86 arm + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 套餐名称 InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"` @@ -1146,6 +1149,10 @@ func (manager *SGuestManager) validateCreateData( } } + if arch := imgProperties["os_arch"]; strings.Contains(arch, "aarch") { + input.OsArch = api.CPU_ARCH_ARM + } + if len(imgProperties) == 0 { imgProperties = map[string]string{"os_type": "Linux"} } @@ -4867,6 +4874,7 @@ func (self *SGuest) ToSchedDesc() *schedapi.ScheduleInput { config.Hypervisor = self.GetHypervisor() desc.ServerConfig = *config + desc.OsArch = self.OsArch return desc } diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 08fd0714d4..398ddcf9b6 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -527,6 +527,10 @@ func (manager *SHostManager) CustomizeFilterList(ctx context.Context, q *sqlchem return filters, nil } +func (self *SHost) IsArmHost() bool { + return self.CpuArchitecture == api.CPU_ARCH_AARCH64 +} + func (self *SHost) GetZone() *SZone { if len(self.ZoneId) == 0 { return nil diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index 013a9e5ef5..27f1e7b7a7 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -66,6 +66,8 @@ type SInstanceSnapshot struct { KeypairId string `width:"36" charset:"ascii" nullable:"true" list:"user"` // 操作系统类型 OsType string `width:"36" charset:"ascii" nullable:"true" list:"user"` + // CPU架构 + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 套餐名称 InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"` } @@ -283,6 +285,7 @@ func (manager *SInstanceSnapshotManager) CreateInstanceSnapshot( instanceSnapshot.SecGroups = jsonutils.Marshal(secIds) } instanceSnapshot.OsType = guest.OsType + instanceSnapshot.OsArch = guest.OsArch instanceSnapshot.ServerMetadata = serverMetadata instanceSnapshot.InstanceType = guest.InstanceType err := manager.TableSpec().Insert(ctx, instanceSnapshot) diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 27b9146671..8ea9f66a9c 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -72,6 +72,7 @@ type SSnapshot struct { DiskType string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 操作系统类型 OsType string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional"` + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // create disk from snapshot, snapshot as disk backing file RefCount int `nullable:"false" default:"0" list:"user"` @@ -346,6 +347,7 @@ func (manager *SSnapshotManager) ValidateCreateData( input.DiskId = disk.Id input.DiskType = disk.DiskType input.Size = disk.DiskSize + input.OsArch = disk.OsArch storage := disk.GetStorage() if len(disk.ExternalId) == 0 { diff --git a/pkg/hostman/guestfs/fsdriver/drivers.go b/pkg/hostman/guestfs/fsdriver/drivers.go index 388ff435ab..4904226b8d 100644 --- a/pkg/hostman/guestfs/fsdriver/drivers.go +++ b/pkg/hostman/guestfs/fsdriver/drivers.go @@ -14,18 +14,27 @@ package fsdriver +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/util/procutils" +) + type newRootFsDriverFunc func(part IDiskPartition) IRootFsDriver var ( privatePrefixes []string rootfsDrivers = make([]newRootFsDriverFunc, 0) + hostCpuArch string ) func GetRootfsDrivers() []newRootFsDriverFunc { return rootfsDrivers } -func Init(initPrivatePrefixes []string) { +func Init(initPrivatePrefixes []string) error { if len(initPrivatePrefixes) > 0 { privatePrefixes = make([]string, len(initPrivatePrefixes)) copy(privatePrefixes, initPrivatePrefixes) @@ -41,4 +50,10 @@ func Init(initPrivatePrefixes []string) { rootfsDrivers = append(rootfsDrivers, NewEsxiRootFs) rootfsDrivers = append(rootfsDrivers, NewWindowsRootFs) rootfsDrivers = append(rootfsDrivers, NewAndroidRootFs) + cpuArch, err := procutils.NewCommand("uname", "-m").Output() + if err != nil { + return errors.Wrap(err, "get cpu architecture") + } + hostCpuArch = strings.TrimSpace(string(cpuArch)) + return nil } diff --git a/pkg/hostman/guestfs/fsdriver/linux.go b/pkg/hostman/guestfs/fsdriver/linux.go index 6010499d45..38b44e09ea 100644 --- a/pkg/hostman/guestfs/fsdriver/linux.go +++ b/pkg/hostman/guestfs/fsdriver/linux.go @@ -23,7 +23,7 @@ import ( "syscall" "github.com/pkg/errors" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -325,9 +325,17 @@ func (l *sLinuxRootFs) GetOs() string { func (l *sLinuxRootFs) GetArch(rootFs IDiskPartition) string { if rootFs.Exists("/lib64", false) && rootFs.Exists("/usr/lib64", false) { - return "x86_64" + if hostCpuArch == "aarch64" { + return "aarch64" + } else { + return "x86_64" + } } else { - return "x86" + if hostCpuArch == "aarch64" { + return "aarch32" + } else { + return "x86" + } } } diff --git a/pkg/hostman/guestfs/fsdriver/windows.go b/pkg/hostman/guestfs/fsdriver/windows.go index d86d9734be..7d073e0e30 100644 --- a/pkg/hostman/guestfs/fsdriver/windows.go +++ b/pkg/hostman/guestfs/fsdriver/windows.go @@ -98,7 +98,7 @@ func (w *SWindowsRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo { if tool.CheckPath() { distro := tool.GetProductName() version := tool.GetVersion() - arch := tool.GetArch() + arch := tool.GetArch(hostCpuArch) lan := tool.GetInstallLanguage() return &deployapi.ReleaseInfo{ Distro: distro, diff --git a/pkg/hostman/hostdeployer/deployserver/deployserver.go b/pkg/hostman/hostdeployer/deployserver/deployserver.go index eb2b89acf2..e39fdaa655 100644 --- a/pkg/hostman/hostdeployer/deployserver/deployserver.go +++ b/pkg/hostman/hostdeployer/deployserver/deployserver.go @@ -376,7 +376,9 @@ func (s *SDeployService) InitService() { if err := s.PrepareEnv(); err != nil { log.Fatalln(err) } - fsdriver.Init(DeployOption.PrivatePrefixes) + if err := fsdriver.Init(DeployOption.PrivatePrefixes); err != nil { + log.Fatalln(err) + } s.O = &DeployOption.BaseOptions if len(DeployOption.DeployServerSocketPath) == 0 { log.Fatalf("missing deploy server socket path") diff --git a/pkg/image/models/image_guest.go b/pkg/image/models/image_guest.go index 8a740d5d83..3c8a5e4a22 100644 --- a/pkg/image/models/image_guest.go +++ b/pkg/image/models/image_guest.go @@ -67,6 +67,8 @@ type SGuestImage struct { db.SSharableVirtualResourceBase Protected tristate.TriState `nullable:"false" default:"true" list:"user" get:"user" create:"optional" update:"user"` + // 操作系统CPU架构 + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` } func (manager *SGuestImageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index d167bed142..7c04e4eb89 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -134,6 +134,8 @@ type SImage struct { IsGuestImage tristate.TriState `nullable:"false" default:"false" create:"optional" list:"user"` // 是否是数据盘镜像 IsData tristate.TriState `nullable:"false" default:"false" create:"optional" list:"user"` + // 操作系统CPU架构 + OsArch string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // image copy from url, save origin checksum before probe // 从镜像时长导入的镜像校验和 diff --git a/pkg/scheduler/algorithm/predicates/error.go b/pkg/scheduler/algorithm/predicates/error.go index 69fd1c78e8..ae5147cb42 100644 --- a/pkg/scheduler/algorithm/predicates/error.go +++ b/pkg/scheduler/algorithm/predicates/error.go @@ -41,6 +41,7 @@ const ( ErrSubtotalOfSplitExceedsDiskSize = `subtotal of split exceeds disk size` ErrBaremetalHasAlreadyBeenOccupied = `baremetal has already been occupied` ErrPrepaidHostOccupied = `prepaid host occupied` + ErrHostCpuArchitectureNotMatch = `host cpu architecture not match` ErrUnknown = `unknown error` ) diff --git a/pkg/scheduler/algorithm/predicates/guest/cpu_predicate.go b/pkg/scheduler/algorithm/predicates/guest/cpu_predicate.go index 6abdd32f17..171ad923f8 100644 --- a/pkg/scheduler/algorithm/predicates/guest/cpu_predicate.go +++ b/pkg/scheduler/algorithm/predicates/guest/cpu_predicate.go @@ -15,6 +15,7 @@ package guest import ( + "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates" "yunion.io/x/onecloud/pkg/scheduler/core" ) @@ -53,6 +54,13 @@ func (f *CPUPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.Pr useRsvd := h.UseReserved() getter := c.Getter() + if d.OsArch == compute.CPU_ARCH_ARM { + host := getter.Host() + if !host.IsArmHost() { + h.Exclude(predicates.ErrHostCpuArchitectureNotMatch) + return h.GetResult() + } + } freeCPUCount := getter.FreeCPUCount(useRsvd) reqCPUCount := int64(d.Ncpu) if freeCPUCount < reqCPUCount { diff --git a/pkg/util/winutils/winutils.go b/pkg/util/winutils/winutils.go index 0967c857c5..0cd7059e34 100644 --- a/pkg/util/winutils/winutils.go +++ b/pkg/util/winutils/winutils.go @@ -605,13 +605,21 @@ func (w *SWinRegTool) GetInstallLanguage() string { } } -func (w *SWinRegTool) GetArch() string { +func (w *SWinRegTool) GetArch(hostCpuArch string) string { prodKey := `HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\CurrentVersion` ver := w.GetRegistry(prodKey) if len(ver) > 0 { - return "x86_64" + if hostCpuArch == "aarch64" { + return "aarch64" + } else { + return "x86_64" + } } else { - return "x86" + if hostCpuArch == "aarch64" { + return "aarch32" + } else { + return "x86" + } } }