resources: virt: convert to use github.com/libvirt/libvirt-go

Convert the code to use the new libvirt Go bindings.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange
2016-12-22 10:40:39 +00:00
committed by James Shubin
parent ecc4aa09d3
commit 0b416e44f8
2 changed files with 62 additions and 53 deletions

View File

@@ -72,7 +72,7 @@ go get github.com/urfave/cli
go get github.com/coreos/go-systemd/dbus go get github.com/coreos/go-systemd/dbus
go get github.com/coreos/go-systemd/util go get github.com/coreos/go-systemd/util
go get github.com/coreos/pkg/capnslog go get github.com/coreos/pkg/capnslog
go get github.com/rgbkrk/libvirt-go go get github.com/libvirt/libvirt-go
``` ```
* stringer (optional for building), available as a package on some platforms, otherwise via `go get` * stringer (optional for building), available as a package on some platforms, otherwise via `go get`
``` ```

View File

@@ -27,8 +27,8 @@ import (
"github.com/purpleidea/mgmt/event" "github.com/purpleidea/mgmt/event"
"github.com/libvirt/libvirt-go"
errwrap "github.com/pkg/errors" errwrap "github.com/pkg/errors"
"github.com/rgbkrk/libvirt-go"
) )
func init() { func init() {
@@ -60,7 +60,7 @@ type VirtRes struct {
URI string `yaml:"uri"` // connection uri, eg: qemu:///session URI string `yaml:"uri"` // connection uri, eg: qemu:///session
State string `yaml:"state"` // running, paused, shutoff State string `yaml:"state"` // running, paused, shutoff
Transient bool `yaml:"transient"` // defined (false) or undefined (true) Transient bool `yaml:"transient"` // defined (false) or undefined (true)
CPUs uint16 `yaml:"cpus"` CPUs uint `yaml:"cpus"`
Memory uint64 `yaml:"memory"` // in KBytes Memory uint64 `yaml:"memory"` // in KBytes
OSInit string `yaml:"osinit"` // init used by lxc OSInit string `yaml:"osinit"` // init used by lxc
Boot []string `yaml:"boot"` // boot order. values: fd, hd, cdrom, network Boot []string `yaml:"boot"` // boot order. values: fd, hd, cdrom, network
@@ -70,13 +70,13 @@ type VirtRes struct {
Filesystem []filesystemDevice `yaml:"filesystem"` Filesystem []filesystemDevice `yaml:"filesystem"`
Auth *VirtAuth `yaml:"auth"` Auth *VirtAuth `yaml:"auth"`
conn libvirt.VirConnection conn *libvirt.Connect
absent bool // cached state absent bool // cached state
uriScheme virtURISchemeType uriScheme virtURISchemeType
} }
// NewVirtRes is a constructor for this resource. It also calls Init() for you. // NewVirtRes is a constructor for this resource. It also calls Init() for you.
func NewVirtRes(name string, uri, state string, transient bool, cpus uint16, memory uint64, osinit string) (*VirtRes, error) { func NewVirtRes(name string, uri, state string, transient bool, cpus uint, memory uint64, osinit string) (*VirtRes, error) {
obj := &VirtRes{ obj := &VirtRes{
BaseRes: BaseRes{ BaseRes: BaseRes{
Name: name, Name: name,
@@ -120,12 +120,31 @@ func (obj *VirtRes) Validate() error {
return nil return nil
} }
func (obj *VirtRes) connect() (conn libvirt.VirConnection, err error) { func (obj *VirtRes) connect() (conn *libvirt.Connect, err error) {
if obj.Auth != nil { if obj.Auth != nil {
conn, err = libvirt.NewVirConnectionWithAuth(obj.URI, obj.Auth.Username, obj.Auth.Password) callback := func(creds []*libvirt.ConnectCredential) {
// Populate credential structs with the
// prepared username/password values
for _, cred := range creds {
if cred.Type == libvirt.CRED_AUTHNAME {
cred.Result = obj.Auth.Username
cred.ResultLen = len(cred.Result)
} else if cred.Type == libvirt.CRED_PASSPHRASE {
cred.Result = obj.Auth.Password
cred.ResultLen = len(cred.Result)
}
}
}
auth := &libvirt.ConnectAuth{
CredType: []libvirt.ConnectCredentialType{
libvirt.CRED_AUTHNAME, libvirt.CRED_PASSPHRASE,
},
Callback: callback,
}
conn, err = libvirt.NewConnectWithAuth(obj.URI, auth, 0)
} }
if obj.Auth == nil || err != nil { if obj.Auth == nil || err != nil {
conn, err = libvirt.NewVirConnection(obj.URI) conn, err = libvirt.NewConnect(obj.URI)
} }
return return
} }
@@ -139,7 +158,7 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
return fmt.Errorf("Connection to libvirt failed with: %s", err) return fmt.Errorf("Connection to libvirt failed with: %s", err)
} }
eventChan := make(chan int) // TODO: do we need to buffer this? eventChan := make(chan libvirt.DomainEventType) // TODO: do we need to buffer this?
errorChan := make(chan error) errorChan := make(chan error)
exitChan := make(chan struct{}) exitChan := make(chan struct{})
defer close(exitChan) defer close(exitChan)
@@ -167,25 +186,16 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
} }
}() }()
callback := libvirt.DomainEventCallback( callback := func(c *libvirt.Connect, d *libvirt.Domain, ev *libvirt.DomainEventLifecycle) {
func(c *libvirt.VirConnection, d *libvirt.VirDomain, eventDetails interface{}, f func()) int {
if lifecycleEvent, ok := eventDetails.(libvirt.DomainLifecycleEvent); ok {
domName, _ := d.GetName() domName, _ := d.GetName()
if domName == obj.GetName() { if domName == obj.GetName() {
eventChan <- lifecycleEvent.Event eventChan <- ev.Event
} }
} else if obj.debug {
log.Printf("%s[%s]: Event details isn't DomainLifecycleEvent", obj.Kind(), obj.GetName())
} }
return 0 callbackID, err := conn.DomainEventLifecycleRegister(nil, callback)
}, if err != nil {
) return err
callbackID := conn.DomainEventRegister( }
libvirt.VirDomain{},
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
&callback,
nil,
)
defer conn.DomainEventDeregister(callbackID) defer conn.DomainEventDeregister(callbackID)
// notify engine that we're running // notify engine that we're running
@@ -201,38 +211,38 @@ func (obj *VirtRes) Watch(processChan chan event.Event) error {
case event := <-eventChan: case event := <-eventChan:
// TODO: shouldn't we do these checks in CheckApply ? // TODO: shouldn't we do these checks in CheckApply ?
switch event { switch event {
case libvirt.VIR_DOMAIN_EVENT_DEFINED: case libvirt.DOMAIN_EVENT_DEFINED:
if obj.Transient { if obj.Transient {
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_UNDEFINED: case libvirt.DOMAIN_EVENT_UNDEFINED:
if !obj.Transient { if !obj.Transient {
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_STARTED: case libvirt.DOMAIN_EVENT_STARTED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_RESUMED: case libvirt.DOMAIN_EVENT_RESUMED:
if obj.State != "running" { if obj.State != "running" {
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_SUSPENDED: case libvirt.DOMAIN_EVENT_SUSPENDED:
if obj.State != "paused" { if obj.State != "paused" {
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_STOPPED: case libvirt.DOMAIN_EVENT_STOPPED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_SHUTDOWN: case libvirt.DOMAIN_EVENT_SHUTDOWN:
if obj.State != "shutoff" { if obj.State != "shutoff" {
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
case libvirt.VIR_DOMAIN_EVENT_PMSUSPENDED: case libvirt.DOMAIN_EVENT_PMSUSPENDED:
fallthrough fallthrough
case libvirt.VIR_DOMAIN_EVENT_CRASHED: case libvirt.DOMAIN_EVENT_CRASHED:
obj.StateOK(false) // dirty obj.StateOK(false) // dirty
send = true send = true
} }
@@ -281,7 +291,7 @@ func (obj *VirtRes) attrCheckApply(apply bool) (bool, error) {
} }
// check memory // check memory
if domInfo.GetMemory() != obj.Memory { if domInfo.Memory != obj.Memory {
checkOK = false checkOK = false
if !apply { if !apply {
return false, nil return false, nil
@@ -293,7 +303,7 @@ func (obj *VirtRes) attrCheckApply(apply bool) (bool, error) {
} }
// check cpus // check cpus
if domInfo.GetNrVirtCpu() != obj.CPUs { if domInfo.NrVirtCpu != obj.CPUs {
checkOK = false checkOK = false
if !apply { if !apply {
return false, nil return false, nil
@@ -309,21 +319,21 @@ func (obj *VirtRes) attrCheckApply(apply bool) (bool, error) {
// domainCreate creates a transient or persistent domain in the correct state. It // domainCreate creates a transient or persistent domain in the correct state. It
// doesn't check the state before hand, as it is a simple helper function. // doesn't check the state before hand, as it is a simple helper function.
func (obj *VirtRes) domainCreate() (libvirt.VirDomain, bool, error) { func (obj *VirtRes) domainCreate() (*libvirt.Domain, bool, error) {
if obj.Transient { if obj.Transient {
var flag uint32 var flag libvirt.DomainCreateFlags
var state string var state string
switch obj.State { switch obj.State {
case "running": case "running":
flag = libvirt.VIR_DOMAIN_NONE flag = libvirt.DOMAIN_NONE
state = "started" state = "started"
case "paused": case "paused":
flag = libvirt.VIR_DOMAIN_START_PAUSED flag = libvirt.DOMAIN_START_PAUSED
state = "paused" state = "paused"
case "shutoff": case "shutoff":
// a transient, shutoff machine, means machine is absent // a transient, shutoff machine, means machine is absent
return libvirt.VirDomain{}, true, nil // returned dom is invalid return nil, true, nil // returned dom is invalid
} }
dom, err := obj.conn.DomainCreateXML(obj.getDomainXML(), flag) dom, err := obj.conn.DomainCreateXML(obj.getDomainXML(), flag)
if err != nil { if err != nil {
@@ -347,7 +357,7 @@ func (obj *VirtRes) domainCreate() (libvirt.VirDomain, bool, error) {
} }
if obj.State == "paused" { if obj.State == "paused" {
if err := dom.CreateWithFlags(libvirt.VIR_DOMAIN_START_PAUSED); err != nil { if err := dom.CreateWithFlags(libvirt.DOMAIN_START_PAUSED); err != nil {
return dom, false, err return dom, false, err
} }
log.Printf("%s[%s]: Domain created paused", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: Domain created paused", obj.Kind(), obj.GetName())
@@ -370,7 +380,7 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
dom, err := obj.conn.LookupDomainByName(obj.GetName()) dom, err := obj.conn.LookupDomainByName(obj.GetName())
if err == nil { if err == nil {
// pass // pass
} else if virErr, ok := err.(libvirt.VirError); ok && virErr.Code == libvirt.VIR_ERR_NO_DOMAIN { } else if virErr, ok := err.(libvirt.Error); ok && virErr.Code == libvirt.ERR_NO_DOMAIN {
// domain not found // domain not found
if obj.absent { if obj.absent {
return true, nil return true, nil
@@ -421,7 +431,7 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
} }
log.Printf("%s[%s]: Domain undefined", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: Domain undefined", obj.Kind(), obj.GetName())
} else { } else {
domXML, err := dom.GetXMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE) domXML, err := dom.GetXMLDesc(libvirt.DOMAIN_XML_INACTIVE)
if err != nil { if err != nil {
return false, errwrap.Wrapf(err, "domain.GetXMLDesc failed") return false, errwrap.Wrapf(err, "domain.GetXMLDesc failed")
} }
@@ -434,13 +444,12 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
} }
// check for valid state // check for valid state
domState := domInfo.GetState()
switch obj.State { switch obj.State {
case "running": case "running":
if domState == libvirt.VIR_DOMAIN_RUNNING { if domInfo.State == libvirt.DOMAIN_RUNNING {
break break
} }
if domState == libvirt.VIR_DOMAIN_BLOCKED { if domInfo.State == libvirt.DOMAIN_BLOCKED {
// TODO: what should happen? // TODO: what should happen?
return false, fmt.Errorf("Domain %s is blocked!", obj.GetName()) return false, fmt.Errorf("Domain %s is blocked!", obj.GetName())
} }
@@ -462,7 +471,7 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
log.Printf("%s[%s]: Domain created", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: Domain created", obj.Kind(), obj.GetName())
case "paused": case "paused":
if domState == libvirt.VIR_DOMAIN_PAUSED { if domInfo.State == libvirt.DOMAIN_PAUSED {
break break
} }
if !apply { if !apply {
@@ -476,14 +485,14 @@ func (obj *VirtRes) CheckApply(apply bool) (bool, error) {
log.Printf("%s[%s]: Domain paused", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: Domain paused", obj.Kind(), obj.GetName())
break break
} }
if err := dom.CreateWithFlags(libvirt.VIR_DOMAIN_START_PAUSED); err != nil { if err := dom.CreateWithFlags(libvirt.DOMAIN_START_PAUSED); err != nil {
return false, errwrap.Wrapf(err, "domain.CreateWithFlags failed") return false, errwrap.Wrapf(err, "domain.CreateWithFlags failed")
} }
checkOK = false checkOK = false
log.Printf("%s[%s]: Domain created paused", obj.Kind(), obj.GetName()) log.Printf("%s[%s]: Domain created paused", obj.Kind(), obj.GetName())
case "shutoff": case "shutoff":
if domState == libvirt.VIR_DOMAIN_SHUTOFF || domState == libvirt.VIR_DOMAIN_SHUTDOWN { if domInfo.State == libvirt.DOMAIN_SHUTOFF || domInfo.State == libvirt.DOMAIN_SHUTDOWN {
break break
} }
if !apply { if !apply {