Add qvm doctor command to diagnose and fix common issues
This commit is contained in:
parent
2aec01b3b2
commit
eb469f1cd8
8 changed files with 660 additions and 170 deletions
|
|
@ -73,3 +73,88 @@ func (c *Client) Shutdown() mo.Result[struct{}] {
|
|||
func (c *Client) Close() error {
|
||||
return c.monitor.Disconnect()
|
||||
}
|
||||
|
||||
// AddChardev adds a vhost-user-fs chardev for a virtiofsd socket.
|
||||
// This is the first step of hot-mounting a filesystem.
|
||||
func (c *Client) AddChardev(id, socketPath string) mo.Result[struct{}] {
|
||||
cmd := fmt.Sprintf(`{"execute":"chardev-add","arguments":{"id":"%s","backend":{"type":"socket","data":{"addr":{"type":"unix","data":{"path":"%s"}},"server":false}}}}`, id, socketPath)
|
||||
raw, err := c.monitor.Run([]byte(cmd))
|
||||
if err != nil {
|
||||
return mo.Err[struct{}](fmt.Errorf("failed to add chardev %s: %w", id, err))
|
||||
}
|
||||
|
||||
// Check for error in response
|
||||
var resp map[string]interface{}
|
||||
if err := json.Unmarshal(raw, &resp); err == nil {
|
||||
if errObj, ok := resp["error"]; ok {
|
||||
return mo.Err[struct{}](fmt.Errorf("QMP error adding chardev: %v", errObj))
|
||||
}
|
||||
}
|
||||
|
||||
return mo.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// AddVhostUserFsDevice adds a vhost-user-fs-pci device connected to a chardev.
|
||||
// This is the second step of hot-mounting a filesystem.
|
||||
func (c *Client) AddVhostUserFsDevice(chardevID, tag string) mo.Result[struct{}] {
|
||||
// Device ID must be unique, derive from chardev ID
|
||||
deviceID := "dev_" + chardevID
|
||||
cmd := fmt.Sprintf(`{"execute":"device_add","arguments":{"driver":"vhost-user-fs-pci","chardev":"%s","tag":"%s","id":"%s","queue-size":1024}}`, chardevID, tag, deviceID)
|
||||
raw, err := c.monitor.Run([]byte(cmd))
|
||||
if err != nil {
|
||||
return mo.Err[struct{}](fmt.Errorf("failed to add vhost-user-fs device for %s: %w", tag, err))
|
||||
}
|
||||
|
||||
// Check for error in response
|
||||
var resp map[string]interface{}
|
||||
if err := json.Unmarshal(raw, &resp); err == nil {
|
||||
if errObj, ok := resp["error"]; ok {
|
||||
return mo.Err[struct{}](fmt.Errorf("QMP error adding device: %v", errObj))
|
||||
}
|
||||
}
|
||||
|
||||
return mo.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// HotMountFilesystem performs a complete hot-mount of a virtiofsd filesystem.
|
||||
// Requires the virtiofsd daemon to already be running and listening on socketPath.
|
||||
func (c *Client) HotMountFilesystem(tag, socketPath string) mo.Result[struct{}] {
|
||||
// Use tag as chardev ID for simplicity
|
||||
chardevID := tag
|
||||
|
||||
// Step 1: Add chardev
|
||||
if result := c.AddChardev(chardevID, socketPath); result.IsError() {
|
||||
return result
|
||||
}
|
||||
|
||||
// Step 2: Add device
|
||||
if result := c.AddVhostUserFsDevice(chardevID, tag); result.IsError() {
|
||||
return result
|
||||
}
|
||||
|
||||
return mo.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// QueryChardevs lists all current chardevs to check if one exists.
|
||||
func (c *Client) QueryChardevs() mo.Result[[]string] {
|
||||
cmd := []byte(`{"execute":"query-chardev"}`)
|
||||
raw, err := c.monitor.Run(cmd)
|
||||
if err != nil {
|
||||
return mo.Err[[]string](fmt.Errorf("failed to query chardevs: %w", err))
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Return []struct {
|
||||
Label string `json:"label"`
|
||||
} `json:"return"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &resp); err != nil {
|
||||
return mo.Err[[]string](fmt.Errorf("failed to parse chardev response: %w", err))
|
||||
}
|
||||
|
||||
var labels []string
|
||||
for _, c := range resp.Return {
|
||||
labels = append(labels, c.Label)
|
||||
}
|
||||
return mo.Ok(labels)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue