diff --git a/Authors b/Authors index 9aad104a..1679d2de 100644 --- a/Authors +++ b/Authors @@ -33,6 +33,7 @@ Jonathan Bryce Jordan Rinke Josh Durgin Josh Kearney +Josh Kleinpeter Joshua McKenty Justin Santa Barbara Kei Masumoto diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy index bbd60bad..b4ba157e 100755 --- a/bin/nova-ajax-console-proxy +++ b/bin/nova-ajax-console-proxy @@ -1,5 +1,5 @@ #!/usr/bin/env python -# pylint: disable-msg=C0103 +# pylint: disable=C0103 # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the diff --git a/bin/nova-api b/bin/nova-api index 06bb855c..a1088c23 100755 --- a/bin/nova-api +++ b/bin/nova-api @@ -1,5 +1,5 @@ #!/usr/bin/env python -# pylint: disable-msg=C0103 +# pylint: disable=C0103 # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the diff --git a/bin/nova-direct-api b/bin/nova-direct-api index bf29d9a5..a2c9f155 100755 --- a/bin/nova-direct-api +++ b/bin/nova-direct-api @@ -1,5 +1,5 @@ #!/usr/bin/env python -# pylint: disable-msg=C0103 +# pylint: disable=C0103 # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the diff --git a/bin/nova-instancemonitor b/bin/nova-instancemonitor index 24cc9fd2..b9d4e49d 100755 --- a/bin/nova-instancemonitor +++ b/bin/nova-instancemonitor @@ -50,7 +50,7 @@ if __name__ == '__main__': if __name__ == '__builtin__': LOG.warn(_('Starting instance monitor')) - # pylint: disable-msg=C0103 + # pylint: disable=C0103 monitor = monitor.InstanceMonitor() # This is the parent service that twistd will be looking for when it diff --git a/bin/nova-manage b/bin/nova-manage index a4d82020..69cbf6f9 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -518,11 +518,12 @@ class NetworkCommands(object): network_size=None, vlan_start=None, vpn_start=None, fixed_range_v6=None, label='public'): """Creates fixed ips for host by range - arguments: [fixed_range=FLAG], [num_networks=FLAG], + arguments: fixed_range=FLAG, [num_networks=FLAG], [network_size=FLAG], [vlan_start=FLAG], [vpn_start=FLAG], [fixed_range_v6=FLAG]""" if not fixed_range: - fixed_range = FLAGS.fixed_range + raise TypeError(_('Fixed range in the form of 10.0.0.0/8 is ' + 'required to create networks.')) if not num_networks: num_networks = FLAGS.num_networks if not network_size: @@ -579,8 +580,10 @@ class VmCommands(object): ctxt = context.get_admin_context() instance_id = ec2utils.ec2_id_to_id(ec2_id) - if FLAGS.connection_type != 'libvirt': - msg = _('Only KVM is supported for now. Sorry!') + if (FLAGS.connection_type != 'libvirt' or + (FLAGS.connection_type == 'libvirt' and + FLAGS.libvirt_type not in ['kvm', 'qemu'])): + msg = _('Only KVM and QEmu are supported for now. Sorry!') raise exception.Error(msg) if (FLAGS.volume_driver != 'nova.volume.driver.AOEDriver' and \ @@ -872,7 +875,7 @@ class InstanceTypeCommands(object): if name == None: inst_types = instance_types.get_all_types() elif name == "--all": - inst_types = instance_types.get_all_types(1) + inst_types = instance_types.get_all_types(True) else: inst_types = instance_types.get_instance_type(name) except exception.DBError, e: diff --git a/bin/nova-objectstore b/bin/nova-objectstore index 9fbe228a..94ef2a8d 100755 --- a/bin/nova-objectstore +++ b/bin/nova-objectstore @@ -49,4 +49,4 @@ if __name__ == '__main__': twistd.serve(__file__) if __name__ == '__builtin__': - application = handler.get_application() # pylint: disable-msg=C0103 + application = handler.get_application() # pylint: disable=C0103 diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py index d8dad8ed..d1e3f2ed 100644 --- a/nova/auth/dbdriver.py +++ b/nova/auth/dbdriver.py @@ -162,6 +162,8 @@ class DbDriver(object): values['description'] = description db.project_update(context.get_admin_context(), project_id, values) + if not self.is_in_project(manager_uid, project_id): + self.add_to_project(manager_uid, project_id) def add_to_project(self, uid, project_id): """Add user to project""" diff --git a/nova/auth/fakeldap.py b/nova/auth/fakeldap.py index 4466051f..79afb910 100644 --- a/nova/auth/fakeldap.py +++ b/nova/auth/fakeldap.py @@ -90,12 +90,12 @@ MOD_DELETE = 1 MOD_REPLACE = 2 -class NO_SUCH_OBJECT(Exception): # pylint: disable-msg=C0103 +class NO_SUCH_OBJECT(Exception): # pylint: disable=C0103 """Duplicate exception class from real LDAP module.""" pass -class OBJECT_CLASS_VIOLATION(Exception): # pylint: disable-msg=C0103 +class OBJECT_CLASS_VIOLATION(Exception): # pylint: disable=C0103 """Duplicate exception class from real LDAP module.""" pass @@ -268,7 +268,7 @@ class FakeLDAP(object): # get the attributes from the store attrs = store.hgetall(key) # turn the values from the store into lists - # pylint: disable-msg=E1103 + # pylint: disable=E1103 attrs = dict([(k, _from_json(v)) for k, v in attrs.iteritems()]) # filter the objects by query @@ -277,12 +277,12 @@ class FakeLDAP(object): attrs = dict([(k, v) for k, v in attrs.iteritems() if not fields or k in fields]) objects.append((key[len(self.__prefix):], attrs)) - # pylint: enable-msg=E1103 + # pylint: enable=E1103 if objects == []: raise NO_SUCH_OBJECT() return objects @property - def __prefix(self): # pylint: disable-msg=R0201 + def __prefix(self): # pylint: disable=R0201 """Get the prefix to use for all keys.""" return 'ldap:' diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py index 5da7751a..fcac5551 100644 --- a/nova/auth/ldapdriver.py +++ b/nova/auth/ldapdriver.py @@ -275,6 +275,8 @@ class LdapDriver(object): attr.append((self.ldap.MOD_REPLACE, 'description', description)) dn = self.__project_to_dn(project_id) self.conn.modify_s(dn, attr) + if not self.is_in_project(manager_uid, project_id): + self.add_to_project(manager_uid, project_id) @sanitize def add_to_project(self, uid, project_id): @@ -632,6 +634,6 @@ class LdapDriver(object): class FakeLdapDriver(LdapDriver): """Fake Ldap Auth driver""" - def __init__(self): # pylint: disable-msg=W0231 + def __init__(self): # pylint: disable=W0231 __import__('nova.auth.fakeldap') self.ldap = sys.modules['nova.auth.fakeldap'] diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 450ab803..48684539 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -22,7 +22,7 @@ Nova authentication management import os import shutil -import string # pylint: disable-msg=W0402 +import string # pylint: disable=W0402 import tempfile import uuid import zipfile @@ -96,10 +96,19 @@ class AuthBase(object): class User(AuthBase): - """Object representing a user""" + """Object representing a user + + The following attributes are defined: + :id: A system identifier for the user. A string (for LDAP) + :name: The user name, potentially in some more friendly format + :access: The 'username' for EC2 authentication + :secret: The 'password' for EC2 authenticatoin + :admin: ??? + """ def __init__(self, id, name, access, secret, admin): AuthBase.__init__(self) + assert isinstance(id, basestring) self.id = id self.name = name self.access = access diff --git a/nova/rpc.py b/nova/rpc.py index fbb90299..5935e1fb 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -62,7 +62,7 @@ class Connection(carrot_connection.BrokerConnection): params['backend_cls'] = fakerabbit.Backend # NOTE(vish): magic is fun! - # pylint: disable-msg=W0142 + # pylint: disable=W0142 if new: return cls(**params) else: @@ -114,7 +114,7 @@ class Consumer(messaging.Consumer): if self.failed_connection: # NOTE(vish): connection is defined in the parent class, we can # recreate it as long as we create the backend too - # pylint: disable-msg=W0201 + # pylint: disable=W0201 self.connection = Connection.recreate() self.backend = self.connection.create_backend() self.declare() @@ -125,7 +125,7 @@ class Consumer(messaging.Consumer): # NOTE(vish): This is catching all errors because we really don't # want exceptions to be logged 10 times a second if some # persistent failure occurs. - except Exception: # pylint: disable-msg=W0703 + except Exception: # pylint: disable=W0703 if not self.failed_connection: LOG.exception(_("Failed to fetch message from queue")) self.failed_connection = True @@ -311,7 +311,7 @@ def _pack_context(msg, context): def call(context, topic, msg): """Sends a message on a topic and wait for a response""" - LOG.debug(_("Making asynchronous call...")) + LOG.debug(_("Making asynchronous call on %s ..."), topic) msg_id = uuid.uuid4().hex msg.update({'_msg_id': msg_id}) LOG.debug(_("MSG_ID is %s") % (msg_id)) @@ -352,7 +352,7 @@ def call(context, topic, msg): def cast(context, topic, msg): """Sends a message on a topic without waiting for a response""" - LOG.debug(_("Making asynchronous cast...")) + LOG.debug(_("Making asynchronous cast on %s..."), topic) _pack_context(msg, context) conn = Connection.instance() publisher = TopicPublisher(connection=conn, topic=topic) diff --git a/nova/tests/hyperv_unittest.py b/nova/tests/hyperv_unittest.py index 3980ae3c..042819b9 100644 --- a/nova/tests/hyperv_unittest.py +++ b/nova/tests/hyperv_unittest.py @@ -51,7 +51,7 @@ class HyperVTestCase(test.TestCase): instance_ref = db.instance_create(self.context, instance) conn = hyperv.get_connection(False) - conn._create_vm(instance_ref) # pylint: disable-msg=W0212 + conn._create_vm(instance_ref) # pylint: disable=W0212 found = [n for n in conn.list_instances() if n == instance_ref['name']] self.assertTrue(len(found) == 1) diff --git a/nova/tests/objectstore_unittest.py b/nova/tests/objectstore_unittest.py index 5a1be08e..4e2ac205 100644 --- a/nova/tests/objectstore_unittest.py +++ b/nova/tests/objectstore_unittest.py @@ -179,7 +179,7 @@ class ObjectStoreTestCase(test.TestCase): class TestHTTPChannel(http.HTTPChannel): """Dummy site required for twisted.web""" - def checkPersistence(self, _, __): # pylint: disable-msg=C0103 + def checkPersistence(self, _, __): # pylint: disable=C0103 """Otherwise we end up with an unclean reactor.""" return False @@ -209,10 +209,10 @@ class S3APITestCase(test.TestCase): root = S3() self.site = TestSite(root) - # pylint: disable-msg=E1101 + # pylint: disable=E1101 self.listening_port = reactor.listenTCP(0, self.site, interface='127.0.0.1') - # pylint: enable-msg=E1101 + # pylint: enable=E1101 self.tcp_port = self.listening_port.getHost().port if not boto.config.has_section('Boto'): @@ -231,11 +231,11 @@ class S3APITestCase(test.TestCase): self.conn.get_http_connection = get_http_connection - def _ensure_no_buckets(self, buckets): # pylint: disable-msg=C0111 + def _ensure_no_buckets(self, buckets): # pylint: disable=C0111 self.assertEquals(len(buckets), 0, "Bucket list was not empty") return True - def _ensure_one_bucket(self, buckets, name): # pylint: disable-msg=C0111 + def _ensure_one_bucket(self, buckets, name): # pylint: disable=C0111 self.assertEquals(len(buckets), 1, "Bucket list didn't have exactly one element in it") self.assertEquals(buckets[0].name, name, "Wrong name") diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index d5c54a1c..fa0e5659 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -20,6 +20,7 @@ import boto from boto.ec2 import regioninfo +from boto.exception import EC2ResponseError import datetime import httplib import random @@ -124,7 +125,7 @@ class ApiEc2TestCase(test.TestCase): self.mox.StubOutWithMock(self.ec2, 'new_http_connection') self.http = FakeHttplibConnection( self.app, '%s:8773' % (self.host), False) - # pylint: disable-msg=E1103 + # pylint: disable=E1103 self.ec2.new_http_connection(host, is_secure).AndReturn(self.http) return self.http @@ -177,6 +178,17 @@ class ApiEc2TestCase(test.TestCase): self.manager.delete_project(project) self.manager.delete_user(user) + def test_terminate_invalid_instance(self): + """Attempt to terminate an invalid instance""" + self.expect_http() + self.mox.ReplayAll() + user = self.manager.create_user('fake', 'fake', 'fake') + project = self.manager.create_project('fake', 'fake', 'fake') + self.assertRaises(EC2ResponseError, self.ec2.terminate_instances, + "i-00000005") + self.manager.delete_project(project) + self.manager.delete_user(user) + def test_get_all_key_pairs(self): """Test that, after creating a user and project and generating a key pair, that the API call to list key pairs works properly""" diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py index 2a781703..885596f5 100644 --- a/nova/tests/test_auth.py +++ b/nova/tests/test_auth.py @@ -299,6 +299,13 @@ class AuthManagerTestCase(object): self.assertEqual('test2', project.project_manager_id) self.assertEqual('new desc', project.description) + def test_modify_project_adds_new_manager(self): + with user_and_project_generator(self.manager): + with user_generator(self.manager, name='test2'): + self.manager.modify_project('testproj', 'test2', 'new desc') + project = self.manager.get_project('testproj') + self.assertTrue('test2' in project.member_ids) + def test_can_delete_project(self): with user_generator(self.manager): self.manager.create_project('testproj', 'test1') diff --git a/nova/tests/test_middleware.py b/nova/tests/test_middleware.py index 9d49167b..6564a695 100644 --- a/nova/tests/test_middleware.py +++ b/nova/tests/test_middleware.py @@ -40,12 +40,12 @@ def conditional_forbid(req): class LockoutTestCase(test.TestCase): """Test case for the Lockout middleware.""" - def setUp(self): # pylint: disable-msg=C0103 + def setUp(self): # pylint: disable=C0103 super(LockoutTestCase, self).setUp() utils.set_time_override() self.lockout = ec2.Lockout(conditional_forbid) - def tearDown(self): # pylint: disable-msg=C0103 + def tearDown(self): # pylint: disable=C0103 utils.clear_time_override() super(LockoutTestCase, self).tearDown() diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index 1b1d7209..5d68ca2a 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -336,8 +336,8 @@ class ISCSITestCase(DriverTestCase): self.mox.StubOutWithMock(self.volume.driver, '_execute') for i in volume_id_list: tid = db.volume_get_iscsi_target_num(self.context, i) - self.volume.driver._execute("sudo ietadm --op show --tid=%(tid)d" - % locals()) + self.volume.driver._execute("sudo", "ietadm", "--op", "show", + "--tid=%(tid)d" % locals()) self.stream.truncate(0) self.mox.ReplayAll() @@ -355,8 +355,9 @@ class ISCSITestCase(DriverTestCase): # the first vblade process isn't running tid = db.volume_get_iscsi_target_num(self.context, volume_id_list[0]) self.mox.StubOutWithMock(self.volume.driver, '_execute') - self.volume.driver._execute("sudo ietadm --op show --tid=%(tid)d" - % locals()).AndRaise(exception.ProcessExecutionError()) + self.volume.driver._execute("sudo", "ietadm", "--op", "show", + "--tid=%(tid)d" % locals() + ).AndRaise(exception.ProcessExecutionError()) self.mox.ReplayAll() self.assertRaises(exception.ProcessExecutionError, diff --git a/po/nova.pot b/po/nova.pot index ce88d731..58140302 100644 --- a/po/nova.pot +++ b/po/nova.pot @@ -300,7 +300,7 @@ msgstr "" msgid "instance %s: starting..." msgstr "" -#. pylint: disable-msg=W0702 +#. pylint: disable=W0702 #: ../nova/compute/manager.py:219 #, python-format msgid "instance %s: Failed to spawn" @@ -440,7 +440,7 @@ msgid "" "instance %(instance_id)s: attaching volume %(volume_id)s to %(mountpoint)s" msgstr "" -#. pylint: disable-msg=W0702 +#. pylint: disable=W0702 #. NOTE(vish): The inline callback eats the exception info so we #. log the traceback here and reraise the same #. ecxception below. @@ -591,7 +591,7 @@ msgstr "" msgid "Starting Bridge interface for %s" msgstr "" -#. pylint: disable-msg=W0703 +#. pylint: disable=W0703 #: ../nova/network/linux_net.py:314 #, python-format msgid "Hupping dnsmasq threw %s" @@ -602,7 +602,7 @@ msgstr "" msgid "Pid %d is stale, relaunching dnsmasq" msgstr "" -#. pylint: disable-msg=W0703 +#. pylint: disable=W0703 #: ../nova/network/linux_net.py:358 #, python-format msgid "killing radvd threw %s" @@ -613,7 +613,7 @@ msgstr "" msgid "Pid %d is stale, relaunching radvd" msgstr "" -#. pylint: disable-msg=W0703 +#. pylint: disable=W0703 #: ../nova/network/linux_net.py:449 #, python-format msgid "Killing dnsmasq threw %s" diff --git a/run_tests.py b/run_tests.py index 3c8d410e..d5d8acd1 100644 --- a/run_tests.py +++ b/run_tests.py @@ -60,6 +60,8 @@ import os import unittest import sys +gettext.install('nova', unicode=1) + from nose import config from nose import core from nose import result