From 221a756550a61ee73a05b5b7d88d9c12ef97675b Mon Sep 17 00:00:00 2001 From: William Wolf Date: Mon, 2 May 2011 16:55:54 -0400 Subject: Update tools/pip-requires and tools/install_venv.py for python2.7 support (works in ubuntu 11.04) --- tools/install_venv.py | 12 ++++++++++-- tools/pip-requires | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/install_venv.py b/tools/install_venv.py index 30ec85374..db9b45cfd 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -31,11 +31,18 @@ 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 +107,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 +141,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 2f4136732..013c3ac49 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 -- cgit From f99c5f60d202e84f5defb63e771f60d20cf43df9 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Mon, 2 May 2011 16:58:06 -0400 Subject: got rid of extra whitespace --- tools/install_venv.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/install_venv.py b/tools/install_venv.py index db9b45cfd..03d93ac7d 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -33,7 +33,6 @@ 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) @@ -42,8 +41,6 @@ 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): """ Runs a command in an out-of-process shell, returning the -- cgit From 5bd57d70135e599e068a6b66d402ce6c75c250cc Mon Sep 17 00:00:00 2001 From: William Wolf Date: Wed, 4 May 2011 21:50:54 -0400 Subject: added myself to Authors --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 1cdeeff99..99c07f7cd 100644 --- a/Authors +++ b/Authors @@ -78,6 +78,7 @@ Trey Morris Tushar Patil Vasiliy Shlykov Vishvananda Ishaya +William Wolf Yoshiaki Tamura Youcef Laribi Zhixue Wu -- cgit From aa73995f9ba7e4aaaee00ddd0db0b92dcd92dd54 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Tue, 10 May 2011 16:11:59 +0000 Subject: Change xenapi's wait_for_task to handle multiple simultaenous queries to fix lp:766404 --- nova/virt/xenapi_conn.py | 86 ++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 0cabccf08..5dc6b034f 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -326,7 +326,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.""" @@ -363,57 +362,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: -- cgit From a67c77ce504ad2e15b013ed40421d0d0b823767f Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Tue, 10 May 2011 18:55:07 +0000 Subject: remove stubbing of XenAPISession.wait_for_task for xenapi tests as it doesn't need to be faked. Also removed duplicate code that stubbed xenapi_conn._parse_xmlrpc_value. --- nova/tests/xenapi/stubs.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index 205f6c902..6db061444 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -28,29 +28,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 +40,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 -- cgit From 1330241020d68f941a56ce1cf93e6523884cccc1 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Thu, 12 May 2011 09:19:01 -0400 Subject: fixed pep8 spacing issue --- tools/install_venv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/install_venv.py b/tools/install_venv.py index 03d93ac7d..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 @@ -38,7 +39,7 @@ def die(message, *args): sys.exit(1) def check_python_version(): - if sys.version_info < (2,6): + if sys.version_info < (2, 6): die("Need Python Version >= 2.6") def run_command(cmd, redirect_output=True, check_exit_code=True): -- cgit From e0dab6d678867e11e107a9418c7baeb5ac055de7 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Thu, 12 May 2011 20:01:32 +0000 Subject: Add a test for parallel builds. verified this test fails before this fix and succeeds after this fix --- nova/tests/test_xenapi.py | 23 +++++++++++++++++++++++ nova/tests/xenapi/stubs.py | 9 +++++++++ 2 files changed, 32 insertions(+) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 375480a2e..a4e679817 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 os import re @@ -197,6 +198,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 6db061444..f3d3d0ceb 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 @@ -115,6 +116,14 @@ def stubout_loopingcall_start(stubs): self.f(*self.args, **self.kw) 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 """ -- cgit From 7dc76508d38370f3cf68029fae2ffb7749a580b2 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Thu, 12 May 2011 20:12:22 +0000 Subject: if a LoopingCall has canceled the loop, break out early instead of sleeping any more than needed --- nova/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/utils.py b/nova/utils.py index 80bf1197f..44ee1b623 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -459,6 +459,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() -- cgit From a84e484d1401d7c82373203b6964c54ab7166dea Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 12 May 2011 20:05:41 -0700 Subject: added flag lost in migration --- nova/compute/manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 556b3b3b9..a2dffb16e 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') -- cgit From 31820248e8d886d37add963f0709f3658fd6087d Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 13 May 2011 10:22:04 -0400 Subject: Update the compute manager so that it breaks out of a loop if set_admin_password is not implemented by the driver. --- nova/compute/manager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 556b3b3b9..149147460 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -426,6 +426,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) -- cgit From a8941345c97cccb9171e3d1e172f607dc8d17e6a Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Fri, 13 May 2011 09:47:08 -0500 Subject: Make set_admin_password non-blocking to API. --- nova/api/openstack/servers.py | 6 ++++-- nova/compute/api.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 547310613..aaff57b4a 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -14,6 +14,7 @@ # under the License. import base64 +import eventlet import traceback from webob import exc @@ -175,8 +176,9 @@ class Controller(common.OpenstackController): builder = self._get_view_builder(req) server = builder.build(inst, is_detail=True) server['server']['adminPass'] = password - self.compute_api.set_admin_password(context, server['server']['id'], - password) + # We don't want this to block + eventlet.spawn(self.compute_api.set_admin_password( + context, server['server']['id'], password)) return server def _deserialize_create(self, request): diff --git a/nova/compute/api.py b/nova/compute/api.py index 63884be97..1c28b6a89 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -484,7 +484,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(30): instance = self.get(context, instance_id) host = instance["host"] if host: -- cgit From b4357fef25a0f6a402979d15c1ecbf4abb8643a8 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Fri, 13 May 2011 10:04:37 -0500 Subject: Make host timeout configurable. --- nova/compute/api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 1c28b6a89..29347bb4c 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -42,6 +42,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): @@ -484,7 +486,7 @@ class API(base.Base): def _find_host(self, context, instance_id): """Find the host associated with an instance.""" - for attempts in xrange(30): + for attempts in xrange(FLAGS.find_host_timeout): instance = self.get(context, instance_id) host = instance["host"] if host: -- cgit From 60dcc66db2a08bd4acfe2f3fc3e66cc382e7d008 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Fri, 13 May 2011 10:26:50 -0500 Subject: Review feedback. --- nova/api/openstack/servers.py | 6 ++---- nova/compute/api.py | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index aaff57b4a..547310613 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -14,7 +14,6 @@ # under the License. import base64 -import eventlet import traceback from webob import exc @@ -176,9 +175,8 @@ class Controller(common.OpenstackController): builder = self._get_view_builder(req) server = builder.build(inst, is_detail=True) server['server']['adminPass'] = password - # We don't want this to block - eventlet.spawn(self.compute_api.set_admin_password( - context, server['server']['id'], password)) + self.compute_api.set_admin_password(context, server['server']['id'], + password) return server def _deserialize_create(self, request): diff --git a/nova/compute/api.py b/nova/compute/api.py index 29347bb4c..a12f8d515 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 @@ -495,6 +496,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. @@ -648,12 +658,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.""" -- cgit From 3f247a628c954d5d4d97def6e6a2f889ab7ec7e3 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Fri, 13 May 2011 16:47:18 +0000 Subject: pep8 fixes --- nova/tests/xenapi/stubs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index f3d3d0ceb..4833ccb07 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -116,6 +116,7 @@ def stubout_loopingcall_start(stubs): self.f(*self.args, **self.kw) stubs.Set(utils.LoopingCall, 'start', fake_start) + def stubout_loopingcall_delay(stubs): def fake_start(self, interval, now=True): self._running = True @@ -125,6 +126,7 @@ def stubout_loopingcall_delay(stubs): 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): -- cgit