mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #14638 from wanyaoqi/feature/server-monitor-support-qmp
feat(region,host): server-monitor support qmp
This commit is contained in:
@@ -104,6 +104,7 @@ func init() {
|
||||
cmd.Perform("cpuset-remove", &options.ServerIdOptions{})
|
||||
cmd.Perform("calculate-record-checksum", &options.ServerIdOptions{})
|
||||
cmd.Perform("set-class-metadata", &baseoptions.ResourceMetadataOptions{})
|
||||
cmd.Perform("monitor", &options.ServerMonitorOptions{})
|
||||
|
||||
cmd.Get("vnc", new(options.ServerIdOptions))
|
||||
cmd.Get("desc", new(options.ServerIdOptions))
|
||||
@@ -305,23 +306,6 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&options.ServerMonitorOptions{}, "server-monitor", "Send commands to qemu monitor", func(s *mcclient.ClientSession, opts *options.ServerMonitorOptions) error {
|
||||
params, err := baseoptions.StructToParams(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ret, err := modules.Servers.PerformAction(s, opts.ID, "monitor", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := ret.GetString("results")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type ServerDiskSnapshotOptions struct {
|
||||
SERVER string `help:"server ID or Name"`
|
||||
DISK string `help:"create snapshot disk id"`
|
||||
|
||||
@@ -840,6 +840,11 @@ type ServerGetCPUSetCoresResp struct {
|
||||
HostUsedCores []int `json:"host_used_cores"`
|
||||
}
|
||||
|
||||
type ServerMonitorInput struct {
|
||||
COMMAND string
|
||||
QMP bool
|
||||
}
|
||||
|
||||
type ServerQemuInfo struct {
|
||||
Version string `json:"version"`
|
||||
Cmdline string `json:"cmdline"`
|
||||
|
||||
@@ -422,7 +422,10 @@ func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *m
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) RequestSoftReset(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
|
||||
_, err := guest.SendMonitorCommand(ctx, task.GetUserCred(), "system_reset")
|
||||
_, err := guest.SendMonitorCommand(
|
||||
ctx, task.GetUserCred(),
|
||||
&api.ServerMonitorInput{COMMAND: "system_reset"},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -115,14 +115,13 @@ func (self *SGuest) PerformMonitor(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
input *api.ServerMonitorInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
if utils.IsInStringArray(self.Status, []string{api.VM_RUNNING, api.VM_BLOCK_STREAM, api.VM_MIGRATING}) {
|
||||
cmd, err := data.GetString("command")
|
||||
if err != nil {
|
||||
if input.COMMAND == "" {
|
||||
return nil, httperrors.NewMissingParameterError("command")
|
||||
}
|
||||
return self.SendMonitorCommand(ctx, userCred, cmd)
|
||||
return self.SendMonitorCommand(ctx, userCred, input)
|
||||
}
|
||||
return nil, httperrors.NewInvalidStatusError("Cannot send command in status %s", self.Status)
|
||||
}
|
||||
@@ -2927,7 +2926,7 @@ func (self *SGuest) PerformSendkeys(ctx context.Context, userCred mcclient.Token
|
||||
if err == nil {
|
||||
cmd = fmt.Sprintf("%s %d", cmd, duration)
|
||||
}
|
||||
_, err = self.SendMonitorCommand(ctx, userCred, cmd)
|
||||
_, err = self.SendMonitorCommand(ctx, userCred, &api.ServerMonitorInput{COMMAND: cmd})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2962,13 +2961,14 @@ func (self *SGuest) IsLegalKey(key string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SGuest) SendMonitorCommand(ctx context.Context, userCred mcclient.TokenCredential, cmd string) (jsonutils.JSONObject, error) {
|
||||
func (self *SGuest) SendMonitorCommand(ctx context.Context, userCred mcclient.TokenCredential, cmd *api.ServerMonitorInput) (jsonutils.JSONObject, error) {
|
||||
host, _ := self.GetHost()
|
||||
url := fmt.Sprintf("%s/servers/%s/monitor", host.ManagerUri, self.Id)
|
||||
header := http.Header{}
|
||||
header.Add("X-Auth-Token", userCred.GetTokenString())
|
||||
body := jsonutils.NewDict()
|
||||
body.Add(jsonutils.NewString(cmd), "cmd")
|
||||
body.Add(jsonutils.NewString(cmd.COMMAND), "cmd")
|
||||
body.Add(jsonutils.NewBool(cmd.QMP), "qmp")
|
||||
_, res, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -230,7 +230,8 @@ func guestMonitor(ctx context.Context, userCred mcclient.TokenCredential, sid st
|
||||
c <- res
|
||||
}
|
||||
cmd, _ := body.GetString("cmd")
|
||||
err := guestman.GetGuestManager().Monitor(sid, cmd, cb)
|
||||
qmp := jsonutils.QueryBoolean(body, "qmp", false)
|
||||
err := guestman.GetGuestManager().Monitor(sid, cmd, qmp, cb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
|
||||
@@ -396,13 +396,19 @@ func (m *SGuestManager) PrepareDeploy(sid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SGuestManager) Monitor(sid, cmd string, callback func(string)) error {
|
||||
func (m *SGuestManager) Monitor(sid, cmd string, qmp bool, callback func(string)) error {
|
||||
if guest, ok := m.GetServer(sid); ok {
|
||||
if guest.IsRunning() {
|
||||
if guest.Monitor == nil {
|
||||
return httperrors.NewBadRequestError("Monitor disconnected??")
|
||||
}
|
||||
guest.Monitor.HumanMonitorCommand(cmd, callback)
|
||||
if qmp {
|
||||
if err := guest.Monitor.QemuMonitorCommand(cmd, callback); err != nil {
|
||||
return errors.Wrap(err, "qemu monitor command")
|
||||
}
|
||||
} else {
|
||||
guest.Monitor.HumanMonitorCommand(cmd, callback)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return httperrors.NewBadRequestError("Server stopped??")
|
||||
|
||||
@@ -150,6 +150,7 @@ type Monitor interface {
|
||||
// The callback function will be called in another goroutine
|
||||
SimpleCommand(cmd string, callback StringCallback)
|
||||
HumanMonitorCommand(cmd string, callback StringCallback)
|
||||
QemuMonitorCommand(cmd string, callback StringCallback) error
|
||||
|
||||
QueryStatus(StringCallback)
|
||||
GetVersion(StringCallback)
|
||||
@@ -269,6 +270,10 @@ func (m *SBaseMonitor) IsConnected() bool {
|
||||
return m.connected
|
||||
}
|
||||
|
||||
func (m *SBaseMonitor) QemuMonitorCommand(cmd string, callback StringCallback) error {
|
||||
return errors.ErrNotSupported
|
||||
}
|
||||
|
||||
func (m *SBaseMonitor) checkReading() bool {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
@@ -348,6 +348,25 @@ func (m *QmpMonitor) SimpleCommand(cmd string, callback StringCallback) {
|
||||
m.Query(c, cb)
|
||||
}
|
||||
|
||||
func (m *QmpMonitor) QemuMonitorCommand(rawCmd string, callback StringCallback) error {
|
||||
c := Command{}
|
||||
if err := json.Unmarshal([]byte(rawCmd), &c); err != nil {
|
||||
return errors.Errorf("unsupport command format: %s", err)
|
||||
}
|
||||
|
||||
cb := func(res *Response) {
|
||||
log.Debugf("Monitor %s ret: %s", m.server, res.Return)
|
||||
if res.ErrorVal != nil {
|
||||
callback(res.ErrorVal.Error())
|
||||
} else {
|
||||
callback(strings.Trim(string(res.Return), `""`))
|
||||
}
|
||||
}
|
||||
|
||||
m.Query(&c, cb)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *QmpMonitor) HumanMonitorCommand(cmd string, callback StringCallback) {
|
||||
var (
|
||||
c = &Command{
|
||||
|
||||
@@ -779,10 +779,14 @@ func (o *ServerSendKeyOptions) Description() string {
|
||||
}
|
||||
|
||||
type ServerMonitorOptions struct {
|
||||
ID string `help:"ID or Name of server" json:"-"`
|
||||
ServerIdOptions
|
||||
|
||||
Qmp bool `help:"Use qmp protocol, default is hmp"`
|
||||
COMMAND string `help:"Qemu Monitor command to send"`
|
||||
Admin *bool `help:"Is this an admin call?"`
|
||||
}
|
||||
|
||||
func (o *ServerMonitorOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
|
||||
type ServerSaveImageOptions struct {
|
||||
|
||||
Reference in New Issue
Block a user