diff options
| author | Rick Harris <rick.harris@rackspace.com> | 2011-05-13 12:16:48 -0500 |
|---|---|---|
| committer | Rick Harris <rick.harris@rackspace.com> | 2011-05-13 12:16:48 -0500 |
| commit | 88b3fa4513ed5cfe2befab692dc3371095f99d98 (patch) | |
| tree | 6ee58b84e53181693a4db5fa40787c5e5bf8a8f9 | |
| parent | 9c44918e524df52471fd9acdbd37305ba7f74464 (diff) | |
| parent | ea5187e449fd72b1443d2ac1558c7a2a07e7a39b (diff) | |
| download | nova-88b3fa4513ed5cfe2befab692dc3371095f99d98.tar.gz nova-88b3fa4513ed5cfe2befab692dc3371095f99d98.tar.xz nova-88b3fa4513ed5cfe2befab692dc3371095f99d98.zip | |
Merging in trunk
| -rw-r--r-- | .mailmap | 3 | ||||
| -rw-r--r-- | Authors | 2 | ||||
| -rw-r--r-- | nova/compute/api.py | 22 | ||||
| -rw-r--r-- | nova/compute/manager.py | 9 | ||||
| -rw-r--r-- | nova/tests/test_xenapi.py | 23 | ||||
| -rw-r--r-- | nova/tests/xenapi/stubs.py | 39 | ||||
| -rw-r--r-- | nova/utils.py | 2 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 86 | ||||
| -rw-r--r-- | tools/install_venv.py | 10 | ||||
| -rw-r--r-- | tools/pip-requires | 2 |
10 files changed, 111 insertions, 87 deletions
@@ -29,6 +29,7 @@ <matt.dietz@rackspace.com> <matthewdietz@Matthew-Dietzs-MacBook-Pro.local> <matt.dietz@rackspace.com> <mdietz@openstack> <mordred@inaugust.com> <mordred@hudson> +<naveedm9@gmail.com> <naveed.massjouni@rackspace.com> <nirmal.ranganathan@rackspace.com> <nirmal.ranganathan@rackspace.coom> <paul@openstack.org> <paul.voccio@rackspace.com> <paul@openstack.org> <pvoccio@castor.local> @@ -36,6 +37,7 @@ <rlane@wikimedia.org> <laner@controller> <sleepsonthefloor@gmail.com> <root@tonbuntu> <soren.hansen@rackspace.com> <soren@linux2go.dk> +<throughnothing@gmail.com> <will.wolf@rackspace.com> <todd@ansolabs.com> <todd@lapex> <todd@ansolabs.com> <todd@rubidine.com> <tushar.vitthal.patil@gmail.com> <tpatil@vertex.co.in> @@ -44,5 +46,4 @@ <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <vishvananda@gmail.com> <root@mirror.nasanebula.net> <vishvananda@gmail.com> <root@ubuntu> -<naveedm9@gmail.com> <naveed.massjouni@rackspace.com> <vishvananda@gmail.com> <vishvananda@yahoo.com> @@ -80,7 +80,7 @@ Trey Morris <trey.morris@rackspace.com> Tushar Patil <tushar.vitthal.patil@gmail.com> Vasiliy Shlykov <vash@vasiliyshlykov.org> Vishvananda Ishaya <vishvananda@gmail.com> -William Wolf <will.wolf@rackspace.com> +William Wolf <throughnothing@gmail.com> Yoshiaki Tamura <yoshi@midokura.jp> Youcef Laribi <Youcef.Laribi@eu.citrix.com> Yuriy Taraday <yorik.sar@gmail.com> diff --git a/nova/compute/api.py b/nova/compute/api.py index 8a7c713a2..7e2494781 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -19,6 +19,7 @@ """Handles all requests relating to instances (guest vms).""" import datetime +import eventlet import re import time @@ -42,6 +43,8 @@ LOG = logging.getLogger('nova.compute.api') FLAGS = flags.FLAGS flags.DECLARE('vncproxy_topic', 'nova.vnc') +flags.DEFINE_integer('find_host_timeout', 30, + 'Timeout after NN seconds when looking for a host.') def generate_default_hostname(instance_id): @@ -491,7 +494,7 @@ class API(base.Base): def _find_host(self, context, instance_id): """Find the host associated with an instance.""" - for attempts in xrange(10): + for attempts in xrange(FLAGS.find_host_timeout): instance = self.get(context, instance_id) host = instance["host"] if host: @@ -500,6 +503,15 @@ class API(base.Base): raise exception.Error(_("Unable to find host for Instance %s") % instance_id) + def _set_admin_password(self, context, instance_id, password): + """Set the root/admin password for the given instance.""" + host = self._find_host(context, instance_id) + + rpc.cast(context, + self.db.queue_get_for(context, FLAGS.compute_topic, host), + {"method": "set_admin_password", + "args": {"instance_id": instance_id, "new_pass": password}}) + def snapshot(self, context, instance_id, name): """Snapshot the given instance. @@ -653,12 +665,8 @@ class API(base.Base): def set_admin_password(self, context, instance_id, password=None): """Set the root/admin password for the given instance.""" - host = self._find_host(context, instance_id) - - rpc.cast(context, - self.db.queue_get_for(context, FLAGS.compute_topic, host), - {"method": "set_admin_password", - "args": {"instance_id": instance_id, "new_pass": password}}) + eventlet.spawn_n(self._set_admin_password(context, instance_id, + password)) def inject_file(self, context, instance_id): """Write a file to the given instance.""" diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 556b3b3b9..923feaa59 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -77,7 +77,8 @@ flags.DEFINE_integer("rescue_timeout", 0, " Set to 0 to disable.") flags.DEFINE_bool('auto_assign_floating_ip', False, 'Autoassigning floating ip to VM') - +flags.DEFINE_integer('host_state_interval', 120, + 'Interval in seconds for querying the host status') LOG = logging.getLogger('nova.compute.manager') @@ -426,6 +427,12 @@ class ComputeManager(manager.SchedulerDependentManager): LOG.audit(_("Instance %s: Root password set"), instance_ref["name"]) break + except NotImplementedError: + # NOTE(dprince): if the driver doesn't implement + # set_admin_password we break to avoid a loop + LOG.warn(_('set_admin_password is not implemented ' + 'by this driver.')) + break except Exception, e: # Catch all here because this could be anything. LOG.exception(e) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 6072f5455..be1e35697 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -16,6 +16,7 @@ """Test suite for XenAPI.""" +import eventlet import functools import json import os @@ -198,6 +199,28 @@ class XenAPIVMTestCase(test.TestCase): self.context = context.RequestContext('fake', 'fake', False) self.conn = xenapi_conn.get_connection(False) + def test_parallel_builds(self): + stubs.stubout_loopingcall_delay(self.stubs) + + def _do_build(id, proj, user, *args): + values = { + 'id': id, + 'project_id': proj, + 'user_id': user, + 'image_id': 1, + 'kernel_id': 2, + 'ramdisk_id': 3, + 'instance_type_id': '3', # m1.large + 'mac_address': 'aa:bb:cc:dd:ee:ff', + 'os_type': 'linux'} + instance = db.instance_create(self.context, values) + self.conn.spawn(instance) + + gt1 = eventlet.spawn(_do_build, 1, self.project.id, self.user.id) + gt2 = eventlet.spawn(_do_build, 2, self.project.id, self.user.id) + gt1.wait() + gt2.wait() + def test_list_instances_0(self): instances = self.conn.list_instances() self.assertEquals(instances, []) diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index 205f6c902..4833ccb07 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -16,6 +16,7 @@ """Stubouts, mocks and fixtures for the test suite""" +import eventlet from nova.virt import xenapi_conn from nova.virt.xenapi import fake from nova.virt.xenapi import volume_utils @@ -28,29 +29,6 @@ def stubout_instance_snapshot(stubs): @classmethod def fake_fetch_image(cls, session, instance_id, image, user, project, type): - # Stubout wait_for_task - def fake_wait_for_task(self, task, id): - class FakeEvent: - - def send(self, value): - self.rv = value - - def wait(self): - return self.rv - - done = FakeEvent() - self._poll_task(id, task, done) - rv = done.wait() - return rv - - def fake_loop(self): - pass - - stubs.Set(xenapi_conn.XenAPISession, 'wait_for_task', - fake_wait_for_task) - - stubs.Set(xenapi_conn.XenAPISession, '_stop_loop', fake_loop) - from nova.virt.xenapi.fake import create_vdi name_label = "instance-%s" % instance_id #TODO: create fake SR record @@ -63,11 +41,6 @@ def stubout_instance_snapshot(stubs): stubs.Set(vm_utils.VMHelper, 'fetch_image', fake_fetch_image) - def fake_parse_xmlrpc_value(val): - return val - - stubs.Set(xenapi_conn, '_parse_xmlrpc_value', fake_parse_xmlrpc_value) - def fake_wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref, original_parent_uuid): from nova.virt.xenapi.fake import create_vdi @@ -144,6 +117,16 @@ def stubout_loopingcall_start(stubs): stubs.Set(utils.LoopingCall, 'start', fake_start) +def stubout_loopingcall_delay(stubs): + def fake_start(self, interval, now=True): + self._running = True + eventlet.sleep(1) + self.f(*self.args, **self.kw) + # This would fail before parallel xenapi calls were fixed + assert self._running == False + stubs.Set(utils.LoopingCall, 'start', fake_start) + + class FakeSessionForVMTests(fake.SessionBase): """ Stubs out a XenAPISession for VM tests """ def __init__(self, uri): diff --git a/nova/utils.py b/nova/utils.py index b55e83e5a..0c469b1de 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -462,6 +462,8 @@ class LoopingCall(object): try: while self._running: self.f(*self.args, **self.kw) + if not self._running: + break greenthread.sleep(interval) except LoopingCallDone, e: self.stop() diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 8e9085277..eb572f295 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -347,7 +347,6 @@ class XenAPISession(object): "(is the Dom0 disk full?)")) with timeout.Timeout(FLAGS.xenapi_login_timeout, exception): self._session.login_with_password(user, pw) - self.loop = None def get_imported_xenapi(self): """Stubout point. This can be replaced with a mock xenapi module.""" @@ -384,57 +383,52 @@ class XenAPISession(object): def wait_for_task(self, task, id=None): """Return the result of the given task. The task is polled - until it completes. Not re-entrant.""" + until it completes.""" done = event.Event() - self.loop = utils.LoopingCall(self._poll_task, id, task, done) - self.loop.start(FLAGS.xenapi_task_poll_interval, now=True) - rv = done.wait() - self.loop.stop() - return rv - - def _stop_loop(self): - """Stop polling for task to finish.""" - #NOTE(sandy-walsh) Had to break this call out to support unit tests. - if self.loop: - self.loop.stop() + loop = utils.LoopingCall(f=None) + + def _poll_task(): + """Poll the given XenAPI task, and return the result if the + action was completed successfully or not. + """ + try: + name = self._session.xenapi.task.get_name_label(task) + status = self._session.xenapi.task.get_status(task) + if id: + action = dict( + instance_id=int(id), + action=name[0:255], # Ensure action is never > 255 + error=None) + if status == "pending": + return + elif status == "success": + result = self._session.xenapi.task.get_result(task) + LOG.info(_("Task [%(name)s] %(task)s status:" + " success %(result)s") % locals()) + done.send(_parse_xmlrpc_value(result)) + else: + error_info = self._session.xenapi.task.get_error_info(task) + action["error"] = str(error_info) + LOG.warn(_("Task [%(name)s] %(task)s status:" + " %(status)s %(error_info)s") % locals()) + done.send_exception(self.XenAPI.Failure(error_info)) + + if id: + db.instance_action_create(context.get_admin_context(), + action) + except self.XenAPI.Failure, exc: + LOG.warn(exc) + done.send_exception(*sys.exc_info()) + loop.stop() + + loop.f = _poll_task + loop.start(FLAGS.xenapi_task_poll_interval, now=True) + return done.wait() def _create_session(self, url): """Stubout point. This can be replaced with a mock session.""" return self.XenAPI.Session(url) - def _poll_task(self, id, task, done): - """Poll the given XenAPI task, and fire the given action if we - get a result. - """ - try: - name = self._session.xenapi.task.get_name_label(task) - status = self._session.xenapi.task.get_status(task) - if id: - action = dict( - instance_id=int(id), - action=name[0:255], # Ensure action is never > 255 - error=None) - if status == "pending": - return - elif status == "success": - result = self._session.xenapi.task.get_result(task) - LOG.info(_("Task [%(name)s] %(task)s status:" - " success %(result)s") % locals()) - done.send(_parse_xmlrpc_value(result)) - else: - error_info = self._session.xenapi.task.get_error_info(task) - action["error"] = str(error_info) - LOG.warn(_("Task [%(name)s] %(task)s status:" - " %(status)s %(error_info)s") % locals()) - done.send_exception(self.XenAPI.Failure(error_info)) - - if id: - db.instance_action_create(context.get_admin_context(), action) - except self.XenAPI.Failure, exc: - LOG.warn(exc) - done.send_exception(*sys.exc_info()) - self._stop_loop() - def _unwrap_plugin_exceptions(self, func, *args, **kwargs): """Parse exception details""" try: diff --git a/tools/install_venv.py b/tools/install_venv.py index 30ec85374..8149a3afa 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -1,3 +1,4 @@ + # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the @@ -31,11 +32,15 @@ ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) VENV = os.path.join(ROOT, '.nova-venv') PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires') TWISTED_NOVA='http://nova.openstack.org/Twisted-10.0.0Nova.tar.gz' +PY_VERSION = "python" + str(sys.version_info[0]) + '.' + str(sys.version_info[1]) def die(message, *args): print >>sys.stderr, message % args sys.exit(1) +def check_python_version(): + if sys.version_info < (2, 6): + die("Need Python Version >= 2.6") def run_command(cmd, redirect_output=True, check_exit_code=True): """ @@ -100,12 +105,12 @@ def install_dependencies(venv=VENV): # Tell the virtual env how to "import nova" - pthfile = os.path.join(venv, "lib", "python2.6", "site-packages", "nova.pth") + pthfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "nova.pth") f = open(pthfile, 'w') f.write("%s\n" % ROOT) # Patch eventlet (see FAQ # 1485) patchsrc = os.path.join(ROOT, 'tools', 'eventlet-patch') - patchfile = os.path.join(venv, "lib", "python2.6", "site-packages", "eventlet", + patchfile = os.path.join(venv, "lib", PY_VERSION, "site-packages", "eventlet", "green", "subprocess.py") patch_cmd = "patch %s %s" % (patchfile, patchsrc) os.system(patch_cmd) @@ -134,6 +139,7 @@ def print_help(): def main(argv): + check_python_version() check_dependencies() create_virtualenv() install_dependencies() diff --git a/tools/pip-requires b/tools/pip-requires index f7eb1703e..8f8018765 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,7 +2,7 @@ SQLAlchemy==0.6.3 pep8==0.5.0 pylint==0.19 IPy==0.70 -Cheetah==2.4.2.1 +Cheetah==2.4.4 M2Crypto==0.20.2 amqplib==0.6.1 anyjson==0.2.4 |
