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.

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
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

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"
+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))
+    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'
+                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()
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
+
+    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)
+
+
+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)
-- 
2.3.5

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to