diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 4621ee6..22e2eea 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -44,6 +44,7 @@ const ( ProcAuthList = 66 ProcConnectGetLibVersion = 157 ProcDomainMigrateSetMaxSpeed = 207 + ProcDomainGetState = 212 ProcDomainUndefineFlags = 231 ProcDomainDestroyFlags = 234 ProcConnectListAllDomains = 273 diff --git a/libvirt.go b/libvirt.go index fb3be48..795e776 100644 --- a/libvirt.go +++ b/libvirt.go @@ -170,6 +170,31 @@ const ( DestroyFlagGraceful ) +// DomainState specifies state of the domain +type DomainState uint32 + +const ( + // DomainStateNoState No state + DomainStateNoState = iota + // DomainStateRunning The domain is running + DomainStateRunning + // DomainStateBlocked The domain is blocked on resource + DomainStateBlocked + // DomainStatePaused The domain is paused by user + DomainStatePaused + // DomainStateShutdown The domain is being shut down + DomainStateShutdown + // DomainStateShutoff The domain is shut off + DomainStateShutoff + // DomainStateCrashed The domain is crashed + DomainStateCrashed + // DomainStatePMSuspended The domain is suspended by guest power management + DomainStatePMSuspended + // DomainStateLast This value will increase over time as new events are added to the libvirt + // API. It reflects the last state supported by this version of the libvirt API. + DomainStateLast +) + // Capabilities returns an XML document describing the host's capabilties. func (l *Libvirt) Capabilities() ([]byte, error) { resp, err := l.request(constants.ProcConnectGetCapabilties, constants.ProgramRemote, nil) @@ -253,6 +278,50 @@ func (l *Libvirt) Domains() ([]Domain, error) { return result.Domains, nil } +// DomainState returns state of the domain managed by libvirt. +func (l *Libvirt) DomainState(dom string) (DomainState, error) { + d, err := l.lookup(dom) + if err != nil { + return DomainStateNoState, err + } + + req := struct { + Domain Domain + Flags uint32 + }{ + Domain: *d, + Flags: 0, + } + + buf, err := encode(&req) + if err != nil { + return DomainStateNoState, err + } + + resp, err := l.request(constants.ProcDomainGetState, constants.ProgramRemote, &buf) + if err != nil { + return DomainStateNoState, err + } + + r := <-resp + if r.Status != StatusOK { + return DomainStateNoState, decodeError(r.Payload) + } + + result := struct { + State uint32 + Reason uint32 + }{} + + dec := xdr.NewDecoder(bytes.NewReader(r.Payload)) + _, err = dec.Decode(&result) + if err != nil { + return DomainStateNoState, err + } + + return DomainState(result.State), nil +} + // Events streams domain events. // If a problem is encountered setting up the event monitor connection // an error will be returned. Errors encountered during streaming will diff --git a/libvirt_test.go b/libvirt_test.go index 9cfc241..871bbab 100644 --- a/libvirt_test.go +++ b/libvirt_test.go @@ -117,6 +117,21 @@ func TestDomains(t *testing.T) { } } +func TestDomainState(t *testing.T) { + conn := libvirttest.New() + l := New(conn) + + wantState := DomainState(DomainStateRunning) + gotState, err := l.DomainState("test") + if err != nil { + t.Error(err) + } + + if gotState != wantState { + t.Errorf("expected domain state %d, got %d", wantState, gotState) + } +} + func TestEvents(t *testing.T) { conn := libvirttest.New() l := New(conn) diff --git a/libvirttest/libvirt.go b/libvirttest/libvirt.go index c22aa51..1528960 100644 --- a/libvirttest/libvirt.go +++ b/libvirttest/libvirt.go @@ -205,6 +205,18 @@ var testDomainsReply = []byte{ 0x00, 0x00, 0x02, } +var testDomainStateReply = []byte{ + 0x00, 0x00, 0x00, 0x24, // length + 0x20, 0x00, 0x80, 0x86, // program + 0x00, 0x00, 0x00, 0x01, // version + 0x00, 0x00, 0x00, 0xd4, // procedure + 0x00, 0x00, 0x00, 0x01, // type + 0x00, 0x00, 0x00, 0x00, // serial + 0x00, 0x00, 0x00, 0x00, // status + 0x00, 0x00, 0x00, 0x01, // state + 0x00, 0x00, 0x00, 0x01, // reason +} + var testUndefineReply = []byte{ 0x00, 0x00, 0x00, 0x1c, // length 0x20, 0x00, 0x80, 0x86, // program @@ -293,6 +305,8 @@ func (m *MockLibvirt) handleRemote(procedure uint32, conn net.Conn) { conn.Write(m.reply(testDomainResponse)) case constants.ProcConnectListAllDomains: conn.Write(m.reply(testDomainsReply)) + case constants.ProcDomainGetState: + conn.Write(m.reply(testDomainStateReply)) case constants.ProcDomainMigrateSetMaxSpeed: conn.Write(m.reply(testSetSpeedReply)) case constants.ProcMigratePerformParams: