mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-13 16:19:14 +08:00
feat(host): try qga guest shutdown first (#25713)
fix(host): bring up lvmlockd on load storages
This commit is contained in:
@@ -43,6 +43,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/isolated_device"
|
||||
"yunion.io/x/onecloud/pkg/hostman/monitor"
|
||||
"yunion.io/x/onecloud/pkg/hostman/monitor/qga"
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
@@ -67,6 +68,9 @@ type SGuestStopTask struct {
|
||||
isFroce bool
|
||||
startPowerdown time.Time
|
||||
c chan context.Context
|
||||
|
||||
qgaStopping bool
|
||||
qgaTiemout int64
|
||||
}
|
||||
|
||||
func NewGuestStopTask(guest *SKVMGuestInstance, ctx context.Context, timeout int64, isForce bool) *SGuestStopTask {
|
||||
@@ -84,7 +88,21 @@ func (s *SGuestStopTask) Start() {
|
||||
s.stopping = true
|
||||
s.startPowerdown = time.Now()
|
||||
if s.IsRunning() && s.IsMonitorAlive() {
|
||||
s.Monitor.SimpleCommand("system_powerdown", s.onPowerdownGuest)
|
||||
if s.guestAgent.GuestPing(1) == nil {
|
||||
// qga stop first
|
||||
if err := s.guestAgent.GuestStop(2); err != nil && err != qga.QgaReadTimeOutErr {
|
||||
log.Errorf("failed qga guest stop %s", err)
|
||||
} else {
|
||||
s.qgaStopping = true
|
||||
s.qgaTiemout = s.timeout / 2
|
||||
if s.qgaTiemout > options.HostOptions.QgaStopTimeout {
|
||||
s.qgaTiemout = options.HostOptions.QgaStopTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
if !s.qgaStopping {
|
||||
s.Monitor.SimpleCommand("system_powerdown", s.onPowerdownGuest)
|
||||
}
|
||||
}
|
||||
s.checkGuestRunning()
|
||||
}
|
||||
@@ -104,6 +122,7 @@ func (s *SGuestStopTask) checkGuestRunning() {
|
||||
case ctx := <-s.c:
|
||||
s.Stop() // force stop
|
||||
s.stopping = false
|
||||
s.qgaStopping = false
|
||||
if ctx != nil {
|
||||
hostutils.TaskComplete(ctx, nil)
|
||||
}
|
||||
@@ -112,7 +131,13 @@ func (s *SGuestStopTask) checkGuestRunning() {
|
||||
if !s.IsRunning() {
|
||||
s.Stop() // force stop
|
||||
s.stopping = false
|
||||
s.qgaStopping = false
|
||||
hostutils.TaskComplete(s.ctx, nil)
|
||||
} else if s.qgaStopping && time.Now().Sub(s.startPowerdown) > time.Duration(s.qgaTiemout)*time.Second {
|
||||
// rollback acpi guest shutdown
|
||||
s.qgaStopping = false
|
||||
s.Monitor.SimpleCommand("system_powerdown", s.onPowerdownGuest)
|
||||
go s.checkGuestRunning()
|
||||
} else if time.Now().Sub(s.startPowerdown) > time.Duration(s.timeout)*time.Second {
|
||||
// timeout
|
||||
if s.isFroce {
|
||||
|
||||
@@ -41,6 +41,8 @@ const (
|
||||
QGA_EXEC_DEFAULT_WAIT_TIMEOUT int = 300
|
||||
)
|
||||
|
||||
const QgaReadTimeOutErr = errors.Error("qga read timeout")
|
||||
|
||||
type QGACallback func([]byte)
|
||||
|
||||
type QemuGuestAgent struct {
|
||||
@@ -276,7 +278,7 @@ func (qga *QemuGuestAgent) execCmd(cmd *monitor.Command, expectResp bool, readTi
|
||||
log.Errorf("failed close qga connection %s", err)
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("qga read timeout")
|
||||
return nil, QgaReadTimeOutErr
|
||||
case res = <-resChan:
|
||||
break
|
||||
}
|
||||
@@ -307,6 +309,14 @@ func (qga *QemuGuestAgent) GuestPing(timeout int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (qga *QemuGuestAgent) GuestStop(timeout int) error {
|
||||
cmd := &monitor.Command{
|
||||
Execute: "guest-shutdown",
|
||||
}
|
||||
_, err := qga.execCmd(cmd, true, timeout)
|
||||
return err
|
||||
}
|
||||
|
||||
type GuestCommand struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -42,6 +42,7 @@ type SHostBaseOptions struct {
|
||||
|
||||
DefaultQemuVersion string `help:"Default qemu version" default:"10.0.7"`
|
||||
NoHpet bool `help:"Disable qemu hpet timer" default:"true"`
|
||||
QgaStopTimeout int64 `default:"30" help:"Qemu guest agent stop timeout"`
|
||||
|
||||
CdromCount int `help:"cdrom count" default:"1"`
|
||||
FloppyCount int `help:"floppy count" default:"1"`
|
||||
|
||||
@@ -290,12 +290,12 @@ $size1 $size2 linear $2 0" | dmsetup create $3
|
||||
return nil
|
||||
}
|
||||
|
||||
func VgDisplay(vgName string) error {
|
||||
func VgDisplay(vgName string) (string, error) {
|
||||
out, err := procutils.NewRemoteCommandAsFarAsPossible("lvm", "vgdisplay", vgName).Output()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "vgdisplay %s failed %s", vgName, out)
|
||||
return "", errors.Wrapf(err, "vgdisplay %s failed %s: %s", vgName, out, err)
|
||||
}
|
||||
return nil
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func VgActive(vgName string, active, autoActivation bool) error {
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s *SCLVMStorage) GetDiskById(diskId string) (IDisk, error) {
|
||||
}
|
||||
|
||||
func (s *SCLVMStorage) Accessible() error {
|
||||
if err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
if _, err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -558,7 +558,7 @@ func (s *SLVMStorage) Accessible() error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "pvscan --cache failed %s", out)
|
||||
}
|
||||
if err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
if _, err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -17,6 +17,7 @@ package storageman
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -25,7 +26,9 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman/lvmutils"
|
||||
"yunion.io/x/onecloud/pkg/hostman/system_service"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
"yunion.io/x/onecloud/pkg/util/qemuimg"
|
||||
)
|
||||
|
||||
@@ -159,12 +162,26 @@ func (s *SSLVMStorage) DeleteSnapshot(ctx context.Context, params interface{}) (
|
||||
}
|
||||
|
||||
func (s *SSLVMStorage) Accessible() error {
|
||||
if err := lvmutils.VgActive(s.Path, true, true); err != nil {
|
||||
log.Warningf("vgactive got %s", err)
|
||||
lvmlockd := system_service.NewBaseSystemService("lvmlockd", nil)
|
||||
if !lvmlockd.IsInstalled() {
|
||||
lvmlockd = system_service.NewBaseSystemService("lvm2-lvmlockd", nil)
|
||||
}
|
||||
|
||||
if err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
if !lvmlockd.IsActive() {
|
||||
if err := lvmlockd.Start(true); err != nil {
|
||||
log.Errorf("lvmlockd start failed: %s", err)
|
||||
return errors.Wrap(err, "lvmlockd.Start")
|
||||
}
|
||||
}
|
||||
if out, err := lvmutils.VgDisplay(s.Path); err != nil {
|
||||
return err
|
||||
} else if strings.Contains(out, "without a lock") {
|
||||
out, err := procutils.NewRemoteCommandAsFarAsPossible("lvm", "vgchange", "--lock-start", s.Path).Output()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "lvmlock vgchange --lock-start %s failed: %s", s.Path, out)
|
||||
}
|
||||
}
|
||||
if err := lvmutils.VgActive(s.Path, true, false); err != nil {
|
||||
log.Warningf("vgactive got %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func storageIsVgExist(ctx context.Context, w http.ResponseWriter, r *http.Reques
|
||||
hostutils.Response(ctx, w, httperrors.NewMissingParameterError("vg_name"))
|
||||
return
|
||||
}
|
||||
if err := lvmutils.VgDisplay(vgName); err != nil {
|
||||
if _, err := lvmutils.VgDisplay(vgName); err != nil {
|
||||
log.Errorf("vg %s display failed %s", vgName, err)
|
||||
hostutils.Response(ctx, w, httperrors.NewInternalServerError("%s", err.Error()))
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user