Merge pull request #14638 from wanyaoqi/feature/server-monitor-support-qmp

feat(region,host): server-monitor support qmp
This commit is contained in:
Zexi Li
2022-07-15 10:54:33 +08:00
committed by GitHub
9 changed files with 57 additions and 30 deletions
+1 -17
View File
@@ -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"`
+5
View File
@@ -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"`
+4 -1
View File
@@ -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
}
+7 -7
View File
@@ -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 {
+8 -2
View File
@@ -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??")
+5
View File
@@ -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()
+19
View File
@@ -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{
+6 -2
View File
@@ -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 {