mirror of
https://github.com/ScottESanDiego/virtwold.git
synced 2024-12-21 21:25:23 +00:00
Switch to libvirt-go and libvirt-go-xml
This commit is contained in:
parent
74c4ca5fa1
commit
7f1162052a
2
go.mod
2
go.mod
@ -14,4 +14,6 @@ require (
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
libvirt.org/go/libvirt v1.9008.0 // indirect
|
||||
libvirt.org/go/libvirtxml v1.9008.0 // indirect
|
||||
)
|
||||
|
4
go.sum
4
go.sum
@ -61,3 +61,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
libvirt.org/go/libvirt v1.9008.0 h1:LLpjuSQm9gChnx7I/44SLLg/eyvTnJpcMAFmKot65Zc=
|
||||
libvirt.org/go/libvirt v1.9008.0/go.mod h1:1WiFE8EjZfq+FCVog+rvr1yatKbKZ9FaFMZgEqxEJqQ=
|
||||
libvirt.org/go/libvirtxml v1.9008.0 h1:xo2U9SqUsufTFtbyjiqs6oDdF329cvtRdqttWN7eojk=
|
||||
libvirt.org/go/libvirtxml v1.9008.0/go.mod h1:7Oq2BLDstLr/XtoQD8Fr3mfDNrzlI3utYKySXF2xkng=
|
||||
|
91
virtwold.go
91
virtwold.go
@ -15,20 +15,16 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/antchfx/xmlquery"
|
||||
"github.com/digitalocean/go-libvirt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/pcap"
|
||||
"libvirt.org/go/libvirt"
|
||||
"libvirt.org/go/libvirtxml"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var iface string // Interface we'll listen on
|
||||
var buffer = int32(1600) // Buffer for packets received
|
||||
var iface string // Interface we'll listen on
|
||||
var buffer = int32(1600) // Buffer for packets received
|
||||
var filter = "udp and broadcast and (len = 102 or len = 144 or len=234)" // PCAP filter to catch UDP WOL packets
|
||||
|
||||
flag.StringVar(&iface, "interface", "", "Network interface name to listen on")
|
||||
@ -75,77 +71,72 @@ func GrabMACAddr(packet gopacket.Packet) (string, error) {
|
||||
|
||||
func WakeVirtualMachine(mac string) bool {
|
||||
// Connect to the local libvirt socket
|
||||
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
|
||||
connection, err := libvirt.NewConnect("qemu+tcp:///system")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to dial libvirt: %v", err)
|
||||
}
|
||||
|
||||
l := libvirt.New(c)
|
||||
if err := l.Connect(); err != nil {
|
||||
log.Fatalf("failed to connect: %v", err)
|
||||
}
|
||||
defer connection.Close()
|
||||
|
||||
// Get a list of all VMs (aka Domains) configured so we can loop through them
|
||||
flags := libvirt.ConnectListDomainsActive | libvirt.ConnectListDomainsInactive
|
||||
domains, _, err := l.ConnectListAllDomains(1, flags)
|
||||
// Get a list of all inactive VMs (aka Domains) configured so we can loop through them
|
||||
domains, err := connection.ListAllDomains(libvirt.CONNECT_LIST_DOMAINS_INACTIVE)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to retrieve domains: %v", err)
|
||||
}
|
||||
|
||||
for _, d := range domains {
|
||||
//fmt.Printf("%d\t%s\t%x\n", d.ID, d.Name, d.UUID)
|
||||
|
||||
for _, domain := range domains {
|
||||
// Now we get the XML Description for each domain
|
||||
xmldesc, err := l.DomainGetXMLDesc(d, 0)
|
||||
xmldesc, err := domain.GetXMLDesc(0)
|
||||
if err != nil {
|
||||
log.Fatalf("failed retrieving interfaces: %v", err)
|
||||
log.Fatalf("failed retrieving XML: %v", err)
|
||||
}
|
||||
|
||||
// Feed the XML output into xmlquery
|
||||
querydoc, err := xmlquery.Parse(strings.NewReader(xmldesc))
|
||||
// Get the details for each domain
|
||||
domcfg := &libvirtxml.Domain{}
|
||||
err = domcfg.Unmarshal(xmldesc)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse XML: %v", err)
|
||||
log.Fatalf("failed retrieving domain configuration: %v", err)
|
||||
}
|
||||
|
||||
// Perform an xmlquery to look for the MAC address in the XML
|
||||
for _, list := range xmlquery.Find(querydoc, "//domain/devices/interface/mac/@address") {
|
||||
// Use the strings.EqualFold function to do a case-insensitive comparison of MACs
|
||||
if strings.EqualFold(list.InnerText(), mac) {
|
||||
stateInt, _, err := l.DomainGetState(d, 0)
|
||||
// Loop through each interface found
|
||||
for _, iface := range domcfg.Devices.Interfaces {
|
||||
domainmac := iface.MAC.Address
|
||||
|
||||
if domainmac == mac {
|
||||
// We'll use the name later, so may as well get it here
|
||||
name := domcfg.Name
|
||||
|
||||
// Get the state of the VM and take action
|
||||
state, _, err := domain.GetState()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to check domain state: %v", err)
|
||||
}
|
||||
|
||||
state := libvirt.DomainState(stateInt)
|
||||
// fmt.Printf("Domain state is %v\n", state)
|
||||
|
||||
switch state {
|
||||
case libvirt.DomainShutoff, libvirt.DomainCrashed:
|
||||
fmt.Printf("Waking system: %s at MAC %s\n", d.Name, mac)
|
||||
if err := l.DomainCreate(d); err != nil {
|
||||
case libvirt.DOMAIN_SHUTDOWN, libvirt.DOMAIN_SHUTOFF, libvirt.DOMAIN_CRASHED:
|
||||
fmt.Printf("Waking system: %s at MAC %s\n", name, mac)
|
||||
if err := domain.Create(); err != nil {
|
||||
log.Fatalf("Failed to start domain: %v", err)
|
||||
}
|
||||
case libvirt.DomainPmsuspended:
|
||||
fmt.Printf("PM Wakeup system: %s at MAC %s\n", d.Name, mac)
|
||||
if err := l.DomainPmWakeup(d, 0); err != nil {
|
||||
log.Fatalf("Failed to pm wakeup domain: %v", err)
|
||||
|
||||
case libvirt.DOMAIN_PMSUSPENDED:
|
||||
fmt.Printf("Unsuspending system: %s at MAC %s\n", name, mac)
|
||||
if err := domain.Create(); err != nil {
|
||||
log.Fatalf("Failed to unsuspend domain: %v", err)
|
||||
}
|
||||
case libvirt.DomainPaused:
|
||||
fmt.Printf("Resume system: %s at MAC %s\n", d.Name, mac)
|
||||
if err := l.DomainResume(d); err != nil {
|
||||
|
||||
case libvirt.DOMAIN_PAUSED:
|
||||
fmt.Printf("Resuming system: %s at MAC %s\n", name, mac)
|
||||
if err := domain.Create(); err != nil {
|
||||
log.Fatalf("Failed to resume domain: %v", err)
|
||||
}
|
||||
default:
|
||||
fmt.Printf("System %s is already running or in a state that cannot be woken from. State: %d\n", d.Name, state)
|
||||
|
||||
default:
|
||||
fmt.Printf("System is already running or in a state that cannot be woken from. State: %d\n", state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := l.Disconnect(); err != nil {
|
||||
log.Fatalf("failed to disconnect: %v", err)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user