From b760e7cf6c84233bba1bcf336f630cbbbe54f672 Mon Sep 17 00:00:00 2001 From: Ricardo Carrillo Cruz Date: Wed, 19 Jan 2011 21:15:23 +0100 Subject: Exception string lacking 'G' for gigabytes unit --- nova/volume/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/volume/api.py b/nova/volume/api.py index ce4831cc3..cab9e4b05 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -44,7 +44,7 @@ class API(base.Base): LOG.warn(_("Quota exceeeded for %s, tried to create %sG volume"), context.project_id, size) raise quota.QuotaError(_("Volume quota exceeded. You cannot " - "create a volume of size %s") % size) + "create a volume of size %sG") % size) options = { 'size': size, -- cgit From 34d1022e8fbcfe2b6aaf30c6916ad01f0fe1769c Mon Sep 17 00:00:00 2001 From: Ricardo Carrillo Cruz Date: Tue, 25 Jan 2011 13:50:11 +0100 Subject: Added myself to ./Authors file --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 82e07a6b5..fb0c87150 100644 --- a/Authors +++ b/Authors @@ -38,6 +38,7 @@ MORITA Kazutaka Muneyuki Noguchi Nachi Ueno Paul Voccio +Ricardo Carrillo Cruz Rick Clark Rick Harris Ryan Lane -- cgit From 9a3d84b29e33eb5249cc1c04f61bb47f8d1fc1f6 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Tue, 25 Jan 2011 11:41:49 -0800 Subject: Adds conditional around sphinx inclusion. --- setup.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/setup.py b/setup.py index 65adbe992..484e50e6c 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,6 @@ import subprocess from setuptools import setup, find_packages from setuptools.command.sdist import sdist -from sphinx.setup_command import BuildDoc from nova.utils import parse_mailmap, str_dict_replace from nova import version @@ -34,14 +33,6 @@ if os.path.isdir('.bzr'): version_file.write(vcsversion) -class local_BuildDoc(BuildDoc): - def run(self): - for builder in ['html', 'man']: - self.builder = builder - self.finalize_options() - BuildDoc.run(self) - - class local_sdist(sdist): """Customized sdist hook - builds the ChangeLog file from VC first""" @@ -57,9 +48,22 @@ class local_sdist(sdist): with open("ChangeLog", "w") as changelog_file: changelog_file.write(str_dict_replace(changelog, mailmap)) sdist.run(self) +nova_cmdclass = {'sdist': local_sdist} + + +try: + from sphinx.setup_command import BuildDoc + class local_BuildDoc(BuildDoc): + def run(self): + for builder in ['html', 'man']: + self.builder = builder + self.finalize_options() + BuildDoc.run(self) + nova_cmdclass['build_sphinx'] = local_BuildDoc + +except: + pass -nova_cmdclass = {'sdist': local_sdist, - 'build_sphinx': local_BuildDoc} try: from babel.messages import frontend as babel -- cgit From 1a44e3cd5e366b0862c505e8d93581184c3162f1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 27 Jan 2011 13:48:19 -0800 Subject: remove all floating addresses on terminate instance --- nova/compute/manager.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0f9bf301f..84de590d7 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -231,22 +231,25 @@ class ComputeManager(manager.Manager): instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_("Terminating instance %s"), instance_id, context=context) - if not FLAGS.stub_network: - address = self.db.instance_get_floating_address(context, - instance_ref['id']) - if address: - LOG.debug(_("Disassociating address %s"), address, + fixed_ip = instance_ref.get('fixed_ip', None) + if not FLAGS.stub_network and fixed_ip: + floating_ips = fixed_ip.get('floating_ips') or [] + for floating_ip in floating_ips: + address = floating_ip['address'] + LOG.debug("Disassociating address %s", address, context=context) # NOTE(vish): Right now we don't really care if the ip is # disassociated. We may need to worry about # checking this later. + network_topic = self.db.queue_get_for(context, + FLAGS.network_topic, + floating_ip['host']) rpc.cast(context, - self.get_network_topic(context), + network_topic, {"method": "disassociate_floating_ip", "args": {"floating_address": address}}) - address = self.db.instance_get_fixed_address(context, - instance_ref['id']) + address = fixed_ip['address'] if address: LOG.debug(_("Deallocating address %s"), address, context=context) @@ -256,7 +259,7 @@ class ComputeManager(manager.Manager): self.network_manager.deallocate_fixed_ip(context.elevated(), address) - volumes = instance_ref.get('volumes', []) or [] + volumes = instance_ref.get('volumes') or [] for volume in volumes: self.detach_volume(context, instance_id, volume['id']) if instance_ref['state'] == power_state.SHUTOFF: -- cgit From c5a691be561615073507b61dca5a9f8f768a48b1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 27 Jan 2011 14:14:10 -0800 Subject: makes sure that : is in the availability zone before it attempts to use it to send instances to a particular host --- nova/scheduler/simple.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nova/scheduler/simple.py b/nova/scheduler/simple.py index baf4966d4..0191ceb3d 100644 --- a/nova/scheduler/simple.py +++ b/nova/scheduler/simple.py @@ -43,7 +43,9 @@ class SimpleScheduler(chance.ChanceScheduler): def schedule_run_instance(self, context, instance_id, *_args, **_kwargs): """Picks a host that is up and has the fewest running instances.""" instance_ref = db.instance_get(context, instance_id) - if instance_ref['availability_zone'] and context.is_admin: + if (instance_ref['availability_zone'] + and ':' in instance_ref['availability_zone'] + and context.is_admin): zone, _x, host = instance_ref['availability_zone'].partition(':') service = db.service_get_by_args(context.elevated(), host, 'nova-compute') @@ -75,7 +77,9 @@ class SimpleScheduler(chance.ChanceScheduler): def schedule_create_volume(self, context, volume_id, *_args, **_kwargs): """Picks a host that is up and has the fewest volumes.""" volume_ref = db.volume_get(context, volume_id) - if (':' in volume_ref['availability_zone']) and context.is_admin: + if (volume_ref['availability_zone'] + and ':' in volume_ref['availability_zone'] + and context.is_admin): zone, _x, host = volume_ref['availability_zone'].partition(':') service = db.service_get_by_args(context.elevated(), host, 'nova-volume') -- cgit From 98cc358d4cc04b61fc19ce77f5db58cf88c6e908 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 27 Jan 2011 16:26:15 -0800 Subject: simplify get and remove extra reference to import logging. --- nova/compute/manager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 84de590d7..f4418af26 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -37,7 +37,6 @@ terminating it. import datetime import random import string -import logging import socket import functools @@ -231,7 +230,7 @@ class ComputeManager(manager.Manager): instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_("Terminating instance %s"), instance_id, context=context) - fixed_ip = instance_ref.get('fixed_ip', None) + fixed_ip = instance_ref.get('fixed_ip') if not FLAGS.stub_network and fixed_ip: floating_ips = fixed_ip.get('floating_ips') or [] for floating_ip in floating_ips: -- cgit From 7b34f59ef8d2f6a752dcd94be3f5d14f0f93d3b2 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Thu, 27 Jan 2011 22:51:36 -0800 Subject: fixes for bug #709057 --- nova/db/sqlalchemy/api.py | 6 +++++ nova/db/sqlalchemy/models.py | 6 ++++- nova/tests/test_compute.py | 58 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 895e7eabe..50c4b2189 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -672,6 +672,9 @@ def instance_destroy(context, instance_id): with session.begin(): instance_ref = instance_get(context, instance_id, session=session) instance_ref.delete(session=session) + session.execute('update security_group_instance_association' + ' set deleted=1 where instance_id=:id', + {'id': instance_id}) @require_context @@ -1583,6 +1586,9 @@ def security_group_destroy(context, security_group_id): # TODO(vish): do we have to use sql here? session.execute('update security_groups set deleted=1 where id=:id', {'id': security_group_id}) + session.execute('update security_group_instance_association' + ' set deleted=1 where security_group_id=:id', + {'id': security_group_id}) session.execute('update security_group_rules set deleted=1 ' 'where group_id=:id', {'id': security_group_id}) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index c54ebe3ba..1399e29ad 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -311,10 +311,14 @@ class SecurityGroup(BASE, NovaBase): secondary="security_group_instance_association", primaryjoin='and_(' 'SecurityGroup.id == ' - 'SecurityGroupInstanceAssociation.security_group_id,' + 'SecurityGroupInstanceAssociation.security_group_id,' + 'SecurityGroupInstanceAssociation.deleted == False,' 'SecurityGroup.deleted == False)', secondaryjoin='and_(' 'SecurityGroupInstanceAssociation.instance_id == Instance.id,' + # (anthony) the condition below shouldn't be necessary now that the + # association is being marked as deleted. However, removing this + # may cause existing deployments to choke, so I'm leaving it 'Instance.deleted == False)', backref='security_groups') diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 09f6ee94a..ad2ac8375 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -49,7 +49,7 @@ class ComputeTestCase(test.TestCase): self.manager = manager.AuthManager() self.user = self.manager.create_user('fake', 'fake', 'fake') self.project = self.manager.create_project('fake', 'fake', 'fake') - self.context = context.get_admin_context() + self.context = context.RequestContext('fake', 'fake', False) def tearDown(self): self.manager.delete_user(self.user) @@ -69,6 +69,13 @@ class ComputeTestCase(test.TestCase): inst['ami_launch_index'] = 0 return db.instance_create(self.context, inst)['id'] + def _create_group(self): + values = {'name': 'testgroup', + 'description': 'testgroup', + 'user_id': self.user.id, + 'project_id': self.project.id} + return db.security_group_create(self.context, values) + def test_create_instance_defaults_display_name(self): """Verify that an instance cannot be created without a display_name.""" cases = [dict(), dict(display_name=None)] @@ -82,23 +89,58 @@ class ComputeTestCase(test.TestCase): def test_create_instance_associates_security_groups(self): """Make sure create associates security groups""" - values = {'name': 'default', - 'description': 'default', - 'user_id': self.user.id, - 'project_id': self.project.id} - group = db.security_group_create(self.context, values) + group = self._create_group() ref = self.compute_api.create( self.context, instance_type=FLAGS.default_instance_type, image_id=None, - security_group=['default']) + security_group=['testgroup']) try: self.assertEqual(len(db.security_group_get_by_instance( - self.context, ref[0]['id'])), 1) + self.context, ref[0]['id'])), 1) + group = db.security_group_get(self.context, group['id']) + self.assert_(len(group.instances) == 1) finally: db.security_group_destroy(self.context, group['id']) db.instance_destroy(self.context, ref[0]['id']) + def test_destroy_instance_disassociates_security_groups(self): + """Make sure destroying disassociates security groups""" + group = self._create_group() + + ref = self.compute_api.create( + self.context, + instance_type=FLAGS.default_instance_type, + image_id=None, + security_group=['testgroup']) + try: + db.instance_destroy(self.context, ref[0]['id']) + instance = db.instance_get(context.get_admin_context( + read_deleted=True), ref[0]['id']) + + group = db.security_group_get(self.context, group['id']) + self.assert_(len(group.instances) == 0) + finally: + db.security_group_destroy(self.context, group['id']) + + def test_destroy_security_group_disassociates_instances(self): + """Make sure destroying security groups disassociates instances""" + group = self._create_group() + + ref = self.compute_api.create( + self.context, + instance_type=FLAGS.default_instance_type, + image_id=None, + security_group=['testgroup']) + + try: + db.security_group_destroy(self.context, group['id']) + group = db.security_group_get(context.get_admin_context( + read_deleted=True), group['id']) + self.assert_(len(group.instances) == 0) + finally: + db.instance_destroy(self.context, ref[0]['id']) + def test_run_terminate(self): """Make sure it is possible to run and terminate instance""" instance_id = self._create_instance() -- cgit From dd7008e4edc6e9be2248ff663664adb2a662e745 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Thu, 27 Jan 2011 23:53:46 -0800 Subject: Fixed a pep8 spacing issue. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 484e50e6c..e3c45ce3e 100644 --- a/setup.py +++ b/setup.py @@ -53,6 +53,7 @@ nova_cmdclass = {'sdist': local_sdist} try: from sphinx.setup_command import BuildDoc + class local_BuildDoc(BuildDoc): def run(self): for builder in ['html', 'man']: -- cgit From af343a09b66ecded610051a443cb24f6b63e48ec Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Fri, 28 Jan 2011 20:10:03 +0300 Subject: Changed default handler for uncaughted exceptions. Logging with level critical instead of print to stderr --- nova/log.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nova/log.py b/nova/log.py index e1c9f46f4..70719e95b 100644 --- a/nova/log.py +++ b/nova/log.py @@ -31,6 +31,7 @@ import cStringIO import json import logging import logging.handlers +import sys import traceback from nova import flags @@ -191,6 +192,10 @@ class NovaLogger(logging.Logger): kwargs.pop('exc_info') self.error(message, **kwargs) +def handle_exception(type, value, tb): + logging.root.critical(str(value), exc_info=(type, value, tb)) + +sys.excepthook = handle_exception logging.setLoggerClass(NovaLogger) -- cgit From 5850b1505cbd9e63418d9edaf003d3bd426279a2 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Fri, 28 Jan 2011 20:46:46 +0300 Subject: Fixed pep8 errors --- nova/log.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/log.py b/nova/log.py index 70719e95b..b541488bd 100644 --- a/nova/log.py +++ b/nova/log.py @@ -192,9 +192,11 @@ class NovaLogger(logging.Logger): kwargs.pop('exc_info') self.error(message, **kwargs) + def handle_exception(type, value, tb): logging.root.critical(str(value), exc_info=(type, value, tb)) + sys.excepthook = handle_exception logging.setLoggerClass(NovaLogger) -- cgit From 29931605602e0eba562f870cd14cb6f16d3a215d Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 28 Jan 2011 09:55:58 -0800 Subject: remove extraneous line --- nova/tests/test_compute.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index ad2ac8375..2aa0690e7 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -115,9 +115,6 @@ class ComputeTestCase(test.TestCase): security_group=['testgroup']) try: db.instance_destroy(self.context, ref[0]['id']) - instance = db.instance_get(context.get_admin_context( - read_deleted=True), ref[0]['id']) - group = db.security_group_get(self.context, group['id']) self.assert_(len(group.instances) == 0) finally: -- cgit From 3f3f169d6b9cdf0b0d4dca308dbded38bf9a87b9 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Fri, 28 Jan 2011 12:32:21 -0800 Subject: Made adminclient get_user return None instead of throwing EC2Exception if requested user not available --- nova/adminclient.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nova/adminclient.py b/nova/adminclient.py index 3cdd8347f..6b7549d26 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -21,6 +21,7 @@ Nova User API client library. import base64 import boto +import boto.exception import httplib from boto.ec2.regioninfo import RegionInfo @@ -287,11 +288,13 @@ class NovaAdminClient(object): return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)]) def get_user(self, name): - """Grab a single user by name.""" - user = self.apiconn.get_object('DescribeUser', {'Name': name}, - UserInfo) - if user.username != None: - return user + """ 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 def has_user(self, username): """Determine if user exists.""" -- cgit From a1a1ee16992c0292de18828cd9bfc93d9bc6c1cc Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Fri, 28 Jan 2011 12:37:19 -0800 Subject: Fixed whitespace --- nova/adminclient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/adminclient.py b/nova/adminclient.py index 6b7549d26..dc949dd95 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -288,7 +288,7 @@ class NovaAdminClient(object): return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)]) def get_user(self, name): - """ grab a single user by name """ + """Grab a single user by name.""" try: return self.apiconn.get_object('DescribeUser', {'Name': name}, UserInfo) except boto.exception.BotoServerError, e: -- cgit From 5becf2ad3dbbb7074202406fdd6f7f05dfef53cc Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 28 Jan 2011 15:31:23 -0800 Subject: incorporate feedback from devin - use sql consistently in instance_destroy also, set deleted_at --- nova/db/sqlalchemy/api.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 50c4b2189..85250d56e 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -19,6 +19,7 @@ Implementation of SQLAlchemy backend. """ +import datetime import warnings from nova import db @@ -670,11 +671,14 @@ def instance_data_get_for_project(context, project_id): def instance_destroy(context, instance_id): session = get_session() with session.begin(): - instance_ref = instance_get(context, instance_id, session=session) - instance_ref.delete(session=session) - session.execute('update security_group_instance_association' - ' set deleted=1 where instance_id=:id', - {'id': instance_id}) + session.execute('update instances set deleted=1,' + 'deleted_at=:at where id=:id', + {'id': instance_id, + 'at': datetime.datetime.utcnow()}) + session.execute('update security_group_instance_association ' + 'set deleted=1,deleted_at=:at where instance_id=:id', + {'id': instance_id, + 'at': datetime.datetime.utcnow()}) @require_context @@ -1586,9 +1590,11 @@ def security_group_destroy(context, security_group_id): # TODO(vish): do we have to use sql here? session.execute('update security_groups set deleted=1 where id=:id', {'id': security_group_id}) - session.execute('update security_group_instance_association' - ' set deleted=1 where security_group_id=:id', - {'id': security_group_id}) + session.execute('update security_group_instance_association ' + 'set deleted=1,deleted_at=:at ' + 'where security_group_id=:id', + {'id': security_group_id, + 'at': datetime.datetime.utcnow()}) session.execute('update security_group_rules set deleted=1 ' 'where group_id=:id', {'id': security_group_id}) -- cgit From 54779a3db8af199f4b72043aa7c1bed208fefd88 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Fri, 28 Jan 2011 22:40:41 -0800 Subject: Added modify project to ec2 admin api --- nova/adminclient.py | 7 +++++++ nova/api/ec2/admin.py | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/nova/adminclient.py b/nova/adminclient.py index 3cdd8347f..64ebdb4d9 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -376,6 +376,13 @@ class NovaAdminClient(object): 'MemberUsers': member_users} return self.apiconn.get_object('RegisterProject', params, ProjectInfo) + def modify_project(self, projectname, manager_user=None, description=None): + """Modifies an existing project.""" + params = {'Name': projectname, + 'ManagerUser': manager_user, + 'Description': description} + return self.apiconn.get_status('ModifyProject', params) + def delete_project(self, projectname): """Permanently deletes the specified project.""" return self.apiconn.get_object('DeregisterProject', diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index d7e899d12..735951082 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -184,6 +184,17 @@ class AdminController(object): description=None, member_users=None)) + def modify_project(self, context, name, manager_user, description=None, + **kwargs): + """Modifies a project""" + msg = _("Modify project: %(name)s managed by" + " %(manager_user)s") % locals() + LOG.audit(msg, context=context) + manager.AuthManager().modify_project(name, + manager_user=manager_user, + description=description) + return True + def deregister_project(self, context, name): """Permanently deletes a project.""" LOG.audit(_("Delete project: %s"), name, context=context) -- cgit From 6ed93f6116ed092e64ceef9a255b46167099bfc3 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Sun, 30 Jan 2011 15:45:17 -0800 Subject: pep8 --- nova/adminclient.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/adminclient.py b/nova/adminclient.py index dc949dd95..4106f0f47 100644 --- a/nova/adminclient.py +++ b/nova/adminclient.py @@ -290,7 +290,9 @@ class NovaAdminClient(object): def get_user(self, name): """Grab a single user by name.""" try: - return self.apiconn.get_object('DescribeUser', {'Name': name}, UserInfo) + 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 -- cgit From 07698fa5826ad65553d0c86594098ad5b980dc8a Mon Sep 17 00:00:00 2001 From: termie Date: Sun, 30 Jan 2011 17:01:49 -0800 Subject: fix austin->bexar db migration --- .../sqlalchemy/migrate_repo/versions/001_austin.py | 24 +++++---------------- .../sqlalchemy/migrate_repo/versions/002_bexar.py | 24 ++++++++++++++++++++- nova/db/sqlalchemy/migration.py | 11 ++++++---- nova/tests/db/nova.austin.sqlite | Bin 0 -> 44032 bytes 4 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 nova/tests/db/nova.austin.sqlite diff --git a/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py b/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py index a312a7190..366944591 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py @@ -134,6 +134,9 @@ instances = Table('instances', meta, Column('ramdisk_id', String(length=255, convert_unicode=False, assert_unicode=None, unicode_error=None, _warn_on_bytestring=False)), + Column('server_name', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), Column('launch_index', Integer()), Column('key_name', String(length=255, convert_unicode=False, assert_unicode=None, @@ -178,23 +181,6 @@ instances = Table('instances', meta, ) -iscsi_targets = Table('iscsi_targets', meta, - Column('created_at', DateTime(timezone=False)), - Column('updated_at', DateTime(timezone=False)), - Column('deleted_at', DateTime(timezone=False)), - Column('deleted', Boolean(create_constraint=True, name=None)), - Column('id', Integer(), primary_key=True, nullable=False), - Column('target_num', Integer()), - Column('host', - String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False)), - Column('volume_id', - Integer(), - ForeignKey('volumes.id'), - nullable=True), - ) - - key_pairs = Table('key_pairs', meta, Column('created_at', DateTime(timezone=False)), Column('updated_at', DateTime(timezone=False)), @@ -523,7 +509,7 @@ def upgrade(migrate_engine): meta.bind = migrate_engine for table in (auth_tokens, export_devices, fixed_ips, floating_ips, - instances, iscsi_targets, key_pairs, networks, + instances, key_pairs, networks, projects, quotas, security_groups, security_group_inst_assoc, security_group_rules, services, users, user_project_association, user_project_role_association, @@ -539,7 +525,7 @@ def upgrade(migrate_engine): def downgrade(migrate_engine): # Operations to reverse the above upgrade go here. for table in (auth_tokens, export_devices, fixed_ips, floating_ips, - instances, iscsi_targets, key_pairs, networks, + instances, key_pairs, networks, projects, quotas, security_groups, security_group_inst_assoc, security_group_rules, services, users, user_project_association, user_project_role_association, diff --git a/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py b/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py index bd3a3e6f8..699b837f8 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py @@ -41,6 +41,10 @@ networks = Table('networks', meta, Column('id', Integer(), primary_key=True, nullable=False), ) +volumes = Table('volumes', meta, + Column('id', Integer(), primary_key=True, nullable=False), + ) + # # New Tables @@ -131,6 +135,23 @@ instance_actions = Table('instance_actions', meta, ) +iscsi_targets = Table('iscsi_targets', meta, + Column('created_at', DateTime(timezone=False)), + Column('updated_at', DateTime(timezone=False)), + Column('deleted_at', DateTime(timezone=False)), + Column('deleted', Boolean(create_constraint=True, name=None)), + Column('id', Integer(), primary_key=True, nullable=False), + Column('target_num', Integer()), + Column('host', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('volume_id', + Integer(), + ForeignKey('volumes.id'), + nullable=True), + ) + + # # Tables to alter # @@ -188,7 +209,8 @@ def upgrade(migrate_engine): # Upgrade operations go here. Don't create your own engine; # bind migrate_engine to your metadata meta.bind = migrate_engine - for table in (certificates, consoles, console_pools, instance_actions): + for table in (certificates, consoles, console_pools, instance_actions, + iscsi_targets): try: table.create() except Exception: diff --git a/nova/db/sqlalchemy/migration.py b/nova/db/sqlalchemy/migration.py index 33d14827b..2a13c5466 100644 --- a/nova/db/sqlalchemy/migration.py +++ b/nova/db/sqlalchemy/migration.py @@ -46,12 +46,15 @@ def db_version(): meta.reflect(bind=engine) try: for table in ('auth_tokens', 'export_devices', 'fixed_ips', - 'floating_ips', 'instances', 'iscsi_targets', + 'floating_ips', 'instances', 'key_pairs', 'networks', 'projects', 'quotas', - 'security_group_rules', - 'security_group_instance_association', 'services', + 'security_group_instance_association', + 'security_group_rules', 'security_groups', + 'services', 'users', 'user_project_association', - 'user_project_role_association', 'volumes'): + 'user_project_role_association', + 'user_role_association', + 'volumes'): assert table in meta.tables return db_version_control(1) except AssertionError: diff --git a/nova/tests/db/nova.austin.sqlite b/nova/tests/db/nova.austin.sqlite new file mode 100644 index 000000000..ad1326bce Binary files /dev/null and b/nova/tests/db/nova.austin.sqlite differ -- cgit From f3652fd4814eb5d9df851422aa946f283263fd07 Mon Sep 17 00:00:00 2001 From: termie Date: Sun, 30 Jan 2011 21:38:58 -0800 Subject: add logging.basicConfig() to tests --- run_tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/run_tests.py b/run_tests.py index 5c8436aee..24786e8ad 100644 --- a/run_tests.py +++ b/run_tests.py @@ -26,6 +26,8 @@ from nose import config from nose import result from nose import core +from nova import log as logging + class NovaTestResult(result.TextTestResult): def __init__(self, *args, **kw): @@ -58,6 +60,7 @@ class NovaTestRunner(core.TextTestRunner): if __name__ == '__main__': + logging.basicConfig() c = config.Config(stream=sys.stdout, env=os.environ, verbosity=3, -- cgit From 86b96d377cb5f0cbaccf40fc87f2c1ad64ae05e1 Mon Sep 17 00:00:00 2001 From: termie Date: Sun, 30 Jan 2011 21:55:32 -0800 Subject: Only run pep8 after tests if running all the tests --- run_tests.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/run_tests.sh b/run_tests.sh index cf1affcea..4e21fe945 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -65,10 +65,15 @@ then if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then # Install the virtualenv and run the test suite in it python tools/install_venv.py - wrapper=${with_venv} + wrapper=${with_venv} fi fi fi fi -run_tests && pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py bin/* nova setup.py || exit 1 +if [ -z "$noseargs" ]; +then + run_tests && pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py bin/* nova setup.py || exit 1 +else + run_tests +fi -- cgit From b1caafa03d0fb36c9df5502282c4267974d1b889 Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Mon, 31 Jan 2011 14:36:40 -0800 Subject: Fix for LP Bug #709510 --- nova/api/ec2/__init__.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index e25943a13..ddcdc673c 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -171,7 +171,7 @@ class Authenticate(wsgi.Middleware): req.path) # Be explicit for what exceptions are 403, the rest bubble as 500 except (exception.NotFound, exception.NotAuthorized) as ex: - LOG.audit(_("Authentication Failure: %s"), ex.args[0]) + LOG.audit(_("Authentication Failure: %s"), unicode(ex)) raise webob.exc.HTTPForbidden() # Authenticated! @@ -316,30 +316,31 @@ class Executor(wsgi.Application): try: result = api_request.invoke(context) except exception.InstanceNotFound as ex: - LOG.info(_('InstanceNotFound raised: %s'), ex.args[0], + LOG.info(_('InstanceNotFound raised: %s'), unicode(ex), context=context) ec2_id = cloud.id_to_ec2_id(ex.instance_id) message = _('Instance %s not found') % ec2_id return self._error(req, context, type(ex).__name__, message) except exception.VolumeNotFound as ex: - LOG.info(_('VolumeNotFound raised: %s'), ex.args[0], + LOG.info(_('VolumeNotFound raised: %s'), unicode(ex), context=context) ec2_id = cloud.id_to_ec2_id(ex.volume_id, 'vol-%08x') message = _('Volume %s not found') % ec2_id return self._error(req, context, type(ex).__name__, message) except exception.NotFound as ex: - LOG.info(_('NotFound raised: %s'), ex.args[0], context=context) - return self._error(req, context, type(ex).__name__, ex.args[0]) + LOG.info(_('NotFound raised: %s'), unicode(ex), context=context) + return self._error(req, context, type(ex).__name__, unicode(ex)) except exception.ApiError as ex: - LOG.exception(_('ApiError raised: %s'), ex.args[0], + LOG.exception(_('ApiError raised: %s'), unicode(ex), context=context) if ex.code: - return self._error(req, context, ex.code, ex.args[0]) + return self._error(req, context, ex.code, unicode(ex)) else: - return self._error(req, context, type(ex).__name__, ex.args[0]) + return self._error(req, context, type(ex).__name__, + unicode(ex)) except Exception as ex: extra = {'environment': req.environ} - LOG.exception(_('Unexpected error raised: %s'), ex.args[0], + LOG.exception(_('Unexpected error raised: %s'), unicode(ex), extra=extra, context=context) return self._error(req, context, -- cgit From 85fe11e11a6332f95a9dac300994e77e7e48dfec Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 31 Jan 2011 14:38:45 -0800 Subject: change ensure_bridge so it doesn't overwrite existing ips --- nova/network/linux_net.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index cdd1f666a..87eefa8b2 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -191,18 +191,19 @@ def ensure_bridge(bridge, interface, net_attrs=None): _execute("sudo brctl stp %s off" % bridge) if interface: _execute("sudo brctl addif %s %s" % (bridge, interface)) + _execute("sudo ifconfig %s up" % bridge) if net_attrs: - _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \ - (bridge, - net_attrs['gateway'], + # NOTE(vish): use ip addr add so it doesn't overwrite + # manual addresses on the bridge. + suffix = net_attrs['cidr'].rpartition('/')[0] + _execute("sudo ip addr add %s/%s brd %s dev %s" % + (net_attrs['gateway'], + suffix, net_attrs['broadcast'], - net_attrs['netmask'])) + bridge)) if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) - _execute("sudo ifconfig %s up" % bridge) - else: - _execute("sudo ifconfig %s up" % bridge) if FLAGS.use_nova_chains: (out, err) = _execute("sudo iptables -N nova_forward", check_exit_code=False) -- cgit From cf5e4de7019091ee931ea911d69732c25a2cc1dd Mon Sep 17 00:00:00 2001 From: Tushar Patil Date: Mon, 31 Jan 2011 14:43:03 -0800 Subject: Fix for LP Bug #709510 --- nova/api/openstack/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index c70bb39ed..056c7dd27 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -51,8 +51,8 @@ class FaultWrapper(wsgi.Middleware): try: return req.get_response(self.application) except Exception as ex: - LOG.exception(_("Caught error: %s"), str(ex)) - exc = webob.exc.HTTPInternalServerError(explanation=str(ex)) + LOG.exception(_("Caught error: %s"), unicode(ex)) + exc = webob.exc.HTTPInternalServerError(explanation=unicode(ex)) return faults.Fault(exc) -- cgit From e4356ceab8b2627dda0b02c7ebbba6d033129360 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 31 Jan 2011 14:43:33 -0800 Subject: rpartition sticks the rhs in [2] --- nova/network/linux_net.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 87eefa8b2..db3ecc7f9 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -195,7 +195,7 @@ def ensure_bridge(bridge, interface, net_attrs=None): if net_attrs: # NOTE(vish): use ip addr add so it doesn't overwrite # manual addresses on the bridge. - suffix = net_attrs['cidr'].rpartition('/')[0] + suffix = net_attrs['cidr'].rpartition('/')[2] _execute("sudo ip addr add %s/%s brd %s dev %s" % (net_attrs['gateway'], suffix, -- cgit From 199e511e17af5e1a0659cc9ca65e9d55a5296947 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Tue, 1 Feb 2011 08:09:34 -0800 Subject: fix pep8 error :/ --- nova/db/sqlalchemy/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 1399e29ad..7efb36c0e 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -316,7 +316,7 @@ class SecurityGroup(BASE, NovaBase): 'SecurityGroup.deleted == False)', secondaryjoin='and_(' 'SecurityGroupInstanceAssociation.instance_id == Instance.id,' - # (anthony) the condition below shouldn't be necessary now that the + # (anthony) the condition below shouldn't be necessary now that the # association is being marked as deleted. However, removing this # may cause existing deployments to choke, so I'm leaving it 'Instance.deleted == False)', -- cgit From 48a0e252be8b001705db98de8143e1c1ad6294ad Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 1 Feb 2011 17:55:14 -0800 Subject: better setup for flatdhcp --- nova/network/linux_net.py | 40 +++++++++++++++++++++++++++++++++------- nova/network/manager.py | 10 ++++++---- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index db3ecc7f9..1a63b759f 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -20,6 +20,7 @@ Implements vlans, bridges, and iptables rules using linux utilities. import os from nova import db +from nova import exception from nova import flags from nova import log as logging from nova import utils @@ -164,7 +165,7 @@ def remove_floating_forward(floating_ip, fixed_ip): % (fixed_ip, floating_ip)) -def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None): +def ensure_vlan_bridge(vlan_num, bridge, net_attrs, set_ip=False): """Create a vlan and bridge unless they already exist""" interface = ensure_vlan(vlan_num) ensure_bridge(bridge, interface, net_attrs) @@ -181,7 +182,7 @@ def ensure_vlan(vlan_num): return interface -def ensure_bridge(bridge, interface, net_attrs=None): +def ensure_bridge(bridge, interface, net_attrs, set_ip=False): """Create a bridge unless it already exists""" if not _device_exists(bridge): LOG.debug(_("Starting Bridge interface for %s"), interface) @@ -189,12 +190,10 @@ def ensure_bridge(bridge, interface, net_attrs=None): _execute("sudo brctl setfd %s 0" % bridge) # _execute("sudo brctl setageing %s 10" % bridge) _execute("sudo brctl stp %s off" % bridge) - if interface: - _execute("sudo brctl addif %s %s" % (bridge, interface)) _execute("sudo ifconfig %s up" % bridge) - if net_attrs: - # NOTE(vish): use ip addr add so it doesn't overwrite - # manual addresses on the bridge. + if set_ip: + # NOTE(vish): The ip for dnsmasq has to be the first address on the + # bridge for it to respond to reqests properly suffix = net_attrs['cidr'].rpartition('/')[2] _execute("sudo ip addr add %s/%s brd %s dev %s" % (net_attrs['gateway'], @@ -204,6 +203,33 @@ def ensure_bridge(bridge, interface, net_attrs=None): if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) + else: + # NOTE(vish): if we don't give an ip to the bridge, we set up a route + # for the guests + out, err = _execute("sudo route add -net %s dev %s" % + (net_attrs['cidr'], bridge), + check_exit_code=False) + if err and err != "SIOCADDRT: File exists\n": + raise exception.Error("Failed to add route: %s" % err) + if interface: + # NOTE(vish): This will break if there is already an ip on the + # interface, so we move any ips to the bridge + out, err = _execute("sudo ip addr show dev %s scope global" % + interface) + for line in out.split("\n"): + fields = line.split() + if fields and fields[0] == "inet": + params = ' '.join(fields[1:-2]) + _execute("sudo ip addr del %s dev %s" % (params, fields[-1])) + _execute("sudo ip addr add %s dev %s" % (params, bridge)) + out, err = _execute("sudo brctl addif %s %s" % + (bridge, interface), + check_exit_code=False) + + if (err and err != "device %s is already a member of a bridge; can't " + "enslave it to bridge %s.\n" % (interface, bridge)): + raise exception.Error("Failed to add interface: %s" % err) + if FLAGS.use_nova_chains: (out, err) = _execute("sudo iptables -N nova_forward", check_exit_code=False) diff --git a/nova/network/manager.py b/nova/network/manager.py index fbcbea131..735327230 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -402,7 +402,8 @@ class FlatDHCPManager(FlatManager): """Sets up matching network for compute hosts.""" network_ref = db.network_get_by_instance(context, instance_id) self.driver.ensure_bridge(network_ref['bridge'], - FLAGS.flat_interface) + FLAGS.flat_interface, + network_ref) def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): """Setup dhcp for this network.""" @@ -427,7 +428,7 @@ class FlatDHCPManager(FlatManager): network_ref = db.network_get(context, network_id) self.driver.ensure_bridge(network_ref['bridge'], FLAGS.flat_interface, - network_ref) + network_ref, True) if not FLAGS.fake_network: self.driver.update_dhcp(context, network_id) if(FLAGS.use_ipv6): @@ -498,7 +499,8 @@ class VlanManager(NetworkManager): """Sets up matching network for compute hosts.""" network_ref = db.network_get_by_instance(context, instance_id) self.driver.ensure_vlan_bridge(network_ref['vlan'], - network_ref['bridge']) + network_ref['bridge'], + network_ref) def create_networks(self, context, cidr, num_networks, network_size, cidr_v6, vlan_start, vpn_start): @@ -565,7 +567,7 @@ class VlanManager(NetworkManager): address = network_ref['vpn_public_address'] self.driver.ensure_vlan_bridge(network_ref['vlan'], network_ref['bridge'], - network_ref) + network_ref, True) # NOTE(vish): only ensure this forward if the address hasn't been set # manually. -- cgit From 08794dba04c3919f9abbbfea1615b651394e5ee8 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 1 Feb 2011 18:42:12 -0800 Subject: don't fail on ip add exists and recreate default route on ip move if needed --- nova/network/linux_net.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 1a63b759f..efeed5bc7 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -195,11 +195,14 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): # NOTE(vish): The ip for dnsmasq has to be the first address on the # bridge for it to respond to reqests properly suffix = net_attrs['cidr'].rpartition('/')[2] - _execute("sudo ip addr add %s/%s brd %s dev %s" % - (net_attrs['gateway'], - suffix, - net_attrs['broadcast'], - bridge)) + out, err = _execute("sudo ip addr add %s/%s brd %s dev %s" % + (net_attrs['gateway'], + suffix, + net_attrs['broadcast'], + bridge), + check_exit_code=False) + if err and err != "RTNETLINK answers: File exists\n": + raise exception.Error("Failed to add ip: %s" % err) if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) @@ -214,14 +217,22 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): if interface: # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge + gateway = None + out, err = _execute("sudo route") + for line in out.split("\n"): + fields = line.split() + if fields and fields[0] == "default" and fields[-1] == interface: + gateway = fields[1] out, err = _execute("sudo ip addr show dev %s scope global" % interface) for line in out.split("\n"): fields = line.split() if fields and fields[0] == "inet": - params = ' '.join(fields[1:-2]) + params = ' '.join(fields[1:-1]) _execute("sudo ip addr del %s dev %s" % (params, fields[-1])) _execute("sudo ip addr add %s dev %s" % (params, bridge)) + if gateway: + _execute("sudo route add default gw %s" % gateway) out, err = _execute("sudo brctl addif %s %s" % (bridge, interface), check_exit_code=False) -- cgit From d647a067acb884ff2c324afa5a962a8dae71c6c6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 1 Feb 2011 19:31:43 -0800 Subject: pass the set_ip from ensure_vlan_bridge --- nova/network/linux_net.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index efeed5bc7..c5cf761f2 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -168,7 +168,7 @@ def remove_floating_forward(floating_ip, fixed_ip): def ensure_vlan_bridge(vlan_num, bridge, net_attrs, set_ip=False): """Create a vlan and bridge unless they already exist""" interface = ensure_vlan(vlan_num) - ensure_bridge(bridge, interface, net_attrs) + ensure_bridge(bridge, interface, net_attrs, set_ip) def ensure_vlan(vlan_num): -- cgit From c98a298c3aefb1f465530537ee4773bd04673fe4 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 2 Feb 2011 11:16:00 +0100 Subject: Set FINAL = True in version.py. --- nova/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/version.py b/nova/version.py index 7b27acb6a..48ac84a03 100644 --- a/nova/version.py +++ b/nova/version.py @@ -24,7 +24,7 @@ except ImportError: NOVA_VERSION = ['2011', '1'] YEAR, COUNT = NOVA_VERSION -FINAL = False # This becomes true at Release Candidate time +FINAL = True # This becomes true at Release Candidate time def canonical_version_string(): -- cgit From 10657adef2028926319fa5c0402f434187213263 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 2 Feb 2011 11:23:08 +0100 Subject: Open Cactus development. --- nova/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/version.py b/nova/version.py index 48ac84a03..c3ecc2245 100644 --- a/nova/version.py +++ b/nova/version.py @@ -21,10 +21,10 @@ except ImportError: 'revision_id': 'LOCALREVISION', 'revno': 0} -NOVA_VERSION = ['2011', '1'] +NOVA_VERSION = ['2011', '2'] YEAR, COUNT = NOVA_VERSION -FINAL = True # This becomes true at Release Candidate time +FINAL = False # This becomes true at Release Candidate time def canonical_version_string(): -- cgit From ef9217548b1ae74d3e4f7282d26e0d9fee5470ce Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 2 Feb 2011 08:15:57 -0800 Subject: moves driver.init_host into the base class so it happens before floating forwards and sets up proper iptables chains --- nova/network/manager.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index fbcbea131..8eb9f041b 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -118,6 +118,10 @@ class NetworkManager(manager.Manager): super(NetworkManager, self).__init__(*args, **kwargs) def init_host(self): + """Do any initialization that needs to be run if this is a + standalone service. + """ + self.driver.init_host() # Set up networking for the projects for which we're already # the designated network host. ctxt = context.get_admin_context() @@ -395,7 +399,6 @@ class FlatDHCPManager(FlatManager): standalone service. """ super(FlatDHCPManager, self).init_host() - self.driver.init_host() self.driver.metadata_forward() def setup_compute_network(self, context, instance_id): @@ -465,7 +468,6 @@ class VlanManager(NetworkManager): standalone service. """ super(VlanManager, self).init_host() - self.driver.init_host() self.driver.metadata_forward() def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): -- cgit From 321f581660aad3fc9da5f88276bfdf11f6960d97 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 3 Feb 2011 13:10:19 -0800 Subject: Don't need a route for guests. Turns out the issue with routing from the guests was due to duplicate macs --- nova/network/linux_net.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index c5cf761f2..3a8bd9435 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -206,14 +206,6 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) - else: - # NOTE(vish): if we don't give an ip to the bridge, we set up a route - # for the guests - out, err = _execute("sudo route add -net %s dev %s" % - (net_attrs['cidr'], bridge), - check_exit_code=False) - if err and err != "SIOCADDRT: File exists\n": - raise exception.Error("Failed to add route: %s" % err) if interface: # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge -- cgit From 62d2a1a101dc97e80cb0a582197a6b7468abf593 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 4 Feb 2011 11:04:55 -0600 Subject: Implementation of 'SAN' volumes A SAN volume is 'special' because the volume service probably won't run on the iSCSI target. Initial support is for Solaris with COMSTAR (Solaris 11) --- nova/volume/driver.py | 10 +- nova/volume/manager.py | 2 +- nova/volume/san.py | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+), 6 deletions(-) create mode 100644 nova/volume/san.py diff --git a/nova/volume/driver.py b/nova/volume/driver.py index da7307733..82f4c2f54 100644 --- a/nova/volume/driver.py +++ b/nova/volume/driver.py @@ -294,8 +294,10 @@ class ISCSIDriver(VolumeDriver): self._execute("sudo ietadm --op delete --tid=%s" % iscsi_target) - def _get_name_and_portal(self, volume_name, host): + def _get_name_and_portal(self, volume): """Gets iscsi name and portal from volume name and host.""" + volume_name = volume['name'] + host = volume['host'] (out, _err) = self._execute("sudo iscsiadm -m discovery -t " "sendtargets -p %s" % host) for target in out.splitlines(): @@ -307,8 +309,7 @@ class ISCSIDriver(VolumeDriver): def discover_volume(self, volume): """Discover volume on a remote host.""" - iscsi_name, iscsi_portal = self._get_name_and_portal(volume['name'], - volume['host']) + iscsi_name, iscsi_portal = self._get_name_and_portal(volume) self._execute("sudo iscsiadm -m node -T %s -p %s --login" % (iscsi_name, iscsi_portal)) self._execute("sudo iscsiadm -m node -T %s -p %s --op update " @@ -319,8 +320,7 @@ class ISCSIDriver(VolumeDriver): def undiscover_volume(self, volume): """Undiscover volume on a remote host.""" - iscsi_name, iscsi_portal = self._get_name_and_portal(volume['name'], - volume['host']) + iscsi_name, iscsi_portal = self._get_name_and_portal(volume) self._execute("sudo iscsiadm -m node -T %s -p %s --op update " "-n node.startup -v manual" % (iscsi_name, iscsi_portal)) diff --git a/nova/volume/manager.py b/nova/volume/manager.py index 6f8e25e19..6e70ec881 100644 --- a/nova/volume/manager.py +++ b/nova/volume/manager.py @@ -87,7 +87,7 @@ class VolumeManager(manager.Manager): if volume['status'] in ['available', 'in-use']: self.driver.ensure_export(ctxt, volume) else: - LOG.info(_("volume %s: skipping export"), volume_ref['name']) + LOG.info(_("volume %s: skipping export"), volume['name']) def create_volume(self, context, volume_id): """Creates and exports the volume.""" diff --git a/nova/volume/san.py b/nova/volume/san.py new file mode 100644 index 000000000..22a0da13f --- /dev/null +++ b/nova/volume/san.py @@ -0,0 +1,373 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# 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. +""" +Drivers for san-stored volumes. +The unique thing about a SAN is that we don't expect that we can run the volume + controller on the SAN hardware. We expect to access it over SSH or some API. +""" + +import os +import paramiko + +from nova import exception +from nova import flags +from nova import log as logging +from nova.volume.driver import ISCSIDriver + +LOG = logging.getLogger("nova.volume.driver") +FLAGS = flags.FLAGS +flags.DEFINE_boolean('san_thin_provision', 'true', + 'Use thin provisioning for SAN volumes?') +flags.DEFINE_string('san_ip', '', + 'IP address of SAN controller') +flags.DEFINE_string('san_login', 'admin', + 'Username for SAN controller') +flags.DEFINE_string('san_password', '', + 'Password for SAN controller') +flags.DEFINE_string('san_cluster_name', '', + 'Cluster name for creating SAN volumes') +flags.DEFINE_string('san_privatekey', '', + 'Filename of private key to use for SSH authentication') + +class SanISCSIDriver(ISCSIDriver): + """ Base class for SAN-style storage volumes + (storage providers we access over SSH)""" + #Override because SAN ip != host ip + def _get_name_and_portal(self, volume): + """Gets iscsi name and portal from volume name and host.""" + volume_name = volume['name'] + + # TODO(justinsb): store in volume, remerge with generic iSCSI code + host = FLAGS.san_ip + + (out, _err) = self._execute("sudo iscsiadm -m discovery -t " + "sendtargets -p %s" % host) + + location = None + find_iscsi_name = self._build_iscsi_target_name(volume) + for target in out.splitlines(): + if find_iscsi_name in target: + (location, _sep, iscsi_name) = target.partition(" ") + break + if not location: + raise exception.Error(_("Could not find iSCSI export " + " for volume %s") % + volume_name) + + iscsi_portal = location.split(",")[0] + LOG.debug("iscsi_name=%s, iscsi_portal=%s" % (iscsi_name, iscsi_portal)) + return (iscsi_name, iscsi_portal) + + def _build_iscsi_target_name(self, volume): + return "%s%s" % (FLAGS.iscsi_target_prefix, volume['name']) + + # discover_volume is still OK + # undiscover_volume is still OK + + def _connect_to_ssh(self): + ssh = paramiko.SSHClient() + #TODO(justinsb): We need a better SSH key policy + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + if FLAGS.san_password: + ssh.connect(FLAGS.san_ip, + username=FLAGS.san_login, + password=FLAGS.san_password) + elif FLAGS.san_privatekey: + privatekeyfile = os.path.expanduser(FLAGS.san_privatekey) + # It sucks that paramiko doesn't support DSA keys + privatekey = paramiko.RSAKey.from_private_key_file(privatekeyfile) + ssh.connect(FLAGS.san_ip, username=FLAGS.san_login, pkey=privatekey) + else: + raise exception.Error("Specify san_password or san_privatekey") + return ssh + + def _run_ssh(self, command, check_exit_code=True): + #TODO(justinsb): SSH connection caching (?) + ssh = self._connect_to_ssh() + + #TODO(justinsb): Reintroduce the retry hack + ret = ssh_execute(ssh, command, check_exit_code=check_exit_code) + + ssh.close() + + return ret + + def ensure_export(self, context, volume): + """Synchronously recreates an export for a logical volume.""" + pass + + def create_export(self, context, volume): + """Exports the volume.""" + pass + + def remove_export(self, context, volume): + """Removes an export for a logical volume.""" + pass + + def check_for_setup_error(self): + """Returns an error if prerequisites aren't met""" + if not (FLAGS.san_password or FLAGS.san_privatekey): + raise exception.Error("Specify san_password or san_privatekey") + + if not (FLAGS.san_ip): + raise exception.Error("san_ip must be set") + +def _collect_lines(data): + """ Split lines from data into an array, trimming them """ + matches = [] + for line in data.splitlines(): + match = line.strip() + matches.append(match) + + return matches + +def _get_prefixed_values(data, prefix): + """Collect lines which start with prefix; with trimming""" + matches = [] + for line in data.splitlines(): + line = line.strip() + if line.startswith(prefix): + match = line[len(prefix):] + match = match.strip() + matches.append(match) + + return matches + +class SolarisISCSIDriver(SanISCSIDriver): + """Executes commands relating to Solaris-hosted ISCSI volumes.""" + + #pkg install storage-server SUNWiscsit + #svcadm enable stmf + #zfs allow justinsb create,mount,destroy rpool + #usermod -P'File System Management' justinsb + # I don't know which perms are needed for sbdadm... + #usermod -P'Primary Administrator' justinsb + # svcadm enable -r svc:/network/iscsi/target:default + # pfexec itadm create-tpg e1000g0 10.1.184.98 + # pfexec itadm create-target -t e1000g0 + + def _view_exists(self, luid): + (out, _err) = self._run_ssh("pfexec /usr/sbin/stmfadm list-view -l %s" % + (luid), + check_exit_code=False) + if "no views found" in out: + return False + + if "View Entry:" in out: + return True + + raise exception.Error("Cannot parse list-view output: %s" % (out)) + + def _get_target_groups(self): + """Gets list of target groups from host.""" + (out, _err) = self._run_ssh("pfexec /usr/sbin/stmfadm list-tg") + matches = _get_prefixed_values(out, 'Target group: ') + LOG.debug("target_groups=%s" % matches) + return matches + + def _target_group_exists(self, target_group_name): + return target_group_name not in self._get_target_groups() + + def _get_target_group_members(self, target_group_name): + (out, _err) = self._run_ssh("pfexec /usr/sbin/stmfadm list-tg -v %s" % + (target_group_name)) + matches = _get_prefixed_values(out, 'Member: ') + LOG.debug("members of %s=%s" % (target_group_name, matches)) + return matches + + def _is_target_group_member(self, target_group_name, iscsi_target_name): + return iscsi_target_name in ( + self._get_target_group_members(target_group_name)) + + def _get_iscsi_targets(self): + cmd = ("pfexec /usr/sbin/itadm list-target | " + "awk '{print $1}' | grep -v ^TARGET") + (out, _err) = self._run_ssh(cmd) + matches = _collect_lines(out) + LOG.debug("_get_iscsi_targets=%s" % (matches)) + return matches + + def _iscsi_target_exists(self, iscsi_target_name): + return iscsi_target_name in self._get_iscsi_targets() + + def _build_zfs_poolname(self, volume): + #TODO(justinsb): rpool should be configurable + zfs_poolname = 'rpool/%s' % (volume['name']) + return zfs_poolname + + def create_volume(self, volume): + """Creates a volume.""" + if int(volume['size']) == 0: + sizestr = '100M' + else: + sizestr = '%sG' % volume['size'] + + zfs_poolname = self._build_zfs_poolname(volume) + + thin_provision_arg = '-s' if FLAGS.san_thin_provision else '' + # Create a zfs volume + self._run_ssh("pfexec /usr/sbin/zfs create %s -V %s %s" % + (thin_provision_arg, + sizestr, + zfs_poolname)) + + return { # 'target_ip': FLAGS.san_ip + } + + def _get_luid(self, volume): + zfs_poolname = self._build_zfs_poolname(volume) + + cmd = ("pfexec /usr/sbin/sbdadm list-lu | " + "grep -w %s | awk '{print $1}'" % + (zfs_poolname)) + + (stdout, _stderr) = self._run_ssh(cmd) + + luid = stdout.strip() + return luid + + def _is_lu_created(self, volume): + luid = self._get_luid(volume) + return luid + + def delete_volume(self, volume): + """Deletes a volume.""" + zfs_poolname = self._build_zfs_poolname(volume) + self._run_ssh("pfexec /usr/sbin/zfs destroy %s" % + (zfs_poolname)) + + def local_path(self, volume): + # TODO(justinsb): Is this needed here? + escaped_group = FLAGS.volume_group.replace('-', '--') + escaped_name = volume['name'].replace('-', '--') + return "/dev/mapper/%s-%s" % (escaped_group, escaped_name) + + def ensure_export(self, context, volume): + """Synchronously recreates an export for a logical volume.""" + #TODO(justinsb): On bootup, this is called for every volume. + # It then runs ~5 SSH commands for each volume, + # most of which fetch the same info each time + # This makes initial start stupid-slow + self._do_export(volume, force_create=False) + + def create_export(self, context, volume): + self._do_export(volume, force_create=True) + + def _do_export(self, volume, force_create): + # Create a Logical Unit (LU) backed by the zfs volume + zfs_poolname = self._build_zfs_poolname(volume) + + if force_create or not self._is_lu_created(volume): + cmd = ("pfexec /usr/sbin/sbdadm create-lu /dev/zvol/rdsk/%s" % + (zfs_poolname)) + self._run_ssh(cmd) + + luid = self._get_luid(volume) + iscsi_name = self._build_iscsi_target_name(volume) + target_group_name = 'tg-%s' % volume['name'] + + # The sequence of commands looks like this: + #pfexec stmfadm create-tg tg-vol2 + # Yes, we add it before we create it! + #pfexec stmfadm add-tg-member -g tg-vol2 iqn.2010-10.org.openstack:vol2 + #pfexec itadm create-target -n iqn.2010-10.org.openstack:vol2 + #pfexec stmfadm add-view -t tg-vol2 600144F051E2440000004D4A0F730004 + + # Create a iSCSI target, mapped to just this volume + if force_create or not self._target_group_exists(target_group_name): + self._run_ssh("pfexec /usr/sbin/stmfadm create-tg %s" % + (target_group_name)) + + # Yes, we add the initiatior before we create it! + if force_create or not self._is_target_group_member(target_group_name, + iscsi_name): + self._run_ssh("pfexec /usr/sbin/stmfadm add-tg-member -g %s %s" % + (target_group_name, iscsi_name)) + if force_create or not self._iscsi_target_exists(iscsi_name): + self._run_ssh("pfexec /usr/sbin/itadm create-target -n %s" % + (iscsi_name)) + if force_create or not self._view_exists(luid): + self._run_ssh("pfexec /usr/sbin/stmfadm add-view -t %s %s" % + (target_group_name, luid)) + + def remove_export(self, context, volume): + """Removes an export for a logical volume.""" + + # This is the reverse of _do_export + luid = self._get_luid(volume) + iscsi_name = self._build_iscsi_target_name(volume) + target_group_name = 'tg-%s' % volume['name'] + + if self._view_exists(luid): + self._run_ssh("pfexec /usr/sbin/stmfadm remove-view -l %s -a" % + (luid)) + + if self._iscsi_target_exists(iscsi_name): + self._run_ssh("pfexec /usr/sbin/stmfadm offline-target %s" % + (iscsi_name)) + self._run_ssh("pfexec /usr/sbin/itadm delete-target %s" % + (iscsi_name)) + + # We don't delete the tg-member; we delete the whole tg! + + if self._target_group_exists(target_group_name): + self._run_ssh("pfexec /usr/sbin/stmfadm delete-tg %s" % + (target_group_name)) + + if self._is_lu_created(volume): + self._run_ssh("pfexec /usr/sbin/sbdadm delete-lu %s" % + (luid)) + + +def ssh_execute(ssh, cmd, process_input=None, + addl_env=None, check_exit_code=True): + LOG.debug(_("Running cmd (subprocess): %s"), cmd) + if addl_env: + raise exception.Error("Environment not supported over SSH") + + if process_input: + # This is (probably) fixable if we need it... + raise exception.Error("process_input not supported over SSH") + + stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) + channel = stdout_stream.channel + + #stdin.write('process_input would go here') + #stdin.flush() + + # I'm suspicious of this... + # ...other SSH clients have buffering issues with this approach + stdout = stdout_stream.read() + stderr = stderr_stream.read() + stdin_stream.close() + + exit_status = channel.recv_exit_status() + + # exit_status == -1 if no exit code was returned + if exit_status != -1: + LOG.debug(_("Result was %s") % exit_status) + if check_exit_code and exit_status != 0: + raise exception.ProcessExecutionError(exit_code=exit_status, + stdout=stdout, + stderr=stderr, + cmd=cmd) + + # Removed, although this is workaround is needed in utils.execute: + # (no reason to believe it's needed here!) + # greenthread.sleep(0) + + return (stdout, stderr) -- cgit From 5315d5068c6250ccf71c1aa67e7e0109a0718f2a Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 4 Feb 2011 13:07:17 -0600 Subject: Fixes for Vish & Devin's feedback --- nova/utils.py | 35 +++++++++++++++++++++++++ nova/volume/san.py | 77 +++++++++++++----------------------------------------- 2 files changed, 53 insertions(+), 59 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 5f5225289..100e26f70 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -152,6 +152,41 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True): return result +def ssh_execute(ssh, cmd, process_input=None, + addl_env=None, check_exit_code=True): + LOG.debug(_("Running cmd (SSH): %s"), cmd) + if addl_env: + raise exception.Error("Environment not supported over SSH") + + if process_input: + # This is (probably) fixable if we need it... + raise exception.Error("process_input not supported over SSH") + + stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) + channel = stdout_stream.channel + + #stdin.write('process_input would go here') + #stdin.flush() + + # NOTE(justinsb): This seems suspicious... + # ...other SSH clients have buffering issues with this approach + stdout = stdout_stream.read() + stderr = stderr_stream.read() + stdin_stream.close() + + exit_status = channel.recv_exit_status() + + # exit_status == -1 if no exit code was returned + if exit_status != -1: + LOG.debug(_("Result was %s") % exit_status) + if check_exit_code and exit_status != 0: + raise exception.ProcessExecutionError(exit_code=exit_status, + stdout=stdout, + stderr=stderr, + cmd=cmd) + + return (stdout, stderr) + def abspath(s): return os.path.join(os.path.dirname(__file__), s) diff --git a/nova/volume/san.py b/nova/volume/san.py index 22a0da13f..1f3417ae5 100644 --- a/nova/volume/san.py +++ b/nova/volume/san.py @@ -26,6 +26,7 @@ import paramiko from nova import exception from nova import flags from nova import log as logging +from nova.utils import ssh_execute from nova.volume.driver import ISCSIDriver LOG = logging.getLogger("nova.volume.driver") @@ -38,8 +39,6 @@ flags.DEFINE_string('san_login', 'admin', 'Username for SAN controller') flags.DEFINE_string('san_password', '', 'Password for SAN controller') -flags.DEFINE_string('san_cluster_name', '', - 'Cluster name for creating SAN volumes') flags.DEFINE_string('san_privatekey', '', 'Filename of private key to use for SSH authentication') @@ -148,17 +147,22 @@ def _get_prefixed_values(data, prefix): return matches class SolarisISCSIDriver(SanISCSIDriver): - """Executes commands relating to Solaris-hosted ISCSI volumes.""" - - #pkg install storage-server SUNWiscsit - #svcadm enable stmf - #zfs allow justinsb create,mount,destroy rpool - #usermod -P'File System Management' justinsb - # I don't know which perms are needed for sbdadm... - #usermod -P'Primary Administrator' justinsb - # svcadm enable -r svc:/network/iscsi/target:default - # pfexec itadm create-tpg e1000g0 10.1.184.98 - # pfexec itadm create-target -t e1000g0 + """Executes commands relating to Solaris-hosted ISCSI volumes. + Basic setup for a Solaris iSCSI server: + pkg install storage-server SUNWiscsit + svcadm enable stmf + svcadm enable -r svc:/network/iscsi/target:default + pfexec itadm create-tpg e1000g0 ${MYIP} + pfexec itadm create-target -t e1000g0 + + Then grant the user that will be logging on lots of permissions. + I'm not sure exactly which though: + zfs allow justinsb create,mount,destroy rpool + usermod -P'File System Management' justinsb + usermod -P'Primary Administrator' justinsb + + Also make sure you can login using san_login & san_password/san_privatekey + """ def _view_exists(self, luid): (out, _err) = self._run_ssh("pfexec /usr/sbin/stmfadm list-view -l %s" % @@ -280,19 +284,13 @@ class SolarisISCSIDriver(SanISCSIDriver): iscsi_name = self._build_iscsi_target_name(volume) target_group_name = 'tg-%s' % volume['name'] - # The sequence of commands looks like this: - #pfexec stmfadm create-tg tg-vol2 - # Yes, we add it before we create it! - #pfexec stmfadm add-tg-member -g tg-vol2 iqn.2010-10.org.openstack:vol2 - #pfexec itadm create-target -n iqn.2010-10.org.openstack:vol2 - #pfexec stmfadm add-view -t tg-vol2 600144F051E2440000004D4A0F730004 - # Create a iSCSI target, mapped to just this volume if force_create or not self._target_group_exists(target_group_name): self._run_ssh("pfexec /usr/sbin/stmfadm create-tg %s" % (target_group_name)) # Yes, we add the initiatior before we create it! + # Otherwise, it complains that the target is already active if force_create or not self._is_target_group_member(target_group_name, iscsi_name): self._run_ssh("pfexec /usr/sbin/stmfadm add-tg-member -g %s %s" % @@ -332,42 +330,3 @@ class SolarisISCSIDriver(SanISCSIDriver): self._run_ssh("pfexec /usr/sbin/sbdadm delete-lu %s" % (luid)) - -def ssh_execute(ssh, cmd, process_input=None, - addl_env=None, check_exit_code=True): - LOG.debug(_("Running cmd (subprocess): %s"), cmd) - if addl_env: - raise exception.Error("Environment not supported over SSH") - - if process_input: - # This is (probably) fixable if we need it... - raise exception.Error("process_input not supported over SSH") - - stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) - channel = stdout_stream.channel - - #stdin.write('process_input would go here') - #stdin.flush() - - # I'm suspicious of this... - # ...other SSH clients have buffering issues with this approach - stdout = stdout_stream.read() - stderr = stderr_stream.read() - stdin_stream.close() - - exit_status = channel.recv_exit_status() - - # exit_status == -1 if no exit code was returned - if exit_status != -1: - LOG.debug(_("Result was %s") % exit_status) - if check_exit_code and exit_status != 0: - raise exception.ProcessExecutionError(exit_code=exit_status, - stdout=stdout, - stderr=stderr, - cmd=cmd) - - # Removed, although this is workaround is needed in utils.execute: - # (no reason to believe it's needed here!) - # greenthread.sleep(0) - - return (stdout, stderr) -- cgit From d86f1af6326d4276e9cbfb3274c211ff3f5629cb Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 4 Feb 2011 17:03:37 -0800 Subject: allow for bridge to be the public interface --- nova/network/linux_net.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 3a8bd9435..69389b333 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -206,6 +206,11 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) + # NOTE(vish): If the public interface is the same as the + # bridge, then the bridge has to be in promiscuous + # to forward packets properly. + if(FLAGS.public_interface == bridge): + _execute("sudo ifconfig %s promisc" % bridge) if interface: # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge -- cgit From 1833ed67ffde756ac1bf1aadbc164a22f7a9b005 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Mon, 7 Feb 2011 10:51:43 +0100 Subject: applied http://launchpadlibrarian.net/63698868/713434.patch --- nova/network/linux_net.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index cdd1f666a..6ed42caae 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -37,6 +37,9 @@ FLAGS = flags.FLAGS flags.DEFINE_string('dhcpbridge_flagfile', '/etc/nova/nova-dhcpbridge.conf', 'location of flagfile for dhcpbridge') +flags.DEFINE_string('dhcp_domain', + 'novalocal', + 'domain to use for building the hostnames') flags.DEFINE_string('networks_path', '$state_path/networks', 'Location to keep network config files') @@ -313,8 +316,9 @@ interface %s def _host_dhcp(fixed_ip_ref): """Return a host string for an address""" instance_ref = fixed_ip_ref['instance'] - return "%s,%s.novalocal,%s" % (instance_ref['mac_address'], + return "%s,%s.%s,%s" % (instance_ref['mac_address'], instance_ref['hostname'], + FLAGS.dhcp_domain, fixed_ip_ref['address']) @@ -359,6 +363,7 @@ def _dnsmasq_cmd(net): ' --strict-order', ' --bind-interfaces', ' --conf-file=', + ' --domain=%s' % FLAGS.dhcp_domain, ' --pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), ' --listen-address=%s' % net['gateway'], ' --except-interface=lo', -- cgit From 26f2f38ef217676292c6cd151664a91fb6c9fd24 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Mon, 7 Feb 2011 11:57:12 +0100 Subject: added myself to the Authors file --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 994a5be9b..27782738f 100644 --- a/Authors +++ b/Authors @@ -6,6 +6,7 @@ Armando Migliaccio Chiradeep Vittal Chmouel Boudjnah Chris Behrens +Christian Berendt Cory Wright David Pravec Dan Prince -- cgit From e12069f79cbf35215eeba5257b2394e9ebde5855 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Mon, 7 Feb 2011 14:29:11 +0100 Subject: replaced all calls to ifconfig with calls to ip --- nova/network/linux_net.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index cdd1f666a..6b8108b14 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -177,7 +177,7 @@ def ensure_vlan(vlan_num): LOG.debug(_("Starting VLAN inteface %s"), interface) _execute("sudo vconfig set_name_type VLAN_PLUS_VID_NO_PAD") _execute("sudo vconfig add %s %s" % (FLAGS.vlan_interface, vlan_num)) - _execute("sudo ifconfig %s up" % interface) + _execute("sudo ip link set %s up" % interface) return interface @@ -192,17 +192,17 @@ def ensure_bridge(bridge, interface, net_attrs=None): if interface: _execute("sudo brctl addif %s %s" % (bridge, interface)) if net_attrs: - _execute("sudo ifconfig %s %s broadcast %s netmask %s up" % \ - (bridge, - net_attrs['gateway'], - net_attrs['broadcast'], - net_attrs['netmask'])) + _execute("sudo ip addr add %s/%s dev %s broadcast %s" % \ + (net_attrs['gateway'], + net_attrs['netmask'], + bridge, + net_attrs['broadcast'])) if(FLAGS.use_ipv6): _execute("sudo ip -f inet6 addr change %s dev %s" % (net_attrs['cidr_v6'], bridge)) - _execute("sudo ifconfig %s up" % bridge) + _execute("sudo ip link set %s up" % bridge) else: - _execute("sudo ifconfig %s up" % bridge) + _execute("sudo ip link set %s up" % bridge) if FLAGS.use_nova_chains: (out, err) = _execute("sudo iptables -N nova_forward", check_exit_code=False) @@ -329,7 +329,8 @@ def _execute(cmd, *args, **kwargs): def _device_exists(device): """Check if ethernet device exists""" - (_out, err) = _execute("ifconfig %s" % device, check_exit_code=False) + (_out, err) = _execute("ip link show dev %s" % device, + check_exit_code=False) return not err -- cgit From e62665a12e0b02ef73562a5d579782972332cbe1 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Mon, 7 Feb 2011 15:20:16 +0100 Subject: fixed format according to PEP8 --- nova/network/linux_net.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 6ed42caae..de0e488ae 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -318,7 +318,7 @@ def _host_dhcp(fixed_ip_ref): instance_ref = fixed_ip_ref['instance'] return "%s,%s.%s,%s" % (instance_ref['mac_address'], instance_ref['hostname'], - FLAGS.dhcp_domain, + FLAGS.dhcp_domain, fixed_ip_ref['address']) @@ -363,7 +363,7 @@ def _dnsmasq_cmd(net): ' --strict-order', ' --bind-interfaces', ' --conf-file=', - ' --domain=%s' % FLAGS.dhcp_domain, + ' --domain=%s' % FLAGS.dhcp_domain, ' --pid-file=%s' % _dhcp_file(net['bridge'], 'pid'), ' --listen-address=%s' % net['gateway'], ' --except-interface=lo', -- cgit From 2613d6449fa9f07c5ee1627a3c44895071fb1a59 Mon Sep 17 00:00:00 2001 From: Anne Gentle Date: Mon, 7 Feb 2011 16:32:04 -0600 Subject: Made updates to multinode install doc --- doc/source/adminguide/multi.node.install.rst | 38 ++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/doc/source/adminguide/multi.node.install.rst b/doc/source/adminguide/multi.node.install.rst index f2f25b060..cf518b26a 100644 --- a/doc/source/adminguide/multi.node.install.rst +++ b/doc/source/adminguide/multi.node.install.rst @@ -37,20 +37,22 @@ From a server you intend to use as a cloud controller node, use this command to :: - wget --no-check-certificate https://github.com/dubsquared/OpenStack-NOVA-Installer-Script/raw/master/Nova_CC_Installer_v0.1 + wget --no-check-certificate https://github.com/dubsquared/OpenStack-NOVA-Installer-Script/raw/master/ nova-CC-install-v1.1.sh Ensure you can execute the script by modifying the permissions on the script file. :: - sudo chmod 755 Nova_CC_Installer_v0.1 + sudo chmod 755 nova-CC-install-v1.1.sh :: - sudo ./Nova_CC_Installer_v0.1 + sudo ./nova-CC-install-v1.1.sh -Next, from a server you intend to use as a compute node (doesn't contain the database), install the nova services. Copy the nova.conf from the cloud controller node to the compute node. +Next, from a server you intend to use as a compute node (doesn't contain the database), install the nova services. You can use the nova-NODE-installer.sh script from the above github-hosted project for the compute node installation. + +Copy the nova.conf from the cloud controller node to the compute node. Restart related services:: @@ -247,7 +249,7 @@ Here is an example of what this looks like with real data:: Note: The nova-manage service assumes that the first IP address is your network (like 192.168.0.0), that the 2nd IP is your gateway (192.168.0.1), and that the broadcast is the very last IP in the range you defined (192.168.0.255). If this is not the case you will need to manually edit the sql db 'networks' table.o. -On running this command, entries are made in the 'networks' and 'fixed_ips' table. However, one of the networks listed in the 'networks' table needs to be marked as bridge in order for the code to know that a bridge exists. The Network is marked as bridged automatically based on the type of network manager selected. This is ONLY necessary if you chose FlatManager as your network type. More information can be found at the end of this document discussing setting up the bridge device. +On running the "nova-manage network create" command, entries are made in the 'networks' and 'fixed_ips' table. However, one of the networks listed in the 'networks' table needs to be marked as bridge in order for the code to know that a bridge exists. The Network is marked as bridged automatically based on the type of network manager selected. You only need to mark the network as a bridge if you chose FlatManager as your network type. More information can be found at the end of this document discussing setting up the bridge device. Step 2 - Create Nova certifications @@ -288,9 +290,35 @@ Another common issue is you cannot ping or SSH your instances after issusing the killall dnsmasq service nova-network restart +To avoid issues with KVM and permissions with Nova, run the following commands to ensure we have VM's that are running optimally:: + + chgrp kvm /dev/kvm + chmod g+rwx /dev/kvm + +If you want to use the 10.04 Ubuntu Enterprise Cloud images that are readily available at http://uec-images.ubuntu.com/releases/10.04/release/, you may run into delays with booting. Any server that does not have nova-api running on it needs this iptables entry so that UEC images can get metadata info. On compute nodes, configure the iptables with this next step:: + + # iptables -t nat -A PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination $NOVA_API_IP:8773 + Testing the Installation ```````````````````````` +You can confirm that your compute node is talking to your cloud controller. From the cloud controller, run this database query:: + + mysql -u$MYSQL_USER -p$MYSQL_PASS nova -e 'select * from services;' + +In return, you should see something similar to this:: + +---------------------+---------------------+------------+---------+----+----------+----------------+-----------+--------------+----------+-------------------+ + | created_at | updated_at | deleted_at | deleted | id | host | binary | topic | report_count | disabled | availability_zone | + +---------------------+---------------------+------------+---------+----+----------+----------------+-----------+--------------+----------+-------------------+ + | 2011-01-28 22:52:46 | 2011-02-03 06:55:48 | NULL | 0 | 1 | osdemo02 | nova-network | network | 46064 | 0 | nova | + | 2011-01-28 22:52:48 | 2011-02-03 06:55:57 | NULL | 0 | 2 | osdemo02 | nova-compute | compute | 46056 | 0 | nova | + | 2011-01-28 22:52:52 | 2011-02-03 06:55:50 | NULL | 0 | 3 | osdemo02 | nova-scheduler | scheduler | 46065 | 0 | nova | + | 2011-01-29 23:49:29 | 2011-02-03 06:54:26 | NULL | 0 | 4 | osdemo01 | nova-compute | compute | 37050 | 0 | nova | + | 2011-01-30 23:42:24 | 2011-02-03 06:55:44 | NULL | 0 | 9 | osdemo04 | nova-compute | compute | 28484 | 0 | nova | + | 2011-01-30 21:27:28 | 2011-02-03 06:54:23 | NULL | 0 | 8 | osdemo05 | nova-compute | compute | 29284 | 0 | nova | + +---------------------+---------------------+------------+---------+----+----------+----------------+-----------+--------------+----------+-------------------+ +You can see that 'osdemo0{1,2,4,5} are all running 'nova-compute.' When you start spinning up instances, they will allocate on any node that is running nova-compute from this list. + You can then use `euca2ools` to test some items:: euca-describe-images -- cgit From a6b913dfd1d940cbf435cb9d9c5c6e2716cf5c2a Mon Sep 17 00:00:00 2001 From: Anne Gentle Date: Mon, 7 Feb 2011 16:35:03 -0600 Subject: Another quick fix to multinode install doc --- doc/source/adminguide/multi.node.install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/adminguide/multi.node.install.rst b/doc/source/adminguide/multi.node.install.rst index cf518b26a..c53455e3e 100644 --- a/doc/source/adminguide/multi.node.install.rst +++ b/doc/source/adminguide/multi.node.install.rst @@ -37,7 +37,7 @@ From a server you intend to use as a cloud controller node, use this command to :: - wget --no-check-certificate https://github.com/dubsquared/OpenStack-NOVA-Installer-Script/raw/master/ nova-CC-install-v1.1.sh + wget --no-check-certificate https://github.com/dubsquared/OpenStack-NOVA-Installer-Script/raw/master/nova-CC-install-v1.1.sh Ensure you can execute the script by modifying the permissions on the script file. -- cgit From 15321719332a5b782ba5ac66d85db0eccc98ccba Mon Sep 17 00:00:00 2001 From: Ryan Lane Date: Mon, 7 Feb 2011 23:01:57 +0000 Subject: Checking whether the instance id is a list or not before assignment. This is to fix a bug relating to nova/boto. The AWK-SDK libraries pass in a string, not a list. the euca tools pass in a list. --- nova/api/ec2/cloud.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 00d044e95..c80e1168a 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -512,8 +512,11 @@ class CloudController(object): def get_console_output(self, context, instance_id, **kwargs): LOG.audit(_("Get console output for instance %s"), instance_id, context=context) - # instance_id is passed in as a list of instances - ec2_id = instance_id[0] + # instance_id may be passed in as a list of instances + if type(instance_id) == list: + ec2_id = instance_id[0] + else: + ec2_id = instance_id instance_id = ec2_id_to_id(ec2_id) output = self.compute_api.get_console_output( context, instance_id=instance_id) -- cgit From a51d187128def4f44ad06cd0880a3e3b4518e073 Mon Sep 17 00:00:00 2001 From: Ryan Lane Date: Tue, 8 Feb 2011 01:00:00 +0000 Subject: Catching all socket errors in _get_my_ip, since any socket error is likely enough to cause a failure in detection. --- nova/flags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/flags.py b/nova/flags.py index 43bc174d2..1d8eba94f 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -208,7 +208,7 @@ def _get_my_ip(): (addr, port) = csock.getsockname() csock.close() return addr - except socket.gaierror as ex: + except socket.error as ex: return "127.0.0.1" -- cgit From 976420e608140e449db5748e57cb18fab74b6d43 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 7 Feb 2011 22:05:45 -0800 Subject: use route -n instead of route to avoid chopped names --- nova/network/linux_net.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 69389b333..b66ca1973 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -215,10 +215,10 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge gateway = None - out, err = _execute("sudo route") + out, err = _execute("sudo route -n") for line in out.split("\n"): fields = line.split() - if fields and fields[0] == "default" and fields[-1] == interface: + if fields and fields[0] == "0.0.0.0" and fields[-1] == interface: gateway = fields[1] out, err = _execute("sudo ip addr show dev %s scope global" % interface) @@ -229,7 +229,7 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): _execute("sudo ip addr del %s dev %s" % (params, fields[-1])) _execute("sudo ip addr add %s dev %s" % (params, bridge)) if gateway: - _execute("sudo route add default gw %s" % gateway) + _execute("sudo route add 0.0.0.0 gw %s" % gateway) out, err = _execute("sudo brctl addif %s %s" % (bridge, interface), check_exit_code=False) -- cgit From 6f30cff7374e91c2920759e13971c0149d96d821 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 8 Feb 2011 10:54:29 -0800 Subject: add docstring and revert set_ip changes as they are unnecessary --- nova/network/linux_net.py | 21 ++++++++++++++++----- nova/network/manager.py | 10 ++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 37993d34a..df54606db 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -168,10 +168,10 @@ def remove_floating_forward(floating_ip, fixed_ip): % (fixed_ip, floating_ip)) -def ensure_vlan_bridge(vlan_num, bridge, net_attrs, set_ip=False): +def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None): """Create a vlan and bridge unless they already exist""" interface = ensure_vlan(vlan_num) - ensure_bridge(bridge, interface, net_attrs, set_ip) + ensure_bridge(bridge, interface, net_attrs) def ensure_vlan(vlan_num): @@ -185,8 +185,19 @@ def ensure_vlan(vlan_num): return interface -def ensure_bridge(bridge, interface, net_attrs, set_ip=False): - """Create a bridge unless it already exists""" +def ensure_bridge(bridge, interface, net_attrs=None): + """Create a bridge unless it already exists. + + :param interface: the interface to create the bridge on. + :param net_attrs: dictionary with attributes used to create the bridge. + + If net_attrs is set, it will add the net_attrs['gateway'] to the bridge + using net_attrs['broadcast'] and net_attrs['cidr']. It will also add + the ip_v6 address specified in net_attrs['cidr_v6'] if use_ipv6 is set. + + The code will attempt to move any ips that already exist on the interface + onto the bridge and reset the default gateway if necessary. + """ if not _device_exists(bridge): LOG.debug(_("Starting Bridge interface for %s"), interface) _execute("sudo brctl addbr %s" % bridge) @@ -194,7 +205,7 @@ def ensure_bridge(bridge, interface, net_attrs, set_ip=False): # _execute("sudo brctl setageing %s 10" % bridge) _execute("sudo brctl stp %s off" % bridge) _execute("sudo ip link set %s up" % bridge) - if set_ip: + if net_attrs: # NOTE(vish): The ip for dnsmasq has to be the first address on the # bridge for it to respond to reqests properly suffix = net_attrs['cidr'].rpartition('/')[2] diff --git a/nova/network/manager.py b/nova/network/manager.py index 735327230..fbcbea131 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -402,8 +402,7 @@ class FlatDHCPManager(FlatManager): """Sets up matching network for compute hosts.""" network_ref = db.network_get_by_instance(context, instance_id) self.driver.ensure_bridge(network_ref['bridge'], - FLAGS.flat_interface, - network_ref) + FLAGS.flat_interface) def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): """Setup dhcp for this network.""" @@ -428,7 +427,7 @@ class FlatDHCPManager(FlatManager): network_ref = db.network_get(context, network_id) self.driver.ensure_bridge(network_ref['bridge'], FLAGS.flat_interface, - network_ref, True) + network_ref) if not FLAGS.fake_network: self.driver.update_dhcp(context, network_id) if(FLAGS.use_ipv6): @@ -499,8 +498,7 @@ class VlanManager(NetworkManager): """Sets up matching network for compute hosts.""" network_ref = db.network_get_by_instance(context, instance_id) self.driver.ensure_vlan_bridge(network_ref['vlan'], - network_ref['bridge'], - network_ref) + network_ref['bridge']) def create_networks(self, context, cidr, num_networks, network_size, cidr_v6, vlan_start, vpn_start): @@ -567,7 +565,7 @@ class VlanManager(NetworkManager): address = network_ref['vpn_public_address'] self.driver.ensure_vlan_bridge(network_ref['vlan'], network_ref['bridge'], - network_ref, True) + network_ref) # NOTE(vish): only ensure this forward if the address hasn't been set # manually. -- cgit From d5501234cfc434fbb4b959b63822598a1a68b88b Mon Sep 17 00:00:00 2001 From: Bilal Akhtar Date: Wed, 9 Feb 2011 11:34:23 +0300 Subject: Give a better error message if the instance type specified is invalid. --- nova/compute/instance_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 196d6a8df..510bfd99e 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -38,8 +38,8 @@ def get_by_type(instance_type): if instance_type is None: return FLAGS.default_instance_type if instance_type not in INSTANCE_TYPES: - raise exception.ApiError(_("Unknown instance type: %s"), - instance_type) + raise exception.ApiError(_("Unknown instance type: %s") % (instance_type), + "Invalid") return instance_type -- cgit From fef2b4edaaf77109457dc2bf80e7f845a65a129e Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 9 Feb 2011 13:22:10 +0100 Subject: Don't convert datetime objects to a string using .isoformat(). Leave it to sqlalchmeny (or pysqlite or whatever it is that does the magic) to work it out. --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 85250d56e..80c844635 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -579,7 +579,7 @@ def fixed_ip_disassociate_all_by_timeout(_context, host, time): 'AND instance_id IS NOT NULL ' 'AND allocated = 0', {'host': host, - 'time': time.isoformat()}) + 'time': time}) return result.rowcount -- cgit From 96fbbcde9c84a72036a74ba07318f31a471eb402 Mon Sep 17 00:00:00 2001 From: Bilal Akhtar Date: Wed, 9 Feb 2011 17:24:36 +0300 Subject: Add my name to AUTHORS, remove parentheses from the substitution made in the previous commit --- Authors | 1 + nova/compute/instance_types.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Authors b/Authors index 27782738f..b359fec22 100644 --- a/Authors +++ b/Authors @@ -3,6 +3,7 @@ Anne Gentle Anthony Young Antony Messerli Armando Migliaccio +Bilal Akhtar Chiradeep Vittal Chmouel Boudjnah Chris Behrens diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 510bfd99e..a41f5fa79 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -38,7 +38,7 @@ def get_by_type(instance_type): if instance_type is None: return FLAGS.default_instance_type if instance_type not in INSTANCE_TYPES: - raise exception.ApiError(_("Unknown instance type: %s") % (instance_type), + raise exception.ApiError(_("Unknown instance type: %s") % instance_type, "Invalid") return instance_type -- cgit From 636bf106d5fc0424b9045e79ea18fb74406e070c Mon Sep 17 00:00:00 2001 From: SuperStack Date: Wed, 9 Feb 2011 09:49:59 -0800 Subject: Added my mail alias (Part of an experiment in using github, which got messy fast...) --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index d13219ab0..c6f6c9a8b 100644 --- a/.mailmap +++ b/.mailmap @@ -33,3 +33,4 @@ + -- cgit From d4b4fa93e7603d73eb99c8edb0e648ff047cda30 Mon Sep 17 00:00:00 2001 From: SuperStack Date: Wed, 9 Feb 2011 11:18:48 -0800 Subject: Fix PEP8 violations --- nova/utils.py | 1 + nova/volume/san.py | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 100e26f70..8d7ff1f64 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -187,6 +187,7 @@ def ssh_execute(ssh, cmd, process_input=None, return (stdout, stderr) + def abspath(s): return os.path.join(os.path.dirname(__file__), s) diff --git a/nova/volume/san.py b/nova/volume/san.py index 1f3417ae5..e7d559a2a 100644 --- a/nova/volume/san.py +++ b/nova/volume/san.py @@ -42,6 +42,7 @@ flags.DEFINE_string('san_password', '', flags.DEFINE_string('san_privatekey', '', 'Filename of private key to use for SSH authentication') + class SanISCSIDriver(ISCSIDriver): """ Base class for SAN-style storage volumes (storage providers we access over SSH)""" @@ -68,7 +69,8 @@ class SanISCSIDriver(ISCSIDriver): volume_name) iscsi_portal = location.split(",")[0] - LOG.debug("iscsi_name=%s, iscsi_portal=%s" % (iscsi_name, iscsi_portal)) + LOG.debug("iscsi_name=%s, iscsi_portal=%s" % + (iscsi_name, iscsi_portal)) return (iscsi_name, iscsi_portal) def _build_iscsi_target_name(self, volume): @@ -89,7 +91,9 @@ class SanISCSIDriver(ISCSIDriver): privatekeyfile = os.path.expanduser(FLAGS.san_privatekey) # It sucks that paramiko doesn't support DSA keys privatekey = paramiko.RSAKey.from_private_key_file(privatekeyfile) - ssh.connect(FLAGS.san_ip, username=FLAGS.san_login, pkey=privatekey) + ssh.connect(FLAGS.san_ip, + username=FLAGS.san_login, + pkey=privatekey) else: raise exception.Error("Specify san_password or san_privatekey") return ssh @@ -125,6 +129,7 @@ class SanISCSIDriver(ISCSIDriver): if not (FLAGS.san_ip): raise exception.Error("san_ip must be set") + def _collect_lines(data): """ Split lines from data into an array, trimming them """ matches = [] @@ -134,6 +139,7 @@ def _collect_lines(data): return matches + def _get_prefixed_values(data, prefix): """Collect lines which start with prefix; with trimming""" matches = [] @@ -146,6 +152,7 @@ def _get_prefixed_values(data, prefix): return matches + class SolarisISCSIDriver(SanISCSIDriver): """Executes commands relating to Solaris-hosted ISCSI volumes. Basic setup for a Solaris iSCSI server: @@ -165,8 +172,8 @@ class SolarisISCSIDriver(SanISCSIDriver): """ def _view_exists(self, luid): - (out, _err) = self._run_ssh("pfexec /usr/sbin/stmfadm list-view -l %s" % - (luid), + cmd = "pfexec /usr/sbin/stmfadm list-view -l %s" % (luid) + (out, _err) = self._run_ssh(cmd, check_exit_code=False) if "no views found" in out: return False @@ -229,9 +236,6 @@ class SolarisISCSIDriver(SanISCSIDriver): sizestr, zfs_poolname)) - return { # 'target_ip': FLAGS.san_ip - } - def _get_luid(self, volume): zfs_poolname = self._build_zfs_poolname(volume) @@ -329,4 +333,3 @@ class SolarisISCSIDriver(SanISCSIDriver): if self._is_lu_created(volume): self._run_ssh("pfexec /usr/sbin/sbdadm delete-lu %s" % (luid)) - -- cgit From b1fbb1a4a087722ce6dc7fd7a1b9fe01cb6ec766 Mon Sep 17 00:00:00 2001 From: SuperStack Date: Wed, 9 Feb 2011 11:25:18 -0800 Subject: Indent args to ssh_connect correctly --- nova/volume/san.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/volume/san.py b/nova/volume/san.py index e7d559a2a..26d6125e7 100644 --- a/nova/volume/san.py +++ b/nova/volume/san.py @@ -92,8 +92,8 @@ class SanISCSIDriver(ISCSIDriver): # It sucks that paramiko doesn't support DSA keys privatekey = paramiko.RSAKey.from_private_key_file(privatekeyfile) ssh.connect(FLAGS.san_ip, - username=FLAGS.san_login, - pkey=privatekey) + username=FLAGS.san_login, + pkey=privatekey) else: raise exception.Error("Specify san_password or san_privatekey") return ssh -- cgit From 216822bdda290f964020134599749ebbadc76566 Mon Sep 17 00:00:00 2001 From: Bilal Akhtar Date: Thu, 10 Feb 2011 13:08:25 +0300 Subject: Wrap line to under 79 characters --- nova/compute/instance_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index a41f5fa79..309313fd0 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -38,8 +38,8 @@ def get_by_type(instance_type): if instance_type is None: return FLAGS.default_instance_type if instance_type not in INSTANCE_TYPES: - raise exception.ApiError(_("Unknown instance type: %s") % instance_type, - "Invalid") + raise exception.ApiError(_("Unknown instance type: %s") % \ + instance_type, "Invalid") return instance_type -- cgit