diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/buildslave/libvirt.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/buildslave/libvirt.py | 302 |
1 files changed, 0 insertions, 302 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/buildslave/libvirt.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/buildslave/libvirt.py deleted file mode 100644 index 5776f10d..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/buildslave/libvirt.py +++ /dev/null @@ -1,302 +0,0 @@ -# This file is part of Buildbot. Buildbot is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Portions Copyright Buildbot Team Members -# Portions Copyright 2010 Isotoma Limited - -from __future__ import absolute_import -import os - -from twisted.internet import defer, utils, threads -from twisted.python import log, failure -from buildbot.buildslave.base import AbstractBuildSlave, AbstractLatentBuildSlave -from buildbot.util.eventual import eventually -from buildbot import config - -try: - import libvirt - libvirt = libvirt -except ImportError: - libvirt = None - - -class WorkQueue(object): - """ - I am a class that turns parallel access into serial access. - - I exist because we want to run libvirt access in threads as we don't - trust calls not to block, but under load libvirt doesn't seem to like - this kind of threaded use. - """ - - def __init__(self): - self.queue = [] - - def _process(self): - log.msg("Looking to start a piece of work now...") - - # Is there anything to do? - if not self.queue: - log.msg("_process called when there is no work") - return - - # Peek at the top of the stack - get a function to call and - # a deferred to fire when its all over - d, next_operation, args, kwargs = self.queue[0] - - # Start doing some work - expects a deferred - try: - d2 = next_operation(*args, **kwargs) - except: - d2 = defer.fail() - - # Whenever a piece of work is done, whether it worked or not - # call this to schedule the next piece of work - def _work_done(res): - log.msg("Completed a piece of work") - self.queue.pop(0) - if self.queue: - log.msg("Preparing next piece of work") - eventually(self._process) - return res - d2.addBoth(_work_done) - - # When the work is done, trigger d - d2.chainDeferred(d) - - def execute(self, cb, *args, **kwargs): - kickstart_processing = not self.queue - d = defer.Deferred() - self.queue.append((d, cb, args, kwargs)) - if kickstart_processing: - self._process() - return d - - def executeInThread(self, cb, *args, **kwargs): - return self.execute(threads.deferToThread, cb, *args, **kwargs) - - -# A module is effectively a singleton class, so this is OK -queue = WorkQueue() - - -class Domain(object): - - """ - I am a wrapper around a libvirt Domain object - """ - - def __init__(self, connection, domain): - self.connection = connection - self.domain = domain - - def name(self): - return queue.executeInThread(self.domain.name) - - def create(self): - return queue.executeInThread(self.domain.create) - - def shutdown(self): - return queue.executeInThread(self.domain.shutdown) - - def destroy(self): - return queue.executeInThread(self.domain.destroy) - - -class Connection(object): - - """ - I am a wrapper around a libvirt Connection object. - """ - - DomainClass = Domain - - def __init__(self, uri): - self.uri = uri - self.connection = libvirt.open(uri) - - @defer.inlineCallbacks - def lookupByName(self, name): - """ I lookup an existing predefined domain """ - res = yield queue.executeInThread(self.connection.lookupByName, name) - defer.returnValue(self.DomainClass(self, res)) - - @defer.inlineCallbacks - def create(self, xml): - """ I take libvirt XML and start a new VM """ - res = yield queue.executeInThread(self.connection.createXML, xml, 0) - defer.returnValue(self.DomainClass(self, res)) - - @defer.inlineCallbacks - def all(self): - domains = [] - domain_ids = yield queue.executeInThread(self.connection.listDomainsID) - - for did in domain_ids: - domain = yield queue.executeInThread(self.connection.lookupByID, did) - domains.append(self.DomainClass(self, domain)) - - defer.returnValue(domains) - - -class LibVirtSlave(AbstractLatentBuildSlave): - - def __init__(self, name, password, connection, hd_image, base_image = None, xml=None, max_builds=None, notify_on_missing=[], - missing_timeout=60*20, build_wait_timeout=60*10, properties={}, locks=None): - AbstractLatentBuildSlave.__init__(self, name, password, max_builds, notify_on_missing, - missing_timeout, build_wait_timeout, properties, locks) - - if not libvirt: - config.error("The python module 'libvirt' is needed to use a LibVirtSlave") - - self.name = name - self.connection = connection - self.image = hd_image - self.base_image = base_image - self.xml = xml - - self.cheap_copy = True - self.graceful_shutdown = False - - self.domain = None - - self.ready = False - self._find_existing_deferred = self._find_existing_instance() - - @defer.inlineCallbacks - def _find_existing_instance(self): - """ - I find existing VMs that are already running that might be orphaned instances of this slave. - """ - if not self.connection: - defer.returnValue(None) - - domains = yield self.connection.all() - for d in domains: - name = yield d.name() - if name.startswith(self.name): - self.domain = d - self.substantiated = True - break - - self.ready = True - - def canStartBuild(self): - if not self.ready: - log.msg("Not accepting builds as existing domains not iterated") - return False - - if self.domain and not self.isConnected(): - log.msg("Not accepting builds as existing domain but slave not connected") - return False - - return AbstractLatentBuildSlave.canStartBuild(self) - - def _prepare_base_image(self): - """ - I am a private method for creating (possibly cheap) copies of a - base_image for start_instance to boot. - """ - if not self.base_image: - return defer.succeed(True) - - if self.cheap_copy: - clone_cmd = "qemu-img" - clone_args = "create -b %(base)s -f qcow2 %(image)s" - else: - clone_cmd = "cp" - clone_args = "%(base)s %(image)s" - - clone_args = clone_args % { - "base": self.base_image, - "image": self.image, - } - - log.msg("Cloning base image: %s %s'" % (clone_cmd, clone_args)) - - def _log_result(res): - log.msg("Cloning exit code was: %d" % res) - return res - - d = utils.getProcessValue(clone_cmd, clone_args.split()) - d.addBoth(_log_result) - return d - - @defer.inlineCallbacks - def start_instance(self, build): - """ - I start a new instance of a VM. - - If a base_image is specified, I will make a clone of that otherwise i will - use image directly. - - If i'm not given libvirt domain definition XML, I will look for my name - in the list of defined virtual machines and start that. - """ - if self.domain is not None: - log.msg("Cannot start_instance '%s' as already active" % self.name) - defer.returnValue(False) - - yield self._prepare_base_image() - - try: - if self.xml: - self.domain = yield self.connection.create(self.xml) - else: - self.domain = yield self.connection.lookupByName(self.name) - yield self.domain.create() - except: - log.err(failure.Failure(), - "Cannot start a VM (%s), failing gracefully and triggering" - "a new build check" % self.name) - self.domain = None - defer.returnValue(False) - - defer.returnValue(True) - - def stop_instance(self, fast=False): - """ - I attempt to stop a running VM. - I make sure any connection to the slave is removed. - If the VM was using a cloned image, I remove the clone - When everything is tidied up, I ask that bbot looks for work to do - """ - log.msg("Attempting to stop '%s'" % self.name) - if self.domain is None: - log.msg("I don't think that domain is even running, aborting") - return defer.succeed(None) - - domain = self.domain - self.domain = None - - if self.graceful_shutdown and not fast: - log.msg("Graceful shutdown chosen for %s" % self.name) - d = domain.shutdown() - else: - d = domain.destroy() - - def _disconnect(res): - log.msg("VM destroyed (%s): Forcing its connection closed." % self.name) - return AbstractBuildSlave.disconnect(self) - d.addCallback(_disconnect) - - def _disconnected(res): - log.msg("We forced disconnection (%s), cleaning up and triggering new build" % self.name) - if self.base_image: - os.remove(self.image) - self.botmaster.maybeStartBuildsForSlave(self.name) - return res - d.addBoth(_disconnected) - - return d - |