diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 95fbdb1a5a..a9b6468d60 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -548,9 +548,10 @@ type ServerDetachnetworkInput struct { type ServerMigrateForecastInput struct { PreferHostId string `json:"prefer_host_id"` // Deprecated - PreferHost string `json:"prefer_host" yunion-deprecated-by:"prefer_host_id"` - LiveMigrate bool `json:"live_migrate"` - SkipCpuCheck bool `josn:"skip_cpu_check"` + PreferHost string `json:"prefer_host" yunion-deprecated-by:"prefer_host_id"` + LiveMigrate bool `json:"live_migrate"` + SkipCpuCheck bool `json:"skip_cpu_check"` + SkipKernelCheck bool `json:"skip_kernel_check"` } type ServerResizeDiskInput struct { diff --git a/pkg/apis/scheduler/api.go b/pkg/apis/scheduler/api.go index 34673e36bb..87a251e7ef 100644 --- a/pkg/apis/scheduler/api.go +++ b/pkg/apis/scheduler/api.go @@ -77,12 +77,14 @@ type ScheduleInput struct { // HostId used by migrate HostId string `json:"host_id"` LiveMigrate bool `json:"live_migrate"` + SkipCpuCheck *bool `json:"skip_cpu_check"` CpuDesc string `json:"cpu_desc"` CpuMicrocode string `json:"cpu_microcode"` CpuMode string `json:"cpu_mode"` OsArch string `json:"os_arch"` - SkipCpuCheck *bool `json:"skip_cpu_check"` + SkipKernelCheck *bool `json:"skip_kernel_check"` + TargetHostKernel string `json:"target_host_kernel"` // In the migrate and create backup cases // we don't need reallocate network diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index c5adc985b1..2a84bc4017 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -436,6 +436,11 @@ func (self *SGuest) GetSchedMigrateParams( schedDesc.CpuMode = api.CPU_MODE_QEMU } schedDesc.SkipCpuCheck = &input.SkipCpuCheck + host, _ := self.GetHost() + if host != nil { + schedDesc.TargetHostKernel, _ = host.SysInfo.GetString("kernel_version") + schedDesc.SkipKernelCheck = &input.SkipKernelCheck + } } schedDesc.ReuseNetwork = true return schedDesc diff --git a/pkg/hostman/hostinfo/hostinfo.go b/pkg/hostman/hostinfo/hostinfo.go index 25c91f7e8a..624769266f 100644 --- a/pkg/hostman/hostinfo/hostinfo.go +++ b/pkg/hostman/hostinfo/hostinfo.go @@ -168,21 +168,22 @@ func (h *SHostInfo) Init() error { log.Infof("Start detectHostInfo") if err := h.detectHostInfo(); err != nil { - return err + return errors.Wrap(err, "detectHostInfo") } if err := hostbridge.Prepare(options.HostOptions.BridgeDriver); err != nil { + err := errors.Errorf("Prepare host bridge %q error: %v", options.HostOptions.BridgeDriver, err) log.Errorln(err) return err } log.Infof("Start parseConfig") if err := h.parseConfig(); err != nil { - return err + return errors.Wrap(err, "parseConfig") } if HasOvnSupport() { if err := h.setupOvnChassis(); err != nil { - return err + return errors.Wrap(err, "Setup OVN Chassis") } } @@ -686,7 +687,7 @@ func (h *SHostInfo) detectOsDist() { func (h *SHostInfo) detectKernelVersion() { out, err := procutils.NewCommand("uname", "-r").Output() if err != nil { - log.Errorln(err) + log.Errorf("detectKernelVersion error: %v", err) } h.sysinfo.KernelVersion = strings.TrimSpace(string(out)) } @@ -1096,7 +1097,7 @@ func (h *SHostInfo) updateHostRecord(hostId string) { content.Set("storage_size", jsonutils.NewInt(int64(storageman.GetManager().GetTotalCapacity()))) // TODO optimize content data struct - content.Set("sys_info", jsonutils.Marshal(h.sysinfo)) + content.Set("sys_info", jsonutils.Marshal(h.getSysInfo())) content.Set("sn", jsonutils.NewString(h.sysinfo.SN)) content.Set("host_type", jsonutils.NewString(options.HostOptions.HostType)) if len(options.HostOptions.Rack) > 0 { diff --git a/pkg/mcclient/options/compute/servers.go b/pkg/mcclient/options/compute/servers.go index f9fb5d3cae..460099b3e7 100644 --- a/pkg/mcclient/options/compute/servers.go +++ b/pkg/mcclient/options/compute/servers.go @@ -882,10 +882,11 @@ func (o *ServerRestartOptions) Params() (jsonutils.JSONObject, error) { } type ServerMigrateForecastOptions struct { - ID string `help:"ID of server" json:"-"` - PreferHost string `help:"Server migration prefer host id or name" json:"prefer_host"` - LiveMigrate *bool `help:"Use live migrate"` - SkipCpuCheck *bool `help:"Skip check CPU mode of the target host" json:"skip_cpu_check"` + ID string `help:"ID of server" json:"-"` + PreferHost string `help:"Server migration prefer host id or name" json:"prefer_host"` + LiveMigrate *bool `help:"Use live migrate"` + SkipCpuCheck *bool `help:"Skip check CPU mode of the target host" json:"skip_cpu_check"` + SkipKernelCheck *bool `help:"Skip target kernel version check" json:"skip_kernel_check"` } func (o *ServerMigrateForecastOptions) GetId() string { @@ -912,9 +913,10 @@ func (o *ServerMigrateOptions) Params() (jsonutils.JSONObject, error) { } type ServerLiveMigrateOptions struct { - ID string `help:"ID of server" json:"-"` - PreferHost string `help:"Server migration prefer host id or name" json:"prefer_host"` - SkipCpuCheck *bool `help:"Skip check CPU mode of the target host" json:"skip_cpu_check"` + ID string `help:"ID of server" json:"-"` + PreferHost string `help:"Server migration prefer host id or name" json:"prefer_host"` + SkipCpuCheck *bool `help:"Skip check CPU mode of the target host" json:"skip_cpu_check"` + SkipKernelCheck *bool `help:"Skip target kernel version check" json:"skip_kernel_check"` } func (o *ServerLiveMigrateOptions) GetId() string { diff --git a/pkg/scheduler/algorithm/predicates/error.go b/pkg/scheduler/algorithm/predicates/error.go index 3c65c03dd3..8b132a792a 100644 --- a/pkg/scheduler/algorithm/predicates/error.go +++ b/pkg/scheduler/algorithm/predicates/error.go @@ -36,6 +36,7 @@ const ( ErrHostIsSpecifiedForMigration = `host_id specified for migration` ErrHostCpuModelIsNotMatchForLiveMigrate = `host cpu mode not match for live migrate` ErrHostCpuMicrocodeNotMatchForLiveMigrate = `host cpu microcode not match for live migrate` + ErrHostKernelNotMatchForLiveMigrate = `host kernel not match for live migrate` ErrMoreThanOneSizeUnspecificSplit = `more than 1 size unspecific split` ErrNoMoreSpaceForUnspecificSplit = `no more space for an unspecific split` ErrSubtotalOfSplitExceedsDiskSize = `subtotal of split exceeds disk size` diff --git a/pkg/scheduler/algorithm/predicates/guest/migrate_predicate.go b/pkg/scheduler/algorithm/predicates/guest/migrate_predicate.go index 2999ac0894..82fbefeecb 100644 --- a/pkg/scheduler/algorithm/predicates/guest/migrate_predicate.go +++ b/pkg/scheduler/algorithm/predicates/guest/migrate_predicate.go @@ -46,17 +46,29 @@ func (p *MigratePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor return h.GetResult() } - if schedData.LiveMigrate && schedData.CpuMode != compute.CPU_MODE_QEMU && (schedData.SkipCpuCheck == nil || *schedData.SkipCpuCheck == false) { + // live migrate check + if schedData.LiveMigrate { host := c.Getter().Host() - if schedData.CpuDesc != host.CpuDesc { - h.Exclude(predicates.ErrHostCpuModelIsNotMatchForLiveMigrate) - return h.GetResult() + // target host cpu check + if schedData.CpuMode != compute.CPU_MODE_QEMU && (schedData.SkipCpuCheck == nil || *schedData.SkipCpuCheck == false) { + if schedData.CpuDesc != host.CpuDesc { + h.Exclude(predicates.ErrHostCpuModelIsNotMatchForLiveMigrate) + return h.GetResult() + } + if len(schedData.CpuMicrocode) > 0 && schedData.CpuMicrocode != host.CpuMicrocode { + h.Exclude(predicates.ErrHostCpuMicrocodeNotMatchForLiveMigrate) + return h.GetResult() + } } - if len(schedData.CpuMicrocode) > 0 && schedData.CpuMicrocode != host.CpuMicrocode { - h.Exclude(predicates.ErrHostCpuMicrocodeNotMatchForLiveMigrate) - return h.GetResult() + + // target host kernel check + if schedData.SkipKernelCheck != nil && !*schedData.SkipKernelCheck { + kv, _ := host.SysInfo.GetString("kernel_version") + if schedData.TargetHostKernel != "" && schedData.TargetHostKernel != kv { + h.Exclude2(predicates.ErrHostCpuMicrocodeNotMatchForLiveMigrate, kv, schedData.TargetHostKernel) + return h.GetResult() + } } } - return h.GetResult() }