On 04/17/2015 09:09 AM, Peter Krempa wrote:
This example allows to use the guest agent event and metadata to
track
vCPU count set via the guest agent (agent-based onlining/offlining) and
keep it persistent accross domain restarts.
s/accross/across (or between)
The daemon listens for the agent lifecycle event, and if it's
received
it looks into doman's metadata to see whether a desired count was set
s/into doman's/into the domain's/
and issues the guest agent command.
---
MANIFEST.in | 2 +
examples/README | 2 +
examples/guest-vcpus/guest-vcpu-daemon.py | 131 ++++++++++++++++++++++++++++++
examples/guest-vcpus/guest-vcpu.py | 76 +++++++++++++++++
4 files changed, 211 insertions(+)
create mode 100755 examples/guest-vcpus/guest-vcpu-daemon.py
create mode 100755 examples/guest-vcpus/guest-vcpu.py
Couple of more nits listed below - some are just typo's others are
observations while reviewing.
I don't have python3 installed in order to try this, but at least the
print and except clauses which caused previous issues appear to follow
the python3 rules.
ACK in general - I'm sure it'll be obvious which nits are relevant.
John
diff --git a/MANIFEST.in b/MANIFEST.in
index dd05221..2cd1b46 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -11,6 +11,8 @@ include examples/domsave.py
include examples/domstart.py
include examples/esxlist.py
include examples/event-test.py
+include examples/guest-vcpus/guest-vcpu-daemon.py
+include examples/guest-vcpus/guest-vcpu.py
include examples/topology.py
include generator.py
include libvirt-lxc-override-api.xml
diff --git a/examples/README b/examples/README
index 1d4b425..0cb4513 100644
--- a/examples/README
+++ b/examples/README
@@ -12,6 +12,8 @@ esxlist.py - list active domains of an VMware ESX host and print some
info.
also demonstrates how to use the libvirt.openAuth() method
dhcpleases.py - list dhcp leases for a given virtual network
domipaddrs.py - list IP addresses for guest domains
+guest-vcpus - two helpers to make the guest agent event useful with agent based
+ vCPU state modification
The XML files in this directory are examples of the XML format that libvirt
expects, and will have to be adapted for your setup. They are only needed
diff --git a/examples/guest-vcpus/guest-vcpu-daemon.py
b/examples/guest-vcpus/guest-vcpu-daemon.py
new file mode 100755
index 0000000..e5a389e
--- /dev/null
+++ b/examples/guest-vcpus/guest-vcpu-daemon.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+import libvirt
+import threading
+from xml.dom import minidom
+import time
+
+uri = "qemu:///system"
Although just an example, this one doesn't allow setting of the uri;
however, the guest-vcpu.py does.
+customXMLuri = "guest-cpu.python.libvirt.org"
+connectRetryTimeout = 5
+
+class workerData:
+ def __init__(self):
+ self.doms = list()
+ self.conn = None
+ self.cond = threading.Condition()
+
+ def notify(self):
+ self.cond.acquire()
+ self.cond.notify()
+ self.cond.release()
+
+ def waitNotify(self):
+ self.cond.acquire()
+ self.cond.wait()
+ self.cond.release()
+
+ def addDomainNotify(self, dom):
+ self.doms.append(dom)
+ self.notify()
+
+ def closeConnectNotify(self):
+ conn = self.conn
+ self.conn = None
+ conn.close()
+ self.notify()
+
+ def setConnect(self, conn):
+ self.conn = conn
+
+ def hasConn(self):
+ return self.conn is not None
+
+ def hasDom(self):
+ return len(self.doms) > 0
+
+ def getDom(self):
+ return self.doms.pop()
+
+ def setDoms(self, doms):
+ self.doms = doms
+
+
+def virEventLoopNativeRun():
+ while True:
+ libvirt.virEventRunDefaultImpl()
+
+def handleAgentLifecycleEvent(conn, dom, state, reason, opaque):
+ if state == libvirt.VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_CONNECTED:
+ opaque.addDomainNotify(dom)
+
+def handleConnectClose(conn, reason, opaque):
+ print('Disconnected from ' + uri)
+ opaque.closeConnectNotify()
+
+def handleLibvirtLibraryError(opaque, error):
+ pass
+
+def processAgentConnect(dom):
+ try:
+ cpus = dom.metadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, customXMLuri,
+ libvirt.VIR_DOMAIN_AFFECT_LIVE)
+ doc = minidom.parseString(cpus)
+ ncpus =
int(doc.getElementsByTagName('ncpus')[0].getAttribute('count'))
+ except:
+ return
+
+ try:
+ dom.setVcpusFlags(ncpus, libvirt.VIR_DOMAIN_AFFECT_LIVE |
libvirt.VIR_DOMAIN_VCPU_GUEST)
+ print("seting vcpus for domain " + dom.name() + " count " +
str(ncpus))
s/seting vcpus/setting vcpu count/ (or set vcpu count, since setting
implies you're about to do it and set implies you've done it)
+ except:
+ print("failed to set vcpu count for domain " + dom.name())
+
+def work():
+ data = workerData()
+
+ print("Using uri: " + uri)
+
+ while True:
+ if not data.hasConn():
+ try:
+ conn = libvirt.open(uri)
+ except:
+ print('Failed to connect to ' + uri + ' Retry in ' +
str(connectRetryTimeout)) + ' seconds'
s/Retry/, retry/
+ time.sleep(connectRetryTimeout)
+ continue
+
+ print('Connected to ' + uri)
+
+ data.setConnect(conn)
+ conn.registerCloseCallback(handleConnectClose, data)
+ conn.setKeepAlive(5, 3)
+ conn.domainEventRegisterAny(None,
+ libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE,
+ handleAgentLifecycleEvent,
+ data)
+
+ data.setDoms(conn.listAllDomains(libvirt.VIR_CONNECT_LIST_DOMAINS_ACTIVE))
+
+ while data.hasConn() and data.hasDom():
+ processAgentConnect(data.getDom())
+
+ data.waitNotify()
+
+def main():
+ libvirt.virEventRegisterDefaultImpl()
+ libvirt.registerErrorHandler(handleLibvirtLibraryError, None)
+
+ worker = threading.Thread(target=work)
+ worker.setDaemon(True)
+ worker.start()
+
+ eventLoop = threading.Thread(target=virEventLoopNativeRun)
+ eventLoop.setDaemon(True)
+ eventLoop.start()
+
+ while True:
+ time.sleep(1)
+
+if __name__ == "__main__":
+ main()
If you decide to allow uri setting then you'll need the usage for this
one as well as obviously parsing the args.
diff --git a/examples/guest-vcpus/guest-vcpu.py
b/examples/guest-vcpus/guest-vcpu.py
new file mode 100755
index 0000000..965b09c
--- /dev/null
+++ b/examples/guest-vcpus/guest-vcpu.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+
+import libvirt
+import sys
+import getopt
+import os
+
+customXMLuri = "guest-cpu.python.libvirt.org"
+
+def usage():
+ print("usage: "+os.path.basename(sys.argv[0])+" [-hcl] domain count
[uri]")
+ print(" uri will default to qemu:///system")
+ print(" --help, -h Print(this help message")
+ print(" --config, -c Modify persistent domain configuration")
+ print(" --live, -l Modify live domain configuration")
+ print("")
+ print("Sets the vCPU count via the guest agent and sets the metadata element
" +
+ "used by guest-vcpu-daemon.py example")
+
+uri = "qemu:///system"
+flags = 0
+live = False;
+config = False;
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "hcl", ["help",
"config", "live"])
+except getopt.GetoptError as err:
+ # print help information and exit:
+ print(str(err)) # will print something like "option -a not recognized"
+ usage()
+ sys.exit(2)
+for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit()
+ if o in ("-c", "--config"):
+ config = True
+ flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
+
extra line
+ if o in ("-l", "--live"):
+ live = True
+ flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
+
+if len(args) < 2:
+ usage()
+ sys.exit(1)
+elif len(args) >= 3:
+ uri = args[2]
+
+domain = args[0]
+count = int(args[1])
+
+conn = libvirt.open(uri)
+dom = conn.lookupByName(domain)
+
+if flags == 0 or config:
+ confvcpus = dom.vcpusFlags(libvirt.VIR_DOMAIN_AFFECT_CONFIG)
+
+ if confvcpus < count:
+ print("Persistent domain configuration has only " + str(confvcpus) +
" vcpus configured")
+ sys.exit(1)
+
+if flags == 0 or live:
+ livevcpus = dom.vcpusFlags(libvirt.VIR_DOMAIN_AFFECT_LIVE)
+
+ if livevcpus < count:
+ print("Live domain configuration has only " + str(livevcpus) + "
vcpus configured")
+ sys.exit(1)
+
another extra line
+
+if flags == 0 or live:
+ dom.setVcpusFlags(count, libvirt.VIR_DOMAIN_AFFECT_LIVE |
libvirt.VIR_DOMAIN_VCPU_GUEST)
+
+meta = "<ncpus count='" + str(count) + "'/>"
+
+dom.setMetadata(libvirt.VIR_DOMAIN_METADATA_ELEMENT, meta, "guestvcpudaemon",
customXMLuri, flags)