qmp

package module
v0.0.0-...-90e8b49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 12, 2020 License: MIT Imports: 11 Imported by: 0

README

go-qmp

GoDoc

Package go-qmp implements a QEMU Machine Protocol for the Go language.

Installation

go get github.com/0xef53/go-qmp

Example

Waiting for a virtual machine completion
mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}
defer mon.Close()

done := make(chan struct{})
go func() {
	ts := time.Now()
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	got, err := mon.GetEvents(ctx, "SHUTDOWN", uint64(ts.Unix()))
	if err != nil {
		log.Printf("Timeout error (type=%T): %s\n", err, err)
	} else {
		log.Printf("OK, got a SHUTDOWN event: %#v\n", got)
	}
	close(done)
}()

log.Println("Sleeping for three seconds ...")

time.Sleep(3 * time.Second)

log.Println("... and sending a 'system_powerdown' command.")

if err := mon.Run(Command{"system_powerdown", nil}, nil); err != nil {
	log.Fatalln(err)
}

<-done
Executing a command via human monitor
mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}

var out string

if err := mon.Run(Command{"human-monitor-command", &HumanCommand{"info vnc"}}, &out); err != nil {
	log.Fatalln(err)
}

fmt.Println(out)

Removing a device from a guest

Completion of the process is signaled with a DEVICE_DELETED event.

mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}

deviceID := struct {
	Id string `json:"id"`
}{
	"blk_alice",
}

ts := time.Now()
if err := mon.Run(Command{"device_del", &deviceID}, nil); err != nil {
	log.Fatalln("device_del error:", err)
}

// ... and wait until the operation is completed
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

switch _, err := mon.WaitDeviceDeletedEvent(ctx, "blk_alice", uint64(ts.Unix())); {
case err == nil:
case err == context.DeadlineExceeded:
	log.Fatalln("device_del timeout error: failed to complete within 60 seconds")
default:
	log.Fatalln(err)
}

Documentation

Use Godoc documentation for reference and usage.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrHandshake   = errors.New("QMP Handshake error: invalid greeting")
	ErrNegotiation = errors.New("QMP Handshake error: negotiations failed")

	ErrOperationCanceled = errors.New("Operation canceled: channel was closed")
)

Functions

func IsSocketClosed

func IsSocketClosed(err error) bool

func IsSocketNotAvailable

func IsSocketNotAvailable(err error) bool

func NewQMPError

func NewQMPError(err *GenericError) error

Types

type BlockJobCompletedEventData

type BlockJobCompletedEventData struct {
	Device     string `json:"device"`
	Type       string `json:"type"`
	ErrMessage string `json:"error"`
}

BlockJobCompletedEventData describes the properties of the BLOCK_JOB_COMPLETED event.

Emitted when a block job has completed.

type BlockJobErrorEventData

type BlockJobErrorEventData struct {
	Device    string `json:"device"`
	Operation string `json:"operation"`
	Action    string `json:"acton"`
}

BlockJobErrorEventData describes the properties of the BLOCK_JOB_ERROR event.

Emitted when a block job encounters an error.

type Command

type Command struct {
	Execute   string      `json:"execute"`
	Arguments interface{} `json:"arguments,omitempty"`
}

Command represents a QMP command. See https://wiki.qemu.org/QMP and https://github.com/qemu/qemu/blob/master/docs/interop/qmp-spec.txt

type CommandNotFound

type CommandNotFound interface {
	Error() string
}

CommandNotFound occurs when a requested command has not been found.

type DeviceDeletedEventData

type DeviceDeletedEventData struct {
	Device string `json:"device"`
	Path   string `json:"path"`
}

DeviceDeletedEventData describes the properties of the DEVICE_DELETED event.

Emitted whenever the device removal completion is acknowledged by the guest.

type DeviceNotActive

type DeviceNotActive interface {
	Error() string
}

DeviceNotActive occurs when a device has failed to be become active.

type DeviceNotFound

type DeviceNotFound interface {
	Error() string
}

DeviceNotFound occurs when a requested device has not been found.

type Event

type Event struct {
	// Type or name of event. E.g., BLOCK_JOB_COMPLETE.
	Type string `json:"event"`

	// Arbitrary event data.
	Data json.RawMessage `json:"data"`

	// Event timestamp, provided by QEMU.
	Timestamp struct {
		Seconds      uint64 `json:"seconds"`
		Microseconds uint64 `json:"microseconds"`
	} `json:"timestamp"`
}

Event represents a QMP asynchronous event.

type GenericError

type GenericError struct {
	Class string `json:"class"`
	Desc  string `json:"desc"`
}

GenericError represents a common structure for the QMP errors that could be accurred. This type also used for errors that doesn't have a specific class (for most of them in fact).

func (*GenericError) Error

func (err *GenericError) Error() string

type HumanCommand

type HumanCommand struct {
	Cmd string `json:"command-line"`
}

HumanCommand represents a query struct to execute a command over the human monitor.

type JobStatusChangeEventData

type JobStatusChangeEventData struct {
	JobID  string `json:"id"`
	Status string `json:"status"`
}

JobStatusChangeEventData describes the properties of the JOB_STATUS_CHANGE event.

Emitted when a job transitions to a different status.

type KVMMissingCap

type KVMMissingCap interface {
	Error() string
}

KVMMissingCap occurs when a requested operation can't be fulfilled because a required KVM capability is missing.

type Monitor

type Monitor struct {
	// contains filtered or unexported fields
}

Monitor represents a connection to communicate with the QMP interface using a UNIX socket.

Example

This example shows how to use the Monitor to communicate with a QEMU instance via QMP.

mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}
defer mon.Close()

done := make(chan struct{})
go func() {
	ts := time.Now()
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	got, err := mon.GetEvents(ctx, "SHUTDOWN", uint64(ts.Unix()))
	if err != nil {
		log.Printf("Timeout error (type=%T): %s\n", err, err)
	} else {
		log.Printf("OK, got a SHUTDOWN event: %#v\n", got)
	}
	close(done)
}()

log.Println("Sleeping for three seconds ...")

time.Sleep(3 * time.Second)

log.Println("... and sending a 'system_powerdown' command.")

if err := mon.Run(Command{"system_powerdown", nil}, nil); err != nil {
	log.Fatalln(err)
}

<-done
Output:

func NewMonitor

func NewMonitor(path string, timeout time.Duration) (*Monitor, error)

NewMonitor creates and configures a connection to the QEMU monitor using a UNIX socket. An error is returned if the socket cannot be successfully dialed, or the dial attempt times out.

Multiple connections to the same QMP socket are not permitted, and will result in the monitor blocking until the existing connection is closed.

func (*Monitor) Close

func (m *Monitor) Close() error

Close closes the QMP connection and releases all resources.

After this call any interaction with the monitor will generate an error of type net.OpError.

func (*Monitor) FindBlockJobCompletedEvent

func (m *Monitor) FindBlockJobCompletedEvent(device string, after uint64) (*Event, bool, error)

FindBlockJobCompletedEvent tries to find a BLOCK_JOB_COMPLETED event for the specified device.

func (*Monitor) FindBlockJobErrorEvent

func (m *Monitor) FindBlockJobErrorEvent(device string, after uint64) (*Event, bool, error)

FindBlockJobErrorEvent tries to find a BLOCK_JOB_ERROR for the specified device.

func (*Monitor) FindEvents

func (m *Monitor) FindEvents(t string, after uint64) ([]Event, bool)

FindEvents tries to find in the buffer at least one event of the specified type that occurred after the specified Unix time (in seconds). If no matches found, the second return value will be false.

func (*Monitor) GetEvents

func (m *Monitor) GetEvents(ctx context.Context, t string, after uint64) ([]Event, error)

GetEvents returns an event list of the specified type that occurred after the specified Unix time (in seconds). If there are events in the buffer, then GetEvents will return them. Otherwise, the function will wait for the first event until the context is closed (manually or using context.WithTimeout).

func (*Monitor) Run

func (m *Monitor) Run(cmd interface{}, res interface{}) error

Run executes the given QAPI command.

Example

An example of executing a command via human monitor.

mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}

var out string

if err := mon.Run(Command{"human-monitor-command", &HumanCommand{"info vnc"}}, &out); err != nil {
	log.Fatalln(err)
}

fmt.Println(out)
Output:

func (*Monitor) RunHuman

func (m *Monitor) RunHuman(cmdline string) (string, error)

RunHuman executes a command using "human-monitor-command".

func (*Monitor) WaitDeviceDeletedEvent

func (m *Monitor) WaitDeviceDeletedEvent(ctx context.Context, device string, after uint64) (*Event, error)
Example

An example of removing a device from a guest. Completion of the process is signaled with a DEVICE_DELETED event.

mon, err := NewMonitor("/var/run/qemu/alice.qmp", 60*time.Second)
if err != nil {
	log.Fatalln(err)
}

deviceID := struct {
	Id string `json:"id"`
}{
	"blk_alice",
}

ts := time.Now()
if err := mon.Run(Command{"device_del", &deviceID}, nil); err != nil {
	log.Fatalln("device_del error:", err)
}

// ... and wait until the operation is completed
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

switch _, err := mon.WaitDeviceDeletedEvent(ctx, "blk_alice", uint64(ts.Unix())); {
case err == nil:
case err == context.DeadlineExceeded:
	log.Fatalln("device_del timeout error: failed to complete within 60 seconds")
default:
	log.Fatalln(err)
}
Output:

func (*Monitor) WaitJobStatusChangeEvent

func (m *Monitor) WaitJobStatusChangeEvent(ctx context.Context, jobID, status string, after uint64) (*Event, error)

WaitJobStatusChangeEvent waits a JOB_STATUS_CHANGE event for the specified job ID.

type Response

type Response struct {
	// Contains the data returned by the command.
	Return *json.RawMessage `json:"return"`

	// Contains details about an error that occurred.
	Error *GenericError `json:"error"`

	// A status change notification message
	// that can be sent unilaterally by the QMP server.
	Event *json.RawMessage `json:"event"`

	// A greeting message that is sent once when
	// a new QMP connection is established.
	Greeting *json.RawMessage `json:"QMP"`
}

Response represents a common structure of QMP response.

type Version

type Version struct {
	Package string `json:"package"`
	QEMU    struct {
		Major int `json:"major"`
		Micro int `json:"micro"`
		Minor int `json:"minor"`
	} `json:"qemu"`
}

Version represents a QEMU version structure returned when a QMP connection is initiated.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL