From ceb8cd14f968aa063bd6a19999340f77c5603568 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Tue, 15 Mar 2011 21:04:38 -0700 Subject: Fixed DescribeUser in ec2 admin client --- nova/adminclient.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/nova/adminclient.py b/nova/adminclient.py index fc3c5c5fe..f570e12c2 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -324,14 +324,11 @@ class NovaAdminClient(object): def get_user(self, name): """Grab a single user by name.""" - try: - return self.apiconn.get_object('DescribeUser', - {'Name': name}, - UserInfo) - except boto.exception.BotoServerError, e: - if e.status == 400 and e.error_code == 'NotFound': - return None - raise + user = self.apiconn.get_object('DescribeUser', + {'Name': name}, + UserInfo) + if user.username != None: + return user def has_user(self, username): """Determine if user exists.""" -- cgit From a7990e0263f2113e3814209118ecb2afc140826e Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 16 Mar 2011 15:01:10 -0700 Subject: Use _ trick to hide base test class, thereby avoiding mixins and helping PyLint --- nova/tests/test_auth.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py index 2a7817032..0d24e5db2 100644 --- a/nova/tests/test_auth.py +++ b/nova/tests/test_auth.py @@ -80,10 +80,10 @@ class user_and_project_generator(object): self.manager.delete_project(self.project) -class AuthManagerTestCase(object): +class _AuthManagerBaseTestCase(test.TestCase): def setUp(self): FLAGS.auth_driver = self.auth_driver - super(AuthManagerTestCase, self).setUp() + super(_AuthManagerBaseTestCase, self).setUp() self.flags(connection_type='fake') self.manager = manager.AuthManager(new=True) @@ -324,11 +324,11 @@ class AuthManagerTestCase(object): self.assertTrue(user.is_admin()) -class AuthManagerLdapTestCase(AuthManagerTestCase, test.TestCase): +class AuthManagerLdapTestCase(_AuthManagerBaseTestCase): auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver' -class AuthManagerDbTestCase(AuthManagerTestCase, test.TestCase): +class AuthManagerDbTestCase(_AuthManagerBaseTestCase): auth_driver = 'nova.auth.dbdriver.DbDriver' -- cgit From 65b11b3b9c76db2440d480bbc41b72f24bee8afc Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 16 Mar 2011 15:11:39 -0700 Subject: Avoid mixins on image tests, keeping pylint much happier --- nova/tests/api/openstack/test_images.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 76f758929..9a33236af 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -41,10 +41,15 @@ from nova.tests.api.openstack import fakes FLAGS = flags.FLAGS -class BaseImageServiceTests(object): +class _BaseImageServiceTests(test.TestCase): """Tasks to test for all image services""" + def __init__(self): + super(_BaseImageServiceTests, self).__init__() + self.service = None + self.context = None + def test_create(self): fixture = {'name': 'test image', @@ -132,8 +137,7 @@ class BaseImageServiceTests(object): self.assertEquals(1, num_images) -class LocalImageServiceTest(test.TestCase, - BaseImageServiceTests): +class LocalImageServiceTest(_BaseImageServiceTests): """Tests the local image service""" @@ -152,8 +156,7 @@ class LocalImageServiceTest(test.TestCase, super(LocalImageServiceTest, self).tearDown() -class GlanceImageServiceTest(test.TestCase, - BaseImageServiceTests): +class GlanceImageServiceTest(_BaseImageServiceTests): """Tests the local image service""" -- cgit From aecd4eb9d363875cd84be5aa6fdb9afeb500b4f4 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 16 Mar 2011 15:44:45 -0700 Subject: Fix __init__ method on unit tests (they take a method_name kwarg) --- nova/tests/api/openstack/test_images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 9a33236af..8814b9b1a 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -45,8 +45,8 @@ class _BaseImageServiceTests(test.TestCase): """Tasks to test for all image services""" - def __init__(self): - super(_BaseImageServiceTests, self).__init__() + def __init__(self, *args, **kwargs): + super(_BaseImageServiceTests, self).__init__(*args, **kwargs) self.service = None self.context = None -- cgit From ec524aae3224a806fa41f6ae6c2975a1ba124f15 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 25 Mar 2011 15:18:57 +0100 Subject: Toss an __init__ in the test extensions dir. This gets it included in the tarball. --- nova/tests/api/openstack/extensions/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 nova/tests/api/openstack/extensions/__init__.py diff --git a/nova/tests/api/openstack/extensions/__init__.py b/nova/tests/api/openstack/extensions/__init__.py new file mode 100644 index 000000000..e69de29bb -- cgit From c4167bd6174838d1df3c77094a22b19e592e88c1 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Fri, 25 Mar 2011 17:46:28 +0300 Subject: Changed use_ipv6 passing to interfaces.template --- nova/virt/libvirt_conn.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2cecb010d..d22461301 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -762,11 +762,12 @@ class LibvirtConnection(driver.ComputeDriver): 'dns': network_ref['dns'], 'address_v6': address_v6, 'gateway_v6': network_ref['gateway_v6'], - 'netmask_v6': network_ref['netmask_v6'], - 'use_ipv6': FLAGS.use_ipv6} + 'netmask_v6': network_ref['netmask_v6']} nets.append(net_info) - net = str(Template(ifc_template, searchList=[{'interfaces': nets}])) + net = str(Template(ifc_template, + searchList=[{'interfaces': nets, + 'use_ipv6': FLAGS.use_ipv6}])) if key or net: inst_name = inst['name'] -- cgit From e6192a67bdc81a74945f230e833006836e94c81b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 25 Mar 2011 09:23:10 -0700 Subject: updated nova.sh --- contrib/nova.sh | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/contrib/nova.sh b/contrib/nova.sh index 55dfb971c..d8031380a 100755 --- a/contrib/nova.sh +++ b/contrib/nova.sh @@ -17,7 +17,10 @@ if [ ! -n "$HOST_IP" ]; then HOST_IP=`LC_ALL=C ifconfig | grep -m 1 'inet addr:'| cut -d: -f2 | awk '{print $1}'` fi -USE_MYSQL=${USE_MYSQL:-0} +INTERFACE=${INTERFACE:-eth0} +FLOATING_RANGE=${FLOATING_RANGE:-10.6.0.0/27} +FIXED_RANGE=${FIXED_RANGE:-10.0.0.0/24} +USE_LDAP=${USE_E_MYSQL:-0} MYSQL_PASS=${MYSQL_PASS:-nova} TEST=${TEST:-0} USE_LDAP=${USE_LDAP:-0} @@ -72,11 +75,14 @@ if [ "$CMD" == "install" ]; then sudo modprobe kvm sudo /etc/init.d/libvirt-bin restart sudo modprobe nbd - sudo apt-get install -y python-twisted python-sqlalchemy python-mox python-greenlet python-carrot - sudo apt-get install -y python-migrate python-eventlet python-gflags python-ipy python-tempita - sudo apt-get install -y python-libvirt python-libxml2 python-routes python-cheetah - sudo apt-get install -y python-netaddr python-paste python-pastedeploy python-glance - sudo apt-get install -y python-multiprocessing + sudo apt-get install -y python-twisted python-mox python-ipy python-paste + sudo apt-get install -y python-migrate python-gflags python-greenlet + sudo apt-get install -y python-libvirt python-libxml2 python-routes + sudo apt-get install -y python-netaddr python-pastedeploy python-eventlet + sudo apt-get install -y python-novaclient python-glance python-cheetah + sudo apt-get install -y python-carrot python-tempita python-sqlalchemy + sudo apt-get install -y python-suds + if [ "$USE_IPV6" == 1 ]; then sudo apt-get install -y radvd @@ -105,7 +111,7 @@ function screen_it { screen -S nova -p $1 -X stuff "$2$NL" } -if [ "$CMD" == "run" ]; then +if [ "$CMD" == "run" ] || [ "$CMD" == "run_detached" ]; then cat >$NOVA_DIR/bin/nova.conf << NOVA_CONF_EOF --verbose @@ -113,6 +119,8 @@ if [ "$CMD" == "run" ]; then --dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf --network_manager=nova.network.manager.$NET_MAN --my_ip=$HOST_IP +--public_interface=$INTERFACE +--vlan_interface=$INTERFACE --sql_connection=$SQL_CONN --auth_driver=nova.auth.$AUTH --libvirt_type=$LIBVIRT_TYPE @@ -168,10 +176,13 @@ NOVA_CONF_EOF # create a project called 'admin' with project manager of 'admin' $NOVA_DIR/bin/nova-manage project create admin admin # create a small network - $NOVA_DIR/bin/nova-manage network create 10.0.0.0/8 1 32 + $NOVA_DIR/bin/nova-manage network create $FIXED_RANGE 1 32 # create some floating ips - $NOVA_DIR/bin/nova-manage floating create `hostname` 10.6.0.0/27 + $NOVA_DIR/bin/nova-manage floating create `hostname` $FLOATING_RANGE + + # convert old images + $NOVA_DIR/bin/nova-manage image convert $DIR/images # nova api crashes if we start it with a regular screen command, # so send the start command by forcing text into the window. @@ -187,8 +198,10 @@ NOVA_CONF_EOF $NOVA_DIR/bin/nova-manage project zipfile admin admin $NOVA_DIR/nova.zip unzip -o $NOVA_DIR/nova.zip -d $NOVA_DIR/ - screen_it test ". $NOVA_DIR/novarc" - screen -S nova -x + screen_it test "export PATH=$NOVA_DIR/bin:$PATH;. $NOVA_DIR/novarc" + if [ "$CMD" != "run_detached" ]; then + screen -S nova -x + fi fi if [ "$CMD" == "run" ] || [ "$CMD" == "terminate" ]; then -- cgit From 5120ad458f011ec32d7e49af64319254d120b306 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 25 Mar 2011 09:40:59 -0700 Subject: fix typos --- contrib/nova.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/nova.sh b/contrib/nova.sh index d8031380a..d7d34dcbd 100755 --- a/contrib/nova.sh +++ b/contrib/nova.sh @@ -17,10 +17,10 @@ if [ ! -n "$HOST_IP" ]; then HOST_IP=`LC_ALL=C ifconfig | grep -m 1 'inet addr:'| cut -d: -f2 | awk '{print $1}'` fi +USE_MYSQL=${USE_MYSQL:-0} INTERFACE=${INTERFACE:-eth0} FLOATING_RANGE=${FLOATING_RANGE:-10.6.0.0/27} FIXED_RANGE=${FIXED_RANGE:-10.0.0.0/24} -USE_LDAP=${USE_E_MYSQL:-0} MYSQL_PASS=${MYSQL_PASS:-nova} TEST=${TEST:-0} USE_LDAP=${USE_LDAP:-0} -- cgit From af8aa36ca07c5e51016df68c0acc7449378fac2f Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 25 Mar 2011 18:23:36 +0100 Subject: Add license and copyright to nova/tests/api/openstack/extensions/__init__.py --- nova/tests/api/openstack/extensions/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nova/tests/api/openstack/extensions/__init__.py b/nova/tests/api/openstack/extensions/__init__.py index e69de29bb..848908a95 100644 --- a/nova/tests/api/openstack/extensions/__init__.py +++ b/nova/tests/api/openstack/extensions/__init__.py @@ -0,0 +1,15 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. -- cgit From b6824009d9767f951373fb1b92c7cb2de83b0d97 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 00:30:13 -0700 Subject: There were two periodic_tasks functions, due to parallel merges in compute.manager. --- nova/compute/manager.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 468771f46..eb8bddd05 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -141,12 +141,6 @@ class ComputeManager(manager.SchedulerDependentManager): """ self.driver.init_host(host=self.host) - def periodic_tasks(self, context=None): - """Tasks to be run at a periodic interval.""" - super(ComputeManager, self).periodic_tasks(context) - if FLAGS.rescue_timeout > 0: - self.driver.poll_rescued_instances(FLAGS.rescue_timeout) - def _update_state(self, context, instance_id): """Update the state of an instance from the driver info.""" # FIXME(ja): include other fields from state? @@ -1028,16 +1022,27 @@ class ComputeManager(manager.SchedulerDependentManager): def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" + + error_list = super(ComputeManager, self).periodic_tasks(context) if error_list is None: error_list = [] + try: + if FLAGS.rescue_timeout > 0: + self.driver.poll_rescued_instances(FLAGS.rescue_timeout) + except Exception as ex: + LOG.warning(_("Error during poll_rescued_instances: %s"), + unicode(ex)) + error_list.append(ex) + try: self._poll_instance_states(context) except Exception as ex: LOG.warning(_("Error during instance poll: %s"), unicode(ex)) error_list.append(ex) + return error_list def _poll_instance_states(self, context): -- cgit From 684865d0b95a14f23e9187a6c3a404b5e8ed61ef Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 00:31:28 -0700 Subject: Added poll_rescued_instances to virt driver base class --- nova/virt/driver.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index f9cf1b8aa..fcd31861d 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -232,3 +232,7 @@ class ComputeDriver(object): def inject_network_info(self, instance): """inject network info for specified instance""" raise NotImplementedError() + + def poll_rescued_instances(self, timeout): + """Poll for rescued instances""" + raise NotImplementedError() -- cgit From b2f7f3e05d18168b3310184aa9a3a6f11c57c154 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 00:32:48 -0700 Subject: pep8 fixes --- nova/compute/manager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index eb8bddd05..f43397e36 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1022,8 +1022,6 @@ class ComputeManager(manager.SchedulerDependentManager): def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" - - error_list = super(ComputeManager, self).periodic_tasks(context) if error_list is None: error_list = [] @@ -1042,7 +1040,7 @@ class ComputeManager(manager.SchedulerDependentManager): LOG.warning(_("Error during instance poll: %s"), unicode(ex)) error_list.append(ex) - + return error_list def _poll_instance_states(self, context): -- cgit From c8969dbdd429c0b4c4f1211bd90311cabec8dd0d Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 00:41:55 -0700 Subject: Assume that if we don't find a VM for an instance in the DB, and the DB state is NOSTATE, that the db instance is in the process of being spawned. Fix for bug744056 --- nova/compute/manager.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 468771f46..f396baa44 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1051,16 +1051,31 @@ class ComputeManager(manager.SchedulerDependentManager): for db_instance in db_instances: name = db_instance['name'] + db_state = db_instance['state'] vm_instance = vm_instances.get(name) + if vm_instance is None: - LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "Setting state to shutoff.") % locals()) - vm_state = power_state.SHUTOFF + #NOTE(justinsb): We have to be very careful here, because a + #concurrent operation could be in progress (e.g. a spawn) + if db_state == power_state.NOSTATE: + #Assume that NOSTATE => spawning + #TODO(justinsb): This does mean that if we crash during a + #spawn, the machine will never leave the spawning state. + #We could have a separate task to correct this error. + #TODO(justinsb): What happens during a live migration? + LOG.info(_("Found instance '%(name)s' in DB but no VM. " + "State=%(db_state), so assuming spawn is in " + "progress.") % locals()) + vm_state = db_state + else: + LOG.info(_("Found instance '%(name)s' in DB but no VM. " + "State=%(db_state), so setting state to " + "shutoff.") % locals()) + vm_state = power_state.SHUTOFF else: vm_state = vm_instance.state vms_not_found_in_db.remove(name) - db_state = db_instance['state'] if vm_state != db_state: LOG.info(_("DB/VM state mismatch. Changing state from " "'%(db_state)s' to '%(vm_state)s'") % locals()) -- cgit From b648f3499626874327d8f1b087a578afe903d010 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 00:44:13 -0700 Subject: pep8 fixes --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f396baa44..2b8494787 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1053,7 +1053,7 @@ class ComputeManager(manager.SchedulerDependentManager): name = db_instance['name'] db_state = db_instance['state'] vm_instance = vm_instances.get(name) - + if vm_instance is None: #NOTE(justinsb): We have to be very careful here, because a #concurrent operation could be in progress (e.g. a spawn) -- cgit From 7ed45fe61416213a4fbfba7e45a765e43b933e16 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 01:05:20 -0700 Subject: Fixed some format strings --- nova/compute/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 2b8494787..0e42a4bd2 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1064,12 +1064,12 @@ class ComputeManager(manager.SchedulerDependentManager): #We could have a separate task to correct this error. #TODO(justinsb): What happens during a live migration? LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "State=%(db_state), so assuming spawn is in " + "State=%(db_state)s, so assuming spawn is in " "progress.") % locals()) vm_state = db_state else: LOG.info(_("Found instance '%(name)s' in DB but no VM. " - "State=%(db_state), so setting state to " + "State=%(db_state)s, so setting state to " "shutoff.") % locals()) vm_state = power_state.SHUTOFF else: -- cgit From 408de4bd5fe436e1829f4b916f0f20042e48eacc Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 01:08:50 -0700 Subject: Clarified note about scope of the _poll_instance_states function --- nova/compute/manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0e42a4bd2..93eca61fb 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1060,7 +1060,9 @@ class ComputeManager(manager.SchedulerDependentManager): if db_state == power_state.NOSTATE: #Assume that NOSTATE => spawning #TODO(justinsb): This does mean that if we crash during a - #spawn, the machine will never leave the spawning state. + #spawn, the machine will never leave the spawning state, + #but this is just the way nova is; this function isn't + #trying to correct that problem. #We could have a separate task to correct this error. #TODO(justinsb): What happens during a live migration? LOG.info(_("Found instance '%(name)s' in DB but no VM. " -- cgit From 7cdc3add34b109e3f956f785b60a5aa5cf273e53 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 28 Mar 2011 12:24:41 +0200 Subject: Do not load extensions that start with a "_" --- nova/api/openstack/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 9d98d849a..439612faa 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -317,7 +317,7 @@ class ExtensionManager(object): LOG.audit(_('Loading extension file: %s'), f) mod_name, file_ext = os.path.splitext(os.path.split(f)[-1]) ext_path = os.path.join(self.path, f) - if file_ext.lower() == '.py': + if file_ext.lower() == '.py' and not mod_name.startswith('_'): mod = imp.load_source(mod_name, ext_path) ext_name = mod_name[0].upper() + mod_name[1:] try: -- cgit From d25968ab494f65ed90981e440169e31a7488befe Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 28 Mar 2011 15:21:53 +0200 Subject: Add friendlier message if an extension fails to include a correctly named class or factory. --- nova/api/openstack/extensions.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 439612faa..4a7236863 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -321,7 +321,14 @@ class ExtensionManager(object): mod = imp.load_source(mod_name, ext_path) ext_name = mod_name[0].upper() + mod_name[1:] try: - new_ext = getattr(mod, ext_name)() + new_ext_class = getattr(mod, ext_name, None) + if not new_ext_class: + LOG.warning(_('Did not find expected name ' + '"%(ext_name)" in %(file)s'), + { 'ext_name': ext_name, + 'file': ext_path }) + continue + new_ext = new_ext_class() self._check_extension(new_ext) self.extensions[new_ext.get_alias()] = new_ext except AttributeError as ex: -- cgit From 9786a19ec0bc5176cc01b56d473a977b85800977 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 28 Mar 2011 15:34:20 +0200 Subject: Spell "warn" correctly. --- nova/api/openstack/extensions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 4a7236863..259d24a7d 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -323,10 +323,10 @@ class ExtensionManager(object): try: new_ext_class = getattr(mod, ext_name, None) if not new_ext_class: - LOG.warning(_('Did not find expected name ' - '"%(ext_name)" in %(file)s'), - { 'ext_name': ext_name, - 'file': ext_path }) + LOG.warn(_('Did not find expected name ' + '"%(ext_name)" in %(file)s'), + { 'ext_name': ext_name, + 'file': ext_path }) continue new_ext = new_ext_class() self._check_extension(new_ext) -- cgit From dbd4eebd7905ae950187dbafeba450f9706e609a Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 28 Mar 2011 10:31:51 -0400 Subject: TopicConsumer -> TopicAdapterConsumer --- bin/nova-ajax-console-proxy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy index b4ba157e1..0342c620a 100755 --- a/bin/nova-ajax-console-proxy +++ b/bin/nova-ajax-console-proxy @@ -115,7 +115,7 @@ class AjaxConsoleProxy(object): {'args': data['args'], 'last_activity': time.time()} conn = rpc.Connection.instance(new=True) - consumer = rpc.TopicConsumer( + consumer = rpc.TopicAdapterConsumer( connection=conn, topic=FLAGS.ajax_console_proxy_topic) consumer.register_callback(Callback()) -- cgit From 5a80f8b3d5ae3be774b0b3e1dbc89c9830273eaa Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Mon, 28 Mar 2011 10:00:33 -0700 Subject: Fix formatting of TODO and NOTE - should be a space after the # --- nova/compute/manager.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 93eca61fb..eb42f054d 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1055,16 +1055,16 @@ class ComputeManager(manager.SchedulerDependentManager): vm_instance = vm_instances.get(name) if vm_instance is None: - #NOTE(justinsb): We have to be very careful here, because a - #concurrent operation could be in progress (e.g. a spawn) + # NOTE(justinsb): We have to be very careful here, because a + # concurrent operation could be in progress (e.g. a spawn) if db_state == power_state.NOSTATE: - #Assume that NOSTATE => spawning - #TODO(justinsb): This does mean that if we crash during a - #spawn, the machine will never leave the spawning state, - #but this is just the way nova is; this function isn't - #trying to correct that problem. - #We could have a separate task to correct this error. - #TODO(justinsb): What happens during a live migration? + # Assume that NOSTATE => spawning + # TODO(justinsb): This does mean that if we crash during a + # spawn, the machine will never leave the spawning state, + # but this is just the way nova is; this function isn't + # trying to correct that problem. + # We could have a separate task to correct this error. + # TODO(justinsb): What happens during a live migration? LOG.info(_("Found instance '%(name)s' in DB but no VM. " "State=%(db_state)s, so assuming spawn is in " "progress.") % locals()) -- cgit From dbf14e9b6cc337233ef95b03fd1c2fdba8ebf8a7 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 28 Mar 2011 10:47:08 -0700 Subject: add snapshot support for libvirt --- nova/virt/libvirt_conn.py | 71 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 36457ee87..4456ffc12 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -38,12 +38,15 @@ Supports KVM, QEMU, UML, and XEN. import multiprocessing import os -import shutil -import sys import random +import shutil import subprocess +import sys +import tempfile +import time import uuid from xml.dom import minidom +from xml.etree import ElementTree from eventlet import greenthread from eventlet import tpool @@ -111,6 +114,8 @@ flags.DEFINE_string('live_migration_flag', 'Define live migration behavior.') flags.DEFINE_integer('live_migration_bandwidth', 0, 'Define live migration behavior') +flags.DEFINE_string('qemu_img', 'qemu-img', + 'binary to use for qemu-img commands') def get_connection(read_only): @@ -397,10 +402,64 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def snapshot(self, instance, image_id): - """ Create snapshot from a running VM instance """ - raise NotImplementedError( - _("Instance snapshotting is not supported for libvirt" - "at this time")) + """Create snapshot from a running VM instance. + + This command only works with qemu 0.14+, the qemu_img flag is + provided so that a locally compiled binary of qemu-img can be used + to support this command. + + """ + image_service = utils.import_object(FLAGS.image_service) + virt_dom = self._conn.lookupByName(instance['name']) + elevated = context.get_admin_context() + + base = image_service.show(elevated, instance['image_id']) + + metadata = {'type': 'machine', + 'is_public': False, + 'properties': {'architecture': base['architecture'], + 'kernel_id': instance['kernel_id'], + 'image_location': 'snapshot', + 'image_state': 'available', + 'owner_id': instance['project_id'], + 'ramdisk_id': instance['ramdisk_id'], + } + } + + # Make the snapshot + snapshot_name = uuid.uuid4().hex + snapshot_xml = """ + + %s + + """ % snapshot_name + snapshot_ptr = virt_dom.snapshotCreateXML(snapshot_xml, 0) + + # Find the disk + xml_desc = virt_dom.XMLDesc(0) + domain = ElementTree.fromstring(xml_desc) + source = domain.find('devices/disk/source') + disk_path = source.get('file') + + # Export the snapshot to a raw image + temp_dir = tempfile.mkdtemp() + out_path = os.path.join(temp_dir, snapshot_name) + qemu_img_cmd = '%s convert -f qcow2 -O raw -s %s %s %s' % ( + FLAGS.qemu_img, + snapshot_name, + disk_path, + out_path) + utils.execute(qemu_img_cmd) + + # Upload that image to the image service + with open(out_path) as image_file: + image_service.update(elevated, + image_id, + metadata, + image_file) + + # Clean up + shutil.rmtree(temp_dir) @exception.wrap_exception def reboot(self, instance): -- cgit From 1e4024b72218a07d1e535878337547cf16406dd8 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 28 Mar 2011 10:47:11 -0700 Subject: update glance params per review --- nova/virt/libvirt_conn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4456ffc12..80eb64f3c 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -415,9 +415,12 @@ class LibvirtConnection(driver.ComputeDriver): base = image_service.show(elevated, instance['image_id']) - metadata = {'type': 'machine', + metadata = {'disk_format': base['disk_format'], + 'container_format': base['container_format'], 'is_public': False, 'properties': {'architecture': base['architecture'], + 'type': base['type'], + 'name': '%s.%s' % (base['name'], image_id), 'kernel_id': instance['kernel_id'], 'image_location': 'snapshot', 'image_state': 'available', -- cgit From 14337b0a31c8f04d8044e234eb295b41a9a9c5ce Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 28 Mar 2011 14:02:53 -0400 Subject: adding shared_ip_groups testing; replacing all shared_ip_groups contoller code with HTTPNotImplemented; moving shared_ip_groups controller to APIRouterV10 --- nova/api/openstack/__init__.py | 8 +++--- nova/api/openstack/shared_ip_groups.py | 6 ++--- nova/tests/api/openstack/test_shared_ip_groups.py | 30 ++++++++++++++++++++--- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 8fabbce8e..cf53ffcd6 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -119,10 +119,6 @@ class APIRouter(wsgi.Router): mapper.resource("image", "images", controller=images.Controller(), collection={'detail': 'GET'}) - mapper.resource("shared_ip_group", "shared_ip_groups", - collection={'detail': 'GET'}, - controller=shared_ip_groups.Controller()) - _limits = limits.LimitsController() mapper.resource("limit", "limits", controller=_limits) @@ -141,6 +137,10 @@ class APIRouterV10(APIRouter): controller=flavors.ControllerV10(), collection={'detail': 'GET'}) + mapper.resource("shared_ip_group", "shared_ip_groups", + collection={'detail': 'GET'}, + controller=shared_ip_groups.Controller()) + class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py index 5d78f9377..ee7991d7f 100644 --- a/nova/api/openstack/shared_ip_groups.py +++ b/nova/api/openstack/shared_ip_groups.py @@ -42,11 +42,11 @@ class Controller(wsgi.Controller): def index(self, req): """ Returns a list of Shared IP Groups for the user """ - return dict(sharedIpGroups=[]) + raise faults.Fault(exc.HTTPNotImplemented()) def show(self, req, id): """ Shows in-depth information on a specific Shared IP Group """ - return _translate_keys({}) + raise faults.Fault(exc.HTTPNotImplemented()) def update(self, req, id): """ You can't update a Shared IP Group """ @@ -58,7 +58,7 @@ class Controller(wsgi.Controller): def detail(self, req): """ Returns a complete list of Shared IP Groups """ - return _translate_detail_keys({}) + raise faults.Fault(exc.HTTPNotImplemented()) def create(self, req): """ Creates a new Shared IP group """ diff --git a/nova/tests/api/openstack/test_shared_ip_groups.py b/nova/tests/api/openstack/test_shared_ip_groups.py index b4de2ef41..c2bd7e45a 100644 --- a/nova/tests/api/openstack/test_shared_ip_groups.py +++ b/nova/tests/api/openstack/test_shared_ip_groups.py @@ -16,25 +16,49 @@ # under the License. import stubout +import webob from nova import test from nova.api.openstack import shared_ip_groups +from nova.tests.api.openstack import fakes class SharedIpGroupsTest(test.TestCase): def setUp(self): super(SharedIpGroupsTest, self).setUp() self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.reset_fake_data() + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_auth(self.stubs) def tearDown(self): self.stubs.UnsetAll() super(SharedIpGroupsTest, self).tearDown() def test_get_shared_ip_groups(self): - pass + req = webob.Request.blank('/v1.0/shared_ip_groups') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 501) def test_create_shared_ip_group(self): - pass + req = webob.Request.blank('/v1.0/shared_ip_groups') + req.method = 'POST' + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 501) + + def test_update_shared_ip_group(self): + req = webob.Request.blank('/v1.0/shared_ip_groups/12') + req.method = 'PUT' + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 501) def test_delete_shared_ip_group(self): - pass + req = webob.Request.blank('/v1.0/shared_ip_groups/12') + req.method = 'DELETE' + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 501) + + def test_deprecated_v11(self): + req = webob.Request.blank('/v1.1/shared_ip_groups') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 404) -- cgit From b6df504c33cfa0fe02e31962578b77d841e1e6d8 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 28 Mar 2011 14:31:12 -0400 Subject: backup_schedule tests corrected; controller moved to APIRouterV10; making controller fully HTTPNotImplemented --- nova/api/openstack/__init__.py | 10 +++++----- nova/api/openstack/backup_schedules.py | 6 +++++- nova/tests/api/openstack/test_servers.py | 22 ++++++++++++++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 8fabbce8e..149abfeb8 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -106,11 +106,6 @@ class APIRouter(wsgi.Router): controller=accounts.Controller(), collection={'detail': 'GET'}) - mapper.resource("backup_schedule", "backup_schedule", - controller=backup_schedules.Controller(), - parent_resource=dict(member_name='server', - collection_name='servers')) - mapper.resource("console", "consoles", controller=consoles.Controller(), parent_resource=dict(member_name='server', @@ -141,6 +136,11 @@ class APIRouterV10(APIRouter): controller=flavors.ControllerV10(), collection={'detail': 'GET'}) + mapper.resource("backup_schedule", "backup_schedule", + controller=backup_schedules.Controller(), + parent_resource=dict(member_name='server', + collection_name='servers')) + class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index 7abb5f884..f2d2d86e8 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -42,7 +42,11 @@ class Controller(wsgi.Controller): def index(self, req, server_id): """ Returns the list of backup schedules for a given instance """ - return _translate_keys({}) + return faults.Fault(exc.HTTPNotImplemented()) + + def show(self, req, server_id, id): + """ Returns a single backup schedule for a given instance """ + return faults.Fault(exc.HTTPNotImplemented()) def create(self, req, server_id): """ No actual update method required, since the existing API allows diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 737b43c7b..989385a8c 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -483,21 +483,31 @@ class ServersTest(test.TestCase): req.get_response(fakes.wsgi_app()) def test_create_backup_schedules(self): - req = webob.Request.blank('/v1.0/servers/1/backup_schedules') + req = webob.Request.blank('/v1.0/servers/1/backup_schedule') req.method = 'POST' res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status, '404 Not Found') + self.assertEqual(res.status_int, 501) def test_delete_backup_schedules(self): - req = webob.Request.blank('/v1.0/servers/1/backup_schedules') + req = webob.Request.blank('/v1.0/servers/1/backup_schedule/1') req.method = 'DELETE' res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status, '404 Not Found') + self.assertEqual(res.status_int, 501) def test_get_server_backup_schedules(self): - req = webob.Request.blank('/v1.0/servers/1/backup_schedules') + req = webob.Request.blank('/v1.0/servers/1/backup_schedule') res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status, '404 Not Found') + self.assertEqual(res.status_int, 501) + + def test_get_server_backup_schedule(self): + req = webob.Request.blank('/v1.0/servers/1/backup_schedule/1') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 501) + + def test_server_backup_schedule_deprecated_v11(self): + req = webob.Request.blank('/v1.1/servers/1/backup_schedule') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 404) def test_get_all_server_details_v1_0(self): req = webob.Request.blank('/v1.0/servers/detail') -- cgit From dea3af64186ff204de7d5ca9852af267e648823e Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 28 Mar 2011 20:36:07 +0200 Subject: Remove now useless try/except block. --- nova/api/openstack/extensions.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 259d24a7d..e2f833d57 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -320,20 +320,16 @@ class ExtensionManager(object): if file_ext.lower() == '.py' and not mod_name.startswith('_'): mod = imp.load_source(mod_name, ext_path) ext_name = mod_name[0].upper() + mod_name[1:] - try: - new_ext_class = getattr(mod, ext_name, None) - if not new_ext_class: - LOG.warn(_('Did not find expected name ' - '"%(ext_name)" in %(file)s'), - { 'ext_name': ext_name, - 'file': ext_path }) - continue - new_ext = new_ext_class() - self._check_extension(new_ext) - self.extensions[new_ext.get_alias()] = new_ext - except AttributeError as ex: - LOG.exception(_("Exception loading extension: %s"), - unicode(ex)) + new_ext_class = getattr(mod, ext_name, None) + if not new_ext_class: + LOG.warn(_('Did not find expected name ' + '"%(ext_name)" in %(file)s'), + { 'ext_name': ext_name, + 'file': ext_path }) + continue + new_ext = new_ext_class() + self._check_extension(new_ext) + self.extensions[new_ext.get_alias()] = new_ext class ResponseExtension(object): -- cgit From 9fdf9967234d8553c3548ad03fc3b2691285fa7d Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Mon, 28 Mar 2011 11:56:19 -0700 Subject: Added image name and description mapping to ec2 api --- nova/api/ec2/cloud.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 0da642318..9e34d3317 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -890,6 +890,8 @@ class CloudController(object): i['imageOwnerId'] = image['properties'].get('owner_id') i['imageLocation'] = image['properties'].get('image_location') i['imageState'] = image['properties'].get('image_state') + i['displayName'] = image.get('name') + i['description'] = image.get('description') i['type'] = image_type i['isPublic'] = str(image['properties'].get('is_public', '')) == 'True' i['architecture'] = image['properties'].get('architecture') -- cgit From 7040eadcc7e86d063c5c69391dedafa181711913 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 28 Mar 2011 22:21:18 +0200 Subject: pep8 --- nova/api/openstack/extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index e2f833d57..b9b7f998d 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -324,8 +324,8 @@ class ExtensionManager(object): if not new_ext_class: LOG.warn(_('Did not find expected name ' '"%(ext_name)" in %(file)s'), - { 'ext_name': ext_name, - 'file': ext_path }) + {'ext_name': ext_name, + 'file': ext_path}) continue new_ext = new_ext_class() self._check_extension(new_ext) -- cgit