From 5b436ffc2a46e34c8b4cc94780a9059dbef58cda Mon Sep 17 00:00:00 2001 From: "paul@openstack.org" <> Date: Wed, 14 Sep 2011 12:10:33 -0500 Subject: exporting auth to keystone (users, projects/tenants, roles, credentials) --- bin/nova-manage | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/bin/nova-manage b/bin/nova-manage index 089b2eeae..5f0c54717 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -61,6 +61,7 @@ import math import netaddr from optparse import OptionParser import os +import StringIO import sys import time @@ -274,6 +275,50 @@ class ShellCommands(object): arguments: path""" exec(compile(open(path).read(), path, 'exec'), locals(), globals()) + @args('--filename', dest='filename', metavar='', help='Export path') + def export(self, filename): + """Export Nova users into a file that can be consumed by Keystone""" + def create_file(filename): + data = generate_file() + with open(filename, 'w') as f: + f.write(data.getvalue()) + + def tenants(data, am): + for project in am.get_projects(): + print >> data, ("tenant add '%s'" % + (project.name)) + for u in project.member_ids: + user = am.get_user(u) + print >> data, ("user add '%s' '%s' '%s'" % + (user.name, user.access, project.name)) + print >> data, ("credentials add 'EC2' '%s' '%s'" % + (user.access, user.secret)) + + def roles(data, am): + for role in am.get_roles(): + print >> data, ("role add '%s'" % (role)) + + def grant_roles(data, am): + roles = am.get_roles() + for project in am.get_projects(): + for u in project.member_ids: + user = am.get_user(u) + for role in roles: + if user.has_role(role): + print >> data, ("role grant '%s', '%s', '%s')," % + (user.name, role, project.name)) + print >> data, footer + + def generate_file(): + data = StringIO.StringIO() + am = manager.AuthManager() + tenants(data, am) + roles(data, am) + data.seek(0) + return data + + create_file(filename) + class RoleCommands(object): """Class for managing roles.""" -- cgit From 94e23a3def4172e58264f051a9558ba536dd1d19 Mon Sep 17 00:00:00 2001 From: "paul@openstack.org" <> Date: Wed, 14 Sep 2011 13:20:16 -0500 Subject: minor changes to credentials for the correct format --- bin/nova-manage | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 5f0c54717..60799024c 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -286,13 +286,13 @@ class ShellCommands(object): def tenants(data, am): for project in am.get_projects(): print >> data, ("tenant add '%s'" % - (project.name)) + (project.name)) for u in project.member_ids: user = am.get_user(u) print >> data, ("user add '%s' '%s' '%s'" % - (user.name, user.access, project.name)) - print >> data, ("credentials add 'EC2' '%s' '%s'" % - (user.access, user.secret)) + (user.name, user.access, project.name)) + print >> data, ("credentials add 'EC2' '%s:%s' '%s' '%s'" % + (user.access, project.id, user.secret, project.id)) def roles(data, am): for role in am.get_roles(): -- cgit From 7e379f6a77f53ad4d6ddc98fbb30cd853933bb08 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 14 Sep 2011 14:38:40 -0500 Subject: Initial pass at automatically confirming resizes after a given window. --- nova/compute/manager.py | 16 ++++++++++++++-- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 22 +++++++++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 7915830ec..6ddbb20b0 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -81,6 +81,9 @@ flags.DEFINE_integer('live_migration_retry_count', 30, flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") +flags.DEFINE_integer("resize_confirm_window", 0, + "Automatically confirm resizes after N seconds." + " Set to 0 to disable.") flags.DEFINE_integer('host_state_interval', 120, 'Interval in seconds for querying the host status') @@ -1644,14 +1647,23 @@ class ComputeManager(manager.SchedulerDependentManager): self.driver.poll_rescued_instances(FLAGS.rescue_timeout) except Exception as ex: LOG.warning(_("Error during poll_rescued_instances: %s"), - unicode(ex)) + unicode(ex)) + error_list.append(ex) + + try: + if FLAGS.resize_confirm_window > 0: + self.driver.poll_unconfirmed_resizes( + FLAGS.resize_confirm_window) + except Exception as ex: + LOG.warning(_("Error during poll_unconfirmed_resizes: %s"), + unicode(ex)) error_list.append(ex) try: self._report_driver_status() except Exception as ex: LOG.warning(_("Error during report_driver_status(): %s"), - unicode(ex)) + unicode(ex)) error_list.append(ex) try: diff --git a/nova/db/api.py b/nova/db/api.py index a9d2dc065..53cdc42c2 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -321,6 +321,11 @@ def migration_get_by_instance_and_status(context, instance_uuid, status): status) +def migration_get_all_unconfirmed(context, confirm_window): + """Finds all unconfirmed migrations within the confirmation window.""" + return IMPL.migration_get_all_unconfirmed(context, confirm_window) + + #################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index e5a661c7f..58e6aef6e 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -15,9 +15,10 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Implementation of SQLAlchemy backend. -""" + +"""Implementation of SQLAlchemy backend.""" + +import datetime import re import warnings @@ -3194,6 +3195,21 @@ def migration_get_by_instance_and_status(context, instance_uuid, status): return result +@require_admin_context +def migration_get_all_unconfirmed(context, confirm_window, session=None): + confirm_window = datetime.datetime.utcnow() - datetime.timedelta( + seconds=confirm_window) + + if not session: + session = get_session() + + results = session.query(models.Migration).\ + filter(models.Migration.updated_at <= confirm_window).\ + filter_by(status="VERIFY_RESIZE").all() + + return results + + ################## -- cgit From 2477ebf17add4c0e44ad9dd9a7ac3b632a8929f4 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Thu, 15 Sep 2011 13:44:49 -0500 Subject: Added virt-level support for polling unconfirmed resizes. --- nova/virt/driver.py | 5 +++++ nova/virt/fake.py | 3 +++ nova/virt/hyperv.py | 3 +++ nova/virt/libvirt/connection.py | 4 ++++ nova/virt/xenapi/vmops.py | 21 +++++++++++++++++++++ nova/virt/xenapi_conn.py | 4 ++++ 6 files changed, 40 insertions(+) diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 301346c6b..fc47d8d2d 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -469,6 +469,11 @@ class ComputeDriver(object): # TODO(Vek): Need to pass context in for access to auth_token raise NotImplementedError() + def poll_unconfirmed_resizes(self, resize_confirm_window): + """Poll for unconfirmed resizes""" + # TODO(Vek): Need to pass context in for access to auth_token + raise NotImplementedError() + def host_power_action(self, host, action): """Reboots, shuts down or powers up the host.""" raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 3596d8353..96f521ee7 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -130,6 +130,9 @@ class FakeConnection(driver.ComputeDriver): def poll_rescued_instances(self, timeout): pass + def poll_unconfirmed_resizes(self, resize_confirm_window): + pass + def migrate_disk_and_power_off(self, instance, dest): pass diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 76925b405..fbf898317 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -487,6 +487,9 @@ class HyperVConnection(driver.ComputeDriver): def poll_rescued_instances(self, timeout): pass + def poll_unconfirmed_resizes(self, resize_confirm_window): + pass + def update_available_resource(self, ctxt, host): """This method is supported only by libvirt.""" return diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 18e643ea8..d480c723f 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -584,6 +584,10 @@ class LibvirtConnection(driver.ComputeDriver): def poll_rescued_instances(self, timeout): pass + @exception.wrap_exception() + def poll_unconfirmed_resizes(self, resize_confirm_window): + pass + # NOTE(ilyaalekseyev): Implementation like in multinics # for xenapi(tr3buchet) @exception.wrap_exception() diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6b56d668e..180e746f1 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -38,6 +38,7 @@ from nova import ipv6 from nova import log as logging from nova import utils +from nova.compute import api as compute from nova.compute import power_state from nova.virt import driver from nova.virt.xenapi.network_utils import NetworkHelper @@ -77,6 +78,7 @@ class VMOps(object): """ def __init__(self, session): self.XenAPI = session.get_imported_xenapi() + self.compute_api = compute.API() self._session = session self.poll_rescue_last_ran = None VMHelper.XenAPI = self.XenAPI @@ -1041,6 +1043,25 @@ class VMOps(object): self._session.call_xenapi("VM.start", original_vm_ref, False, False) + def poll_unconfirmed_resizes(self, resize_confirm_window): + """Poll for unconfirmed resizes. + + Look for any unconfirmed resizes that are older than + `resize_confirm_window` and automatically confirm them. + """ + ctxt = nova_context.get_admin_context() + migrations = db.migration_get_all_unconfirmed(ctxt, + resize_confirm_window) + + migrations_info = dict(migration_count=len(migrations), + confirm_window=FLAGS.resize_confirm_window) + LOG.info(_("Found %(migration_count)d unconfirmed migrations older " + "than %(confirm_window)d seconds") % migrations_info) + + for migration in migrations: + LOG.info(_("Automatically confirming migration %d"), migration.id) + self.compute_api.confirm_resize(ctxt, migration.instance_uuid) + def get_info(self, instance): """Return data about VM instance.""" vm_ref = self._get_vm_opaque_ref(instance) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index f6dbc19f8..7fc683a9f 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -254,6 +254,10 @@ class XenAPIConnection(driver.ComputeDriver): """Poll for rescued instances""" self._vmops.poll_rescued_instances(timeout) + def poll_unconfirmed_resizes(self, resize_confirm_window): + """Poll for unconfirmed resizes""" + self._vmops.poll_unconfirmed_resizes(resize_confirm_window) + def reset_network(self, instance): """reset networking for specified instance""" self._vmops.reset_network(instance) -- cgit From 62516cac832bd24003f1bf29b4a03e7f5d9a1579 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Thu, 15 Sep 2011 14:09:14 -0500 Subject: Added a unit test. --- nova/tests/test_virt_drivers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py index 440d3401b..8e20e999f 100644 --- a/nova/tests/test_virt_drivers.py +++ b/nova/tests/test_virt_drivers.py @@ -176,6 +176,10 @@ class _VirtDriverTestCase(test.TestCase): def test_poll_rescued_instances(self): self.connection.poll_rescued_instances(10) + @catch_notimplementederror + def test_poll_unconfirmed_resizes(self): + self.connection.poll_unconfirmed_resizes(10) + @catch_notimplementederror def test_migrate_disk_and_power_off(self): instance_ref = test_utils.get_test_instance() -- cgit From 90f01055a92153709a90115688a8fce3d3029976 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Fri, 16 Sep 2011 13:06:21 -0500 Subject: Only log migration info if they exist. --- nova/virt/xenapi/vmops.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 180e746f1..55a6a4a78 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1055,8 +1055,10 @@ class VMOps(object): migrations_info = dict(migration_count=len(migrations), confirm_window=FLAGS.resize_confirm_window) - LOG.info(_("Found %(migration_count)d unconfirmed migrations older " - "than %(confirm_window)d seconds") % migrations_info) + + if migrations_info["migration_count"] > 0: + LOG.info(_("Found %(migration_count)d unconfirmed migrations " + "older than %(confirm_window)d seconds") % migrations_info) for migration in migrations: LOG.info(_("Automatically confirming migration %d"), migration.id) -- cgit From 358dffe941cd280a69134dc59d3670e50b811800 Mon Sep 17 00:00:00 2001 From: "paul@openstack.org" <> Date: Fri, 16 Sep 2011 21:12:50 -0500 Subject: fixed grant user, added stdout support --- bin/nova-manage | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 60799024c..4e9307273 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -275,11 +275,13 @@ class ShellCommands(object): arguments: path""" exec(compile(open(path).read(), path, 'exec'), locals(), globals()) - @args('--filename', dest='filename', metavar='', help='Export path') + @args('--filename', dest='filename', metavar='', default=False, + help='Export file path') def export(self, filename): """Export Nova users into a file that can be consumed by Keystone""" + def create_file(filename): - data = generate_file() + data = generate_data() with open(filename, 'w') as f: f.write(data.getvalue()) @@ -303,21 +305,27 @@ class ShellCommands(object): for project in am.get_projects(): for u in project.member_ids: user = am.get_user(u) - for role in roles: - if user.has_role(role): - print >> data, ("role grant '%s', '%s', '%s')," % - (user.name, role, project.name)) - print >> data, footer + for role in db.user_get_roles_for_project(ctxt, u, + project.id): + print >> data, ("role grant '%s', '%s', '%s')," % + (user.name, role, project.name)) + print >> data - def generate_file(): + def generate_data(): data = StringIO.StringIO() am = manager.AuthManager() tenants(data, am) roles(data, am) + grant_roles(data, am) data.seek(0) return data - create_file(filename) + ctxt = context.get_admin_context() + if filename: + create_file(filename) + else: + data = generate_data() + print data.getvalue() class RoleCommands(object): -- cgit From bd5a0a2bf42686efb81bb08de5d6938e2c076f0b Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Mon, 19 Sep 2011 11:10:50 -0500 Subject: Corrected the status in DB call. --- 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 779f20ae1..6fe46eb88 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -3210,7 +3210,7 @@ def migration_get_all_unconfirmed(context, confirm_window, session=None): results = session.query(models.Migration).\ filter(models.Migration.updated_at <= confirm_window).\ - filter_by(status="VERIFY_RESIZE").all() + filter_by(status="FINISHED").all() return results -- cgit From 66977838d02ad51ced525321b21e648bcc2065bc Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Mon, 19 Sep 2011 11:58:20 -0500 Subject: Added unit test. --- nova/tests/test_db_api.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index 60d7abd8c..c99709ffa 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -18,6 +18,8 @@ """Unit tests for the DB API""" +import datetime + from nova import test from nova import context from nova import db @@ -95,3 +97,26 @@ class DbApiTestCase(test.TestCase): self.assertEqual(result[0].id, inst2.id) self.assertEqual(result[1].id, inst1.id) self.assertTrue(result[1].deleted) + + def test_migration_get_all_unconfirmed(self): + ctxt = context.get_admin_context() + + # Ensure no migrations are returned. + results = db.migration_get_all_unconfirmed(ctxt, 10) + self.assertEqual(0, len(results)) + + # Ensure one migration older than 10 seconds is returned. + updated_at = datetime.datetime(2000, 01, 01, 12, 00, 00) + values = {"status": "FINISHED", "updated_at": updated_at} + migration = db.migration_create(ctxt, values) + results = db.migration_get_all_unconfirmed(ctxt, 10) + self.assertEqual(1, len(results)) + db.migration_update(ctxt, migration.id, {"status": "CONFIRMED"}) + + # Ensure the new migration is not returned. + updated_at = datetime.datetime.utcnow() + values = {"status": "FINISHED", "updated_at": updated_at} + migration = db.migration_create(ctxt, values) + results = db.migration_get_all_unconfirmed(ctxt, 10) + self.assertEqual(0, len(results)) + db.migration_update(ctxt, migration.id, {"status": "CONFIRMED"}) -- cgit From eee411b90f7c6eda0de898489daff6e6aa006bb1 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Mon, 19 Sep 2011 15:56:42 -0500 Subject: now raising instead of setting bridge to br100 and warning as was noted --- bin/nova-manage | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 089b2eeae..4d90dd1b3 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -710,16 +710,7 @@ class NetworkCommands(object): bridge_required = ['nova.network.manager.FlatManager', 'nova.network.manager.FlatDHCPManager'] if FLAGS.network_manager in bridge_required: - # TODO(tr3buchet) - swap print statement and following line for - # raise statement in diablo 4 - print _('--bridge parameter required or FLAG ' - 'flat_network_bridge must be set to create networks\n' - 'WARNING! ACHTUNG! Setting the bridge to br100 ' - 'automatically is deprecated and will be removed in ' - 'Diablo milestone 4. Prepare yourself accordingly.') - time.sleep(10) - bridge = 'br100' - #raise exception.NetworkNotCreated(req='--bridge') + raise exception.NetworkNotCreated(req='--bridge') bridge_interface = bridge_interface or FLAGS.flat_interface or \ FLAGS.vlan_interface -- cgit From 83aca0e78727a870fb6aa788158920a1c8321541 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 19 Sep 2011 14:53:17 -0700 Subject: Removed the extra code added to support filtering instances by instance uuids. Instead, added 'uuid' to the list of exact_filter_match names. Updated the caller to add 'uuid: uuid_list' to the filters dictionary, instead of passing it in as another argument. Updated the ID to UUID mapping code to return a dictionary, which allows the caller to be more efficient... It removes an extra loop there. A couple of typo fixes. --- nova/compute/api.py | 5 +++-- nova/db/api.py | 13 ++++++------- nova/db/sqlalchemy/api.py | 40 ++++++++++++---------------------------- nova/network/manager.py | 9 +++------ nova/tests/fake_network.py | 8 +++++--- nova/tests/test_compute.py | 4 ++-- 6 files changed, 31 insertions(+), 48 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 853e6ef9e..76e1e7a60 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -937,9 +937,10 @@ class API(base.Base): filters) # NOTE(jkoelker) It is possible that we will get the same # instance uuid twice (one for ipv4 and ipv6) - ids = set([r['instance_uuid'] for r in res]) + uuids = set([r['instance_uuid'] for r in res]) + filters['uuid'] = uuids - return self.db.instance_get_all_by_filters(context, filters, ids) + return self.db.instance_get_all_by_filters(context, filters) def _cast_compute_message(self, method, context, instance_id, host=None, params=None): diff --git a/nova/db/api.py b/nova/db/api.py index f68e1c48e..0f959a606 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -463,7 +463,7 @@ def virtual_interface_delete_by_instance(context, instance_id): def virtual_interface_get_all(context): - """Gets all virtual interfaces from the table,""" + """Gets all virtual interfaces from the table""" return IMPL.virtual_interface_get_all(context) @@ -505,10 +505,9 @@ def instance_get_all(context): return IMPL.instance_get_all(context) -def instance_get_all_by_filters(context, filters, instance_uuids=None): +def instance_get_all_by_filters(context, filters): """Get all instances that match all filters.""" - return IMPL.instance_get_all_by_filters(context, filters, - instance_uuids=instance_uuids) + return IMPL.instance_get_all_by_filters(context, filters) def instance_get_active_by_window(context, begin, end=None, project_id=None): @@ -612,9 +611,9 @@ def instance_get_actions(context, instance_id): return IMPL.instance_get_actions(context, instance_id) -def instance_get_uuids_by_ids(context, ids): - """Return the UUIDs of the instances given the ids""" - return IMPL.instance_get_uuids_by_ids(context, ids) +def instance_get_id_to_uuid_mapping(context, ids): + """Return a dictionary containing 'ID: UUID' given the ids""" + return IMPL.instance_get_id_to_uuid_mapping(context, ids) ################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index c4bff8308..6a2c0f743 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1203,7 +1203,7 @@ def instance_get_all(context): @require_context -def instance_get_all_by_filters(context, filters, instance_uuids=None): +def instance_get_all_by_filters(context, filters): """Return instances that match all filters. Deleted instances will be returned by default, unless there's a filter that says otherwise""" @@ -1234,7 +1234,7 @@ def instance_get_all_by_filters(context, filters, instance_uuids=None): """Do exact match against a column. value to match can be a list so you can match any value in the list. """ - if isinstance(value, list): + if isinstance(value, list) or isinstance(value, set): column_attr = getattr(models.Instance, column) return query.filter(column_attr.in_(value)) else: @@ -1268,7 +1268,7 @@ def instance_get_all_by_filters(context, filters, instance_uuids=None): # Filters for exact matches that we can do along with the SQL query... # For other filters that don't match this, we will do regexp matching exact_match_filter_names = ['project_id', 'user_id', 'image_ref', - 'vm_state', 'instance_type_id', 'deleted'] + 'vm_state', 'instance_type_id', 'deleted', 'uuid'] query_filters = [key for key in filters.iterkeys() if key in exact_match_filter_names] @@ -1279,30 +1279,10 @@ def instance_get_all_by_filters(context, filters, instance_uuids=None): query_prefix = _exact_match_filter(query_prefix, filter_name, filters.pop(filter_name)) - db_instances = query_prefix.all() - db_uuids = [instance['uuid'] for instance in db_instances \ - if instance['uuid']] - - if instance_uuids is None: - instance_uuids = [] - - uuids = [] - - # NOTE(jkoelker): String UUIDs only! - if not instance_uuids: - uuids = db_uuids - elif not db_instances: - uuids = instance_uuids - else: - uuids = list(set(instance_uuids) & set(db_uuids)) - - if not uuids: + instances = query_prefix.all() + if not instances: return [] - instances = session.query(models.Instance).\ - filter(models.Instance.uuid.in_(uuids)).\ - all() - # Now filter on everything else for regexp matching.. # For filters not in the list, we'll attempt to use the filter_name # as a column name in Instance.. @@ -1320,6 +1300,8 @@ def instance_get_all_by_filters(context, filters, instance_uuids=None): filter_l = lambda instance: _regexp_filter_by_column(instance, filter_name, filter_re) instances = filter(filter_l, instances) + if not instances: + break return instances @@ -1564,13 +1546,15 @@ def instance_get_actions(context, instance_id): @require_context -def instance_get_uuids_by_ids(context, ids): +def instance_get_id_to_uuid_mapping(context, ids): session = get_session() instances = session.query(models.Instance).\ filter(models.Instance.id.in_(ids)).\ all() - return [{'uuid': instance['uuid'], - 'id': instance['id']} for instance in instances] + mapping = {} + for instance in instances: + mapping[instance['id']] = instance['uuid'] + return mapping ################### diff --git a/nova/network/manager.py b/nova/network/manager.py index 2687d8faf..ffb9f976c 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -410,7 +410,7 @@ class NetworkManager(manager.SchedulerDependentManager): ip_filter = re.compile(str(filters.get('ip'))) ipv6_filter = re.compile(str(filters.get('ip6'))) - # NOTE(jkoelker) Should probably figur out a better way to do + # NOTE(jkoelker) Should probably figure out a better way to do # this. But for now it "works", this could suck on # large installs. @@ -448,12 +448,9 @@ class NetworkManager(manager.SchedulerDependentManager): # NOTE(jkoelker) Until we switch over to instance_uuid ;) ids = [res['instance_id'] for res in results] - uuids = self.db.instance_get_uuids_by_ids(context, ids) + uuid_map = self.db.instance_get_id_to_uuid_mapping(context, ids) for res in results: - uuid = [u['uuid'] for u in uuids if u['id'] == res['instance_id']] - # NOTE(jkoelker) UUID must exist, so no test here - res['instance_uuid'] = uuid[0] - + res['instance_uuid'] = uuid_map.get(res['instance_id']) return results def _get_networks_for_instance(self, context, instance_id, project_id, diff --git a/nova/tests/fake_network.py b/nova/tests/fake_network.py index d839f20b0..febac5e09 100644 --- a/nova/tests/fake_network.py +++ b/nova/tests/fake_network.py @@ -105,10 +105,12 @@ class FakeNetworkManager(network_manager.NetworkManager): 'floating_ips': [floats[2]]}]}] return vifs - def instance_get_uuids_by_ids(self, context, ids): + def instance_get_id_to_uuid_mapping(self, context, ids): # NOTE(jkoelker): This is just here until we can rely on UUIDs - return [{'uuid': str(utils.gen_uuid()), - 'id': id} for id in ids] + mapping = {} + for id in ids: + mapping[id] = str(utils.gen_uuid()) + return mapping def __init__(self): self.db = self.FakeDB() diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 4ef57b760..948c7ad40 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1033,8 +1033,8 @@ class ComputeTestCase(test.TestCase): 'get_instance_uuids_by_ip_filter', network_manager.get_instance_uuids_by_ip_filter) self.stubs.Set(network_manager.db, - 'instance_get_uuids_by_ids', - db.instance_get_uuids_by_ids) + 'instance_get_id_to_uuid_mapping', + db.instance_get_id_to_uuid_mapping) instance_id1 = self._create_instance({'display_name': 'woot', 'id': 0}) -- cgit From b0ca3a42995cc25852420083e431c3be5071d221 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 19 Sep 2011 15:08:25 -0700 Subject: fix a test where list order was assumed --- nova/tests/test_db_api.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index 5ebab9cc8..aaf5212d0 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -92,6 +92,9 @@ class DbApiTestCase(test.TestCase): db.instance_destroy(self.context, inst1.id) result = db.instance_get_all_by_filters(self.context.elevated(), {}) self.assertEqual(2, len(result)) - self.assertEqual(result[0].id, inst1.id) - self.assertEqual(result[1].id, inst2.id) - self.assertTrue(result[0].deleted) + self.assertIn(inst1.id, [result[0].id, result[1].id]) + self.assertIn(inst2.id, [result[0].id, result[1].id]) + if inst1.id == result[0].id: + self.assertTrue(result[0].deleted) + else: + self.assertTrue(result[1].deleted) -- cgit From 83023c3035746f296fd024b282c355e8499770f1 Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Mon, 19 Sep 2011 15:23:52 -0700 Subject: fix unrelated pep8 issue in trunk --- nova/network/linux_net.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 2f9805fa3..9bf98fc27 100755 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -824,7 +824,6 @@ class LinuxNetInterfaceDriver(object): raise NotImplementedError() - # plugs interfaces using Linux Bridge class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver): -- cgit From f8d62435f5171ab47aba7d966b2b8b0561c5f5ba Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Mon, 19 Sep 2011 17:27:25 -0500 Subject: run the alter on the right table --- .../migrate_repo/versions/047_remove_instances_fk_from_vif.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py index 818925c32..ae9486e58 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py @@ -45,7 +45,7 @@ def upgrade(migrate_engine): refcolumns=[instances.c.id]).drop() except Exception: try: - migrate_engine.execute("ALTER TABLE migrations DROP " \ + migrate_engine.execute("ALTER TABLE virtual_interfaces DROP " \ "FOREIGN KEY " \ "`virtual_interfaces_ibfk_2`;") except Exception: -- cgit From 869b0724e897d75695c2a1a559d1447745f9dce8 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 19 Sep 2011 22:04:32 -0400 Subject: Update migration 047 to dynamically lookup the name of the instance_id fkey before dropping it. We can't hard code the name of the fkey since we didn't name it explicitly on create. --- .../versions/047_remove_instances_fk_from_vif.py | 32 ++++++++-------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py index ae9486e58..dadcefc39 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/047_remove_instances_fk_from_vif.py @@ -17,21 +17,9 @@ from migrate import ForeignKeyConstraint from nova import log as logging - meta = MetaData() -instances = Table('instances', meta, - Column('id', Integer(), primary_key=True, nullable=False), - ) - - -vifs = Table('virtual_interfaces', meta, - Column('id', Integer(), primary_key=True, nullable=False), - Column('instance_id', Integer()), - ) - - def upgrade(migrate_engine): # Upgrade operations go here. Don't create your own engine; # bind migrate_engine to your metadata @@ -40,17 +28,18 @@ def upgrade(migrate_engine): if dialect.startswith('sqlite'): return + instances = Table('instances', meta, autoload=True) + vifs = Table('virtual_interfaces', meta, autoload=True) + try: + fkey_name = vifs.c.instance_id.foreign_keys[0].constraint.name ForeignKeyConstraint(columns=[vifs.c.instance_id], - refcolumns=[instances.c.id]).drop() + refcolumns=[instances.c.id], + name=fkey_name).drop() + except Exception: - try: - migrate_engine.execute("ALTER TABLE virtual_interfaces DROP " \ - "FOREIGN KEY " \ - "`virtual_interfaces_ibfk_2`;") - except Exception: - logging.error(_("foreign key constraint couldn't be removed")) - raise + logging.error(_("foreign key constraint couldn't be removed")) + raise def downgrade(migrate_engine): @@ -60,6 +49,9 @@ def downgrade(migrate_engine): if dialect.startswith('sqlite'): return + instances = Table('instances', meta, autoload=True) + vifs = Table('virtual_interfaces', meta, autoload=True) + try: ForeignKeyConstraint(columns=[vifs.c.instance_id], refcolumns=[instances.c.id]).create() -- cgit From 5a9c4ef3786d99373b1d3c16b499420425221ae0 Mon Sep 17 00:00:00 2001 From: "Brad McConnell bmcconne@rackspace.com" <> Date: Mon, 19 Sep 2011 21:35:47 -0500 Subject: Fixed --uuid network command in nova-manage to desc to "uuid" instead of "net_uuid" --- bin/nova-manage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/nova-manage b/bin/nova-manage index 4e9307273..8a1a8537d 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -738,7 +738,7 @@ class NetworkCommands(object): help='Multi host') @args('--dns1', dest="dns1", metavar="", help='First DNS') @args('--dns2', dest="dns2", metavar="", help='Second DNS') - @args('--uuid', dest="net_uuid", metavar="", + @args('--uuid', dest="uuid", metavar="", help='Network UUID') @args('--project_id', dest="project_id", metavar="", help='Project id') -- cgit From b9c708064a256f0fc4c1559b28265c0485ef634f Mon Sep 17 00:00:00 2001 From: "Brad McConnell bmcconne@rackspace.com" <> Date: Mon, 19 Sep 2011 22:21:10 -0500 Subject: added to authors cuz trey said I cant patch otherwise! --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index 4e0848692..8d6837ea4 100644 --- a/Authors +++ b/Authors @@ -12,6 +12,7 @@ Armando Migliaccio Arvind Somya Bilal Akhtar Brad Hall +Brad McConnell Brian Lamar Brian Schott Brian Waldon -- cgit