From cb2c9d4014905f222d0a4776f637d421eaa6c8ec Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 19 Jan 2011 10:26:55 -0800 Subject: [PATCH 01/20] add helpful error messages to nova-manage and update nova.sh --- bin/nova-manage | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index d0901ddf..b116e79a 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -61,6 +61,7 @@ import sys import time import IPy +from sqlalchemy import exc # If ../nova/__init__.py exists, add ../ to Python search path, so that # it will override what happens to be installed in /usr/(local/)lib/python... @@ -255,6 +256,13 @@ class RoleCommands(object): self.manager.remove_role(user, role, project) +def _db_error(caught_exception): + print caught_exception + print _("The above error may show that the database has not " + "been created.\nPlease create a database using " + "nova-manage sync db before running this command.") + exit(1) + class UserCommands(object): """Class for managing users.""" @@ -270,13 +278,19 @@ class UserCommands(object): def admin(self, name, access=None, secret=None): """creates a new admin and prints exports arguments: name [access] [secret]""" - user = self.manager.create_user(name, access, secret, True) + try: + user = self.manager.create_user(name, access, secret, True) + except exc.OperationalError, e: + _db_error(e) self._print_export(user) def create(self, name, access=None, secret=None): """creates a new user and prints exports arguments: name [access] [secret]""" - user = self.manager.create_user(name, access, secret, False) + try: + user = self.manager.create_user(name, access, secret, False) + except exc.OperationalError, e: + _db_error(e) self._print_export(user) def delete(self, name): @@ -397,9 +411,14 @@ class ProjectCommands(object): with open(filename, 'w') as f: f.write(zip_file) except db.api.NoMoreNetworks: - print ('No more networks available. If this is a new ' - 'installation, you need\nto call something like this:\n\n' - ' nova-manage network create 10.0.0.0/8 10 64\n\n') + print _('No more networks available. If this is a new ' + 'installation, you need\nto call something like this:\n\n' + ' nova-manage network create 10.0.0.0/8 10 64\n\n') + except exception.ProcessExecutionError, e: + print e + print _("The above error may show that the certificate db has not " + "been created.\nPlease create a database by running a " + "nova-api server on this host.") class FloatingIpCommands(object): From 61983f98b4c0e80c6d27568cafce7d025cfb6a01 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Thu, 20 Jan 2011 16:47:46 -0800 Subject: [PATCH 02/20] Fix for LP Bug #699654 --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 608fec52..33895be7 100644 --- a/Authors +++ b/Authors @@ -49,6 +49,7 @@ Soren Hansen Thierry Carrez Todd Willey Trey Morris +Tushar Patil Vishvananda Ishaya Youcef Laribi Zhixue Wu From c6ce24d12bf7b3a97feeab82546667a937c5d19c Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 21 Jan 2011 15:48:10 -0800 Subject: [PATCH 03/20] wrap sqlalchemy exceptions in a generic error --- bin/nova-manage | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index b116e79a..70355a59 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -61,7 +61,6 @@ import sys import time import IPy -from sqlalchemy import exc # If ../nova/__init__.py exists, add ../ to Python search path, so that # it will override what happens to be installed in /usr/(local/)lib/python... @@ -280,7 +279,7 @@ class UserCommands(object): arguments: name [access] [secret]""" try: user = self.manager.create_user(name, access, secret, True) - except exc.OperationalError, e: + except exception.DBError, e: _db_error(e) self._print_export(user) @@ -289,7 +288,7 @@ class UserCommands(object): arguments: name [access] [secret]""" try: user = self.manager.create_user(name, access, secret, False) - except exc.OperationalError, e: + except exception.DBError, e: _db_error(e) self._print_export(user) From 44face17c3a570058d9fde9aadb13ab188d3e2c9 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Sat, 22 Jan 2011 21:20:09 +0000 Subject: [PATCH 04/20] Use Glance to relate machine image with kernel and ramdisk --- krm_mapping.json.sample | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 krm_mapping.json.sample diff --git a/krm_mapping.json.sample b/krm_mapping.json.sample deleted file mode 100644 index 1ecfba63..00000000 --- a/krm_mapping.json.sample +++ /dev/null @@ -1,3 +0,0 @@ -{ - "machine" : ["kernel", "ramdisk"] -} From 613bc0da5745c8313bea2e01133f0f3760a69a46 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 25 Jan 2011 00:15:23 -0800 Subject: [PATCH 05/20] add ip and network to nwfilter test --- nova/tests/test_virt.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index f6800e3d..12fb0159 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -474,6 +474,19 @@ class NWFilterTestCase(test.TestCase): 'project_id': 'fake'}) inst_id = instance_ref['id'] + ip = '10.11.12.13' + + network_ref = db.project_get_network(self.context, + 'fake') + + fixed_ip = {'address': ip, + 'network_id': network_ref['id']} + + admin_ctxt = context.get_admin_context() + db.fixed_ip_create(admin_ctxt, fixed_ip) + db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, + 'instance_id': instance_ref['id']}) + def _ensure_all_called(): instance_filter = 'nova-instance-%s' % instance_ref['name'] secgroup_filter = 'nova-secgroup-%s' % self.security_group['id'] From 6f654d49dc3394de254193a8da04cb5b7f643b6e Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Tue, 25 Jan 2011 11:46:24 -0800 Subject: [PATCH 06/20] updated authors since build is failing --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 608fec52..33895be7 100644 --- a/Authors +++ b/Authors @@ -49,6 +49,7 @@ Soren Hansen Thierry Carrez Todd Willey Trey Morris +Tushar Patil Vishvananda Ishaya Youcef Laribi Zhixue Wu From c1edf8ba941d3470083e76e70d9631cdbff9864f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 25 Jan 2011 15:29:30 -0800 Subject: [PATCH 08/20] fix pep8 issue (and my commit hook that didn't catch it) --- bin/nova-manage | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/nova-manage b/bin/nova-manage index 4f3cfc50..1b70ebf1 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -274,6 +274,7 @@ def _db_error(caught_exception): "nova-manage sync db before running this command.") exit(1) + class UserCommands(object): """Class for managing users.""" From 16ce2ceeed82c003d16886aecc5745e76e11bfe5 Mon Sep 17 00:00:00 2001 From: Jordan Rinke Date: Tue, 25 Jan 2011 15:32:41 -0800 Subject: [PATCH 09/20] Added myself to the authors list. --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 608fec52..c3d09d57 100644 --- a/Authors +++ b/Authors @@ -22,6 +22,7 @@ Jesse Andrews Joe Heck Joel Moore Jonathan Bryce +Jordan Rinke Josh Durgin Josh Kearney Joshua McKenty From d59e9bf1aa62294e8dea3b54cd07fc46f7764bcb Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 25 Jan 2011 15:56:55 -0800 Subject: [PATCH 10/20] Change how libvirt firewall drivers work to have meaningful flags. --- nova/tests/test_virt.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 0b9b847a..1760b73a 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -221,7 +221,12 @@ class IptablesFirewallTestCase(test.TestCase): self.project = self.manager.create_project('fake', 'fake', 'fake') self.context = context.RequestContext('fake', 'fake') self.network = utils.import_object(FLAGS.network_manager) - self.fw = libvirt_conn.IptablesFirewallDriver() + + class Mock(object): + pass + self.fake_libvirt_connection = Mock() + self.fw = libvirt_conn.IptablesFirewallDriver( + get_connection=lambda: self.fake_libvirt_connection) def tearDown(self): self.manager.delete_project(self.project) From d3b15ff65158a8e76c165dd184fb61352209e59f Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 25 Jan 2011 16:40:23 -0800 Subject: [PATCH 11/20] Add DescribeInstanceTypes to admin api (dashboard uses it). --- nova/adminclient.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/nova/adminclient.py b/nova/adminclient.py index b2609c8c..3cdd8347 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -190,6 +190,45 @@ class HostInfo(object): setattr(self, name, value) +class InstanceType(object): + """ + Information about a Nova instance type, as parsed through SAX. + + **Fields include** + + * name + * vcpus + * disk_gb + * memory_mb + * flavor_id + + """ + + def __init__(self, connection=None): + self.connection = connection + self.name = None + self.vcpus = None + self.disk_gb = None + self.memory_mb = None + self.flavor_id = None + + def __repr__(self): + return 'InstanceType:%s' % self.name + + def startElement(self, name, attrs, connection): + return None + + def endElement(self, name, value, connection): + if name == "memoryMb": + self.memory_mb = str(value) + elif name == "flavorId": + self.flavor_id = str(value) + elif name == "diskGb": + self.disk_gb = str(value) + else: + setattr(self, name, str(value)) + + class NovaAdminClient(object): def __init__( @@ -373,3 +412,8 @@ class NovaAdminClient(object): def get_hosts(self): return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)]) + + def get_instance_types(self): + """Grabs the list of all users.""" + return self.apiconn.get_list('DescribeInstanceTypes', {}, + [('item', InstanceType)]) From 9313a83fdd47429ff2c1762372beee243ebb088c Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 25 Jan 2011 17:13:34 -0800 Subject: [PATCH 12/20] Rename Mock, since it wasn't a Mock. --- nova/tests/test_virt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 1760b73a..1008f32a 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -222,9 +222,9 @@ class IptablesFirewallTestCase(test.TestCase): self.context = context.RequestContext('fake', 'fake') self.network = utils.import_object(FLAGS.network_manager) - class Mock(object): + class FakeLibvirtConnection(object): pass - self.fake_libvirt_connection = Mock() + self.fake_libvirt_connection = FakeLibvirtConnection() self.fw = libvirt_conn.IptablesFirewallDriver( get_connection=lambda: self.fake_libvirt_connection) From 0c84298892a6cd763458587516bc53fa13ecdfef Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Wed, 26 Jan 2011 16:58:24 -0500 Subject: [PATCH 13/20] Changed method signature of create_network --- bin/nova-manage | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 1b70ebf1..7835ca55 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -495,9 +495,9 @@ class NetworkCommands(object): cidr=fixed_range, num_networks=int(num_networks), network_size=int(network_size), + cidr_v6=fixed_range_v6, vlan_start=int(vlan_start), - vpn_start=int(vpn_start), - cidr_v6=fixed_range_v6) + vpn_start=int(vpn_start)) class ServiceCommands(object): From 8403db15452cea8672265f6ed750ebd4f3796e1c Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 26 Jan 2011 18:34:56 -0500 Subject: [PATCH 14/20] Add dan.prince to Authors. --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 549a493f..638d13de 100644 --- a/Authors +++ b/Authors @@ -8,6 +8,7 @@ Chmouel Boudjnah Chris Behrens Cory Wright David Pravec +Dan Prince Dean Troyer Devin Carlen Ed Leafe From ef3f38d94a67ed0db1011d2d28c4ac025c643209 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 27 Jan 2011 15:45:24 +0100 Subject: [PATCH 16/20] Add unit test for xmlns version matching request version. --- nova/tests/test_api.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index 66a16b0c..2569e262 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -36,6 +36,7 @@ from nova.auth import manager class FakeHttplibSocket(object): """a fake socket implementation for httplib.HTTPResponse, trivial""" def __init__(self, response_string): + self.response_string = response_string self._buffer = StringIO.StringIO(response_string) def makefile(self, _mode, _other): @@ -66,13 +67,16 @@ class FakeHttplibConnection(object): # For some reason, the response doesn't have "HTTP/1.0 " prepended; I # guess that's a function the web server usually provides. resp = "HTTP/1.0 %s" % resp - sock = FakeHttplibSocket(resp) - self.http_response = httplib.HTTPResponse(sock) + self.sock = FakeHttplibSocket(resp) + self.http_response = httplib.HTTPResponse(self.sock) self.http_response.begin() def getresponse(self): return self.http_response + def getresponsebody(self): + return self.sock.response_string + def close(self): """Required for compatibility with boto/tornado""" pass @@ -104,7 +108,7 @@ class ApiEc2TestCase(test.TestCase): self.app = ec2.Authenticate(ec2.Requestify(ec2.Executor(), 'nova.api.ec2.cloud.CloudController')) - def expect_http(self, host=None, is_secure=False): + def expect_http(self, host=None, is_secure=False, api_version=None): """Returns a new EC2 connection""" self.ec2 = boto.connect_ec2( aws_access_key_id='fake', @@ -113,13 +117,31 @@ class ApiEc2TestCase(test.TestCase): region=regioninfo.RegionInfo(None, 'test', self.host), port=8773, path='/services/Cloud') + if api_version: + self.ec2.APIVersion = api_version self.mox.StubOutWithMock(self.ec2, 'new_http_connection') - http = FakeHttplibConnection( + self.http = FakeHttplibConnection( self.app, '%s:8773' % (self.host), False) # pylint: disable-msg=E1103 - self.ec2.new_http_connection(host, is_secure).AndReturn(http) - return http + self.ec2.new_http_connection(host, is_secure).AndReturn(self.http) + return self.http + + def test_xmlns_version_matches_request_version(self): + self.expect_http(api_version='2010-10-30') + self.mox.ReplayAll() + + user = self.manager.create_user('fake', 'fake', 'fake') + project = self.manager.create_project('fake', 'fake', 'fake') + + # Any request should be fine + self.ec2.get_all_instances() + self.assertTrue(self.ec2.APIVersion in self.http.getresponsebody(), + 'The version in the xmlns of the response does ' + 'not match the API version given in the request.') + + self.manager.delete_project(project) + self.manager.delete_user(user) def test_describe_instances(self): """Test that, after creating a user and a project, the describe From 5543714de56cb369e83fa962fcb3d6209fd75621 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 27 Jan 2011 12:52:55 -0600 Subject: [PATCH 18/20] Added the test for localized string formatting --- nova/tests/test_localization.py | 95 +++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 nova/tests/test_localization.py diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py new file mode 100644 index 00000000..a546b3e7 --- /dev/null +++ b/nova/tests/test_localization.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import glob +import logging +import os +import re +import sys + +import nova +from nova import test + +LOG = logging.getLogger('nova.tests.localization_unittest') + + +class LocalizationTestCase(test.TestCase): + def setUp(self): + super(LocalizationTestCase, self).setUp() + + def tearDown(self): + super(LocalizationTestCase, self).tearDown() + + def test_multiple_positional_format_placeholders(self): + pat = re.compile("\W_\(") + single_pat = re.compile("\W%\W") + root_path = os.path.dirname(nova.__file__) + problems = {} + for root, dirs, files in os.walk(root_path): + for fname in files: + if not fname.endswith(".py"): + continue + pth = os.path.join(root, fname) + txt = fulltext = file(pth).read() + txt_lines = fulltext.splitlines() + if not pat.search(txt): + continue + problems[pth] = [] + pos = txt.find("_(") + while pos > -1: + # Make sure that this isn't part of a dunder; + # e.g., __init__(... + # or something like 'self.assert_(...' + test_txt = txt[pos - 1: pos + 10] + if not (pat.search(test_txt)): + txt = txt[pos + 2:] + pos = txt.find("_(") + continue + pos += 2 + txt = txt[pos:] + innerChars = [] + # Count pairs of open/close parens until _() closing + # paren is found. + parenCount = 1 + pos = 0 + while parenCount > 0: + char = txt[pos] + if char == "(": + parenCount += 1 + elif char == ")": + parenCount -= 1 + innerChars.append(char) + pos += 1 + inner_all = "".join(innerChars) + # Filter out '%%' and '%(' + inner = inner_all.replace("%%", "").replace("%(", "") + # Filter out the single '%' operators + inner = single_pat.sub("", inner) + # Within the remaining content, count % + fmtCount = inner.count("%") + if fmtCount > 1: + inner_first = inner_all.splitlines()[0] + lns = ["%s" % (p + 1) + for p, t in enumerate(txt_lines) + if inner_first in t] + lnums = ", ".join(lns) + # Using ugly string concatenation to avoid having + # this test fail itself. + inner_all = "_" + "(" + "%s" % inner_all + problems[pth].append("Line: %s Text: %s" % + (lnums, inner_all)) + # Look for more + pos = txt.find("_(") + if not problems[pth]: + del problems[pth] + if problems: + out = ["Problem(s) found in localized string formatting", + "(see http://www.gnu.org/software/hello/manual/" + "gettext/Python.html for more information)", + "", + " ------------ Files to fix ------------"] + for pth in problems: + out.append(" %s:" % pth) + for val in set(problems[pth]): + out.append(" %s" % val) + raise AssertionError("\n".join(out)) From 35d0ac4dcb46438b44562b08333b600ff09d755f Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 27 Jan 2011 13:52:10 -0600 Subject: [PATCH 19/20] Fixed formatting issues in current codebase. --- nova/tests/test_localization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py index a546b3e7..0368ac01 100644 --- a/nova/tests/test_localization.py +++ b/nova/tests/test_localization.py @@ -65,7 +65,7 @@ class LocalizationTestCase(test.TestCase): inner = inner_all.replace("%%", "").replace("%(", "") # Filter out the single '%' operators inner = single_pat.sub("", inner) - # Within the remaining content, count % + # Within the remaining content, count % fmtCount = inner.count("%") if fmtCount > 1: inner_first = inner_all.splitlines()[0] From 03e7d87cb1abc475ea5f9a11e9e70975503fc698 Mon Sep 17 00:00:00 2001 From: Ed Leafe Date: Thu, 27 Jan 2011 16:54:59 -0600 Subject: [PATCH 20/20] Made changes based on code review --- nova/tests/test_localization.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py index 0368ac01..6992773f 100644 --- a/nova/tests/test_localization.py +++ b/nova/tests/test_localization.py @@ -1,25 +1,30 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# 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. import glob import logging import os import re import sys +import unittest import nova -from nova import test - -LOG = logging.getLogger('nova.tests.localization_unittest') -class LocalizationTestCase(test.TestCase): - def setUp(self): - super(LocalizationTestCase, self).setUp() - - def tearDown(self): - super(LocalizationTestCase, self).tearDown() - +class LocalizationTestCase(unittest.TestCase): def test_multiple_positional_format_placeholders(self): pat = re.compile("\W_\(") single_pat = re.compile("\W%\W")