Adding basic wrappers
- Wrapper for Host connection called Host - Allows for easier usage of the API - Wrapper for Domains called GuestVM, which pulls VM information and allows other functionality in a better way
This commit is contained in:
parent
bab4f2506b
commit
4ecf05bf82
18
README.md
18
README.md
@ -54,3 +54,21 @@ Overall goals:
|
||||
- Connection management (to other libvirt hosts)
|
||||
- Create a simple WebUI with HTMX to monitor that stuff
|
||||
- Add the ability to manage that stuff once we can monitor it, through the WebUI.
|
||||
|
||||
## Special XMLNS definitions
|
||||
|
||||
### Domain
|
||||
|
||||
- `xmlns:clustvirt="https://git.staur.ca/stobbsm/clustvirt"`
|
||||
|
||||
```xml
|
||||
<metadata>
|
||||
<clustvirt:data xmlns:clustvirt="https://git.staur.ca/stobbsm/clustvirt/">
|
||||
<clustvirt:created>true</clustvirt:created>
|
||||
<clustvirt:managed>true</clustvirt:managed>
|
||||
<clustvirt:currentHost>host01</clustvirt:currentHost>
|
||||
<clustvirt:origHost>host02</clustvirt:origHost>
|
||||
<clustvirt:baseGuest>rocky-9-base</clustvirt:baseGuest>
|
||||
</clustvirt:data>
|
||||
</metadata>
|
||||
```
|
||||
|
53
domains.go
Normal file
53
domains.go
Normal file
@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
// GuestVM holds a handle is used to communicate to Domains
|
||||
type GuestVM struct {
|
||||
Name string
|
||||
ID uint
|
||||
BackupXML string
|
||||
|
||||
close chan struct{}
|
||||
closeErr chan error
|
||||
dom *libvirt.Domain
|
||||
}
|
||||
|
||||
// GetGuest loads guest information by name and returns it
|
||||
func GetGuest(name string, conn *libvirt.Connect) (*GuestVM, error) {
|
||||
g := &GuestVM{
|
||||
Name: name,
|
||||
close: make(chan struct{}),
|
||||
closeErr: make(chan error),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if g.dom, err = conn.LookupDomainByName(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if g.ID, err = g.dom.GetID(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if g.BackupXML, err = g.dom.BackupGetXMLDesc(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(g.closeErr)
|
||||
<-g.close
|
||||
g.closeErr <- g.dom.Free()
|
||||
}()
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// Close closes an open connection
|
||||
func (g *GuestVM) Close() error {
|
||||
close(g.close)
|
||||
return <-g.closeErr
|
||||
}
|
69
host.go
Normal file
69
host.go
Normal file
@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
// Host holds information and acts as a connection handle for a Host
|
||||
// If a connection is closed prematurely, will re-open the connection and
|
||||
// try the attempted method again
|
||||
type Host struct {
|
||||
HostName string
|
||||
|
||||
conn *libvirt.Connect
|
||||
close chan struct{}
|
||||
closeErr chan error
|
||||
}
|
||||
|
||||
// ConnectHost creates a host connection wrapper that can be used regularly
|
||||
func ConnectHost(host string) (*Host, error) {
|
||||
h := &Host{
|
||||
HostName: host,
|
||||
}
|
||||
|
||||
if err := h.connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.close = make(chan struct{})
|
||||
h.closeErr = make(chan error)
|
||||
|
||||
go func() {
|
||||
defer close(h.closeErr)
|
||||
<-h.close
|
||||
_, err := h.conn.Close()
|
||||
h.closeErr <- err
|
||||
}()
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// connect creates a host connection
|
||||
func (h *Host) connect() error {
|
||||
var err error
|
||||
h.conn, err = libvirt.NewConnect(
|
||||
fmt.Sprintf("qemu+ssh://%s/system", h.HostName),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetGuestByName returns a GuestVM instance that exists on the given host
|
||||
func (h *Host) GetGuestByName(name string) (*GuestVM, error) {
|
||||
if g, err := GetGuest(name, h.conn); err == nil {
|
||||
return g, nil
|
||||
} else {
|
||||
lverr, ok := err.(libvirt.Error)
|
||||
if ok && lverr.Code == libvirt.ERR_INVALID_CONN {
|
||||
// try again after creating a new connection
|
||||
return GetGuest(name, h.conn)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Close triggers closing the host connection
|
||||
func (h *Host) Close() error {
|
||||
close(h.close)
|
||||
return <-h.closeErr
|
||||
}
|
16
main.go
16
main.go
@ -2,23 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"libvirt.org/go/libvirt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Starting clustvirt, the libvirt cluster manager")
|
||||
|
||||
// Try connecting to libvirt
|
||||
conn, err := libvirt.NewConnect("qemu+ssh://earth.staur.ca/system")
|
||||
doms, err := GetDomsInCluster("earth.staur.ca", "mars.staur.ca", "venus.staur.ca")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
doms, err := conn.ListAllDomains(libvirt.CONNECT_LIST_DOMAINS_ACTIVE | libvirt.CONNECT_LIST_DOMAINS_INACTIVE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Printf("Domains in cluster: %d", len(doms))
|
||||
// Example of xmlns uri found in libvirt xml definition:
|
||||
// xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0"
|
||||
for _, d := range doms {
|
||||
log.Println(d.GetMetadata(0, "", 0))
|
||||
d.Free()
|
||||
}
|
||||
log.Printf("Domains on earth: %d", len(doms))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user