From 710d5ac2cceb125218620c198540c5230e7a63a6 Mon Sep 17 00:00:00 2001 From: wanyaoqi <18528551+wanyaoqi@users.noreply.github.com> Date: Sat, 10 Feb 2024 16:29:05 +0800 Subject: [PATCH] fix(region,host): rescue mode update initramfs, vnc login no passwd (#19478) --- build/docker/Dockerfile.host-deployer | 2 +- pkg/apis/compute/guest_rescue.go | 11 +- pkg/compute/guestdrivers/base.go | 4 - pkg/compute/guestdrivers/kvm.go | 12 -- pkg/compute/models/guest_rescue.go | 25 +-- pkg/compute/models/guestdrivers.go | 1 - pkg/compute/tasks/guest_rescue_task.go | 18 +- .../guestman/guesthandlers/guesthandler.go | 10 +- pkg/hostman/guestman/guestman.go | 21 +- pkg/hostman/guestman/guesttasks.go | 48 ----- pkg/hostman/guestman/qemu-kvm.go | 185 +----------------- pkg/hostman/guestman/qemu-kvmhelper.go | 6 - pkg/hostman/guestman/qemu/generate.go | 25 +-- 13 files changed, 41 insertions(+), 327 deletions(-) diff --git a/build/docker/Dockerfile.host-deployer b/build/docker/Dockerfile.host-deployer index a23d73055cd..32646d30f94 100644 --- a/build/docker/Dockerfile.host-deployer +++ b/build/docker/Dockerfile.host-deployer @@ -1,4 +1,4 @@ -FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.4 +FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.6 MAINTAINER "Yaoqi Wan wanyaoqi@yunionyun.com" diff --git a/pkg/apis/compute/guest_rescue.go b/pkg/apis/compute/guest_rescue.go index 3fe3d87752a..0d64bd4f70a 100644 --- a/pkg/apis/compute/guest_rescue.go +++ b/pkg/apis/compute/guest_rescue.go @@ -16,13 +16,6 @@ package compute // Rescue constants are used for rescue mode const ( - GUEST_RESCUE_RELATIVE_PATH = "rescue" // serverxxx/rescue - - GUEST_RESCUE_INITRAMFS = "initramfs" - GUEST_RESCUE_KERNEL = "kernel" - GUEST_RESCUE_INITRAMFS_ARM64 = "initramfs_aarch64" - GUEST_RESCUE_KERNEL_ARM64 = "kernel_aarch64" - - GUEST_RESCUE_SYS_DISK_NAME = "sys_img" - GUEST_RESCUE_SYS_DISK_SIZE = 500 // MB + GUEST_RESCUE_INITRAMFS = "initramfs" + GUEST_RESCUE_KERNEL = "kernel" ) diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 0c5636a8cff..15c1eed2e9b 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -557,10 +557,6 @@ func (self *SBaseGuestDriver) RequestStartRescue(ctx context.Context, task taskm return httperrors.ErrNotImplemented } -func (self *SBaseGuestDriver) RequestStopRescue(ctx context.Context, task taskman.ITask, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) error { - return httperrors.ErrNotImplemented -} - func (base *SBaseGuestDriver) ValidateGuestChangeConfigInput(ctx context.Context, guest *models.SGuest, input api.ServerChangeConfigInput) (*api.ServerChangeConfigSettings, error) { confs := api.ServerChangeConfigSettings{} diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 12d2a984f1a..d43a2d81662 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -1195,18 +1195,6 @@ func (self *SKVMGuestDriver) RequestStartRescue(ctx context.Context, task taskma return nil } -func (self *SKVMGuestDriver) RequestStopRescue(ctx context.Context, task taskman.ITask, body jsonutils.JSONObject, host *models.SHost, guest *models.SGuest) error { - header := self.getTaskRequestHeader(task) - client := httputils.GetDefaultClient() - url := fmt.Sprintf("%s/servers/%s/stop-rescue", host.ManagerUri, guest.Id) - _, _, err := httputils.JSONRequest(client, ctx, "POST", url, header, body, false) - if err != nil { - return err - } - - return nil -} - func (self *SKVMGuestDriver) ValidateSyncOSInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest) error { if !utils.IsInStringArray(guest.Status, []string{api.VM_RUNNING, api.VM_READY}) { return httperrors.NewBadRequestError("can't sync guest os info in status %s", guest.Status) diff --git a/pkg/compute/models/guest_rescue.go b/pkg/compute/models/guest_rescue.go index 11908439c4c..9a74f0d2507 100644 --- a/pkg/compute/models/guest_rescue.go +++ b/pkg/compute/models/guest_rescue.go @@ -30,31 +30,16 @@ import ( func (self *SGuest) PerformStartRescue(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) { - return nil, httperrors.NewInvalidStatusError("guest status must be ready or running") + if self.Hypervisor != api.HYPERVISOR_KVM { + return nil, httperrors.NewBadRequestError("Cannot rescue guest hypervisor %s", self.Hypervisor) } - // Check vmem size, need to be greater than 2G - if self.VmemSize < 2048 { - return nil, httperrors.NewInvalidStatusError("vmem size must be greater than 2G") - } - - // Get baremetal agent - host, err := self.GetHost() - if err != nil { - return nil, httperrors.NewInvalidStatusError("guest.GetHost: %s", err.Error()) - } - bmAgent := BaremetalagentManager.GetAgent(api.AgentTypeBaremetal, host.ZoneId) - if bmAgent == nil { - return nil, httperrors.NewInvalidStatusError("BaremetalagentManager.GetAgent: %s", "Baremetal agent not found") + if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) { + return nil, httperrors.NewInvalidStatusError("guest status must be ready or running") } - // Set available baremetal agent managerURi to data - dataDict := data.(*jsonutils.JSONDict) - dataDict.Add(jsonutils.NewString(bmAgent.ManagerUri), "manager_uri") - // Start rescue vm task - err = self.StartRescueTask(ctx, userCred, dataDict, "") + err := self.StartRescueTask(ctx, userCred, jsonutils.NewDict(), "") if err != nil { return nil, httperrors.NewInvalidStatusError("guest.StartGuestRescueTask: %s", err.Error()) } diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 3bddb0847c2..61a4cc17237 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -251,7 +251,6 @@ type IGuestDriver interface { ValidateSetOSInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, input *api.ServerSetOSInfoInput) error ValidateSyncOSInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error RequestStartRescue(ctx context.Context, task taskman.ITask, body jsonutils.JSONObject, host *SHost, guest *SGuest) error - RequestStopRescue(ctx context.Context, task taskman.ITask, body jsonutils.JSONObject, host *SHost, guest *SGuest) error } var guestDrivers map[string]IGuestDriver diff --git a/pkg/compute/tasks/guest_rescue_task.go b/pkg/compute/tasks/guest_rescue_task.go index 102dfb35c66..19b92815163 100644 --- a/pkg/compute/tasks/guest_rescue_task.go +++ b/pkg/compute/tasks/guest_rescue_task.go @@ -69,14 +69,14 @@ func (self *StartRescueTask) OnServerStopCompleteFailed(ctx context.Context, gue func (self *StartRescueTask) PrepareRescue(ctx context.Context, guest *models.SGuest) { db.OpsLog.LogEvent(guest, db.ACT_START_RESCUE, nil, self.UserCred) guest.SetStatus(ctx, self.UserCred, api.VM_START_RESCUE, "PrepareRescue") - self.SetStage("OnRescuePrepareComplete", nil) host, _ := guest.GetHost() - err := guest.GetDriver().RequestStartRescue(ctx, self, self.GetParams(), host, guest) + err := guest.GetDriver().RequestStartRescue(ctx, self, jsonutils.NewDict(), host, guest) if err != nil { self.OnRescuePrepareCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) return } + self.OnRescuePrepareComplete(ctx, guest, nil) } func (self *StartRescueTask) OnRescuePrepareComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { @@ -166,20 +166,16 @@ func (self *StopRescueTask) OnServerStopCompleteFailed(ctx context.Context, gues func (self *StopRescueTask) ClearRescue(ctx context.Context, guest *models.SGuest) { db.OpsLog.LogEvent(guest, db.ACT_STOP_RESCUE, nil, self.UserCred) guest.SetStatus(ctx, self.UserCred, api.VM_STOP_RESCUE, "ClearRescue") - self.SetStage("OnRescueClearComplete", nil) - - host, _ := guest.GetHost() - err := guest.GetDriver().RequestStopRescue(ctx, self, nil, host, guest) - if err != nil { - self.OnRescueClearCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) - return - } + self.OnRescueClearComplete(ctx, guest, nil) } func (self *StopRescueTask) OnRescueClearComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { db.OpsLog.LogEvent(guest, db.ACT_STOP_RESCUE, guest.GetShortDesc(ctx), self.UserCred) logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_STOP_RESCUE, guest.GetShortDesc(ctx), self.UserCred, true) - guest.UpdateRescueMode(false) + if err := guest.UpdateRescueMode(false); err != nil { + self.OnRescueClearCompleteFailed(ctx, guest, jsonutils.NewString(err.Error())) + return + } self.RescueStartServer(ctx, guest) } diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 0b7941ed2cf..73e7512aa23 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -106,7 +106,6 @@ func AddGuestTaskHandler(prefix string, app *appsrv.Application) { "qga-set-network": qgaSetNetwork, "qga-get-os-info": qgaGetOsInfo, "start-rescue": guestStartRescue, - "stop-rescue": guestStopRescue, } { app.AddHandler("POST", fmt.Sprintf("%s/%s//%s", prefix, keyWord, action), @@ -950,14 +949,7 @@ func qgaGetOsInfo(ctx context.Context, userCred mcclient.TokenCredential, sid st return gm.QgaGetOsInfo(sid) } -// guestStartRescue prepare rescue files +// prepare rescue files func guestStartRescue(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) { - // Start rescue guest return guestman.GetGuestManager().GuestStartRescue(ctx, userCred, sid, body) } - -// guestStopRescue clear rescue files -func guestStopRescue(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (interface{}, error) { - // Stop rescue guest - return guestman.GetGuestManager().GuestStopRescue(ctx, userCred, sid, body) -} diff --git a/pkg/hostman/guestman/guestman.go b/pkg/hostman/guestman/guestman.go index b676eea5a4f..5e92b6c2202 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -911,21 +911,14 @@ func (m *SGuestManager) GuestStop(ctx context.Context, sid string, timeout int64 } func (m *SGuestManager) GuestStartRescue(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { - baremetalManagerUri, err := body.GetString("manager_uri") - if err != nil { - return nil, httperrors.NewInputParameterError("manager_uri required") - } if guest, ok := m.GetServer(sid); ok { - guest.ExecStartRescueTask(ctx, baremetalManagerUri) - return nil, nil - } else { - return nil, httperrors.NewNotFoundError("Guest %s not found", sid) - } -} - -func (m *SGuestManager) GuestStopRescue(ctx context.Context, userCred mcclient.TokenCredential, sid string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if guest, ok := m.GetServer(sid); ok { - guest.ExecStopRescueTask(ctx, body) + // initrd and kernel should be prepared by host-deployer + if !fileutils2.Exists(guest.getRescueInitrdPath()) { + return nil, httperrors.NewInternalServerError("guest initrd not ready") + } + if !fileutils2.Exists(guest.getRescueKernelPath()) { + return nil, httperrors.NewInternalServerError("guest kernel not ready") + } return nil, nil } else { return nil, httperrors.NewNotFoundError("Guest %s not found", sid) diff --git a/pkg/hostman/guestman/guesttasks.go b/pkg/hostman/guestman/guesttasks.go index 2c0c0539b16..8eeffd29e59 100644 --- a/pkg/hostman/guestman/guesttasks.go +++ b/pkg/hostman/guestman/guesttasks.go @@ -102,54 +102,6 @@ func (s *SGuestStopTask) CheckGuestRunningLater() { s.checkGuestRunning() } -// SGuestStartRescueTask Start a rescue vm -type SGuestStartRescueTask struct { - *SKVMGuestInstance - ctx context.Context - BaremetalManagerUri string -} - -func NewGuestStartRescueTask(guest *SKVMGuestInstance, ctx context.Context, baremetalManagerUri string) *SGuestStartRescueTask { - return &SGuestStartRescueTask{ - SKVMGuestInstance: guest, - ctx: ctx, - BaremetalManagerUri: baremetalManagerUri, - } -} - -func (s *SGuestStartRescueTask) Start() { - if err := s.prepareRescue(s.ctx, s.BaremetalManagerUri); err != nil { - log.Errorf("prepareRescue fail %s", err) - hostutils.TaskFailed(s.ctx, err.Error()) - return - } - - hostutils.TaskComplete(s.ctx, nil) -} - -// SGuestStopRescueTask Stop a rescue vm, clean rescue files -type SGuestStopRescueTask struct { - *SKVMGuestInstance - ctx context.Context -} - -func NewGuestStopRescueTask(guest *SKVMGuestInstance, ctx context.Context) *SGuestStopRescueTask { - return &SGuestStopRescueTask{ - SKVMGuestInstance: guest, - ctx: ctx, - } -} - -func (s *SGuestStopRescueTask) Start() { - if err := s.clearRescue(s.ctx); err != nil { - log.Errorf("clearRescue fail %s", err) - hostutils.TaskFailed(s.ctx, err.Error()) - return - } - - hostutils.TaskComplete(s.ctx, nil) -} - type SGuestSuspendTask struct { *SKVMGuestInstance ctx context.Context diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 95bb8aee9da..c0093ed601d 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -17,9 +17,7 @@ package guestman import ( "context" "fmt" - "io" "io/ioutil" - "net/http" "os" "path" "path/filepath" @@ -34,8 +32,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/appctx" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/httputils" - "yunion.io/x/pkg/util/qemuimgfmt" "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/util/seclib" "yunion.io/x/pkg/util/version" @@ -395,19 +391,11 @@ func (s *SKVMGuestInstance) GetSourceDescFilePath() string { } func (s *SKVMGuestInstance) GetRescueDirPath() string { - return path.Join(s.HomeDir(), api.GUEST_RESCUE_RELATIVE_PATH) -} - -func (s *SKVMGuestInstance) CreateRescueDirPath() (string, error) { - rescueDir := path.Join(s.HomeDir(), api.GUEST_RESCUE_RELATIVE_PATH) - - // Check if rescue dir exists - output, err := procutils.NewCommand("mkdir", "-p", rescueDir).Output() - if err != nil { - return "", errors.Wrapf(err, "mkdir %s failed: %s", s.HomeDir(), output) + if s.manager.host.IsAarch64() { + return path.Join("/opt/cloud/host-deployer/yunionos/aarch64") + } else { + return path.Join("/opt/cloud/host-deployer/yunionos/x86_64") } - - return rescueDir, nil } func (s *SKVMGuestInstance) LoadDesc() error { @@ -2013,19 +2001,6 @@ func (s *SKVMGuestInstance) ExecStopTask(ctx context.Context, params interface{} return nil, nil } -func (s *SKVMGuestInstance) ExecStartRescueTask(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { - baremetalManagerUri, ok := params.(string) - if !ok { - return nil, hostutils.ParamsError - } - NewGuestStartRescueTask(s, ctx, baremetalManagerUri).Start() - return nil, nil -} - -func (s *SKVMGuestInstance) ExecStopRescueTask(ctx context.Context, params interface{}) { - NewGuestStopRescueTask(s, ctx).Start() -} - func (s *SKVMGuestInstance) ExecSuspendTask(ctx context.Context) { NewGuestSuspendTask(s, ctx, nil).Start() } @@ -3176,155 +3151,3 @@ func (s *SKVMGuestInstance) CPUSetRemove(ctx context.Context) error { } return nil } - -func (s *SKVMGuestInstance) clearRescue(ctx context.Context) error { - rescueDir := s.GetRescueDirPath() - if err := fileutils2.Cleandir(rescueDir, false); err != nil { - return errors.Wrap(err, "clear rescue dir failed") - } - - return nil -} - -func (s *SKVMGuestInstance) prepareRescue(ctx context.Context, baremetalManagerUri string) error { - files := []string{ - api.GUEST_RESCUE_INITRAMFS, - api.GUEST_RESCUE_KERNEL, - } - - // Support arm64 - if s.manager.host.IsAarch64() { - files = []string{ - api.GUEST_RESCUE_INITRAMFS_ARM64, - api.GUEST_RESCUE_KERNEL_ARM64, - } - } - - // Prepare files - for _, file := range files { - err := s.downloadFromBaremetal(file, baremetalManagerUri) - if err != nil { - return errors.Wrapf(err, "download %s from baremetal failed", file) - } - } - - // Create disk - diskPath := path.Join(s.GetRescueDirPath(), api.GUEST_RESCUE_SYS_DISK_NAME) - err := s.createTempDisk(diskPath, api.GUEST_RESCUE_SYS_DISK_SIZE, qemuimgfmt.QCOW2.String(), nil, "") - if err != nil { - return errors.Wrapf(err, "create disk %s failed", diskPath) - } - - return nil -} - -func (s *SKVMGuestInstance) downloadFromBaremetal(filename, baremetalManagerUri string) error { - rescueDir, err := s.CreateRescueDirPath() - if err != nil { - return errors.Wrap(err, "SKVMGuestInstance.GetRescueDirPath") - } - - // Check file is exist - filePath := path.Join(rescueDir, filename) - if fileutils2.Exists(filePath) { - // File already exist - log.Debugf("File %s already exist", filePath) - - return nil - } - - // Create file - file, err := os.Create(filePath) - if err != nil { - return errors.Wrapf(err, "create file %s failed", filePath) - } - defer file.Close() - - // Get filepath - fileURL, err := s.getTftpFileUrl(filename, baremetalManagerUri) - if err != nil { - return errors.Wrapf(err, "getTftpFileUrl") - } - - // Request for file - resp, err := httputils.Request( - httputils.GetDefaultClient(), - context.Background(), - "GET", - fileURL, - nil, - nil, - false) - if err != nil || resp.StatusCode != http.StatusOK { - return errors.Wrapf(err, "request %s failed", fileURL) - } - - // Write file - if _, err := io.Copy(file, resp.Body); err != nil { - return errors.Wrapf(err, "write file %s failed", filePath) - } - - return nil -} - -func (s *SKVMGuestInstance) createTempDisk(path string, sizeMB int, diskFormat string, encryptInfo *apis.SEncryptInfo, back string) error { - if fileutils2.Exists(path) { - os.Remove(path) - } - - img, err := qemuimg.NewQemuImage(path) - if err != nil { - log.Errorln(err) - return err - } - - switch diskFormat { - case "qcow2": - if encryptInfo != nil { - err = img.CreateQcow2(sizeMB, false, back, encryptInfo.Key, qemuimg.EncryptFormatLuks, encryptInfo.Alg) - } else { - err = img.CreateQcow2(sizeMB, false, back, "", "", "") - } - case "vmdk": - err = img.CreateVmdk(sizeMB, false) - default: - err = img.CreateRaw(sizeMB) - } - if err != nil { - return errors.Wrapf(err, "create_raw: Fail to create disk") - } - - return nil -} - -func (s *SKVMGuestInstance) getTftpFileUrl(filename, baremetalManagerUri string) (string, error) { - endpoint, err := s.getTftpEndpoint(baremetalManagerUri) - if err != nil { - log.Errorf("Get http file server endpoint: %v", err) - return filename, err - } - return fmt.Sprintf("http://%s/tftp/%s", endpoint, filename), nil -} - -func (s *SKVMGuestInstance) getTftpEndpoint(baremetalManagerUri string) (string, error) { - // Split with : - addrs := strings.Split(baremetalManagerUri, "//") - if len(addrs) < 2 { - return "", errors.Errorf("baremetal manager uri is invalid") - } - endpoints := strings.Split(addrs[1], ":") - if len(endpoints) < 2 { - return "", errors.Errorf("baremetal manager uri is invalid") - } - - // Plus baremetal agent port with 1000 - port, err := strconv.Atoi(endpoints[1]) - if err != nil { - return "", errors.Wrapf(err, "convert port failed") - } - - // Concat new endpoint url - endpoint := fmt.Sprintf("%s:%d", endpoints[0], port+1000) - - return endpoint, nil -} diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index 78332dee6d8..60b88b86c42 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -577,16 +577,10 @@ function nic_mtu() { } func (s *SKVMGuestInstance) getRescueInitrdPath() string { - if s.manager.GetHost().IsAarch64() { - return path.Join(s.GetRescueDirPath(), api.GUEST_RESCUE_INITRAMFS_ARM64) - } return path.Join(s.GetRescueDirPath(), api.GUEST_RESCUE_INITRAMFS) } func (s *SKVMGuestInstance) getRescueKernelPath() string { - if s.manager.GetHost().IsAarch64() { - return path.Join(s.GetRescueDirPath(), api.GUEST_RESCUE_KERNEL_ARM64) - } return path.Join(s.GetRescueDirPath(), api.GUEST_RESCUE_KERNEL) } diff --git a/pkg/hostman/guestman/qemu/generate.go b/pkg/hostman/guestman/qemu/generate.go index 301c6195fcb..6a99f6c2280 100644 --- a/pkg/hostman/guestman/qemu/generate.go +++ b/pkg/hostman/guestman/qemu/generate.go @@ -223,6 +223,7 @@ func generateInitrdOptions(drvOpt QemuOptions, initrdPath, kernel string) []stri opts := make([]string, 0) opts = append(opts, drvOpt.Initrd(initrdPath)) opts = append(opts, drvOpt.Kernel(kernel)) + opts = append(opts, "-append yn_rescue_mode=true") return opts } @@ -795,20 +796,22 @@ func GenerateStartOptions( } opts = append(opts, nicOpts...) - if input.QemuArch == Arch_aarch64 { - if input.GuestDesc.Usb != nil { - opts = append(opts, generatePCIDeviceOption(input.GuestDesc.Usb.PCIDevice)) + if !input.GuestDesc.LightMode { + if input.QemuArch == Arch_aarch64 { + if input.GuestDesc.Usb != nil { + opts = append(opts, generatePCIDeviceOption(input.GuestDesc.Usb.PCIDevice)) + for _, device := range input.Devices { + opts = append(opts, drvOpt.Device(device)) + } + } + } else { + opts = append(opts, drvOpt.USB()) for _, device := range input.Devices { opts = append(opts, drvOpt.Device(device)) } - } - } else { - opts = append(opts, drvOpt.USB()) - for _, device := range input.Devices { - opts = append(opts, drvOpt.Device(device)) - } - if input.GuestDesc.Usb != nil { - opts = append(opts, generatePCIDeviceOption(input.GuestDesc.Usb.PCIDevice)) + if input.GuestDesc.Usb != nil { + opts = append(opts, generatePCIDeviceOption(input.GuestDesc.Usb.PCIDevice)) + } } }