[libvirt] [python PATCH] examples: Add example to make guest agent lifecycle event useful

John Ferlan jferlan at redhat.com
Wed Apr 29 15:32:09 UTC 2015



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




More information about the libvir-list mailing list