refactor from all in main to lib
- lib/guest is for managing, displaying, etc. virtual machines - lib/host is the same for hosts
This commit is contained in:
parent
4ecf05bf82
commit
5b16a75bdf
53
domains.go
53
domains.go
@ -1,53 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
221
lib/guest/domains.go
Normal file
221
lib/guest/domains.go
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
// Package guest implements utilities and structured data for libvirt virtual machines
|
||||||
|
package guest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"libvirt.org/go/libvirt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
|
||||||
|
// ErrVMNotFound error when virtual machine is not found
|
||||||
|
var ErrVMNotFound = errors.New("virtual machine not found")
|
||||||
|
|
||||||
|
// VM holds a handle is used to communicate to Domains
|
||||||
|
type VM struct {
|
||||||
|
Name string
|
||||||
|
HostName string
|
||||||
|
ID uint
|
||||||
|
BackupXML string
|
||||||
|
Autostart bool
|
||||||
|
BlockIOParameters BlockIOParametersInfo
|
||||||
|
Disks []DiskInfo
|
||||||
|
Users []UserInfo
|
||||||
|
OS OSInfo
|
||||||
|
TimeZone TimeZoneInfo
|
||||||
|
NetIFace []NetIFaceInfo
|
||||||
|
|
||||||
|
close chan struct{}
|
||||||
|
closeErr chan error
|
||||||
|
dom *libvirt.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockIOParametersInfo is the struct describing VM block IO parameters
|
||||||
|
type BlockIOParametersInfo struct {
|
||||||
|
Weight uint
|
||||||
|
DeviceWeight string
|
||||||
|
DeviceReadIops string
|
||||||
|
DeviceWriteIops string
|
||||||
|
DeviceReadBps string
|
||||||
|
DeviceWriteBps string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiskInfo is the struct for guest disk information, and is used in VM
|
||||||
|
type DiskInfo struct {
|
||||||
|
Name string
|
||||||
|
Partition bool
|
||||||
|
Alias string
|
||||||
|
GuestAlias string
|
||||||
|
DiskDependency []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserInfo is the struct for VM user information, and is used in VM
|
||||||
|
type UserInfo struct {
|
||||||
|
Name string
|
||||||
|
Domain string
|
||||||
|
LoginTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// OSInfo is the struct for guest operating system information, and is used in VM
|
||||||
|
type OSInfo struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
PrettyName string
|
||||||
|
Version string
|
||||||
|
VersionID string
|
||||||
|
KernelRelease string
|
||||||
|
KernelVersion string
|
||||||
|
Machine string
|
||||||
|
Variant string
|
||||||
|
VariantID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeZoneInfo provides guest timezone information, and is used in VM
|
||||||
|
type TimeZoneInfo struct {
|
||||||
|
Name string
|
||||||
|
Offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetIFaceInfo provides guest Network Interface information, and is used in VM
|
||||||
|
type NetIFaceInfo struct {
|
||||||
|
Name string
|
||||||
|
HWAddr string
|
||||||
|
IP []IPInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPInfo provides guest IP network information, and is used in NetIFaceInfo
|
||||||
|
type IPInfo struct {
|
||||||
|
Type string
|
||||||
|
Addr string
|
||||||
|
Prefix uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGuest loads guest information by name and returns it
|
||||||
|
func GetGuest(name string, conn *libvirt.Connect) (*VM, error) {
|
||||||
|
g := &VM{
|
||||||
|
Name: name,
|
||||||
|
close: make(chan struct{}),
|
||||||
|
closeErr: make(chan error),
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// If the domain can't be found by name, exit early with an error
|
||||||
|
if g.dom, err = conn.LookupDomainByName(name); err != nil {
|
||||||
|
return g, ErrVMNotFound
|
||||||
|
}
|
||||||
|
if g.ID, err = g.dom.GetID(); err != nil {
|
||||||
|
return g, err
|
||||||
|
}
|
||||||
|
if g.BackupXML, err = g.dom.BackupGetXMLDesc(0); err != nil {
|
||||||
|
return g, err
|
||||||
|
}
|
||||||
|
if g.Autostart, err = g.dom.GetAutostart(); err != nil {
|
||||||
|
return g, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blkiop, err := g.dom.GetBlkioParameters(0)
|
||||||
|
if err != nil {
|
||||||
|
return g, err
|
||||||
|
}
|
||||||
|
g.BlockIOParameters.Weight = blkiop.Weight
|
||||||
|
g.BlockIOParameters.DeviceWeight = setNotSet(blkiop.DeviceWeight, blkiop.DeviceWeightSet)
|
||||||
|
g.BlockIOParameters.DeviceReadIops = setNotSet(blkiop.DeviceReadIops, blkiop.DeviceReadIopsSet)
|
||||||
|
g.BlockIOParameters.DeviceWriteIops = setNotSet(blkiop.DeviceWriteIops, blkiop.DeviceWriteIopsSet)
|
||||||
|
g.BlockIOParameters.DeviceReadBps = setNotSet(blkiop.DeviceReadBps, blkiop.DeviceReadBpsSet)
|
||||||
|
g.BlockIOParameters.DeviceWriteBps = setNotSet(blkiop.DeviceWriteBps, blkiop.DeviceWriteBpsSet)
|
||||||
|
|
||||||
|
// Set as much guest info as possible
|
||||||
|
info, err := g.dom.GetGuestInfo(
|
||||||
|
libvirt.DOMAIN_GUEST_INFO_USERS|libvirt.DOMAIN_GUEST_INFO_OS|
|
||||||
|
libvirt.DOMAIN_GUEST_INFO_DISKS|libvirt.DOMAIN_GUEST_INFO_HOSTNAME|
|
||||||
|
libvirt.DOMAIN_GUEST_INFO_INTERFACES|libvirt.DOMAIN_GUEST_INFO_TIMEZONE|
|
||||||
|
libvirt.DOMAIN_GUEST_INFO_FILESYSTEM,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return g, err
|
||||||
|
}
|
||||||
|
// Set disk info
|
||||||
|
if len(info.Disks) > 0 {
|
||||||
|
g.Disks = make([]DiskInfo, len(info.Disks))
|
||||||
|
for i, n := range info.Disks {
|
||||||
|
g.Disks[i].Name = setNotSet(n.Name, n.NameSet)
|
||||||
|
g.Disks[i].Alias = setNotSet(n.Alias, n.AliasSet)
|
||||||
|
g.Disks[i].Partition = n.Partition
|
||||||
|
g.Disks[i].GuestAlias = setNotSet(n.GuestAlias, n.GuestAliasSet)
|
||||||
|
g.Disks[i].DiskDependency = make([]string, len(n.Dependencies))
|
||||||
|
for j, k := range n.Dependencies {
|
||||||
|
g.Disks[i].DiskDependency[j] = setNotSet(k.Name, k.NameSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(info.Users) > 0 {
|
||||||
|
g.Users = make([]UserInfo, len(info.Users))
|
||||||
|
for i, n := range info.Users {
|
||||||
|
g.Users[i].Name = setNotSet(n.Name, n.NameSet)
|
||||||
|
g.Users[i].Domain = setNotSet(n.Domain, n.DomainSet)
|
||||||
|
g.Users[i].LoginTime = time.Unix(int64(n.LoginTime), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.OS.ID = setNotSet(info.OS.ID, info.OS.IDSet)
|
||||||
|
g.OS.Name = setNotSet(info.OS.Name, info.OS.NameSet)
|
||||||
|
g.OS.Machine = setNotSet(info.OS.Machine, info.OS.MachineSet)
|
||||||
|
g.OS.Variant = setNotSet(info.OS.Variant, info.OS.VariantSet)
|
||||||
|
g.OS.Version = setNotSet(info.OS.Version, info.OS.VersionSet)
|
||||||
|
g.OS.VariantID = setNotSet(info.OS.VariantID, info.OS.VariantIDSet)
|
||||||
|
g.OS.VersionID = setNotSet(info.OS.VersionID, info.OS.VersionIDSet)
|
||||||
|
g.OS.PrettyName = setNotSet(info.OS.PrettyName, info.OS.PrettyNameSet)
|
||||||
|
g.OS.KernelRelease = setNotSet(info.OS.KernelRelease, info.OS.KernelReleaseSet)
|
||||||
|
g.OS.KernelVersion = setNotSet(info.OS.KernelVersion, info.OS.KernelVersionSet)
|
||||||
|
g.TimeZone.Name = setNotSet(info.TimeZone.Name, info.TimeZone.NameSet)
|
||||||
|
g.TimeZone.Offset = info.TimeZone.Offset
|
||||||
|
|
||||||
|
// Set the hostname from the guest if it is set, otherwise use the VM name
|
||||||
|
if info.HostnameSet {
|
||||||
|
g.HostName = info.Hostname
|
||||||
|
} else {
|
||||||
|
g.HostName = g.Name
|
||||||
|
}
|
||||||
|
if len(info.Interfaces) > 0 {
|
||||||
|
g.NetIFace = make([]NetIFaceInfo, len(info.Interfaces))
|
||||||
|
for i, n := range info.Interfaces {
|
||||||
|
g.NetIFace[i].HWAddr = setNotSet(n.Hwaddr, n.HwaddrSet)
|
||||||
|
g.NetIFace[i].Name = setNotSet(n.Name, n.NameSet)
|
||||||
|
if len(n.Addrs) > 0 {
|
||||||
|
g.NetIFace[i].IP = make([]IPInfo, len(n.Addrs))
|
||||||
|
for j, a := range n.Addrs {
|
||||||
|
g.NetIFace[i].IP[j].Addr = setNotSet(a.Addr, a.AddrSet)
|
||||||
|
g.NetIFace[i].IP[j].Type = setNotSet(a.Type, a.TypeSet)
|
||||||
|
g.NetIFace[i].IP[j].Prefix = a.Prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(g.closeErr)
|
||||||
|
<-g.close
|
||||||
|
g.closeErr <- g.dom.Free()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return g, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to set a string value to "NotSet" if it wasn't actually set
|
||||||
|
func setNotSet(v string, s bool) string {
|
||||||
|
if s {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return "Notset"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes an open connection
|
||||||
|
func (g *VM) Close() error {
|
||||||
|
close(g.close)
|
||||||
|
return <-g.closeErr
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
package main
|
package host
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.staur.ca/stobbsm/clustvirt/lib/guest"
|
||||||
"libvirt.org/go/libvirt"
|
"libvirt.org/go/libvirt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,17 +50,18 @@ func (h *Host) connect() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetGuestByName returns a GuestVM instance that exists on the given host
|
// GetGuestByName returns a GuestVM instance that exists on the given host
|
||||||
func (h *Host) GetGuestByName(name string) (*GuestVM, error) {
|
func (h *Host) GetGuestByName(name string) (*guest.VM, error) {
|
||||||
if g, err := GetGuest(name, h.conn); err == nil {
|
g, err := guest.GetGuest(name, h.conn)
|
||||||
|
if err == nil {
|
||||||
return g, 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
|
|
||||||
}
|
}
|
||||||
|
lverr, ok := err.(libvirt.Error)
|
||||||
|
if ok && lverr.Code == libvirt.ERR_INVALID_CONN {
|
||||||
|
// try again after creating a new connection
|
||||||
|
return guest.GetGuest(name, h.conn)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close triggers closing the host connection
|
// Close triggers closing the host connection
|
Loading…
Reference in New Issue
Block a user