From 089bdfa8c2f0f116b55c69bbcde6fca6632cb145 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 15:20:23 -0600 Subject: should be writing some kindof network info to the xenstore now, hopefully --- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 6 ++++++ nova/db/sqlalchemy/models.py | 1 + nova/virt/xenapi/vmops.py | 39 +++++++++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 8 deletions(-) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index f9d561587..7b37bce2f 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -501,6 +501,11 @@ def network_get(context, network_id): return IMPL.network_get(context, network_id) +def network_get_all(context): + """Get all networks""" + returm IMPL.network_get_all(context) + + # pylint: disable-msg=C0103 def network_get_associated_fixed_ips(context, network_id): """Get all network's ips that have been associated.""" diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index b63b84bed..053780158 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1054,6 +1054,12 @@ def network_get(context, network_id, session=None): return result +@require_context +def network_get_all(context): + session = get_session() + return session.query(models.Network).all() + + # NOTE(vish): pylint complains because of the long method name, but # it fits with the names of the rest of the methods # pylint: disable-msg=C0103 diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index c54ebe3ba..dc476acf4 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -369,6 +369,7 @@ class Network(BASE, NovaBase): "vpn_public_port"), {'mysql_engine': 'InnoDB'}) id = Column(Integer, primary_key=True) + label = Column(String(255)) injected = Column(Boolean, default=False) cidr = Column(String(255), unique=True) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6c2fd6a68..882b9d9d6 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -67,11 +67,6 @@ class VMOps(object): raise exception.Duplicate(_('Attempted to create' ' non-unique name %s') % instance.name) - bridge = db.network_get_by_instance(context.get_admin_context(), - instance['id'])['bridge'] - network_ref = \ - NetworkHelper.find_network_with_bridge(self._session, bridge) - user = AuthManager().get_user(instance.user_id) project = AuthManager().get_project(instance.project_id) #if kernel is not present we must download a raw disk @@ -99,9 +94,29 @@ class VMOps(object): instance, kernel, ramdisk, pv_kernel) VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True) - if network_ref: - VMHelper.create_vif(self._session, vm_ref, - network_ref, instance.mac_address) + # write network info + network = db.network_get_by_instance(context.get_admin_context(), + instance['id']) + for network in db.network_get_all(): + mapping = {'label': network['label'], + 'gateway': network['gateway'], + 'mac': instance.mac_address, + 'dns': network['dns'], + 'ips': [{'netmask': network['netmask'], + 'enabled': '1', + 'ip': 192.168.3.3}]} # <===== CHANGE!!!! + self.write_network_config_to_xenstore(vm_ref, mapping) + + bridge = network['bridge'] + network_ref = \ + NetworkHelper.find_network_with_bridge(self._session, bridge) + + if network_ref: + VMHelper.create_vif(self._session, vm_ref, + network_ref, instance.mac_address) + + # call reset networking + LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) LOG.info(_('Spawning VM %s created %s.'), instance.name, vm_ref) @@ -341,6 +356,14 @@ class VMOps(object): # TODO: implement this! return 'http://fakeajaxconsole/fake_url' + def reset_networking(self, instance): + vm = self._get_vm_opaque_ref(instance) + self.write_to_xenstore(vm, "resetnetwork", "") + + def write_network_config_to_xenstore(self, instance): + vm = self._get_vm_opaque_ref(instance) + self.write_to_param_xenstore(vm, mapping) + def list_from_xenstore(self, vm, path): """Runs the xenstore-ls command to get a listing of all records from 'path' downward. Returns a dict with the sub-paths as keys, -- cgit From 9b993d50835c79d23dca422335de362ebaf7f4fa Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 15:47:08 -0600 Subject: added plugin call for resetnetworking --- nova/virt/xenapi/vmops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 882b9d9d6..7f9e78df5 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -358,7 +358,8 @@ class VMOps(object): def reset_networking(self, instance): vm = self._get_vm_opaque_ref(instance) - self.write_to_xenstore(vm, "resetnetwork", "") + args = {'id': str(uuid.uuid4())} + resp = self._make_agent_call('resetnetwork', vm, '', args) def write_network_config_to_xenstore(self, instance): vm = self._get_vm_opaque_ref(instance) -- cgit From 8d1798008fcec536f1117a275b168ca449f1dfbf Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 16:19:07 -0600 Subject: syntax error --- nova/db/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index 7b37bce2f..f22cd5615 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -503,7 +503,7 @@ def network_get(context, network_id): def network_get_all(context): """Get all networks""" - returm IMPL.network_get_all(context) + return IMPL.network_get_all(context) # pylint: disable-msg=C0103 -- cgit From f77043d44aa640e1811a3fe236fc8fd5dfecf990 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 16:27:09 -0600 Subject: syntax --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 7f9e78df5..1045d5d98 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -104,7 +104,7 @@ class VMOps(object): 'dns': network['dns'], 'ips': [{'netmask': network['netmask'], 'enabled': '1', - 'ip': 192.168.3.3}]} # <===== CHANGE!!!! + 'ip': '192.168.3.3'}]} # <===== CHANGE!!!! self.write_network_config_to_xenstore(vm_ref, mapping) bridge = network['bridge'] -- cgit From f38196b0eb7a11501f9b0ffa9409c05510798761 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 18:08:01 -0600 Subject: added default label to nova-manage and create_networks --- nova/network/manager.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index 61de8055a..a377c40c6 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -325,11 +325,12 @@ class FlatManager(NetworkManager): pass def create_networks(self, context, cidr, num_networks, network_size, - cidr_v6, *args, **kwargs): + cidr_v6, label, *args, **kwargs): """Create networks based on parameters.""" fixed_net = IPy.IP(cidr) fixed_net_v6 = IPy.IP(cidr_v6) significant_bits_v6 = 64 + count = 1 for index in range(num_networks): start = index * network_size significant_bits = 32 - int(math.log(network_size, 2)) @@ -342,6 +343,11 @@ class FlatManager(NetworkManager): net['gateway'] = str(project_net[1]) net['broadcast'] = str(project_net.broadcast()) net['dhcp_start'] = str(project_net[2]) + if num_networks > 1: + net['label'] = "%s_%d" % (label, count) + else: + net['label'] = label + count += 1 if(FLAGS.use_ipv6): cidr_v6 = "%s/%s" % (fixed_net_v6[0], significant_bits_v6) -- cgit From a9f9a0fcb7443b93db3f4de8f68218f20f0cc1a9 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 18:36:18 -0600 Subject: really added migration for networks label --- .../sqlalchemy/migrate_repo/versions/003_cactus.py | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py (limited to 'nova') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py new file mode 100644 index 000000000..13b4766d8 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py @@ -0,0 +1,47 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +from sqlalchemy import * +from migrate import * + +from nova import log as logging + + +meta = MetaData() + + +# +# New Tables +# + + +# +# Tables to alter +# + +networks_label = Column( + 'label', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + networks.create_column(networks_label) -- cgit From d4a643976adbe49ec52db53694481e9ba687cddf Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 20 Jan 2011 18:40:04 -0600 Subject: fixed the migration --- nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py index 13b4766d8..ddfe114cb 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py @@ -25,6 +25,11 @@ from nova import log as logging meta = MetaData() +networks = Table('networks', meta, + Column('id', Integer(), primary_key=True, nullable=False), + ) + + # # New Tables # -- cgit From 0c7893e4119bcccdfdfdcdef0931fcc8802688e8 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Wed, 26 Jan 2011 14:59:17 -0600 Subject: added mapping parameter to write_network_config_to_xenstore --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c7310987b..68fa1ecd6 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -391,7 +391,7 @@ class VMOps(object): args = {'id': str(uuid.uuid4())} resp = self._make_agent_call('resetnetwork', vm, '', args) - def write_network_config_to_xenstore(self, instance): + def write_network_config_to_xenstore(self, instance, mapping): vm = self._get_vm_opaque_ref(instance) self.write_to_param_xenstore(vm, mapping) -- cgit From eabc4c00eea8859c37efed3f180edbc41fd3b71d Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 27 Jan 2011 23:53:28 -0600 Subject: Working on api / manager / db support for zones --- nova/api/openstack/__init__.py | 5 +++++ nova/db/api.py | 8 ++++++++ nova/db/sqlalchemy/api.py | 9 +++++++++ 3 files changed, 22 insertions(+) (limited to 'nova') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index c70bb39ed..025fa12a4 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -34,6 +34,7 @@ from nova.api.openstack import flavors from nova.api.openstack import images from nova.api.openstack import servers from nova.api.openstack import shared_ip_groups +from nova.api.openstack import zones LOG = logging.getLogger('nova.api.openstack') @@ -79,6 +80,10 @@ class APIRouter(wsgi.Router): server_members["actions"] = "GET" server_members['suspend'] = 'POST' server_members['resume'] = 'POST' + + mapper.resource("zone", "zones", controller=zones.Controller(), + collection={'detail': 'GET'}, + member=zone_members) mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, diff --git a/nova/db/api.py b/nova/db/api.py index 789cb8ebb..dc35f20b2 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -980,3 +980,11 @@ def console_get_all_by_instance(context, instance_id): def console_get(context, console_id, instance_id=None): """Get a specific console (possibly on a given instance).""" return IMPL.console_get(context, console_id, instance_id) + + +#################### + + +def create_zone(context, name): + """Create a new Zone entry for this deployment.""" + return IMPL.create_zone(context, name) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 895e7eabe..ec36c481e 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1996,3 +1996,12 @@ def console_get(context, console_id, instance_id=None): raise exception.NotFound(_("No console with id %(console_id)s" " %(idesc)s") % locals()) return result + + +################## + + +@require_admin_context +def create_zone(context, zone): + session = get_session() + print "Creating Zone", zone -- cgit From f76a0a9d4d8aa3d8cc2669da1a8eea7d610a8616 Mon Sep 17 00:00:00 2001 From: termie Date: Sun, 30 Jan 2011 15:55:48 -0800 Subject: trivial cleanup for context.py --- nova/context.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/context.py b/nova/context.py index f2669c9f1..76e46703a 100644 --- a/nova/context.py +++ b/nova/context.py @@ -28,7 +28,6 @@ from nova import utils class RequestContext(object): - def __init__(self, user, project, is_admin=None, read_deleted=False, remote_address=None, timestamp=None, request_id=None): if hasattr(user, 'id'): @@ -53,7 +52,7 @@ class RequestContext(object): self.read_deleted = read_deleted self.remote_address = remote_address if not timestamp: - timestamp = datetime.datetime.utcnow() + timestampe = utils.utcnow() if isinstance(timestamp, str) or isinstance(timestamp, unicode): timestamp = utils.parse_isotime(timestamp) self.timestamp = timestamp @@ -101,7 +100,7 @@ class RequestContext(object): return cls(**values) def elevated(self, read_deleted=False): - """Return a version of this context with admin flag set""" + """Return a version of this context with admin flag set.""" return RequestContext(self.user_id, self.project_id, True, -- cgit From 701c71999a135996575dd76a7171eb707b4d74ef Mon Sep 17 00:00:00 2001 From: termie Date: Sun, 30 Jan 2011 16:04:52 -0800 Subject: woops --- nova/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/context.py b/nova/context.py index 76e46703a..0256bf448 100644 --- a/nova/context.py +++ b/nova/context.py @@ -52,7 +52,7 @@ class RequestContext(object): self.read_deleted = read_deleted self.remote_address = remote_address if not timestamp: - timestampe = utils.utcnow() + timestamp = utils.utcnow() if isinstance(timestamp, str) or isinstance(timestamp, unicode): timestamp = utils.parse_isotime(timestamp) self.timestamp = timestamp -- cgit From 620eba09a96f25a059249c23a5e73efd18aaf89a Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 1 Feb 2011 14:11:21 -0600 Subject: forgot context param for network_get_all --- nova/virt/xenapi/vmops.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 68fa1ecd6..da2e5c672 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -95,9 +95,10 @@ class VMOps(object): VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True) # write network info - network = db.network_get_by_instance(context.get_admin_context(), + admin_context = context.get_admin_context() + network = db.network_get_by_instance(admin_context, instance['id']) - for network in db.network_get_all(): + for network in db.network_get_all(admin_context): mapping = {'label': network['label'], 'gateway': network['gateway'], 'mac': instance.mac_address, -- cgit From 0e6b1c02b3ae82526f3cf83ce70213e7a107701d Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 1 Feb 2011 15:41:53 -0600 Subject: added to inject networking data into the xenstore --- nova/virt/xenapi/vmops.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index da2e5c672..6edeae5c0 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -99,14 +99,16 @@ class VMOps(object): network = db.network_get_by_instance(admin_context, instance['id']) for network in db.network_get_all(admin_context): + mac_id = instance.mac_address.replace(':', '') + location = 'vm-data/networking/%s' % mac_id mapping = {'label': network['label'], 'gateway': network['gateway'], 'mac': instance.mac_address, - 'dns': network['dns'], + 'dns': [network['dns']], 'ips': [{'netmask': network['netmask'], 'enabled': '1', 'ip': '192.168.3.3'}]} # <===== CHANGE!!!! - self.write_network_config_to_xenstore(vm_ref, mapping) + self.write_to_param_xenstore(vm_ref, {location: mapping}) bridge = network['bridge'] network_ref = \ @@ -392,10 +394,6 @@ class VMOps(object): args = {'id': str(uuid.uuid4())} resp = self._make_agent_call('resetnetwork', vm, '', args) - def write_network_config_to_xenstore(self, instance, mapping): - vm = self._get_vm_opaque_ref(instance) - self.write_to_param_xenstore(vm, mapping) - def list_from_xenstore(self, vm, path): """Runs the xenstore-ls command to get a listing of all records from 'path' downward. Returns a dict with the sub-paths as keys, -- cgit From 3cae5a2573c96900f224d0145cee5077b01424b5 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 4 Feb 2011 11:36:09 -0600 Subject: Don't swallow exception stack traces by doing 'raise e'; just use 'raise' --- nova/compute/api.py | 4 ++-- nova/volume/manager.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/compute/api.py b/nova/compute/api.py index ac02dbcfa..b409dc1e0 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -70,7 +70,7 @@ class API(base.Base): except exception.NotFound as e: LOG.warning(_("Instance %d was not found in get_network_topic"), instance_id) - raise e + raise host = instance['host'] if not host: @@ -296,7 +296,7 @@ class API(base.Base): except exception.NotFound as e: LOG.warning(_("Instance %d was not found during terminate"), instance_id) - raise e + raise if (instance['state_description'] == 'terminating'): LOG.warning(_("Instance %d is already being terminated"), diff --git a/nova/volume/manager.py b/nova/volume/manager.py index 6f8e25e19..3e63e7b26 100644 --- a/nova/volume/manager.py +++ b/nova/volume/manager.py @@ -114,7 +114,7 @@ class VolumeManager(manager.Manager): except Exception as e: self.db.volume_update(context, volume_ref['id'], {'status': 'error'}) - raise e + raise now = datetime.datetime.utcnow() self.db.volume_update(context, @@ -141,7 +141,7 @@ class VolumeManager(manager.Manager): self.db.volume_update(context, volume_ref['id'], {'status': 'error_deleting'}) - raise e + raise self.db.volume_destroy(context, volume_id) LOG.debug(_("volume %s: deleted successfully"), volume_ref['name']) -- cgit From 645f4733081dfe03554cc30221ccc1a8b359d1ea Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 4 Feb 2011 16:20:24 -0600 Subject: Removed (newly) unused exception variables --- nova/compute/api.py | 4 ++-- nova/volume/manager.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/compute/api.py b/nova/compute/api.py index b409dc1e0..4a7c1c9e9 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -67,7 +67,7 @@ class API(base.Base): """Get the network topic for an instance.""" try: instance = self.get(context, instance_id) - except exception.NotFound as e: + except exception.NotFound: LOG.warning(_("Instance %d was not found in get_network_topic"), instance_id) raise @@ -293,7 +293,7 @@ class API(base.Base): LOG.debug(_("Going to try to terminate %s"), instance_id) try: instance = self.get(context, instance_id) - except exception.NotFound as e: + except exception.NotFound: LOG.warning(_("Instance %d was not found during terminate"), instance_id) raise diff --git a/nova/volume/manager.py b/nova/volume/manager.py index 3e63e7b26..5771a6384 100644 --- a/nova/volume/manager.py +++ b/nova/volume/manager.py @@ -111,7 +111,7 @@ class VolumeManager(manager.Manager): LOG.debug(_("volume %s: creating export"), volume_ref['name']) self.driver.create_export(context, volume_ref) - except Exception as e: + except Exception: self.db.volume_update(context, volume_ref['id'], {'status': 'error'}) raise @@ -137,7 +137,7 @@ class VolumeManager(manager.Manager): self.driver.remove_export(context, volume_ref) LOG.debug(_("volume %s: deleting"), volume_ref['name']) self.driver.delete_volume(volume_ref) - except Exception as e: + except Exception: self.db.volume_update(context, volume_ref['id'], {'status': 'error_deleting'}) -- cgit From 93d6050078214945fd2c842a15fb177f24811fa1 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Mon, 7 Feb 2011 17:06:30 +0000 Subject: Fix for bug #714709 --- nova/virt/xenapi/vm_utils.py | 5 +++++ nova/virt/xenapi/vmops.py | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 4bbd522c1..4f6de7588 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -438,7 +438,12 @@ class VMHelper(HelperBase): return vdis else: return None + @classmethod + def lookup_kernel_ramdisk(cls,session,vm): + vm_rec = session.get_xenapi().VM.get_record(vm) + return (vm_rec['PV_kernel'],vm_rec['PV_ramdisk']) + @classmethod def compile_info(cls, record): """Fill record with VM status information""" diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index e84ce20c4..fe95d881b 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -286,8 +286,23 @@ class VMOps(object): def _destroy_vm(self, instance, vm): """Destroys a VM record """ try: - task = self._session.call_xenapi('Async.VM.destroy', vm) - self._session.wait_for_task(instance.id, task) + kernel = None + ramdisk = None + if instance.kernel_id or instance.ramdisk_id: + (kernel, ramdisk) = VMHelper.lookup_kernel_ramdisk( + self._session, vm) + task1 = self._session.call_xenapi('Async.VM.destroy', vm) + LOG.debug(_("Removing kernel/ramdisk files")) + fn = "remove_kernel_ramdisk" + args = {} + if kernel: + args['kernel-file'] = kernel + if ramdisk: + args['ramdisk-file'] = ramdisk + task2 = self._session.async_call_plugin('glance', fn, args) + self._session.wait_for_task(instance.id, task1) + self._session.wait_for_task(instance.id, task2) + LOG.debug(_("kernel/ramdisk files removed")) except self.XenAPI.Failure, exc: LOG.exception(exc) -- cgit From 41e615b843c284631a0d878db2c93ef97f2eb4b8 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 7 Feb 2011 14:46:54 -0400 Subject: minor --- nova/api/openstack/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 025fa12a4..8901a8987 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -83,7 +83,7 @@ class APIRouter(wsgi.Router): mapper.resource("zone", "zones", controller=zones.Controller(), collection={'detail': 'GET'}, - member=zone_members) + collection_name='zones') mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, -- cgit From b6022c1f7d7dc9294f6b1b613c7e99bd9437a72e Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Mon, 7 Feb 2011 13:43:23 -0600 Subject: added network_get_all_by_instance(), call to reset_network in vmops --- nova/db/sqlalchemy/api.py | 19 +++++++++++++------ nova/virt/xenapi/vmops.py | 11 +++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'nova') diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 31865d553..26b685e43 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1055,12 +1055,6 @@ def network_get(context, network_id, session=None): return result -@require_context -def network_get_all(context): - session = get_session() - return session.query(models.Network).all() - - # NOTE(vish): pylint complains because of the long method name, but # it fits with the names of the rest of the methods # pylint: disable-msg=C0103 @@ -1104,6 +1098,19 @@ def network_get_by_instance(_context, instance_id): return rv +@require_admin_context +def network_get_all_by_instance(_context, instance_id): + session = get_session() + rv = session.query(models.Network).\ + filter_by(deleted=False).\ + join(models.Network.fixed_ips).\ + filter_by(instance_id=instance_id).\ + filter_by(deleted=False) + if not rv: + raise exception.NotFound(_('No network for instance %s') % instance_id) + return rv + + @require_admin_context def network_set_host(context, network_id, host_id): session = get_session() diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6edeae5c0..4056e99bc 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -96,9 +96,11 @@ class VMOps(object): # write network info admin_context = context.get_admin_context() - network = db.network_get_by_instance(admin_context, - instance['id']) - for network in db.network_get_all(admin_context): + #network = db.network_get_by_instance(admin_context, + # instance['id']) + + for network in db.network_get_all_by_instance(admin_context, + instance['id']): mac_id = instance.mac_address.replace(':', '') location = 'vm-data/networking/%s' % mac_id mapping = {'label': network['label'], @@ -119,6 +121,7 @@ class VMOps(object): network_ref, instance.mac_address) # call reset networking + self.reset_network(vm_ref) LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) @@ -389,7 +392,7 @@ class VMOps(object): # TODO: implement this! return 'http://fakeajaxconsole/fake_url' - def reset_networking(self, instance): + def reset_network(self, instance): vm = self._get_vm_opaque_ref(instance) args = {'id': str(uuid.uuid4())} resp = self._make_agent_call('resetnetwork', vm, '', args) -- cgit From 2ecd9de1a0b26cd7168a008f44caad47ecb49c01 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 8 Feb 2011 10:14:51 +0000 Subject: Fixed pep8 errors Unit tests passed --- nova/virt/xenapi/vm_utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 4f6de7588..2d2200805 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -438,12 +438,15 @@ class VMHelper(HelperBase): return vdis else: return None + @classmethod - def lookup_kernel_ramdisk(cls,session,vm): + def lookup_kernel_ramdisk(cls, session, vm): vm_rec = session.get_xenapi().VM.get_record(vm) - return (vm_rec['PV_kernel'],vm_rec['PV_ramdisk']) + if 'PV_kernel' in vm_rec and 'PV_ramdisk' in vm_rec: + return (vm_rec['PV_kernel'], vm_rec['PV_ramdisk']) + else: + return (None, None) - @classmethod def compile_info(cls, record): """Fill record with VM status information""" -- cgit From 653ff11692fa5cd5ec5f9ea75cddc03df1b3dcd5 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Tue, 8 Feb 2011 16:39:46 +0000 Subject: avoiding HOST_UNAVAILABLE exception: if there is not enough free memory does not spawn the VM at all. instance state is set to "SHUTDOWN" --- nova/virt/xenapi/vm_utils.py | 11 +++++++++++ nova/virt/xenapi/vmops.py | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 4bbd522c1..3a0f0a149 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -138,6 +138,17 @@ class VMHelper(HelperBase): LOG.debug(_('Created VM %(instance_name)s as %(vm_ref)s.') % locals()) return vm_ref + @classmethod + def ensure_free_mem(cls, session, instance): + instance_type = instance_types.INSTANCE_TYPES[instance.instance_type] + mem = str(long(instance_type['memory_mb']) * 1024 * 1024) + #get free memory from host + host = session.get_xenapi_host() + host_free_mem = session.get_xenapi().host.compute_free_memory(host) + if (host_free_mem < mem ): + return False + return True + @classmethod def create_vbd(cls, session, vm_ref, vdi_ref, userdevice, bootable): """Create a VBD record. Returns a Deferred that gives the new diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index e84ce20c4..2d4e53083 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -66,7 +66,14 @@ class VMOps(object): if vm is not None: raise exception.Duplicate(_('Attempted to create' ' non-unique name %s') % instance.name) - + #ensure enough free memory, otherwise don't bother + if not VMHelper.ensure_free_mem(self._session,instance): + LOG.exception(_('instance %s: not enough free memory'), + instance['name']) + db.instance_set_state(context.get_admin_context(), + instance['id'], + power_state.SHUTDOWN) + return bridge = db.network_get_by_instance(context.get_admin_context(), instance['id'])['bridge'] network_ref = \ -- cgit From f6ec9568561dd430bd772f171f5bbddd0bd038c6 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 9 Feb 2011 10:08:15 +0000 Subject: Added test case for 'not enough memory' Successfully ran unit tests Fixed pep8 errors --- nova/compute/manager.py | 2 +- nova/compute/power_state.py | 4 +++- nova/tests/test_xenapi.py | 11 +++++++++-- nova/virt/xenapi/fake.py | 4 ++++ nova/virt/xenapi/vm_utils.py | 4 ++-- nova/virt/xenapi/vmops.py | 7 ++++--- 6 files changed, 23 insertions(+), 9 deletions(-) (limited to 'nova') diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f4418af26..bb999931c 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -127,7 +127,7 @@ class ComputeManager(manager.Manager): info = self.driver.get_info(instance_ref['name']) state = info['state'] except exception.NotFound: - state = power_state.NOSTATE + state = power_state.FAILED self.db.instance_set_state(context, instance_id, state) def get_console_topic(self, context, **_kwargs): diff --git a/nova/compute/power_state.py b/nova/compute/power_state.py index 37039d2ec..adfc2dff0 100644 --- a/nova/compute/power_state.py +++ b/nova/compute/power_state.py @@ -27,6 +27,7 @@ SHUTDOWN = 0x04 SHUTOFF = 0x05 CRASHED = 0x06 SUSPENDED = 0x07 +FAILED = 0x08 def name(code): @@ -38,5 +39,6 @@ def name(code): SHUTDOWN: 'shutdown', SHUTOFF: 'shutdown', CRASHED: 'crashed', - SUSPENDED: 'suspended'} + SUSPENDED: 'suspended', + FAILED: 'failed to spawn'} return d[code] diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 9f5b266f3..d5660c5d1 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -243,7 +243,8 @@ class XenAPIVMTestCase(test.TestCase): # Check that the VM is running according to XenAPI. self.assertEquals(vm['power_state'], 'Running') - def _test_spawn(self, image_id, kernel_id, ramdisk_id): + def _test_spawn(self, image_id, kernel_id, ramdisk_id, + instance_type="m1.large"): stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) values = {'name': 1, 'id': 1, @@ -252,7 +253,7 @@ class XenAPIVMTestCase(test.TestCase): 'image_id': image_id, 'kernel_id': kernel_id, 'ramdisk_id': ramdisk_id, - 'instance_type': 'm1.large', + 'instance_type': instance_type, 'mac_address': 'aa:bb:cc:dd:ee:ff', } conn = xenapi_conn.get_connection(False) @@ -260,6 +261,12 @@ class XenAPIVMTestCase(test.TestCase): conn.spawn(instance) self.check_vm_record(conn) + def test_spawn_not_enough_memory(self): + FLAGS.xenapi_image_service = 'glance' + self.assertRaises(Exception, + self._test_spawn, + 1, 2, 3, "m1.xlarge") + def test_spawn_raw_objectstore(self): FLAGS.xenapi_image_service = 'objectstore' self._test_spawn(1, None, None) diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index e8352771c..018d0dcd3 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -286,6 +286,10 @@ class SessionBase(object): rec['currently_attached'] = False rec['device'] = '' + def host_compute_free_memory(self, _1, ref): + #Always return 12GB available + return 12 * 1024 * 1024 * 1024 + def xenapi_request(self, methodname, params): if methodname.startswith('login'): self._login(methodname, params) diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 3a0f0a149..c6ac969b9 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -141,11 +141,11 @@ class VMHelper(HelperBase): @classmethod def ensure_free_mem(cls, session, instance): instance_type = instance_types.INSTANCE_TYPES[instance.instance_type] - mem = str(long(instance_type['memory_mb']) * 1024 * 1024) + mem = long(instance_type['memory_mb']) * 1024 * 1024 #get free memory from host host = session.get_xenapi_host() host_free_mem = session.get_xenapi().host.compute_free_memory(host) - if (host_free_mem < mem ): + if (host_free_mem < mem): return False return True diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 2d4e53083..e3c303d91 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -67,13 +67,13 @@ class VMOps(object): raise exception.Duplicate(_('Attempted to create' ' non-unique name %s') % instance.name) #ensure enough free memory, otherwise don't bother - if not VMHelper.ensure_free_mem(self._session,instance): + if not VMHelper.ensure_free_mem(self._session, instance): LOG.exception(_('instance %s: not enough free memory'), instance['name']) db.instance_set_state(context.get_admin_context(), instance['id'], power_state.SHUTDOWN) - return + return bridge = db.network_get_by_instance(context.get_admin_context(), instance['id'])['bridge'] network_ref = \ @@ -168,7 +168,8 @@ class VMOps(object): instance_name = instance_or_vm.name vm = VMHelper.lookup(self._session, instance_name) if vm is None: - raise Exception(_('Instance not present %s') % instance_name) + raise exception.NotFound( + _('Instance not present %s') % instance_name) return vm def snapshot(self, instance, image_id): -- cgit From 9a55136eb691de8d795ec47c5720556160899244 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Wed, 9 Feb 2011 15:39:37 +0000 Subject: Fixed pep8 error in vm_utils.py --- nova/virt/xenapi/vm_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 2d2200805..f5c19099a 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -445,7 +445,7 @@ class VMHelper(HelperBase): if 'PV_kernel' in vm_rec and 'PV_ramdisk' in vm_rec: return (vm_rec['PV_kernel'], vm_rec['PV_ramdisk']) else: - return (None, None) + return (None, None) @classmethod def compile_info(cls, record): -- cgit From 6e881239c9b8a1fb209868addf1a2b83042f2128 Mon Sep 17 00:00:00 2001 From: brian-lamar Date: Wed, 9 Feb 2011 13:30:40 -0500 Subject: 1) Moved tests for limiter to test_common.py (from __init__.py) and expanded test suite to include bad inputs and tests for custom limits (#2) 2) Wrapped int() calls in blocks to ensure logic regardless of input. 3) Moved 1000 hard limit hard-coding to a keyword param. 4) Added comments as I went. --- nova/api/openstack/common.py | 33 ++++--- nova/tests/api/openstack/__init__.py | 28 ------ nova/tests/api/openstack/test_common.py | 161 ++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 41 deletions(-) create mode 100644 nova/tests/api/openstack/test_common.py (limited to 'nova') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 6d2fa16e8..1dc3767e2 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -18,22 +18,29 @@ from nova import exception -def limited(items, req): - """Return a slice of items according to requested offset and limit. - - items - a sliceable - req - wobob.Request possibly containing offset and limit GET variables. - offset is where to start in the list, and limit is the maximum number - of items to return. +def limited(items, request, max_limit=1000): + """ + Return a slice of items according to requested offset and limit. - If limit is not specified, 0, or > 1000, defaults to 1000. + @param items: A sliceable entity + @param request: `webob.Request` possibly containing 'offset' and 'limit' + GET variables. 'offset' is where to start in the list, + and 'limit' is the maximum number of items to return. If + 'limit' is not specified, 0, or > max_limit, we default + to max_limit. + @kwarg max_limit: The maximum number of items to return from 'items' """ + try: + offset = int(request.GET.get('offset', 0)) + except ValueError: + offset = 0 + + try: + limit = int(request.GET.get('limit', max_limit)) + except ValueError: + limit = max_limit - offset = int(req.GET.get('offset', 0)) - limit = int(req.GET.get('limit', 0)) - if not limit: - limit = 1000 - limit = min(1000, limit) + limit = min(max_limit, limit or max_limit) range_end = offset + limit return items[offset:range_end] diff --git a/nova/tests/api/openstack/__init__.py b/nova/tests/api/openstack/__init__.py index 14eaaa62c..77b1dd37f 100644 --- a/nova/tests/api/openstack/__init__.py +++ b/nova/tests/api/openstack/__init__.py @@ -92,31 +92,3 @@ class RateLimitingMiddlewareTest(unittest.TestCase): self.assertEqual(middleware.limiter.__class__.__name__, "Limiter") middleware = RateLimitingMiddleware(simple_wsgi, service_host='foobar') self.assertEqual(middleware.limiter.__class__.__name__, "WSGIAppProxy") - - -class LimiterTest(unittest.TestCase): - - def test_limiter(self): - items = range(2000) - req = Request.blank('/') - self.assertEqual(limited(items, req), items[:1000]) - req = Request.blank('/?offset=0') - self.assertEqual(limited(items, req), items[:1000]) - req = Request.blank('/?offset=3') - self.assertEqual(limited(items, req), items[3:1003]) - req = Request.blank('/?offset=2005') - self.assertEqual(limited(items, req), []) - req = Request.blank('/?limit=10') - self.assertEqual(limited(items, req), items[:10]) - req = Request.blank('/?limit=0') - self.assertEqual(limited(items, req), items[:1000]) - req = Request.blank('/?limit=3000') - self.assertEqual(limited(items, req), items[:1000]) - req = Request.blank('/?offset=1&limit=3') - self.assertEqual(limited(items, req), items[1:4]) - req = Request.blank('/?offset=3&limit=0') - self.assertEqual(limited(items, req), items[3:1003]) - req = Request.blank('/?offset=3&limit=1500') - self.assertEqual(limited(items, req), items[3:1003]) - req = Request.blank('/?offset=3000&limit=10') - self.assertEqual(limited(items, req), []) diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py new file mode 100644 index 000000000..9d9837cc9 --- /dev/null +++ b/nova/tests/api/openstack/test_common.py @@ -0,0 +1,161 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# 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. + +""" +Test suites for 'common' code used throughout the OpenStack HTTP API. +""" + +import unittest + +from webob import Request + +from nova.api.openstack.common import limited + + +class LimiterTest(unittest.TestCase): + """ + Unit tests for the `nova.api.openstack.common.limited` method which takes + in a list of items and, depending on the 'offset' and 'limit' GET params, + returns a subset or complete set of the given items. + """ + + def setUp(self): + """ + Run before each test. + """ + self.tiny = range(1) + self.small = range(10) + self.medium = range(1000) + self.large = range(10000) + + def test_limiter_offset_zero(self): + """ + Test offset key works with 0. + """ + req = Request.blank('/?offset=0') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_offset_medium(self): + """ + Test offset key works with a medium sized number. + """ + req = Request.blank('/?offset=10') + self.assertEqual(limited(self.tiny, req), []) + self.assertEqual(limited(self.small, req), self.small[10:]) + self.assertEqual(limited(self.medium, req), self.medium[10:]) + self.assertEqual(limited(self.large, req), self.large[10:1010]) + + def test_limiter_offset_over_max(self): + """ + Test offset key works with a number over 1000 (max_limit). + """ + req = Request.blank('/?offset=1001') + self.assertEqual(limited(self.tiny, req), []) + self.assertEqual(limited(self.small, req), []) + self.assertEqual(limited(self.medium, req), []) + self.assertEqual(limited(self.large, req), self.large[1001:2001]) + + def test_limiter_offset_blank(self): + """ + Test offset key works with a blank offset. + """ + req = Request.blank('/?offset=') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_offset_bad(self): + """ + Test offset key works with a BAD offset. + """ + req = Request.blank(u'/?offset=\u0020aa') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_nothing(self): + """ + Test request with no offset or limit + """ + req = Request.blank('/') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_limit_zero(self): + """ + Test limit of zero. + """ + req = Request.blank('/?limit=0') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_limit_medium(self): + """ + Test limit of 10. + """ + req = Request.blank('/?limit=10') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium[:10]) + self.assertEqual(limited(self.large, req), self.large[:10]) + + def test_limiter_limit_over_max(self): + """ + Test limit of 3000. + """ + req = Request.blank('/?limit=3000') + self.assertEqual(limited(self.tiny, req), self.tiny) + self.assertEqual(limited(self.small, req), self.small) + self.assertEqual(limited(self.medium, req), self.medium) + self.assertEqual(limited(self.large, req), self.large[:1000]) + + def test_limiter_limit_and_offset(self): + """ + Test request with both limit and offset. + """ + items = range(2000) + req = Request.blank('/?offset=1&limit=3') + self.assertEqual(limited(items, req), items[1:4]) + req = Request.blank('/?offset=3&limit=0') + self.assertEqual(limited(items, req), items[3:1003]) + req = Request.blank('/?offset=3&limit=1500') + self.assertEqual(limited(items, req), items[3:1003]) + req = Request.blank('/?offset=3000&limit=10') + self.assertEqual(limited(items, req), []) + + def test_limiter_custom_max_limit(self): + """ + Test a max_limit other than 1000. + """ + items = range(2000) + req = Request.blank('/?offset=1&limit=3') + self.assertEqual(limited(items, req, max_limit=2000), items[1:4]) + req = Request.blank('/?offset=3&limit=0') + self.assertEqual(limited(items, req, max_limit=2000), items[3:]) + req = Request.blank('/?offset=3&limit=2500') + self.assertEqual(limited(items, req, max_limit=2000), items[3:]) + req = Request.blank('/?offset=3000&limit=10') + self.assertEqual(limited(items, req, max_limit=2000), []) -- cgit From 52e1ad5321590b7b4671349373217bc8fce275fc Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 9 Feb 2011 15:55:29 -0500 Subject: - population of public and private addresses containers in openstack api - replacement of sqlalchemy model in instance stub with dict --- nova/api/openstack/servers.py | 18 +++++++++ nova/tests/api/openstack/test_servers.py | 66 ++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 17c5519a1..60f3d96e3 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -64,6 +64,24 @@ def _translate_detail_keys(inst): inst_dict['status'] = power_mapping[inst_dict['status']] inst_dict['addresses'] = dict(public=[], private=[]) + + # grab single private fixed ip + try: + private_ip = inst['fixed_ip']['address'] + if private_ip: + inst_dict['addresses']['private'].append(private_ip) + except KeyError: + LOG.debug(_("Failed to read private ip")) + pass + + # grab all public floating ips + try: + [inst_dict['addresses']['public'].append(floating['address']) \ + for floating in inst['fixed_ip']['floating_ips']] + except KeyError: + LOG.debug(_("Failed to read public ip(s)")) + pass + inst_dict['metadata'] = {} inst_dict['hostId'] = '' diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 724f14f19..816a0ab8c 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -17,6 +17,7 @@ import json import unittest +import datetime import stubout import webob @@ -39,6 +40,13 @@ def return_server(context, id): return stub_instance(id) +def return_server_with_addresses(private, public): + def _return_server(context, id): + return stub_instance(id, private_address=private, + public_addresses=public) + return _return_server + + def return_servers(context, user_id=1): return [stub_instance(i, user_id) for i in xrange(5)] @@ -55,9 +63,45 @@ def instance_address(context, instance_id): return None -def stub_instance(id, user_id=1): - return Instance(id=id, state=0, image_id=10, user_id=user_id, - display_name='server%s' % id) +def stub_instance(id, user_id=1, private_address=None, public_addresses=None): + if public_addresses == None: + public_addresses = list() + + instance = { + "id": id, + "admin_pass": "", + "user_id": user_id, + "project_id": "", + "image_id": 10, + "kernel_id": "", + "ramdisk_id": "", + "launch_index": 0, + "key_name": "", + "key_data": "", + "state": 0, + "state_description": "", + "memory_mb": 0, + "vcpus": 0, + "local_gb": 0, + "hostname": "", + "host": "", + "instance_type": "", + "user_data": "", + "reservation_id": "", + "mac_address": "", + "scheduled_at": datetime.datetime.now(), + "launched_at": datetime.datetime.now(), + "terminated_at": datetime.datetime.now(), + "availability_zone": "", + "display_name": "server%s" % id, + "display_description": "", + "locked": False} + + instance["fixed_ip"] = { + "address": private_address, + "floating_ips": [{"address":ip} for ip in public_addresses]} + + return instance def fake_compute_api(cls, req, id): @@ -105,6 +149,22 @@ class ServersTest(unittest.TestCase): self.assertEqual(res_dict['server']['id'], '1') self.assertEqual(res_dict['server']['name'], 'server1') + def test_get_server_by_id_with_addresses(self): + private = "192.168.0.3" + public = ["1.2.3.4"] + new_return_server = return_server_with_addresses(private, public) + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + req = webob.Request.blank('/v1.0/servers/1') + res = req.get_response(fakes.wsgi_app()) + res_dict = json.loads(res.body) + self.assertEqual(res_dict['server']['id'], '1') + self.assertEqual(res_dict['server']['name'], 'server1') + addresses = res_dict['server']['addresses'] + self.assertEqual(len(addresses["public"]), len(public)) + self.assertEqual(addresses["public"][0], public[0]) + self.assertEqual(len(addresses["private"]), 1) + self.assertEqual(addresses["private"][0], private) + def test_get_server_list(self): req = webob.Request.blank('/v1.0/servers') res = req.get_response(fakes.wsgi_app()) -- cgit From 16ffc15b1fb45a09de14cece6b382357a030b9dc Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 10 Feb 2011 08:43:46 -0400 Subject: removed ZoneCommands from nova-manage --- nova/api/openstack/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 8901a8987..69a4d66c0 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -80,7 +80,7 @@ class APIRouter(wsgi.Router): server_members["actions"] = "GET" server_members['suspend'] = 'POST' server_members['resume'] = 'POST' - + mapper.resource("zone", "zones", controller=zones.Controller(), collection={'detail': 'GET'}, collection_name='zones') -- cgit From 389b548e332a496bcc74d637030f753c66add570 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 10 Feb 2011 16:08:19 -0400 Subject: template adjusted to NOVA_TOOLS, zone db & os api layers added --- nova/api/openstack/zones.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ nova/auth/novarc.template | 7 ++--- nova/db/api.py | 26 +++++++++++++-- nova/db/sqlalchemy/api.py | 41 ++++++++++++++++++++++-- nova/db/sqlalchemy/models.py | 11 ++++++- 5 files changed, 149 insertions(+), 11 deletions(-) create mode 100644 nova/api/openstack/zones.py (limited to 'nova') diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py new file mode 100644 index 000000000..a12d1cc0c --- /dev/null +++ b/nova/api/openstack/zones.py @@ -0,0 +1,75 @@ +# Copyright 2010 OpenStack LLC. +# 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. + +import logging + +from nova import flags +from nova import wsgi +from nova import db + + +FLAGS = flags.FLAGS + + +def _filter_keys(item, keys): + """ + Filters all model attributes except for keys + item is a dict + + """ + return dict((k, v) for k, v in item.iteritems() if k in keys) + + +class Controller(wsgi.Controller): + + _serialization_metadata = { + 'application/xml': { + "attributes": { + "zone": ["id", "api_url"]}}} + + def index(self, req): + """Return all zones in brief""" + items = db.zone_get_all(req.environ['nova.context']) + items = common.limited(items, req) + items = [_filter_keys(item, ('id', 'api_url')) for item in items] + return dict(zones=items) + + def detail(self, req): + """Return all zones in detail""" + return self.index(req) + + def show(self, req, id): + """Return data about the given zone id""" + zone_id = int(id) + zone = db.zone_get(req.environ['nova.context'], zone_id) + return dict(zone=zone) + + def delete(self, req, id): + zone_id = int(id) + db.zone_delete(req.environ['nova.context'], zone_id) + return {} + + def create(self, req): + context = req.environ['nova.context'] + env = self._deserialize(req.body, req) + zone = db.zone_create(context, env["zone"]) + return dict(zone=zone) + + def update(self, req, id): + context = req.environ['nova.context'] + env = self._deserialize(req.body, req) + zone_id = int(id) + zone = db.zone_update(context, zone_id, env["zone"]) + return dict(zone=zone) diff --git a/nova/auth/novarc.template b/nova/auth/novarc.template index c53a4acdc..702df3bb0 100644 --- a/nova/auth/novarc.template +++ b/nova/auth/novarc.template @@ -10,7 +10,6 @@ export NOVA_CERT=${NOVA_KEY_DIR}/%(nova)s export EUCALYPTUS_CERT=${NOVA_CERT} # euca-bundle-image seems to require this set alias ec2-bundle-image="ec2-bundle-image --cert ${EC2_CERT} --privatekey ${EC2_PRIVATE_KEY} --user 42 --ec2cert ${NOVA_CERT}" alias ec2-upload-bundle="ec2-upload-bundle -a ${EC2_ACCESS_KEY} -s ${EC2_SECRET_KEY} --url ${S3_URL} --ec2cert ${NOVA_CERT}" -export CLOUD_SERVERS_API_KEY="%(access)s" -export CLOUD_SERVERS_USERNAME="%(user)s" -export CLOUD_SERVERS_URL="%(os)s" - +export NOVA_TOOLS_API_KEY="%(access)s" +export NOVA_TOOLS_USERNAME="%(user)s" +export NOVA_TOOLS_URL="%(os)s" diff --git a/nova/db/api.py b/nova/db/api.py index dc35f20b2..fa73d86ad 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -985,6 +985,26 @@ def console_get(context, console_id, instance_id=None): #################### -def create_zone(context, name): - """Create a new Zone entry for this deployment.""" - return IMPL.create_zone(context, name) +def zone_create(context, values): + """Create a new ChildZone entry in this Zone.""" + return IMPL.zone_create(context, values) + + +def zone_update(context, zone_id, values): + """Update a ChildZone entry in this Zone.""" + return IMPL.zone_update(context, values) + + +def zone_delete(context, zone_id): + """Delete a ChildZone.""" + return IMPL.zone_delete(context, zone_id) + + +def zone_get(context, zone_id): + """Get a specific ChildZone.""" + return IMPL.zone_get(context, zone_id) + + +def zone_get_all(context): + """Get all ChildZone's.""" + return IMPL.zone_get_all(context) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index f568d3470..cdd6db25f 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2010,10 +2010,45 @@ def console_get(context, console_id, instance_id=None): return result -################## +#################### + + +@require_admin_context +def zone_create(context, values): + zone = models.ChildZone() + zone.update(values) + zone.save() + return zone + + +@require_admin_context +def zone_update(context, zone_id, values): + zone = session.query(models.ChildZone).filter_by(id=zone_id).first() + if not zone: + raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) + zone.update(values) + zone.save() + return zone + + +@require_admin_context +def zone_delete(context, zone_id): + session = get_session() + with session.begin(): + session.execute('delete from childzones ' + 'where id=:id', {'id': zone_id}) + + +@require_admin_context +def zone_get(context, zone_id): + session = get_session() + result = session.query(models.ChildZone).filter_by(id=zone_id).first() + if not result: + raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) + return result @require_admin_context -def create_zone(context, zone): +def zone_get_all(context): session = get_session() - print "Creating Zone", zone + return session.query(models.ChildZone).filter_by(id=zone_id).all() diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 7efb36c0e..3c677cad8 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -535,6 +535,15 @@ class Console(BASE, NovaBase): pool = relationship(ConsolePool, backref=backref('consoles')) +class ChildZone(BASE, NovaBase): + """Represents a child zone of this zone.""" + __tablename__ = 'childzones' + id = Column(Integer, primary_key=True) + api_url = Column(String(255)) + username = Column(String(255)) + password = Column(String(255)) + + def register_models(): """Register Models and create metadata. @@ -547,7 +556,7 @@ def register_models(): Volume, ExportDevice, IscsiTarget, FixedIp, FloatingIp, Network, SecurityGroup, SecurityGroupIngressRule, SecurityGroupInstanceAssociation, AuthToken, User, - Project, Certificate, ConsolePool, Console) # , Image, Host + Project, Certificate, ConsolePool, Console, ChildZone) engine = create_engine(FLAGS.sql_connection, echo=False) for model in models: model.metadata.create_all(engine) -- cgit From b0c6190e0b098af4d808d993c6dcd0796cc80e83 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 10 Feb 2011 14:18:16 -0600 Subject: forgot to add network_get_all_by_instance to db.api --- nova/db/api.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index f22cd5615..a38f187a8 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -522,6 +522,11 @@ def network_get_by_instance(context, instance_id): return IMPL.network_get_by_instance(context, instance_id) +def network_get_all_by_instance(context, instance_id): + """Get all networks by instance id or raise if it does not exist.""" + return IMPL.network_get_all_by_instance(context, instance_id) + + def network_get_index(context, network_id): """Get non-conflicting index for network.""" return IMPL.network_get_index(context, network_id) -- cgit From 87d0b5203610f1e0a7a2e09033c79071fabacaba Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 10 Feb 2011 15:01:31 -0600 Subject: passing instance to reset_network instead of vm_ref, also not converting to an opaque ref before making plugin call --- nova/virt/xenapi/vmops.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 4056e99bc..575e53f80 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -121,7 +121,7 @@ class VMOps(object): network_ref, instance.mac_address) # call reset networking - self.reset_network(vm_ref) + self.reset_network(instance) LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) @@ -393,9 +393,8 @@ class VMOps(object): return 'http://fakeajaxconsole/fake_url' def reset_network(self, instance): - vm = self._get_vm_opaque_ref(instance) args = {'id': str(uuid.uuid4())} - resp = self._make_agent_call('resetnetwork', vm, '', args) + resp = self._make_agent_call('resetnetwork', instance, '', args) def list_from_xenstore(self, vm, path): """Runs the xenstore-ls command to get a listing of all records -- cgit From 57e58ba23c5c6a1af0f132385d3d9b9cc370b47d Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 10 Feb 2011 16:26:08 -0600 Subject: added get IPs by instance --- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 11 +++++++++++ 2 files changed, 16 insertions(+) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index a38f187a8..a2c1dbdce 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -294,6 +294,11 @@ def fixed_ip_get_by_address(context, address): return IMPL.fixed_ip_get_by_address(context, address) +def fixed_ip_get_all_by_instance(context, instance_id): + """Get fixed ips by instance or raise if none exist.""" + return IMPL.fixed_ip_get_all_by_instance(context, instance_id) + + def fixed_ip_get_instance(context, address): """Get an instance for a fixed ip by address.""" return IMPL.fixed_ip_get_instance(context, address) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 26b685e43..f20f4e266 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -606,6 +606,17 @@ def fixed_ip_get_instance(context, address): return fixed_ip_ref.instance +@require_context +def fixed_ip_get_all_by_instance(context, instance_id): + session = get_session() + rv = session.query(models.Network.fixed_ips).\ + filter_by(instance_id=instance_id).\ + filter_by(deleted=False) + if not rv: + raise exception.NotFound(_('No address for instance %s') % instance_id) + return rv + + @require_context def fixed_ip_get_instance_v6(context, address): session = get_session() -- cgit From e32a0131cfa0d7655545aca50559d9988e62142d Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Fri, 11 Feb 2011 13:08:41 +0000 Subject: Following Rick and Jay's suggestions: - Fixed LOG.debug for translation - improved vm_utils.VM_Helper.ensure_free_mem --- nova/virt/xenapi/vm_utils.py | 7 +++---- nova/virt/xenapi/vmops.py | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index c6ac969b9..dd5e74a85 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -144,10 +144,9 @@ class VMHelper(HelperBase): mem = long(instance_type['memory_mb']) * 1024 * 1024 #get free memory from host host = session.get_xenapi_host() - host_free_mem = session.get_xenapi().host.compute_free_memory(host) - if (host_free_mem < mem): - return False - return True + host_free_mem = long(session.get_xenapi().host. + compute_free_memory(host)) + return host_free_mem >= mem @classmethod def create_vbd(cls, session, vm_ref, vdi_ref, userdevice, bootable): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index e3c303d91..786768ab5 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -66,10 +66,11 @@ class VMOps(object): if vm is not None: raise exception.Duplicate(_('Attempted to create' ' non-unique name %s') % instance.name) - #ensure enough free memory, otherwise don't bother + #ensure enough free memory is available if not VMHelper.ensure_free_mem(self._session, instance): - LOG.exception(_('instance %s: not enough free memory'), - instance['name']) + name = instance['name'] + LOG.exception(_('instance %(name)s: not enough free memory') + % locals()) db.instance_set_state(context.get_admin_context(), instance['id'], power_state.SHUTDOWN) -- cgit From c230dba962a3db2a3a8bb502dfb33313f0ef274b Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Fri, 11 Feb 2011 11:25:55 -0400 Subject: rough cut at zone api tests --- nova/tests/api/openstack/test_zones.py | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 nova/tests/api/openstack/test_zones.py (limited to 'nova') diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py new file mode 100644 index 000000000..8a817bebe --- /dev/null +++ b/nova/tests/api/openstack/test_zones.py @@ -0,0 +1,74 @@ +# Copyright 2010 OpenStack LLC. +# 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. + +import unittest + +import stubout +import webob + +import nova.api +from nova.api.openstack import zones +from nova.tests.api.openstack import fakes + + +class ZonesTest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + fakes.FakeAuthManager.auth_data = {} + fakes.FakeAuthDatabase.data = {} + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + fakes.stub_out_auth(self.stubs) + + def tearDown(self): + self.stubs.UnsetAll() + + def test_get_zone_list(self): + req = webob.Request.blank('/v1.0/zones') + res = req.get_response(fakes.wsgi_app()) + + def test_get_zone_by_id(self): + req = webob.Request.blank('/v1.0/zones/1') + res = req.get_response(fakes.wsgi_app()) + + def test_zone_delete(self): + req = webob.Request.blank('/v1.0/zones/1') + res = req.get_response(fakes.wsgi_app()) + + def test_zone_create(self): + body = dict(server=dict(api_url='http://blah.zoo', username='bob', + password='qwerty')) + req = webob.Request.blank('/v1.0/zones') + req.method = 'POST' + req.body = json.dumps(body) + + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 200) + + def test_zone_update(self): + body = dict(server=dict(api_url='http://blah.zoo', username='zeb', + password='sneaky')) + req = webob.Request.blank('/v1.0/zones/1') + req.method = 'PUT' + req.body = json.dumps(body) + + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 200) + + +if __name__ == '__main__': + unittest.main() -- cgit From df9bf23ecda1f32fd31ebffc6013e2f60f7fd3fa Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Fri, 11 Feb 2011 15:13:05 -0400 Subject: zone api tests passing --- nova/api/openstack/__init__.py | 3 +- nova/api/openstack/zones.py | 1 + nova/tests/api/openstack/test_zones.py | 81 +++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 7 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 8aeb69693..33d040ab3 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -82,8 +82,7 @@ class APIRouter(wsgi.Router): server_members['resume'] = 'POST' mapper.resource("zone", "zones", controller=zones.Controller(), - collection={'detail': 'GET'}, - collection_name='zones') + collection={'detail': 'GET'}) mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index a12d1cc0c..e84b38fa9 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import common import logging from nova import flags diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py index 8a817bebe..8dbdffa41 100644 --- a/nova/tests/api/openstack/test_zones.py +++ b/nova/tests/api/openstack/test_zones.py @@ -17,12 +17,50 @@ import unittest import stubout import webob +import json -import nova.api +import nova.db +from nova import context +from nova import flags from nova.api.openstack import zones from nova.tests.api.openstack import fakes +FLAGS = flags.FLAGS +FLAGS.verbose = True + + +def zone_get(context, zone_id): + return dict(id=1, api_url='http://foo.com', username='bob', + password='xxx') + + +def zone_create(context, values): + zone = dict(id=1) + zone.update(values) + return zone + + +def zone_update(context, zone_id, values): + zone = dict(id=zone_id, api_url='http://foo.com', username='bob', + password='xxx') + zone.update(values) + return zone + + +def zone_delete(context, zone_id): + pass + + +def zone_get_all(context): + return [ + dict(id=1, api_url='http://foo.com', username='bob', + password='xxx'), + dict(id=2, api_url='http://blah.com', username='alice', + password='qwerty') + ] + + class ZonesTest(unittest.TestCase): def setUp(self): self.stubs = stubout.StubOutForTesting() @@ -32,42 +70,75 @@ class ZonesTest(unittest.TestCase): fakes.stub_out_rate_limiting(self.stubs) fakes.stub_out_auth(self.stubs) + self.allow_admin = FLAGS.allow_admin_api + FLAGS.allow_admin_api = True + + self.stubs.Set(nova.db, 'zone_get', zone_get) + self.stubs.Set(nova.db, 'zone_get_all', zone_get_all) + self.stubs.Set(nova.db, 'zone_update', zone_update) + self.stubs.Set(nova.db, 'zone_create', zone_create) + self.stubs.Set(nova.db, 'zone_delete', zone_delete) + def tearDown(self): self.stubs.UnsetAll() + FLAGS.allow_admin_api = self.allow_admin def test_get_zone_list(self): req = webob.Request.blank('/v1.0/zones') res = req.get_response(fakes.wsgi_app()) + res_dict = json.loads(res.body) + + self.assertEqual(res.status_int, 200) + self.assertEqual(len(res_dict['zones']), 2) def test_get_zone_by_id(self): req = webob.Request.blank('/v1.0/zones/1') res = req.get_response(fakes.wsgi_app()) + res_dict = json.loads(res.body) + + self.assertEqual(res_dict['zone']['id'], 1) + self.assertEqual(res_dict['zone']['api_url'], 'http://foo.com') + self.assertEqual(res_dict['zone']['username'], 'bob') + self.assertEqual(res_dict['zone']['password'], 'xxx') + + self.assertEqual(res.status_int, 200) def test_zone_delete(self): req = webob.Request.blank('/v1.0/zones/1') res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + def test_zone_create(self): - body = dict(server=dict(api_url='http://blah.zoo', username='bob', - password='qwerty')) + body = dict(zone=dict(api_url='http://blah.zoo', username='fred', + password='fubar')) req = webob.Request.blank('/v1.0/zones') req.method = 'POST' req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) + res_dict = json.loads(res.body) self.assertEqual(res.status_int, 200) + self.assertEqual(res_dict['zone']['id'], 1) + self.assertEqual(res_dict['zone']['api_url'], 'http://blah.zoo') + self.assertEqual(res_dict['zone']['username'], 'fred') + self.assertEqual(res_dict['zone']['password'], 'fubar') def test_zone_update(self): - body = dict(server=dict(api_url='http://blah.zoo', username='zeb', - password='sneaky')) + body = dict(zone=dict(username='zeb', password='sneaky')) req = webob.Request.blank('/v1.0/zones/1') req.method = 'PUT' req.body = json.dumps(body) res = req.get_response(fakes.wsgi_app()) + res_dict = json.loads(res.body) self.assertEqual(res.status_int, 200) + self.assertEqual(res_dict['zone']['id'], 1) + self.assertEqual(res_dict['zone']['api_url'], 'http://foo.com') + self.assertEqual(res_dict['zone']['username'], 'zeb') + self.assertEqual(res_dict['zone']['password'], 'sneaky') if __name__ == '__main__': -- cgit From c8521da3539d28dce56a914d89c43c4908e46e57 Mon Sep 17 00:00:00 2001 From: Brian Schott Date: Fri, 11 Feb 2011 19:03:45 -0500 Subject: fixed exceptions import from python migrate --- nova/db/sqlalchemy/migration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/db/sqlalchemy/migration.py b/nova/db/sqlalchemy/migration.py index 2a13c5466..acd03ba34 100644 --- a/nova/db/sqlalchemy/migration.py +++ b/nova/db/sqlalchemy/migration.py @@ -22,7 +22,7 @@ from nova import flags import sqlalchemy from migrate.versioning import api as versioning_api -from migrate.versioning import exceptions as versioning_exceptions +from migrate import exceptions as versioning_exceptions FLAGS = flags.FLAGS -- cgit From 17cca3c90f203a023d921e7b01a667e68ef695b5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 13 Feb 2011 21:48:14 -0800 Subject: re-add input_chain because it got deleted at some point --- nova/network/linux_net.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova') diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index ed37e8ba7..c1cbff7d8 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -54,6 +54,8 @@ flags.DEFINE_string('routing_source_ip', '$my_ip', 'Public IP of network host') flags.DEFINE_bool('use_nova_chains', False, 'use the nova_ routing chains instead of default') +flags.DEFINE_string('input_chain', 'INPUT', + 'chain to add nova_input to') flags.DEFINE_string('dns_server', None, 'if set, uses specific dns server for dnsmasq') -- cgit From 64a2a487d8ad524c0e948545a2318cebfefb36fe Mon Sep 17 00:00:00 2001 From: Vasiliy Shlykov Date: Mon, 14 Feb 2011 16:02:58 +0300 Subject: Fixed tables creation order and added clearing db after errors. --- nova/db/sqlalchemy/migrate_repo/versions/001_austin.py | 14 ++++++++------ nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'nova') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py b/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py index 366944591..9e7ab3554 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/001_austin.py @@ -508,17 +508,19 @@ def upgrade(migrate_engine): # bind migrate_engine to your metadata meta.bind = migrate_engine - for table in (auth_tokens, export_devices, fixed_ips, floating_ips, - instances, key_pairs, networks, - projects, quotas, security_groups, security_group_inst_assoc, - security_group_rules, services, users, - user_project_association, user_project_role_association, - user_role_association, volumes): + tables = [auth_tokens, + instances, key_pairs, networks, fixed_ips, floating_ips, + quotas, security_groups, security_group_inst_assoc, + security_group_rules, services, users, projects, + user_project_association, user_project_role_association, + user_role_association, volumes, export_devices] + for table in tables: try: table.create() except Exception: logging.info(repr(table)) logging.exception('Exception while creating table') + meta.drop_all(tables=tables) raise diff --git a/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py b/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py index 699b837f8..413536a59 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/002_bexar.py @@ -209,13 +209,16 @@ 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, - iscsi_targets): + + tables = [certificates, console_pools, consoles, instance_actions, + iscsi_targets] + for table in tables: try: table.create() except Exception: logging.info(repr(table)) logging.exception('Exception while creating table') + meta.drop_all(tables=tables) raise auth_tokens.c.user_id.alter(type=String(length=255, -- cgit From 9c0862b5f84cdb09b7ab0aafca669d30f261a666 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Mon, 14 Feb 2011 10:21:16 -0600 Subject: support for multiple IPs per network --- nova/virt/xenapi/vmops.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 575e53f80..db05a24ff 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -96,22 +96,36 @@ class VMOps(object): # write network info admin_context = context.get_admin_context() - #network = db.network_get_by_instance(admin_context, - # instance['id']) + # TODO(tr3buchet) - remove comment in multi-nic + # I've decided to go ahead and consider multiple IPs and networks + # at this stage even though they aren't implemented because these will + # be needed for multi-nic and there was no sense writing it for single + # network/single IP and then having to turn around and re-write it + IPs = db.fixed_ip_get_all_by_instance(admin_context, instance['id']) for network in db.network_get_all_by_instance(admin_context, instance['id']): + network_IPs = [ip for ip in IPs if ip.network_id == network.id] + + def ip_dict(ip): + return {'netmask': network['netmask'], + 'enabled': '1', + 'ip': ip.address} + mac_id = instance.mac_address.replace(':', '') location = 'vm-data/networking/%s' % mac_id mapping = {'label': network['label'], 'gateway': network['gateway'], 'mac': instance.mac_address, 'dns': [network['dns']], - 'ips': [{'netmask': network['netmask'], - 'enabled': '1', - 'ip': '192.168.3.3'}]} # <===== CHANGE!!!! + 'ips': [ip_dict(ip) for ip in network_IPs]} self.write_to_param_xenstore(vm_ref, {location: mapping}) + # TODO(tr3buchet) - remove comment in multi-nic + # this bit here about creating the vifs will be updated + # in multi-nic to handle multiple IPs on the same network + # and multiple networks + # for now it works as there is only one of each bridge = network['bridge'] network_ref = \ NetworkHelper.find_network_with_bridge(self._session, bridge) -- cgit From ee26d0827b7ad3e4d7869614835fe58abe32dfc8 Mon Sep 17 00:00:00 2001 From: Ricardo Carrillo Cruz Date: Mon, 14 Feb 2011 17:43:39 +0100 Subject: Got rid of BadParameter, just using standard python ValueError --- nova/network/manager.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index 8eb9f041b..d911844a1 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -505,6 +505,12 @@ class VlanManager(NetworkManager): def create_networks(self, context, cidr, num_networks, network_size, cidr_v6, vlan_start, vpn_start): """Create networks based on parameters.""" + # Check that num_networks + vlan_start is not > 4094, fixes lp708025 + if num_networks + vlan_start > 4094: + raise ValueError(_('The sum between the number of networks and' + ' the vlan start cannot be greater' + ' than 4094')) + fixed_net = IPy.IP(cidr) fixed_net_v6 = IPy.IP(cidr_v6) network_size_v6 = 1 << 64 -- cgit From 3f96e6dbf12533355aa6722eeb498814df076aea Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Mon, 14 Feb 2011 12:32:33 -0600 Subject: added call to reset_network from openstack api down to vmops --- nova/api/openstack/servers.py | 14 ++++++++++++++ nova/compute/api.py | 9 ++++++++- nova/compute/manager.py | 12 ++++++++++++ nova/virt/xenapi_conn.py | 4 ++++ 4 files changed, 38 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8cbcebed2..c604bd215 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -242,6 +242,20 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() + def reset_network(self, req, id): + """ + admin only operation which resets networking on an instance + + """ + context = req.environ['nova.context'] + try: + self.compute_api.reset_network(context, id) + except: + readable = traceback.format_exc() + LOG.exception(_("Compute.api::reset_network %s"), readable) + return faults.Fault(exc.HTTPUnprocessableEntity()) + return exc.HTTPAccepted() + def pause(self, req, id): """ Permit Admins to Pause the server. """ ctxt = req.environ['nova.context'] diff --git a/nova/compute/api.py b/nova/compute/api.py index 6a3fe08b6..43332ed27 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1,4 +1,4 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# vim: tabstop=5 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. @@ -463,6 +463,13 @@ class API(base.Base): instance = self.get(context, instance_id) return instance['locked'] + def reset_network(self, context, instance_id): + """ + resets networking on the instance + + """ + self._cast_compute_message('reset_network', context, instance_id) + def attach_volume(self, context, instance_id, volume_id, device): if not re.match("^/dev/[a-z]d[a-z]+$", device): raise exception.ApiError(_("Invalid device specified: %s. " diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 6f09ce674..b03f58693 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -494,6 +494,18 @@ class ComputeManager(manager.Manager): instance_ref = self.db.instance_get(context, instance_id) return instance_ref['locked'] + @checks_instance_lock + def reset_network(self, context, instance_id): + """ + resets the networking on the instance + + """ + context = context.elevated() + instance_ref = self.db.instance_get(context, instance_id) + LOG.debug(_('instance %s: reset network'), instance_id, + context=context) + self.driver.reset_network(instance_ref) + @exception.wrap_exception def get_console_output(self, context, instance_id): """Send the console output for an instance.""" diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 927f5905b..4e5442aa6 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -188,6 +188,10 @@ class XenAPIConnection(object): """resume the specified instance""" self._vmops.resume(instance, callback) + def reset_network(self, instance): + """reset networking for specified instance""" + self._vmops.reset_network(instance) + def get_info(self, instance_id): """Return data about VM instance""" return self._vmops.get_info(instance_id) -- cgit From ee4cba7779daa5b2e7415fb69cabc698b7dd60da Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Mon, 14 Feb 2011 12:59:46 -0600 Subject: corrected model for table lookup --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index f20f4e266..827f81ae2 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -609,7 +609,7 @@ def fixed_ip_get_instance(context, address): @require_context def fixed_ip_get_all_by_instance(context, instance_id): session = get_session() - rv = session.query(models.Network.fixed_ips).\ + rv = session.query(models.FixedIp).\ filter_by(instance_id=instance_id).\ filter_by(deleted=False) if not rv: -- cgit From 89ca05c457cb951e91060359493e5f830fe5eeda Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 14 Feb 2011 21:06:16 +0100 Subject: Use eventlet.green.subprocess instead of standard subprocess Eventlet's monkey patching causes the os.wait call in the standard subprocess module to be non-blocking. This means that if it happens to call self.wait on a Popen object that hasn't completely terminated it'll be left as a zombie and its fd's are also leaked. --- nova/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/utils.py b/nova/utils.py index 8d7ff1f64..ba71ebf39 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -25,7 +25,6 @@ import inspect import json import os import random -import subprocess import socket import struct import sys @@ -36,6 +35,7 @@ import netaddr from eventlet import event from eventlet import greenthread +from eventlet.green import subprocess from nova import exception from nova.exception import ProcessExecutionError -- cgit From 96d0edff2348040362b77491892e525217a17562 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 14 Feb 2011 23:19:15 +0100 Subject: Resurrect logdir option. --- nova/flags.py | 2 ++ nova/log.py | 11 +++++++++-- nova/twistd.py | 2 -- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index 3ba3fe6fa..f64a62da9 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -282,6 +282,8 @@ DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger') DEFINE_string('state_path', os.path.join(os.path.dirname(__file__), '../'), "Top-level directory for maintaining nova's state") +DEFINE_string('logdir', None, 'output to a per-service log file in named ' + 'directory') DEFINE_string('sql_connection', 'sqlite:///$state_path/nova.sqlite', diff --git a/nova/log.py b/nova/log.py index b541488bd..a5b4828d5 100644 --- a/nova/log.py +++ b/nova/log.py @@ -28,9 +28,11 @@ It also allows setting of formatting information through flags. import cStringIO +import inspect import json import logging import logging.handlers +import os import sys import traceback @@ -123,8 +125,13 @@ def basicConfig(): syslog = SysLogHandler(address='/dev/log') syslog.setFormatter(_formatter) logging.root.addHandler(syslog) - if FLAGS.logfile: - logfile = FileHandler(FLAGS.logfile) + if FLAGS.logfile or FLAGS.logdir: + if FLAGS.logfile: + logfile = FLAGS.logfile + else: + binary = os.path.basename(inspect.stack()[-1][1]) + logpath = '%s.log' % (os.path.join(FLAGS.logdir, binary),) + logfile = FileHandler(logpath) logfile.setFormatter(_formatter) logging.root.addHandler(logfile) diff --git a/nova/twistd.py b/nova/twistd.py index 6390a8144..60ff7879a 100644 --- a/nova/twistd.py +++ b/nova/twistd.py @@ -43,8 +43,6 @@ else: FLAGS = flags.FLAGS -flags.DEFINE_string('logdir', None, 'directory to keep log files in ' - '(will be prepended to $logfile)') class TwistdServerOptions(ServerOptions): -- cgit From 2816ca39281bf7c1994791d969bc63d22c86f911 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 14 Feb 2011 23:27:31 +0100 Subject: Use RotatingFileHandler instead of FileHandler. --- nova/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index b541488bd..413dd946b 100644 --- a/nova/log.py +++ b/nova/log.py @@ -92,7 +92,7 @@ critical = logging.critical log = logging.log # handlers StreamHandler = logging.StreamHandler -FileHandler = logging.FileHandler +FileHandler = logging.RotatingFileHandler # logging.SysLogHandler is nicer than logging.logging.handler.SysLogHandler. SysLogHandler = logging.handlers.SysLogHandler -- cgit From 6147a606cbe6b7e764865d2471d86f503437051b Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 14 Feb 2011 14:52:58 -0800 Subject: fixed template and added migration --- nova/auth/novarc.template | 6 +-- .../sqlalchemy/migrate_repo/versions/003_cactus.py | 62 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py (limited to 'nova') diff --git a/nova/auth/novarc.template b/nova/auth/novarc.template index 702df3bb0..cda2ecc28 100644 --- a/nova/auth/novarc.template +++ b/nova/auth/novarc.template @@ -10,6 +10,6 @@ export NOVA_CERT=${NOVA_KEY_DIR}/%(nova)s export EUCALYPTUS_CERT=${NOVA_CERT} # euca-bundle-image seems to require this set alias ec2-bundle-image="ec2-bundle-image --cert ${EC2_CERT} --privatekey ${EC2_PRIVATE_KEY} --user 42 --ec2cert ${NOVA_CERT}" alias ec2-upload-bundle="ec2-upload-bundle -a ${EC2_ACCESS_KEY} -s ${EC2_SECRET_KEY} --url ${S3_URL} --ec2cert ${NOVA_CERT}" -export NOVA_TOOLS_API_KEY="%(access)s" -export NOVA_TOOLS_USERNAME="%(user)s" -export NOVA_TOOLS_URL="%(os)s" +export NOVA_API_KEY="%(access)s" +export NOVA_USERNAME="%(user)s" +export NOVA_URL="%(os)s" diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py new file mode 100644 index 000000000..eb3287077 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py @@ -0,0 +1,62 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +from sqlalchemy import * +from migrate import * + +from nova import log as logging + + +meta = MetaData() + + +# +# New Tables +# +child_zones = Table('child_zones', 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('api_url', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('username', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('password', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + ) + + +# +# Tables to alter +# + +# (none currently) + + +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 (child_zones, ): + try: + table.create() + except Exception: + logging.info(repr(table)) -- cgit From 1da5dcc0644a13cfb99852f3438649f710feb2bc Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 14 Feb 2011 14:54:04 -0800 Subject: removed debugging --- nova/api/openstack/auth.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index a383ef086..473071738 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -79,7 +79,6 @@ class AuthMiddleware(wsgi.Middleware): except KeyError: return faults.Fault(webob.exc.HTTPUnauthorized()) - logging.debug("**** USERNAME %s, PASSWORD %s" % (username, key)) token, user = self._authorize_user(username, key, req) if user and token: res = webob.Response() -- cgit From e65291cf34894322bd0f3f6661907e48e7a6a0b5 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 14 Feb 2011 20:11:29 -0400 Subject: fixed nova-combined debug hack and renamed ChildZone to Zone --- nova/db/api.py | 10 +++++----- nova/db/sqlalchemy/api.py | 10 +++++----- nova/db/sqlalchemy/migration.py | 2 +- nova/db/sqlalchemy/models.py | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index fa73d86ad..939f1a069 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -986,25 +986,25 @@ def console_get(context, console_id, instance_id=None): def zone_create(context, values): - """Create a new ChildZone entry in this Zone.""" + """Create a new child Zone entry.""" return IMPL.zone_create(context, values) def zone_update(context, zone_id, values): - """Update a ChildZone entry in this Zone.""" + """Update a child Zone entry.""" return IMPL.zone_update(context, values) def zone_delete(context, zone_id): - """Delete a ChildZone.""" + """Delete a child Zone.""" return IMPL.zone_delete(context, zone_id) def zone_get(context, zone_id): - """Get a specific ChildZone.""" + """Get a specific child Zone.""" return IMPL.zone_get(context, zone_id) def zone_get_all(context): - """Get all ChildZone's.""" + """Get all child Zones.""" return IMPL.zone_get_all(context) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index b3320c819..abd65b67b 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2021,7 +2021,7 @@ def console_get(context, console_id, instance_id=None): @require_admin_context def zone_create(context, values): - zone = models.ChildZone() + zone = models.Zone() zone.update(values) zone.save() return zone @@ -2029,7 +2029,7 @@ def zone_create(context, values): @require_admin_context def zone_update(context, zone_id, values): - zone = session.query(models.ChildZone).filter_by(id=zone_id).first() + zone = session.query(models.Zone).filter_by(id=zone_id).first() if not zone: raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) zone.update(values) @@ -2041,14 +2041,14 @@ def zone_update(context, zone_id, values): def zone_delete(context, zone_id): session = get_session() with session.begin(): - session.execute('delete from child_zones ' + session.execute('delete from zones ' 'where id=:id', {'id': zone_id}) @require_admin_context def zone_get(context, zone_id): session = get_session() - result = session.query(models.ChildZone).filter_by(id=zone_id).first() + result = session.query(models.Zone).filter_by(id=zone_id).first() if not result: raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) return result @@ -2057,4 +2057,4 @@ def zone_get(context, zone_id): @require_admin_context def zone_get_all(context): session = get_session() - return session.query(models.ChildZone).all() + return session.query(models.Zone).all() diff --git a/nova/db/sqlalchemy/migration.py b/nova/db/sqlalchemy/migration.py index 194ecc627..1d9c041f5 100644 --- a/nova/db/sqlalchemy/migration.py +++ b/nova/db/sqlalchemy/migration.py @@ -45,7 +45,7 @@ def db_version(): engine = sqlalchemy.create_engine(FLAGS.sql_connection, echo=False) meta.reflect(bind=engine) try: - for table in ('auth_tokens', 'child_zones', 'export_devices', + for table in ('auth_tokens', 'zones', 'export_devices', 'fixed_ips', 'floating_ips', 'instances', 'key_pairs', 'networks', 'projects', 'quotas', 'security_group_instance_association', diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 071d57fca..4930c7a2a 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -535,9 +535,9 @@ class Console(BASE, NovaBase): pool = relationship(ConsolePool, backref=backref('consoles')) -class ChildZone(BASE, NovaBase): +class Zone(BASE, NovaBase): """Represents a child zone of this zone.""" - __tablename__ = 'child_zones' + __tablename__ = 'zones' id = Column(Integer, primary_key=True) api_url = Column(String(255)) username = Column(String(255)) @@ -556,7 +556,7 @@ def register_models(): Volume, ExportDevice, IscsiTarget, FixedIp, FloatingIp, Network, SecurityGroup, SecurityGroupIngressRule, SecurityGroupInstanceAssociation, AuthToken, User, - Project, Certificate, ConsolePool, Console, ChildZone) + Project, Certificate, ConsolePool, Console, Zone) engine = create_engine(FLAGS.sql_connection, echo=False) for model in models: model.metadata.create_all(engine) -- cgit From f1e536fb296c927a9fc953b1dfe24b9060a0387a Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 14 Feb 2011 19:51:51 -0500 Subject: Updates to that S3ImageService kernel_id and ramdisk_id mappings work with EC2 API. --- nova/api/ec2/cloud.py | 3 +++ nova/compute/api.py | 4 ++-- nova/image/s3.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 16a3a4521..6919cd8d2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -883,6 +883,9 @@ class CloudController(object): % attribute) try: image = self.image_service.show(context, image_id) + image = self._format_image(context, + self.image_service.show(context, + image_id)) except IndexError: raise exception.ApiError(_('invalid id: %s') % image_id) result = {'image_id': image_id, 'launchPermission': []} diff --git a/nova/compute/api.py b/nova/compute/api.py index ac02dbcfa..740dd3935 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -103,9 +103,9 @@ class API(base.Base): if not is_vpn: image = self.image_service.show(context, image_id) if kernel_id is None: - kernel_id = image.get('kernelId', None) + kernel_id = image.get('kernel_id', None) if ramdisk_id is None: - ramdisk_id = image.get('ramdiskId', None) + ramdisk_id = image.get('ramdisk_id', None) # No kernel and ramdisk for raw images if kernel_id == str(FLAGS.null_kernel): kernel_id = None diff --git a/nova/image/s3.py b/nova/image/s3.py index 71304cdd6..14135a1ee 100644 --- a/nova/image/s3.py +++ b/nova/image/s3.py @@ -94,7 +94,7 @@ class S3ImageService(service.BaseImageService): if FLAGS.connection_type == 'fake': return {'imageId': 'bar'} result = self.index(context) - result = [i for i in result if i['imageId'] == image_id] + result = [i for i in result if i['id'] == image_id] if not result: raise exception.NotFound(_('Image %s could not be found') % image_id) -- cgit From c15289a63c90218a573d5e75833985ec2ad8691e Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Mon, 14 Feb 2011 23:02:26 -0400 Subject: better filtering --- nova/api/openstack/zones.py | 13 ++++++++----- nova/tests/api/openstack/test_zones.py | 10 +++------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 2c93c0c7b..830464ffd 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -33,6 +33,10 @@ def _filter_keys(item, keys): return dict((k, v) for k, v in item.iteritems() if k in keys) +def _scrub_zone(zone): + return _filter_keys(zone, ('id', 'api_url')) + + class Controller(wsgi.Controller): _serialization_metadata = { @@ -44,7 +48,7 @@ class Controller(wsgi.Controller): """Return all zones in brief""" items = db.zone_get_all(req.environ['nova.context']) items = common.limited(items, req) - items = [_filter_keys(item, ('id', 'api_url')) for item in items] + items = [_scrub_zone(item) for item in items] return dict(zones=items) def detail(self, req): @@ -55,8 +59,7 @@ class Controller(wsgi.Controller): """Return data about the given zone id""" zone_id = int(id) zone = db.zone_get(req.environ['nova.context'], zone_id) - zone = _filter_keys(zone, ('id', 'api_url')) - return dict(zone=zone) + return dict(zone=_scrub_zone(zone)) def delete(self, req, id): zone_id = int(id) @@ -67,11 +70,11 @@ class Controller(wsgi.Controller): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone = db.zone_create(context, env["zone"]) - return dict(zone=zone) + return dict(zone=_scrub_zone(zone)) def update(self, req, id): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone_id = int(id) zone = db.zone_update(context, zone_id, env["zone"]) - return dict(zone=zone) + return dict(zone=_scrub_zone(zone)) diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py index 8dbdffa41..5542a1cf3 100644 --- a/nova/tests/api/openstack/test_zones.py +++ b/nova/tests/api/openstack/test_zones.py @@ -98,9 +98,7 @@ class ZonesTest(unittest.TestCase): self.assertEqual(res_dict['zone']['id'], 1) self.assertEqual(res_dict['zone']['api_url'], 'http://foo.com') - self.assertEqual(res_dict['zone']['username'], 'bob') - self.assertEqual(res_dict['zone']['password'], 'xxx') - + self.assertFalse('password' in res_dict['zone']) self.assertEqual(res.status_int, 200) def test_zone_delete(self): @@ -122,8 +120,7 @@ class ZonesTest(unittest.TestCase): self.assertEqual(res.status_int, 200) self.assertEqual(res_dict['zone']['id'], 1) self.assertEqual(res_dict['zone']['api_url'], 'http://blah.zoo') - self.assertEqual(res_dict['zone']['username'], 'fred') - self.assertEqual(res_dict['zone']['password'], 'fubar') + self.assertFalse('username' in res_dict['zone']) def test_zone_update(self): body = dict(zone=dict(username='zeb', password='sneaky')) @@ -137,8 +134,7 @@ class ZonesTest(unittest.TestCase): self.assertEqual(res.status_int, 200) self.assertEqual(res_dict['zone']['id'], 1) self.assertEqual(res_dict['zone']['api_url'], 'http://foo.com') - self.assertEqual(res_dict['zone']['username'], 'zeb') - self.assertEqual(res_dict['zone']['password'], 'sneaky') + self.assertFalse('username' in res_dict['zone']) if __name__ == '__main__': -- cgit From 9ab97a9b0860f912be2a085327eea6b9a7fa7674 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 15 Feb 2011 12:33:31 +0100 Subject: Break out of the "for group in rv" loop in security group unit tests so that we are use we are dealing with the correct group. --- nova/tests/test_api.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova') diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index 2569e262b..efd6d94a8 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -258,6 +258,7 @@ class ApiEc2TestCase(test.TestCase): self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(len(group.rules[0].grants), 1) self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0') + break self.expect_http() self.mox.ReplayAll() @@ -324,6 +325,7 @@ class ApiEc2TestCase(test.TestCase): self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(len(group.rules[0].grants), 1) self.assertEquals(str(group.rules[0].grants[0]), '::/0') + break self.expect_http() self.mox.ReplayAll() -- cgit From bf8d9d3adfcb5e5cd97ae0d7451e6253892622b1 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 15 Feb 2011 13:18:27 +0100 Subject: Beautify it a little bit, thanks to dabo. --- nova/tests/test_api.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'nova') diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index efd6d94a8..fa27825cd 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -248,17 +248,14 @@ class ApiEc2TestCase(test.TestCase): self.mox.ReplayAll() rv = self.ec2.get_all_security_groups() - # I don't bother checkng that we actually find it here, - # because the create/delete unit test further up should - # be good enough for that. - for group in rv: - if group.name == security_group_name: - self.assertEquals(len(group.rules), 1) - self.assertEquals(int(group.rules[0].from_port), 80) - self.assertEquals(int(group.rules[0].to_port), 81) - self.assertEquals(len(group.rules[0].grants), 1) - self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0') - break + + group = [grp for grp in rv if grp.name == security_group_name][0] + + self.assertEquals(len(group.rules), 1) + self.assertEquals(int(group.rules[0].from_port), 80) + self.assertEquals(int(group.rules[0].to_port), 81) + self.assertEquals(len(group.rules[0].grants), 1) + self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0') self.expect_http() self.mox.ReplayAll() @@ -315,17 +312,13 @@ class ApiEc2TestCase(test.TestCase): self.mox.ReplayAll() rv = self.ec2.get_all_security_groups() - # I don't bother checkng that we actually find it here, - # because the create/delete unit test further up should - # be good enough for that. - for group in rv: - if group.name == security_group_name: - self.assertEquals(len(group.rules), 1) - self.assertEquals(int(group.rules[0].from_port), 80) - self.assertEquals(int(group.rules[0].to_port), 81) - self.assertEquals(len(group.rules[0].grants), 1) - self.assertEquals(str(group.rules[0].grants[0]), '::/0') - break + + group = [grp for grp in rv if grp.name == security_group_name][0] + self.assertEquals(len(group.rules), 1) + self.assertEquals(int(group.rules[0].from_port), 80) + self.assertEquals(int(group.rules[0].to_port), 81) + self.assertEquals(len(group.rules[0].grants), 1) + self.assertEquals(str(group.rules[0].grants[0]), '::/0') self.expect_http() self.mox.ReplayAll() -- cgit From dfcf07192cf40d0451c7dfa3802994e4cef8d116 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 15 Feb 2011 14:02:19 +0100 Subject: Naïve attempt at threading rpc requests. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nova/rpc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/rpc.py b/nova/rpc.py index 2b1f7298b..efe6164ad 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -29,6 +29,7 @@ import uuid from carrot import connection as carrot_connection from carrot import messaging +from eventlet import greenpool from eventlet import greenthread from nova import context @@ -155,11 +156,15 @@ class AdapterConsumer(TopicConsumer): def __init__(self, connection=None, topic="broadcast", proxy=None): LOG.debug(_('Initing the Adapter Consumer for %s') % topic) self.proxy = proxy + self.pool = greenpool.GreenPool(1024) super(AdapterConsumer, self).__init__(connection=connection, topic=topic) + def receive(self, *args, **kwargs): + self.pool.spawn_n(self._receive, *args, **kwargs) + @exception.wrap_exception - def receive(self, message_data, message): + def _receive(self, message_data, message): """Magically looks for a method on the proxy object and calls it Message data should be a dictionary with two keys: -- cgit From 5a988eb393c306097250a7f17ea65f0919fd9219 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Tue, 15 Feb 2011 12:43:29 -0400 Subject: fixed / renamed migration scripts --- .../migrate_repo/versions/003_add_zone_tables.py | 62 ++++++++++++++++++++++ .../sqlalchemy/migrate_repo/versions/003_cactus.py | 62 ---------------------- 2 files changed, 62 insertions(+), 62 deletions(-) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_add_zone_tables.py delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py (limited to 'nova') diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_add_zone_tables.py b/nova/db/sqlalchemy/migrate_repo/versions/003_add_zone_tables.py new file mode 100644 index 000000000..d2b6b9570 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_add_zone_tables.py @@ -0,0 +1,62 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +from sqlalchemy import * +from migrate import * + +from nova import log as logging + + +meta = MetaData() + + +# +# New Tables +# +zones = Table('zones', 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('api_url', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('username', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('password', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + ) + + +# +# Tables to alter +# + +# (none currently) + + +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 (zones, ): + try: + table.create() + except Exception: + logging.info(repr(table)) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py deleted file mode 100644 index eb3287077..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -from sqlalchemy import * -from migrate import * - -from nova import log as logging - - -meta = MetaData() - - -# -# New Tables -# -child_zones = Table('child_zones', 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('api_url', - String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False)), - Column('username', - String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False)), - Column('password', - String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False)), - ) - - -# -# Tables to alter -# - -# (none currently) - - -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 (child_zones, ): - try: - table.create() - except Exception: - logging.info(repr(table)) -- cgit From 503749849df73df1732583bc9452e7952bf78ac2 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 15 Feb 2011 15:25:48 -0600 Subject: moved reset network to after boot durrrrr... --- nova/virt/xenapi/vmops.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 00028cdaa..dd9f48ddf 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -134,9 +134,6 @@ class VMOps(object): VMHelper.create_vif(self._session, vm_ref, network_ref, instance.mac_address) - # call reset networking - self.reset_network(instance) - LOG.debug(_('Starting VM %s...'), vm_ref) self._session.call_xenapi('VM.start', vm_ref, False, False) instance_name = instance.name @@ -164,6 +161,10 @@ class VMOps(object): timer.stop() timer.f = _wait_for_boot + + # call reset networking + self.reset_network(instance) + return timer.start(interval=0.5, now=True) def _get_vm_opaque_ref(self, instance_or_vm): -- cgit From 9b4150ad66abcdeb5dd46927fa320f9f2c6c99f6 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 15 Feb 2011 15:30:44 -0600 Subject: changed d to s --- nova/virt/xenapi/vm_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 574ef0944..80cc3035d 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -394,7 +394,7 @@ class VMHelper(HelperBase): pv = True elif pv_str.lower() == 'false': pv = False - LOG.debug(_("PV Kernel in VDI:%d"), pv) + LOG.debug(_("PV Kernel in VDI:%s"), pv) return pv @classmethod -- cgit From 52a443dfb53e8fa2226e7ae8b8dac0fa6e32a69d Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 15 Feb 2011 23:11:51 +0100 Subject: Refactor code that decides which logfile to use, if any. Adds unit tests. --- nova/log.py | 17 +++++++++++------ nova/tests/test_log.py | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index a5b4828d5..ec6681edd 100644 --- a/nova/log.py +++ b/nova/log.py @@ -112,6 +112,15 @@ def _dictify_context(context): context = context.to_dict() return context +def _get_binary_name(): + return os.path.basename(inspect.stack()[-1][1]) + +def get_log_file_path(binary=None): + if FLAGS.logfile: + return FLAGS.logfile + if FLAGS.logdir: + binary = binary or _get_binary_name() + return '%s.log' % (os.path.join(FLAGS.logdir, binary),) def basicConfig(): logging.basicConfig() @@ -125,12 +134,8 @@ def basicConfig(): syslog = SysLogHandler(address='/dev/log') syslog.setFormatter(_formatter) logging.root.addHandler(syslog) - if FLAGS.logfile or FLAGS.logdir: - if FLAGS.logfile: - logfile = FLAGS.logfile - else: - binary = os.path.basename(inspect.stack()[-1][1]) - logpath = '%s.log' % (os.path.join(FLAGS.logdir, binary),) + logpath = get_log_file_path() + if logpath: logfile = FileHandler(logpath) logfile.setFormatter(_formatter) logging.root.addHandler(logfile) diff --git a/nova/tests/test_log.py b/nova/tests/test_log.py index 868a5ead3..7a5c52935 100644 --- a/nova/tests/test_log.py +++ b/nova/tests/test_log.py @@ -46,6 +46,27 @@ class RootLoggerTestCase(test.TestCase): self.assert_(True) # didn't raise exception +class LogHandlerTestCase(test.TestCase): + def test_log_path_logdir(self): + self.flags(logdir='/some/path') + self.assertEquals(log.get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') + + def test_log_path_logfile(self): + self.flags(logfile='/some/path/foo-bar.log') + self.assertEquals(log.get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') + + def test_log_path_none(self): + self.assertIsNone(log.get_log_file_path(binary='foo-bar')) + + def test_log_path_logfile_overrides_logdir(self): + self.flags(logdir='/some/other/path', + logfile='/some/path/foo-bar.log') + self.assertEquals(log.get_log_file_path(binary='foo-bar'), + '/some/path/foo-bar.log') + + class NovaFormatterTestCase(test.TestCase): def setUp(self): super(NovaFormatterTestCase, self).setUp() -- cgit From 297fdbfead55017340150412cd00b3aa7b962257 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 15 Feb 2011 23:13:25 +0100 Subject: Don't hide RotatingFileHandler behind FileHandler's name. --- nova/log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 413dd946b..32b6d4629 100644 --- a/nova/log.py +++ b/nova/log.py @@ -92,7 +92,7 @@ critical = logging.critical log = logging.log # handlers StreamHandler = logging.StreamHandler -FileHandler = logging.RotatingFileHandler +RotatingFileHandler = logging.handlers.RotatingFileHandler # logging.SysLogHandler is nicer than logging.logging.handler.SysLogHandler. SysLogHandler = logging.handlers.SysLogHandler @@ -124,7 +124,7 @@ def basicConfig(): syslog.setFormatter(_formatter) logging.root.addHandler(syslog) if FLAGS.logfile: - logfile = FileHandler(FLAGS.logfile) + logfile = RotatingFileHandler(FLAGS.logfile) logfile.setFormatter(_formatter) logging.root.addHandler(logfile) -- cgit From 00f785dab7d269b9baf403f51bc1d4b2ea1dc06a Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 16 Feb 2011 00:10:17 +0100 Subject: Make rpc thread pool size configurable. --- nova/rpc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/rpc.py b/nova/rpc.py index efe6164ad..067d954d0 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -43,6 +43,8 @@ from nova import utils FLAGS = flags.FLAGS LOG = logging.getLogger('nova.rpc') +FLAGS.DEFINE_integer('rpc_thread_pool_size', 1024, 'Size of RPC thread pool') + class Connection(carrot_connection.BrokerConnection): """Connection instance object""" @@ -156,7 +158,7 @@ class AdapterConsumer(TopicConsumer): def __init__(self, connection=None, topic="broadcast", proxy=None): LOG.debug(_('Initing the Adapter Consumer for %s') % topic) self.proxy = proxy - self.pool = greenpool.GreenPool(1024) + self.pool = greenpool.GreenPool(FLAGS.rpc_thread_pool_size) super(AdapterConsumer, self).__init__(connection=connection, topic=topic) -- cgit From 1b9413e11ba1b4b49b50965e3f812e636f2319d5 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Tue, 15 Feb 2011 18:20:44 -0600 Subject: stubbed out reset networkin xenapi VM tests to solve domid problem --- nova/tests/test_xenapi.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'nova') diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index d5660c5d1..6b8efc9d8 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -32,6 +32,7 @@ from nova.virt import xenapi_conn from nova.virt.xenapi import fake as xenapi_fake from nova.virt.xenapi import volume_utils from nova.virt.xenapi.vmops import SimpleDH +from nova.virt.xenapi.vmops import VMOps from nova.tests.db import fakes as db_fakes from nova.tests.xenapi import stubs from nova.tests.glance import stubs as glance_stubs @@ -141,6 +142,10 @@ class XenAPIVolumeTestCase(test.TestCase): self.stubs.UnsetAll() +def reset_network(*args): + pass + + class XenAPIVMTestCase(test.TestCase): """ Unit tests for VM operations @@ -162,6 +167,7 @@ class XenAPIVMTestCase(test.TestCase): stubs.stubout_session(self.stubs, stubs.FakeSessionForVMTests) stubs.stubout_get_this_vm_uuid(self.stubs) stubs.stubout_stream_disk(self.stubs) + self.stubs.Set(VMOps, 'reset_network', reset_network) glance_stubs.stubout_glance_client(self.stubs, glance_stubs.FakeGlance) self.conn = xenapi_conn.get_connection(False) -- cgit From a00b8b78ce16bbfe4368f0e5e383b7b8f49ba9ef Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 16 Feb 2011 10:02:17 +0100 Subject: assertIsNone is a 2.7-ism. --- nova/tests/test_log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/tests/test_log.py b/nova/tests/test_log.py index 7a5c52935..c2c9d7772 100644 --- a/nova/tests/test_log.py +++ b/nova/tests/test_log.py @@ -58,7 +58,7 @@ class LogHandlerTestCase(test.TestCase): '/some/path/foo-bar.log') def test_log_path_none(self): - self.assertIsNone(log.get_log_file_path(binary='foo-bar')) + self.assertTrue(log.get_log_file_path(binary='foo-bar') is None) def test_log_path_logfile_overrides_logdir(self): self.flags(logdir='/some/other/path', -- cgit From 9f1c46f5be0520afac21c3320e206ced98acd9ba Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 16 Feb 2011 10:46:59 +0100 Subject: Fix PEP-8 stuff --- nova/log.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index ec6681edd..90c40cca7 100644 --- a/nova/log.py +++ b/nova/log.py @@ -112,9 +112,11 @@ def _dictify_context(context): context = context.to_dict() return context + def _get_binary_name(): return os.path.basename(inspect.stack()[-1][1]) + def get_log_file_path(binary=None): if FLAGS.logfile: return FLAGS.logfile @@ -122,6 +124,7 @@ def get_log_file_path(binary=None): binary = binary or _get_binary_name() return '%s.log' % (os.path.join(FLAGS.logdir, binary),) + def basicConfig(): logging.basicConfig() for handler in logging.root.handlers: -- cgit From 7f8595b88df2271c278ae59b6d187b5c3b8dde40 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Wed, 16 Feb 2011 12:15:48 +0100 Subject: added functionality to nova-manage to list created networks --- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 9 +++++++++ 2 files changed, 14 insertions(+) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index 789cb8ebb..d06f3731f 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -500,6 +500,11 @@ def network_get(context, network_id): return IMPL.network_get(context, network_id) +def network_get_all(context): + """Return all defined networks.""" + return IMPL.network_get_all(context) + + # pylint: disable-msg=C0103 def network_get_associated_fixed_ips(context, network_id): """Get all network's ips that have been associated.""" diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 02855e7a9..a11572947 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1056,6 +1056,15 @@ def network_get(context, network_id, session=None): return result +@require_admin_context +def network_get_all(context): + session = get_session() + result = session.query(models.Network) + if not result: + raise exception.NotFound('No networks defined') + return result + + # NOTE(vish): pylint complains because of the long method name, but # it fits with the names of the rest of the methods # pylint: disable-msg=C0103 -- cgit From 9be342534ee54f86c274f03d1d4a0c310f08e4ae Mon Sep 17 00:00:00 2001 From: Brian Schott Date: Wed, 16 Feb 2011 13:24:46 -0500 Subject: fixed authors, import sys in migration.py --- nova/db/sqlalchemy/migration.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova') diff --git a/nova/db/sqlalchemy/migration.py b/nova/db/sqlalchemy/migration.py index 3b6b4707a..d2671e1a3 100644 --- a/nova/db/sqlalchemy/migration.py +++ b/nova/db/sqlalchemy/migration.py @@ -17,6 +17,7 @@ # under the License. import os +import sys from nova import flags -- cgit From 56ebab08b29da2ed9a4ec29bb1c0695371acc142 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 16 Feb 2011 20:34:17 +0100 Subject: Spell flags correctly (i.e. not in upper case) --- nova/rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/rpc.py b/nova/rpc.py index 067d954d0..205bb524a 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -43,7 +43,7 @@ from nova import utils FLAGS = flags.FLAGS LOG = logging.getLogger('nova.rpc') -FLAGS.DEFINE_integer('rpc_thread_pool_size', 1024, 'Size of RPC thread pool') +flags.DEFINE_integer('rpc_thread_pool_size', 1024, 'Size of RPC thread pool') class Connection(carrot_connection.BrokerConnection): -- cgit From 6bd620fa3d378b4fe437e498ef17888bf632b9d6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 16 Feb 2011 12:02:10 -0800 Subject: sanitize all args to strings before sending them to ldap --- nova/auth/ldapdriver.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'nova') diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py index e652f1caa..99cbb43f9 100644 --- a/nova/auth/ldapdriver.py +++ b/nova/auth/ldapdriver.py @@ -73,6 +73,23 @@ LOG = logging.getLogger("nova.ldapdriver") # creating this now because I'm expecting an auth refactor # in which we may want to change the interface a bit more. +def _clean(attr): + """Clean attr for insertion into ldap""" + if attr is None: + return None + if type(attr) is unicode: + return str(attr) + return attr + +def sanitize(fn): + """Decorator to sanitize all args""" + def _wrapped(self, *args, **kwargs): + args = [_clean(x) for x in args] + kwargs = dict((k, _clean(v)) for (k, v) in kwargs) + return fn(self, *args, **kwargs) + _wrapped.func_name = fn.func_name + return _wrapped + class LdapDriver(object): """Ldap Auth driver @@ -106,23 +123,27 @@ class LdapDriver(object): self.conn.unbind_s() return False + @sanitize def get_user(self, uid): """Retrieve user by id""" attr = self.__get_ldap_user(uid) return self.__to_user(attr) + @sanitize def get_user_from_access_key(self, access): """Retrieve user by access key""" query = '(accessKey=%s)' % access dn = FLAGS.ldap_user_subtree return self.__to_user(self.__find_object(dn, query)) + @sanitize def get_project(self, pid): """Retrieve project by id""" dn = self.__project_to_dn(pid) attr = self.__find_object(dn, LdapDriver.project_pattern) return self.__to_project(attr) + @sanitize def get_users(self): """Retrieve list of users""" attrs = self.__find_objects(FLAGS.ldap_user_subtree, @@ -134,6 +155,7 @@ class LdapDriver(object): users.append(user) return users + @sanitize def get_projects(self, uid=None): """Retrieve list of projects""" pattern = LdapDriver.project_pattern @@ -143,6 +165,7 @@ class LdapDriver(object): pattern) return [self.__to_project(attr) for attr in attrs] + @sanitize def create_user(self, name, access_key, secret_key, is_admin): """Create a user""" if self.__user_exists(name): @@ -196,6 +219,7 @@ class LdapDriver(object): self.conn.add_s(self.__uid_to_dn(name), attr) return self.__to_user(dict(attr)) + @sanitize def create_project(self, name, manager_uid, description=None, member_uids=None): """Create a project""" @@ -231,6 +255,7 @@ class LdapDriver(object): self.conn.add_s(dn, attr) return self.__to_project(dict(attr)) + @sanitize def modify_project(self, project_id, manager_uid=None, description=None): """Modify an existing project""" if not manager_uid and not description: @@ -249,21 +274,25 @@ class LdapDriver(object): dn = self.__project_to_dn(project_id) self.conn.modify_s(dn, attr) + @sanitize def add_to_project(self, uid, project_id): """Add user to project""" dn = self.__project_to_dn(project_id) return self.__add_to_group(uid, dn) + @sanitize def remove_from_project(self, uid, project_id): """Remove user from project""" dn = self.__project_to_dn(project_id) return self.__remove_from_group(uid, dn) + @sanitize def is_in_project(self, uid, project_id): """Check if user is in project""" dn = self.__project_to_dn(project_id) return self.__is_in_group(uid, dn) + @sanitize def has_role(self, uid, role, project_id=None): """Check if user has role @@ -273,6 +302,7 @@ class LdapDriver(object): role_dn = self.__role_to_dn(role, project_id) return self.__is_in_group(uid, role_dn) + @sanitize def add_role(self, uid, role, project_id=None): """Add role for user (or user and project)""" role_dn = self.__role_to_dn(role, project_id) @@ -283,11 +313,13 @@ class LdapDriver(object): else: return self.__add_to_group(uid, role_dn) + @sanitize def remove_role(self, uid, role, project_id=None): """Remove role for user (or user and project)""" role_dn = self.__role_to_dn(role, project_id) return self.__remove_from_group(uid, role_dn) + @sanitize def get_user_roles(self, uid, project_id=None): """Retrieve list of roles for user (or user and project)""" if project_id is None: @@ -307,6 +339,7 @@ class LdapDriver(object): roles = self.__find_objects(project_dn, query) return [role['cn'][0] for role in roles] + @sanitize def delete_user(self, uid): """Delete a user""" if not self.__user_exists(uid): @@ -332,12 +365,14 @@ class LdapDriver(object): # Delete entry self.conn.delete_s(self.__uid_to_dn(uid)) + @sanitize def delete_project(self, project_id): """Delete a project""" project_dn = self.__project_to_dn(project_id) self.__delete_roles(project_dn) self.__delete_group(project_dn) + @sanitize def modify_user(self, uid, access_key=None, secret_key=None, admin=None): """Modify an existing user""" if not access_key and not secret_key and admin is None: -- cgit From 5b82416998369203f07f3b3adef9570622caa369 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 16 Feb 2011 12:03:59 -0800 Subject: pep8 fixes --- nova/auth/ldapdriver.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova') diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py index 99cbb43f9..5da7751a0 100644 --- a/nova/auth/ldapdriver.py +++ b/nova/auth/ldapdriver.py @@ -73,6 +73,7 @@ LOG = logging.getLogger("nova.ldapdriver") # creating this now because I'm expecting an auth refactor # in which we may want to change the interface a bit more. + def _clean(attr): """Clean attr for insertion into ldap""" if attr is None: @@ -81,6 +82,7 @@ def _clean(attr): return str(attr) return attr + def sanitize(fn): """Decorator to sanitize all args""" def _wrapped(self, *args, **kwargs): -- cgit From c6b8f129ae57da2ea0cd844150e58d4fac7eb71d Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Wed, 16 Feb 2011 14:12:54 -0600 Subject: added test for reset_network to openstack api tests, tabstop 5 to 4, renamed migration --- nova/api/openstack/__init__.py | 1 + nova/compute/api.py | 2 +- .../versions/003_add_label_to_networks.py | 52 ++++++++++++++++++++++ .../sqlalchemy/migrate_repo/versions/003_cactus.py | 52 ---------------------- nova/tests/api/openstack/test_servers.py | 12 +++++ 5 files changed, 66 insertions(+), 53 deletions(-) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py delete mode 100644 nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py (limited to 'nova') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 056c7dd27..dc3738d4a 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -79,6 +79,7 @@ class APIRouter(wsgi.Router): server_members["actions"] = "GET" server_members['suspend'] = 'POST' server_members['resume'] = 'POST' + server_members['reset_network'] = 'POST' mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, diff --git a/nova/compute/api.py b/nova/compute/api.py index 857028605..71879b5b7 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1,4 +1,4 @@ -# vim: tabstop=5 shiftwidth=4 softtabstop=4 +# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py b/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py new file mode 100644 index 000000000..ddfe114cb --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py @@ -0,0 +1,52 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +from sqlalchemy import * +from migrate import * + +from nova import log as logging + + +meta = MetaData() + + +networks = Table('networks', meta, + Column('id', Integer(), primary_key=True, nullable=False), + ) + + +# +# New Tables +# + + +# +# Tables to alter +# + +networks_label = Column( + 'label', + String(length=255, convert_unicode=False, assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + networks.create_column(networks_label) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py b/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py deleted file mode 100644 index ddfe114cb..000000000 --- a/nova/db/sqlalchemy/migrate_repo/versions/003_cactus.py +++ /dev/null @@ -1,52 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -from sqlalchemy import * -from migrate import * - -from nova import log as logging - - -meta = MetaData() - - -networks = Table('networks', meta, - Column('id', Integer(), primary_key=True, nullable=False), - ) - - -# -# New Tables -# - - -# -# Tables to alter -# - -networks_label = Column( - 'label', - String(length=255, convert_unicode=False, assert_unicode=None, - unicode_error=None, _warn_on_bytestring=False)) - - -def upgrade(migrate_engine): - # Upgrade operations go here. Don't create your own engine; - # bind migrate_engine to your metadata - meta.bind = migrate_engine - networks.create_column(networks_label) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 724f14f19..89e192eed 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -281,6 +281,18 @@ class ServersTest(unittest.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 202) + def test_server_reset_network(self): + FLAGS.allow_admin_api = True + body = dict(server=dict( + name='server_test', imageId=2, flavorId=2, metadata={}, + personality={})) + req = webob.Request.blank('/v1.0/servers/1/reset_network') + req.method = 'POST' + req.content_type = 'application/json' + req.body = json.dumps(body) + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 202) + def test_server_diagnostics(self): req = webob.Request.blank("/v1.0/servers/1/diagnostics") req.method = "GET" -- cgit From 5faa6e59ff9dff02e8d583e6711bd08dd1f821fd Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 16 Feb 2011 14:15:41 -0800 Subject: add periodic disassociate from VlanManager to FlatDHCPManager. --- nova/network/manager.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index 8eb9f041b..a4a4c6064 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -394,6 +394,18 @@ class FlatDHCPManager(FlatManager): like FlatDHCPManager. """ + def periodic_tasks(self, context=None): + """Tasks to be run at a periodic interval.""" + super(FlatDHCPManager, self).periodic_tasks(context) + now = datetime.datetime.utcnow() + timeout = FLAGS.fixed_ip_disassociate_timeout + time = now - datetime.timedelta(seconds=timeout) + num = self.db.fixed_ip_disassociate_all_by_timeout(context, + self.host, + time) + if num: + LOG.debug(_("Dissassociated %s stale fixed ip(s)"), num) + def init_host(self): """Do any initialization that needs to be run if this is a standalone service. -- cgit From f50101fcf845e93637f50e426ceb759641a20b76 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 17 Feb 2011 13:46:24 +0100 Subject: Make eth0 the default for FLAGS.public_interface. --- nova/network/linux_net.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index c1cbff7d8..535ce87bc 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -44,7 +44,7 @@ flags.DEFINE_string('dhcp_domain', flags.DEFINE_string('networks_path', '$state_path/networks', 'Location to keep network config files') -flags.DEFINE_string('public_interface', 'vlan1', +flags.DEFINE_string('public_interface', 'eth0', 'Interface for public IP addresses') flags.DEFINE_string('vlan_interface', 'eth0', 'network device for vlans') -- cgit From bf7ec579786d3f02e63fc870fdfcb1e9c2674f05 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Thu, 17 Feb 2011 15:14:45 +0100 Subject: added i18n of 'No networks defined' --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index a11572947..65436ab0f 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1061,7 +1061,7 @@ def network_get_all(context): session = get_session() result = session.query(models.Network) if not result: - raise exception.NotFound('No networks defined') + raise exception.NotFound(_('No networks defined')) return result -- cgit From e28ce7f82d1c89ab0c4e5ebfa98c12f502a33138 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 17 Feb 2011 09:48:16 -0500 Subject: removing superfluous pass statements; replacing list comprehension with for loop; alphabetizing imports --- nova/api/openstack/servers.py | 6 ++---- nova/tests/api/openstack/test_servers.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 60f3d96e3..312d83ba5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -72,15 +72,13 @@ def _translate_detail_keys(inst): inst_dict['addresses']['private'].append(private_ip) except KeyError: LOG.debug(_("Failed to read private ip")) - pass # grab all public floating ips try: - [inst_dict['addresses']['public'].append(floating['address']) \ - for floating in inst['fixed_ip']['floating_ips']] + for floating in inst['fixed_ip']['floating_ips']: + inst_dict['addresses']['public'].append(floating['address']) except KeyError: LOG.debug(_("Failed to read public ip(s)")) - pass inst_dict['metadata'] = {} inst_dict['hostId'] = '' diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 816a0ab8c..ace3b6850 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -15,9 +15,9 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import json import unittest -import datetime import stubout import webob -- cgit From 7bb9e4c598f829a16cc6444346e087ddb506182a Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Thu, 17 Feb 2011 16:58:00 +0100 Subject: added new functionality to list all defined fixed ips --- nova/db/api.py | 5 +++++ nova/db/sqlalchemy/api.py | 11 +++++++++++ 2 files changed, 16 insertions(+) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index 789cb8ebb..2b621044a 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -288,6 +288,11 @@ def fixed_ip_disassociate_all_by_timeout(context, host, time): return IMPL.fixed_ip_disassociate_all_by_timeout(context, host, time) +def fixed_ip_get_all(context): + """Get all defined fixed ips.""" + return IMPL.fixed_ip_get_all(context) + + def fixed_ip_get_by_address(context, address): """Get a fixed ip by address or raise if it does not exist.""" return IMPL.fixed_ip_get_by_address(context, address) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 02855e7a9..55f2f28bd 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -583,6 +583,17 @@ def fixed_ip_disassociate_all_by_timeout(_context, host, time): return result.rowcount +@require_admin_context +def fixed_ip_get_all(context, session=None): + if not session: + session = get_session() + result = session.query(models.FixedIp).all() + if not result: + raise exception.NotFound(_('No fixed ips defined')) + + return result + + @require_context def fixed_ip_get_by_address(context, address, session=None): if not session: -- cgit From ea4d21b546d9447bac50cf97a62c11129da12d21 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Thu, 17 Feb 2011 13:10:37 -0600 Subject: comments + Englilish, changed copyright in migration, removed network_get_all from db.api (vestigial) --- nova/api/openstack/servers.py | 2 +- nova/compute/api.py | 2 +- nova/compute/manager.py | 2 +- nova/db/api.py | 7 +------ .../sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py | 3 +-- nova/virt/xenapi/vmops.py | 6 ++++++ 6 files changed, 11 insertions(+), 11 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8b72704ba..33cc3bbde 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -251,7 +251,7 @@ class Controller(wsgi.Controller): def reset_network(self, req, id): """ - admin only operation which resets networking on an instance + Reset networking on an instance (admin only). """ context = req.environ['nova.context'] diff --git a/nova/compute/api.py b/nova/compute/api.py index 71879b5b7..ed6f0e34a 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -468,7 +468,7 @@ class API(base.Base): def reset_network(self, context, instance_id): """ - resets networking on the instance + Reset networking on the instance. """ self._cast_compute_message('reset_network', context, instance_id) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 1e2b95294..6fab1a41c 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -501,7 +501,7 @@ class ComputeManager(manager.Manager): @checks_instance_lock def reset_network(self, context, instance_id): """ - resets the networking on the instance + Reset networking on the instance. """ context = context.elevated() diff --git a/nova/db/api.py b/nova/db/api.py index 850a5126f..ce3395932 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -505,11 +505,6 @@ def network_get(context, network_id): return IMPL.network_get(context, network_id) -def network_get_all(context): - """Get all networks""" - return IMPL.network_get_all(context) - - # pylint: disable-msg=C0103 def network_get_associated_fixed_ips(context, network_id): """Get all network's ips that have been associated.""" @@ -527,7 +522,7 @@ def network_get_by_instance(context, instance_id): def network_get_all_by_instance(context, instance_id): - """Get all networks by instance id or raise if it does not exist.""" + """Get all networks by instance id or raise if none exist.""" return IMPL.network_get_all_by_instance(context, instance_id) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py b/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py index ddfe114cb..5ba7910f1 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/003_add_label_to_networks.py @@ -1,7 +1,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 OpenStack LLC # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index ea99ff626..842e08f22 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -151,6 +151,8 @@ class VMOps(object): % locals()) # NOTE(armando): Do we really need to do this in virt? + # NOTE(tr3buchet): not sure but wherever we do it, we need to call + # reset_network afterwards timer = utils.LoopingCall(f=None) def _wait_for_boot(): @@ -437,6 +439,10 @@ class VMOps(object): return 'http://fakeajaxconsole/fake_url' def reset_network(self, instance): + """ + Creates uuid arg to pass to make_agent_call and calls it. + + """ args = {'id': str(uuid.uuid4())} resp = self._make_agent_call('resetnetwork', instance, '', args) -- cgit From e3f461b3b1087fa6342942daa764ba6ffb9ae383 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 17 Feb 2011 22:47:02 +0100 Subject: Add **kwargs to VlanManager's create_networks so that optional args from other managers don't break. --- nova/network/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index b906a83ed..6647692ca 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -509,7 +509,7 @@ class VlanManager(NetworkManager): network_ref['bridge']) def create_networks(self, context, cidr, num_networks, network_size, - cidr_v6, vlan_start, vpn_start): + cidr_v6, vlan_start, vpn_start, **kwargs): """Create networks based on parameters.""" # Check that num_networks + vlan_start is not > 4094, fixes lp708025 if num_networks + vlan_start > 4094: -- cgit From 60ed73265a52f264021bb7452cde9f83181b3dfc Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Thu, 17 Feb 2011 17:51:24 -0400 Subject: copyright notice --- nova/api/openstack/servers.py | 2 -- nova/db/sqlalchemy/migrate_repo/versions/004_add_zone_tables.py | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index c7f863764..009ef6db1 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -1,5 +1,3 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright 2010 OpenStack LLC. # All Rights Reserved. # diff --git a/nova/db/sqlalchemy/migrate_repo/versions/004_add_zone_tables.py b/nova/db/sqlalchemy/migrate_repo/versions/004_add_zone_tables.py index d2b6b9570..ade981687 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/004_add_zone_tables.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/004_add_zone_tables.py @@ -1,5 +1,4 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. +# Copyright 2010 OpenStack LLC. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may -- cgit From f6f0135bb320de3cde093f48cb3189380c173b12 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 17 Feb 2011 14:14:07 -0800 Subject: Correctly pass the associate paramater to project_get_network --- nova/db/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/db/api.py b/nova/db/api.py index 52c2bb84d..d7f3746d2 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -576,7 +576,7 @@ def project_get_network(context, project_id, associate=True): """ - return IMPL.project_get_network(context, project_id) + return IMPL.project_get_network(context, project_id, associate) def project_get_network_v6(context, project_id): -- cgit From fe576e28a6ed8e15d4cdb96313d9f58426715bb0 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 17 Feb 2011 14:39:36 -0800 Subject: move periodic tasks to base class based on class variable as per review --- nova/network/manager.py | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index a4a4c6064..78b7f0ae1 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -110,6 +110,7 @@ class NetworkManager(manager.Manager): This class must be subclassed to support specific topologies. """ + timeout_fixed_ips = True def __init__(self, network_driver=None, *args, **kwargs): if not network_driver: @@ -138,6 +139,19 @@ class NetworkManager(manager.Manager): self.driver.ensure_floating_forward(floating_ip['address'], fixed_address) + def periodic_tasks(self, context=None): + """Tasks to be run at a periodic interval.""" + super(NetworkManager, self).periodic_tasks(context) + if self.timeout_fixed_ips: + now = utils.utcnow() + timeout = FLAGS.fixed_ip_disassociate_timeout + time = now - datetime.timedelta(seconds=timeout) + num = self.db.fixed_ip_disassociate_all_by_timeout(context, + self.host, + time) + if num: + LOG.debug(_("Dissassociated %s stale fixed ip(s)"), num) + def set_network_host(self, context, network_id): """Safely sets the host of the network.""" LOG.debug(_("setting network host"), context=context) @@ -306,6 +320,7 @@ class FlatManager(NetworkManager): not do any setup in this mode, it must be done manually. Requests to 169.254.169.254 port 80 will need to be forwarded to the api server. """ + timeout_fixed_ips = False def allocate_fixed_ip(self, context, instance_id, *args, **kwargs): """Gets a fixed ip from the pool.""" @@ -397,14 +412,7 @@ class FlatDHCPManager(FlatManager): def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" super(FlatDHCPManager, self).periodic_tasks(context) - now = datetime.datetime.utcnow() - timeout = FLAGS.fixed_ip_disassociate_timeout - time = now - datetime.timedelta(seconds=timeout) - num = self.db.fixed_ip_disassociate_all_by_timeout(context, - self.host, - time) - if num: - LOG.debug(_("Dissassociated %s stale fixed ip(s)"), num) + self._disassociate_old_ips(context) def init_host(self): """Do any initialization that needs to be run if this is a @@ -463,18 +471,6 @@ class VlanManager(NetworkManager): instances in its subnet. """ - def periodic_tasks(self, context=None): - """Tasks to be run at a periodic interval.""" - super(VlanManager, self).periodic_tasks(context) - now = datetime.datetime.utcnow() - timeout = FLAGS.fixed_ip_disassociate_timeout - time = now - datetime.timedelta(seconds=timeout) - num = self.db.fixed_ip_disassociate_all_by_timeout(context, - self.host, - time) - if num: - LOG.debug(_("Dissassociated %s stale fixed ip(s)"), num) - def init_host(self): """Do any initialization that needs to be run if this is a standalone service. -- cgit From eef994eb690a9454e187a2b0cdbde85aba4c55cd Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 17 Feb 2011 14:50:29 -0800 Subject: remove leftover periodic tasks --- nova/network/manager.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'nova') diff --git a/nova/network/manager.py b/nova/network/manager.py index 78b7f0ae1..9f37d966a 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -409,11 +409,6 @@ class FlatDHCPManager(FlatManager): like FlatDHCPManager. """ - def periodic_tasks(self, context=None): - """Tasks to be run at a periodic interval.""" - super(FlatDHCPManager, self).periodic_tasks(context) - self._disassociate_old_ips(context) - def init_host(self): """Do any initialization that needs to be run if this is a standalone service. -- cgit From 982ac6b348981fa26ef6b70b8673da45477a6b36 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 18 Feb 2011 10:24:55 +0100 Subject: Use WatchedFileHandler instead of RotatingFileHandler. --- nova/log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 87a6dd51b..6b201ffcc 100644 --- a/nova/log.py +++ b/nova/log.py @@ -94,7 +94,7 @@ critical = logging.critical log = logging.log # handlers StreamHandler = logging.StreamHandler -RotatingFileHandler = logging.handlers.RotatingFileHandler +WatchedFileHandler = logging.handlers.WatchedFileHandler # logging.SysLogHandler is nicer than logging.logging.handler.SysLogHandler. SysLogHandler = logging.handlers.SysLogHandler @@ -139,7 +139,7 @@ def basicConfig(): logging.root.addHandler(syslog) logpath = get_log_file_path() if logpath: - logfile = RotatingFileHandler(logpath) + logfile = WatchedFileHandler(logpath) logfile.setFormatter(_formatter) logging.root.addHandler(logfile) -- cgit From be898f26984da4ee92da1a027e47775cd816fed5 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 18 Feb 2011 14:35:12 -0800 Subject: Fix typo (?) in authentication logic --- nova/api/openstack/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 473071738..0b6ef8fc5 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -121,8 +121,8 @@ class AuthMiddleware(wsgi.Middleware): req - webob.Request object """ ctxt = context.get_admin_context() - user = self.auth.get_user_from_access_key(key) - if user and user.name == username: + user = self.auth.get_user_from_access_key(username) + if user and user.secret == key: token_hash = hashlib.sha1('%s%s%f' % (username, key, time.time())).hexdigest() token_dict = {} -- cgit From b4c67400324df02480b171b84ba73cfe8a6d044e Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 18 Feb 2011 14:36:01 -0800 Subject: If there are no keypairs, output a useful error message --- nova/api/openstack/servers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 486eca508..ce9601ecb 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -162,8 +162,12 @@ class Controller(wsgi.Controller): if not env: return faults.Fault(exc.HTTPUnprocessableEntity()) - key_pair = auth_manager.AuthManager.get_key_pairs( - req.environ['nova.context'])[0] + key_pairs = auth_manager.AuthManager.get_key_pairs( + req.environ['nova.context']) + if not key_pairs: + raise exception.NotFound(_("No keypairs defined")) + key_pair = key_pairs[0] + image_id = common.get_image_id_from_image_hash(self._image_service, req.environ['nova.context'], env['server']['imageId']) kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( -- cgit From e21567404aa31c39bf1b14b8a8b2f02703fd5905 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 18 Feb 2011 21:00:58 -0800 Subject: remove the weird is_vpn logic in compute/api.py --- nova/compute/api.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'nova') diff --git a/nova/compute/api.py b/nova/compute/api.py index 0d2690c72..81ea6dc53 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -100,25 +100,23 @@ class API(base.Base): "run %s more instances of this type.") % num_instances, "InstanceLimitExceeded") - is_vpn = image_id == FLAGS.vpn_image_id - if not is_vpn: - image = self.image_service.show(context, image_id) - if kernel_id is None: - kernel_id = image.get('kernel_id', None) - if ramdisk_id is None: - ramdisk_id = image.get('ramdisk_id', None) - # No kernel and ramdisk for raw images - if kernel_id == str(FLAGS.null_kernel): - kernel_id = None - ramdisk_id = None - LOG.debug(_("Creating a raw instance")) - # Make sure we have access to kernel and ramdisk (if not raw) - logging.debug("Using Kernel=%s, Ramdisk=%s" % - (kernel_id, ramdisk_id)) - if kernel_id: - self.image_service.show(context, kernel_id) - if ramdisk_id: - self.image_service.show(context, ramdisk_id) + image = self.image_service.show(context, image_id) + if kernel_id is None: + kernel_id = image.get('kernel_id', None) + if ramdisk_id is None: + ramdisk_id = image.get('ramdisk_id', None) + # No kernel and ramdisk for raw images + if kernel_id == str(FLAGS.null_kernel): + kernel_id = None + ramdisk_id = None + LOG.debug(_("Creating a raw instance")) + # Make sure we have access to kernel and ramdisk (if not raw) + logging.debug("Using Kernel=%s, Ramdisk=%s" % + (kernel_id, ramdisk_id)) + if kernel_id: + self.image_service.show(context, kernel_id) + if ramdisk_id: + self.image_service.show(context, ramdisk_id) if security_group is None: security_group = ['default'] -- cgit From e518ab4d16ec6166c0ea391af4c94aaf4d8aa2db Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 18 Feb 2011 22:49:13 -0800 Subject: replace context.user.is_admin() with context.is_admin because it is much faster --- nova/api/ec2/cloud.py | 12 ++++++------ nova/objectstore/bucket.py | 2 +- nova/objectstore/image.py | 2 +- nova/volume/api.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 6919cd8d2..3b8c60c31 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -290,7 +290,7 @@ class CloudController(object): for key_pair in key_pairs: # filter out the vpn keys suffix = FLAGS.vpn_key_suffix - if context.user.is_admin() or \ + if context..is_admin or \ not key_pair['name'].endswith(suffix): result.append({ 'keyName': key_pair['name'], @@ -318,7 +318,7 @@ class CloudController(object): def describe_security_groups(self, context, group_name=None, **kwargs): self.compute_api.ensure_default_security_group(context) - if context.user.is_admin(): + if context..is_admin: groups = db.security_group_get_all(context) else: groups = db.security_group_get_by_project(context, @@ -674,7 +674,7 @@ class CloudController(object): else: instances = self.compute_api.get_all(context, **kwargs) for instance in instances: - if not context.user.is_admin(): + if not context..is_admin: if instance['image_id'] == FLAGS.vpn_image_id: continue i = {} @@ -702,7 +702,7 @@ class CloudController(object): i['dnsName'] = i['publicDnsName'] or i['privateDnsName'] i['keyName'] = instance['key_name'] - if context.user.is_admin(): + if context..is_admin: i['keyName'] = '%s (%s, %s)' % (i['keyName'], instance['project_id'], instance['host']) @@ -736,7 +736,7 @@ class CloudController(object): def format_addresses(self, context): addresses = [] - if context.user.is_admin(): + if context..is_admin: iterator = db.floating_ip_get_all(context) else: iterator = db.floating_ip_get_all_by_project(context, @@ -750,7 +750,7 @@ class CloudController(object): ec2_id = id_to_ec2_id(instance_id) address_rv = {'public_ip': address, 'instance_id': ec2_id} - if context.user.is_admin(): + if context..is_admin: details = "%s (%s)" % (address_rv['instance_id'], floating_ip_ref['project_id']) address_rv['instance_id'] = details diff --git a/nova/objectstore/bucket.py b/nova/objectstore/bucket.py index 82767e52f..b213e18e8 100644 --- a/nova/objectstore/bucket.py +++ b/nova/objectstore/bucket.py @@ -107,7 +107,7 @@ class Bucket(object): def is_authorized(self, context): try: - return context.user.is_admin() or \ + return context.is_admin or \ self.owner_id == context.project_id except Exception, e: return False diff --git a/nova/objectstore/image.py b/nova/objectstore/image.py index 41e0abd80..27227e2ca 100644 --- a/nova/objectstore/image.py +++ b/nova/objectstore/image.py @@ -69,7 +69,7 @@ class Image(object): # but only modified by admin or owner. try: return (self.metadata['isPublic'] and readonly) or \ - context.user.is_admin() or \ + context.is_admin or \ self.metadata['imageOwnerId'] == context.project_id except: return False diff --git a/nova/volume/api.py b/nova/volume/api.py index 478c83486..5201c7d90 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -85,7 +85,7 @@ class API(base.Base): return self.db.volume_get(context, volume_id) def get_all(self, context): - if context.user.is_admin(): + if context.is_admin: return self.db.volume_get_all(context) return self.db.volume_get_all_by_project(context, context.project_id) -- cgit From c4a0f200b023ba96024d58bf731307483dcbe288 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 18 Feb 2011 23:00:28 -0800 Subject: remove extra . --- nova/api/ec2/cloud.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 3b8c60c31..05cdcc57e 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -290,7 +290,7 @@ class CloudController(object): for key_pair in key_pairs: # filter out the vpn keys suffix = FLAGS.vpn_key_suffix - if context..is_admin or \ + if context.is_admin or \ not key_pair['name'].endswith(suffix): result.append({ 'keyName': key_pair['name'], @@ -318,7 +318,7 @@ class CloudController(object): def describe_security_groups(self, context, group_name=None, **kwargs): self.compute_api.ensure_default_security_group(context) - if context..is_admin: + if context.is_admin: groups = db.security_group_get_all(context) else: groups = db.security_group_get_by_project(context, @@ -674,7 +674,7 @@ class CloudController(object): else: instances = self.compute_api.get_all(context, **kwargs) for instance in instances: - if not context..is_admin: + if not context.is_admin: if instance['image_id'] == FLAGS.vpn_image_id: continue i = {} @@ -702,7 +702,7 @@ class CloudController(object): i['dnsName'] = i['publicDnsName'] or i['privateDnsName'] i['keyName'] = instance['key_name'] - if context..is_admin: + if context.is_admin: i['keyName'] = '%s (%s, %s)' % (i['keyName'], instance['project_id'], instance['host']) @@ -736,7 +736,7 @@ class CloudController(object): def format_addresses(self, context): addresses = [] - if context..is_admin: + if context.is_admin: iterator = db.floating_ip_get_all(context) else: iterator = db.floating_ip_get_all_by_project(context, @@ -750,7 +750,7 @@ class CloudController(object): ec2_id = id_to_ec2_id(instance_id) address_rv = {'public_ip': address, 'instance_id': ec2_id} - if context..is_admin: + if context.is_admin: details = "%s (%s)" % (address_rv['instance_id'], floating_ip_ref['project_id']) address_rv['instance_id'] = details -- cgit From a60d4cb45f4298ce39cbc34ad3c0133ba344fa66 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 18 Feb 2011 23:15:42 -0800 Subject: more optimizations context.user.id to context.user_id --- nova/api/ec2/__init__.py | 2 +- nova/api/ec2/cloud.py | 8 ++++---- nova/volume/api.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 1a06b3f01..01ef6bf6d 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -294,7 +294,7 @@ class Authorizer(wsgi.Middleware): return True if 'none' in roles: return False - return any(context.project.has_role(context.user.id, role) + return any(context.project.has_role(context.user_id, role) for role in roles) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 05cdcc57e..882cdcfc9 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -282,7 +282,7 @@ class CloudController(object): 'description': 'fixme'}]} def describe_key_pairs(self, context, key_name=None, **kwargs): - key_pairs = db.key_pair_get_all_by_user(context, context.user.id) + key_pairs = db.key_pair_get_all_by_user(context, context.user_id) if not key_name is None: key_pairs = [x for x in key_pairs if x['name'] in key_name] @@ -301,7 +301,7 @@ class CloudController(object): def create_key_pair(self, context, key_name, **kwargs): LOG.audit(_("Create key pair %s"), key_name, context=context) - data = _gen_key(context, context.user.id, key_name) + data = _gen_key(context, context.user_id, key_name) return {'keyName': key_name, 'keyFingerprint': data['fingerprint'], 'keyMaterial': data['private_key']} @@ -310,7 +310,7 @@ class CloudController(object): def delete_key_pair(self, context, key_name, **kwargs): LOG.audit(_("Delete key pair %s"), key_name, context=context) try: - db.key_pair_destroy(context, context.user.id, key_name) + db.key_pair_destroy(context, context.user_id, key_name) except exception.NotFound: # aws returns true even if the key doesn't exist pass @@ -494,7 +494,7 @@ class CloudController(object): if db.security_group_exists(context, context.project_id, group_name): raise exception.ApiError(_('group %s already exists') % group_name) - group = {'user_id': context.user.id, + group = {'user_id': context.user_id, 'project_id': context.project_id, 'name': group_name, 'description': group_description} diff --git a/nova/volume/api.py b/nova/volume/api.py index 5201c7d90..2f4494845 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -49,7 +49,7 @@ class API(base.Base): options = { 'size': size, - 'user_id': context.user.id, + 'user_id': context.user_id, 'project_id': context.project_id, 'availability_zone': FLAGS.storage_availability_zone, 'status': "creating", -- cgit From 990a0fdce67971e81665aa2151e43b071d8bcb7c Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 18 Feb 2011 23:33:06 -0800 Subject: Fix FakeAuthManager so that unit tests pass; I believe it was matching the wrong field --- nova/tests/api/openstack/fakes.py | 8 ++++++-- nova/tests/api/openstack/test_auth.py | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'nova') diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index fb282f1c9..e0b7b8029 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -221,7 +221,8 @@ class FakeAuthDatabase(object): class FakeAuthManager(object): auth_data = {} - def add_user(self, key, user): + def add_user(self, user): + key = user.id FakeAuthManager.auth_data[key] = user def get_user(self, uid): @@ -234,7 +235,10 @@ class FakeAuthManager(object): return None def get_user_from_access_key(self, key): - return FakeAuthManager.auth_data.get(key, None) + for k, v in FakeAuthManager.auth_data.iteritems(): + if v.access == key: + return v + return None class FakeRateLimiter(object): diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py index 0dd65d321..eab78b50c 100644 --- a/nova/tests/api/openstack/test_auth.py +++ b/nova/tests/api/openstack/test_auth.py @@ -48,7 +48,7 @@ class Test(unittest.TestCase): def test_authorize_user(self): f = fakes.FakeAuthManager() - f.add_user('derp', nova.auth.manager.User(1, 'herp', None, None, None)) + f.add_user(nova.auth.manager.User(1, 'herp', 'herp', 'derp', None)) req = webob.Request.blank('/v1.0/') req.headers['X-Auth-User'] = 'herp' @@ -62,7 +62,7 @@ class Test(unittest.TestCase): def test_authorize_token(self): f = fakes.FakeAuthManager() - f.add_user('derp', nova.auth.manager.User(1, 'herp', None, None, None)) + f.add_user(nova.auth.manager.User(1, 'herp', 'herp', 'derp', None)) req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'}) req.headers['X-Auth-User'] = 'herp' @@ -144,7 +144,7 @@ class TestLimiter(unittest.TestCase): def test_authorize_token(self): f = fakes.FakeAuthManager() - f.add_user('derp', nova.auth.manager.User(1, 'herp', None, None, None)) + f.add_user(nova.auth.manager.User(1, 'herp', 'herp', 'derp', None)) req = webob.Request.blank('/v1.0/') req.headers['X-Auth-User'] = 'herp' -- cgit From a3c6106f99085da69ab3c51b80135d3cedd81c4d Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 19 Feb 2011 01:22:27 -0800 Subject: store time when RequestLogging starts instead of using context's time --- nova/api/ec2/__init__.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 1a06b3f01..4e7e3267d 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -56,6 +56,7 @@ class RequestLogging(wsgi.Middleware): @webob.dec.wsgify def __call__(self, req): + self.start = datetime.datetime.utcnow() rv = req.get_response(self.application) self.log_request_completion(rv, req) return rv @@ -66,13 +67,9 @@ class RequestLogging(wsgi.Middleware): controller = controller.__class__.__name__ action = request.environ.get('ec2.action', None) ctxt = request.environ.get('ec2.context', None) - seconds = 'X' - microseconds = 'X' - if ctxt: - delta = datetime.datetime.utcnow() - \ - ctxt.timestamp - seconds = delta.seconds - microseconds = delta.microseconds + delta = datetime.datetime.utcnow() - self.start + seconds = delta.seconds + microseconds = delta.microseconds LOG.info( "%s.%ss %s %s %s %s:%s %s [%s] %s %s", seconds, -- cgit From 86a858d076c62ddd7c27e04300aeb5d21111b986 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 19 Feb 2011 01:27:48 -0800 Subject: pass start time as a param instead of making it an attribute --- nova/api/ec2/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 4e7e3267d..cda34bc3a 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -56,18 +56,18 @@ class RequestLogging(wsgi.Middleware): @webob.dec.wsgify def __call__(self, req): - self.start = datetime.datetime.utcnow() + start = datetime.datetime.utcnow() rv = req.get_response(self.application) - self.log_request_completion(rv, req) + self.log_request_completion(rv, req, start) return rv - def log_request_completion(self, response, request): + def log_request_completion(self, response, request, start): controller = request.environ.get('ec2.controller', None) if controller: controller = controller.__class__.__name__ action = request.environ.get('ec2.action', None) ctxt = request.environ.get('ec2.context', None) - delta = datetime.datetime.utcnow() - self.start + delta = datetime.datetime.utcnow() - start seconds = delta.seconds microseconds = delta.microseconds LOG.info( -- cgit From d4a37dc28daf990d903ffd14607862cb2eafb1c8 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Sat, 19 Feb 2011 01:36:13 -0800 Subject: move from datetime.datetime.utcnow -> utils.utcnow --- nova/api/ec2/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index cda34bc3a..f892123fd 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -20,7 +20,6 @@ Starting point for routing EC2 requests. """ -import datetime import webob import webob.dec import webob.exc @@ -56,7 +55,7 @@ class RequestLogging(wsgi.Middleware): @webob.dec.wsgify def __call__(self, req): - start = datetime.datetime.utcnow() + start = utils.utcnow() rv = req.get_response(self.application) self.log_request_completion(rv, req, start) return rv @@ -67,7 +66,7 @@ class RequestLogging(wsgi.Middleware): controller = controller.__class__.__name__ action = request.environ.get('ec2.action', None) ctxt = request.environ.get('ec2.context', None) - delta = datetime.datetime.utcnow() - start + delta = utils.utcnow() - start seconds = delta.seconds microseconds = delta.microseconds LOG.info( -- cgit From 915d6e70106b30ed6919fa850749b8041c3e690d Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 19 Feb 2011 01:51:13 -0800 Subject: pep8 leftover --- nova/tests/api/openstack/test_zones.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/tests/api/openstack/test_zones.py b/nova/tests/api/openstack/test_zones.py index 5542a1cf3..df497ef1b 100644 --- a/nova/tests/api/openstack/test_zones.py +++ b/nova/tests/api/openstack/test_zones.py @@ -57,8 +57,7 @@ def zone_get_all(context): dict(id=1, api_url='http://foo.com', username='bob', password='xxx'), dict(id=2, api_url='http://blah.com', username='alice', - password='qwerty') - ] + password='qwerty')] class ZonesTest(unittest.TestCase): -- cgit From 89a63f53116b04a8d0681265ba8ce71eeeb5be0b Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Sat, 19 Feb 2011 01:59:07 -0800 Subject: fix ec2 launchtime response not in iso format bug --- nova/api/ec2/apirequest.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova') diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py index 7e72d67fb..00b527d62 100644 --- a/nova/api/ec2/apirequest.py +++ b/nova/api/ec2/apirequest.py @@ -20,6 +20,7 @@ APIRequest class """ +import datetime import re # TODO(termie): replace minidom with etree from xml.dom import minidom @@ -171,6 +172,8 @@ class APIRequest(object): self._render_dict(xml, data_el, data.__dict__) elif isinstance(data, bool): data_el.appendChild(xml.createTextNode(str(data).lower())) + elif isinstance(data, datetime.datetime): + data_el.appendChild(xml.createTextNode(data.isoformat())) elif data != None: data_el.appendChild(xml.createTextNode(str(data))) -- cgit From 106eb47eff0551c73b2e90385b9c3a910fec8633 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 20 Feb 2011 23:16:10 -0800 Subject: fixes for various logging errors and issues --- nova/api/openstack/auth.py | 1 - nova/api/openstack/backup_schedules.py | 1 - nova/api/openstack/images.py | 2 - nova/api/openstack/servers.py | 1 - nova/api/openstack/shared_ip_groups.py | 2 - nova/api/openstack/zones.py | 1 - nova/console/manager.py | 2 +- nova/console/xvp.py | 2 +- nova/flags.py | 4 ++ nova/log.py | 117 ++++++++++++++++++++------------- nova/test.py | 2 + nova/tests/fake_flags.py | 2 + nova/tests/test_auth.py | 9 --- nova/tests/test_console.py | 2 - nova/tests/test_direct.py | 1 - nova/tests/test_localization.py | 1 - nova/tests/test_log.py | 65 +++++++++--------- nova/utils.py | 2 +- 18 files changed, 115 insertions(+), 102 deletions(-) (limited to 'nova') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 473071738..1dfdd5318 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -19,7 +19,6 @@ import datetime import hashlib import json import time -import logging import webob.exc import webob.dec diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index 197125d86..7abb5f884 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -15,7 +15,6 @@ # License for the specific language governing permissions and limitations # under the License. -import logging import time from webob import exc diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 9d56bc508..cf85a496f 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -15,8 +15,6 @@ # License for the specific language governing permissions and limitations # under the License. -import logging - from webob import exc from nova import compute diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index ce9601ecb..0bac4c64d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -33,7 +33,6 @@ import nova.api.openstack LOG = logging.getLogger('server') -LOG.setLevel(logging.DEBUG) FLAGS = flags.FLAGS diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py index bd3cc23a8..5d78f9377 100644 --- a/nova/api/openstack/shared_ip_groups.py +++ b/nova/api/openstack/shared_ip_groups.py @@ -15,8 +15,6 @@ # License for the specific language governing permissions and limitations # under the License. -import logging - from webob import exc from nova import wsgi diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 830464ffd..d5206da20 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -14,7 +14,6 @@ # under the License. import common -import logging from nova import flags from nova import wsgi diff --git a/nova/console/manager.py b/nova/console/manager.py index 5697e7cb1..57c75cf4f 100644 --- a/nova/console/manager.py +++ b/nova/console/manager.py @@ -20,11 +20,11 @@ Console Proxy Service """ import functools -import logging import socket from nova import exception from nova import flags +from nova import log as logging from nova import manager from nova import rpc from nova import utils diff --git a/nova/console/xvp.py b/nova/console/xvp.py index ee66dac46..cd257e0a6 100644 --- a/nova/console/xvp.py +++ b/nova/console/xvp.py @@ -20,7 +20,6 @@ XVP (Xenserver VNC Proxy) driver. """ import fcntl -import logging import os import signal import subprocess @@ -31,6 +30,7 @@ from nova import context from nova import db from nova import exception from nova import flags +from nova import log as logging from nova import utils flags.DEFINE_string('console_xvp_conf_template', diff --git a/nova/flags.py b/nova/flags.py index f64a62da9..2f3bdd675 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -38,6 +38,7 @@ class FlagValues(gflags.FlagValues): defined after the initial parsing. """ + initialized = False def __init__(self, extra_context=None): gflags.FlagValues.__init__(self) @@ -45,6 +46,8 @@ class FlagValues(gflags.FlagValues): self.__dict__['__was_already_parsed'] = False self.__dict__['__stored_argv'] = [] self.__dict__['__extra_context'] = extra_context + # NOTE(vish): force a pseudo flag to keep track of whether + # flags have been parsed already def __call__(self, argv): # We're doing some hacky stuff here so that we don't have to copy @@ -90,6 +93,7 @@ class FlagValues(gflags.FlagValues): self.__dict__['__stored_argv'] = original_argv self.__dict__['__was_already_parsed'] = True self.ClearDirty() + FlagValues.initialized = True return args def Reset(self): diff --git a/nova/log.py b/nova/log.py index 6b201ffcc..12b695a41 100644 --- a/nova/log.py +++ b/nova/log.py @@ -117,7 +117,22 @@ def _get_binary_name(): return os.path.basename(inspect.stack()[-1][1]) -def get_log_file_path(binary=None): +def _get_level_from_flags(name): + # if exactly "nova", or a child logger, honor the verbose flag + if (name == "nova" or name.startswith("nova.")) and FLAGS.verbose: + return 'DEBUG' + for pair in FLAGS.default_log_levels: + logger, _sep, level = pair.partition('=') + # NOTE(todd): if we set a.b, we want a.b.c to have the same level + # (but not a.bc, so we check the dot) + if name == logger: + return level + if name.startswith(logger) and name[len(logger)] == '.': + return level + return 'INFO' + + +def _get_log_file_path(binary=None): if FLAGS.logfile: return FLAGS.logfile if FLAGS.logdir: @@ -126,22 +141,13 @@ def get_log_file_path(binary=None): def basicConfig(): - logging.basicConfig() - for handler in logging.root.handlers: - handler.setFormatter(_formatter) - if FLAGS.verbose: - logging.root.setLevel(logging.DEBUG) - else: - logging.root.setLevel(logging.INFO) - if FLAGS.use_syslog: - syslog = SysLogHandler(address='/dev/log') - syslog.setFormatter(_formatter) - logging.root.addHandler(syslog) - logpath = get_log_file_path() - if logpath: - logfile = WatchedFileHandler(logpath) - logfile.setFormatter(_formatter) - logging.root.addHandler(logfile) + pass + + +logging.basicConfig = basicConfig +_syslog = SysLogHandler(address='/dev/log') +_filelog = None +_streamlog = StreamHandler() class NovaLogger(logging.Logger): @@ -151,23 +157,24 @@ class NovaLogger(logging.Logger): This becomes the class that is instanciated by logging.getLogger. """ def __init__(self, name, level=NOTSET): - level_name = self._get_level_from_flags(name, FLAGS) - level = globals()[level_name] logging.Logger.__init__(self, name, level) - - def _get_level_from_flags(self, name, FLAGS): - # if exactly "nova", or a child logger, honor the verbose flag - if (name == "nova" or name.startswith("nova.")) and FLAGS.verbose: - return 'DEBUG' - for pair in FLAGS.default_log_levels: - logger, _sep, level = pair.partition('=') - # NOTE(todd): if we set a.b, we want a.b.c to have the same level - # (but not a.bc, so we check the dot) - if name == logger: - return level - if name.startswith(logger) and name[len(logger)] == '.': - return level - return 'INFO' + self.initialized = False + if flags.FlagValues.initialized: + self._setup_from_flags() + + def _setup_from_flags(self): + """Setup logger from flags""" + level_name = _get_level_from_flags(self.name) + self.setLevel(globals()[level_name]) + self.initialized = True + if not logging.root.initialized: + logging.root._setup_from_flags() + + def isEnabledFor(self, level): + """Reset level after flags have been loaded""" + if not self.initialized and flags.FlagValues.initialized: + self._setup_from_flags() + return logging.Logger.isEnabledFor(self, level) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): """Extract context from any log call""" @@ -176,12 +183,12 @@ class NovaLogger(logging.Logger): if context: extra.update(_dictify_context(context)) extra.update({"nova_version": version.version_string_with_vcs()}) - logging.Logger._log(self, level, msg, args, exc_info, extra) + return logging.Logger._log(self, level, msg, args, exc_info, extra) def addHandler(self, handler): """Each handler gets our custom formatter""" handler.setFormatter(_formatter) - logging.Logger.addHandler(self, handler) + return logging.Logger.addHandler(self, handler) def audit(self, msg, *args, **kwargs): """Shortcut for our AUDIT level""" @@ -192,7 +199,7 @@ class NovaLogger(logging.Logger): """Logging.exception doesn't handle kwargs, so breaks context""" if not kwargs.get('exc_info'): kwargs['exc_info'] = 1 - self.error(msg, *args, **kwargs) + return self.error(msg, *args, **kwargs) # NOTE(todd): does this really go here, or in _log ? extra = kwargs.get('extra') if not extra: @@ -209,6 +216,8 @@ class NovaLogger(logging.Logger): def handle_exception(type, value, tb): + if len(logging.root.handlers) == 0: + logging.root.addHandler(_streamlog) logging.root.critical(str(value), exc_info=(type, value, tb)) @@ -216,15 +225,6 @@ sys.excepthook = handle_exception logging.setLoggerClass(NovaLogger) -class NovaRootLogger(NovaLogger): - pass - -if not isinstance(logging.root, NovaRootLogger): - logging.root = NovaRootLogger("nova.root", WARNING) - NovaLogger.root = logging.root - NovaLogger.manager.root = logging.root - - class NovaFormatter(logging.Formatter): """ A nova.context.RequestContext aware formatter configured through flags. @@ -271,6 +271,33 @@ class NovaFormatter(logging.Formatter): _formatter = NovaFormatter() +class NovaRootLogger(NovaLogger): + def __init__(self, name, level=NOTSET): + NovaLogger.__init__(self, name, level) + self.addHandler(_streamlog) + + def _setup_from_flags(self): + """Setup logger from flags""" + global _filelog + if FLAGS.use_syslog: + self.addHandler(_syslog) + logpath = _get_log_file_path() + if logpath: + if not _filelog: + _filelog = WatchedFileHandler(logpath) + self.addHandler(_filelog) + self.removeHandler(_streamlog) + return NovaLogger._setup_from_flags(self) + + +if not isinstance(logging.root, NovaRootLogger): + for handler in logging.root.handlers: + logging.root.removeHandler(handler) + logging.root = NovaRootLogger("nova") + NovaLogger.root = logging.root + NovaLogger.manager.root = logging.root + + def audit(msg, *args, **kwargs): """Shortcut for logging to root log with sevrity 'AUDIT'.""" if len(logging.root.handlers) == 0: diff --git a/nova/test.py b/nova/test.py index a12cf9d32..a649b4c5f 100644 --- a/nova/test.py +++ b/nova/test.py @@ -60,6 +60,8 @@ class TestCase(unittest.TestCase): def setUp(self): """Run before each test method to initialize test environment""" super(TestCase, self).setUp() + # NOTE(vish): pretend like we've loaded flags from command line + flags.FlagValues.initialized = True # NOTE(vish): We need a better method for creating fixtures for tests # now that we have some required db setup for the system # to work properly. diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 1097488ec..68b14a46e 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -41,3 +41,5 @@ FLAGS.iscsi_num_targets = 8 FLAGS.verbose = True FLAGS.sql_connection = 'sqlite:///nova.sqlite' FLAGS.use_ipv6 = True +FLAGS.logfile = 'run_tests.err' +flags.FlagValues.initialized = True diff --git a/nova/tests/test_auth.py b/nova/tests/test_auth.py index 35ffffb67..2a7817032 100644 --- a/nova/tests/test_auth.py +++ b/nova/tests/test_auth.py @@ -327,15 +327,6 @@ class AuthManagerTestCase(object): class AuthManagerLdapTestCase(AuthManagerTestCase, test.TestCase): auth_driver = 'nova.auth.ldapdriver.FakeLdapDriver' - def __init__(self, *args, **kwargs): - AuthManagerTestCase.__init__(self) - test.TestCase.__init__(self, *args, **kwargs) - import nova.auth.fakeldap as fakeldap - if FLAGS.flush_db: - LOG.info("Flushing datastore") - r = fakeldap.Store.instance() - r.flushdb() - class AuthManagerDbTestCase(AuthManagerTestCase, test.TestCase): auth_driver = 'nova.auth.dbdriver.DbDriver' diff --git a/nova/tests/test_console.py b/nova/tests/test_console.py index 85bf94458..49ff24413 100644 --- a/nova/tests/test_console.py +++ b/nova/tests/test_console.py @@ -21,7 +21,6 @@ Tests For Console proxy. """ import datetime -import logging from nova import context from nova import db @@ -38,7 +37,6 @@ FLAGS = flags.FLAGS class ConsoleTestCase(test.TestCase): """Test case for console proxy""" def setUp(self): - logging.getLogger().setLevel(logging.DEBUG) super(ConsoleTestCase, self).setUp() self.flags(console_driver='nova.console.fake.FakeConsoleProxy', stub_compute=True) diff --git a/nova/tests/test_direct.py b/nova/tests/test_direct.py index 8a74b2296..7656f5396 100644 --- a/nova/tests/test_direct.py +++ b/nova/tests/test_direct.py @@ -19,7 +19,6 @@ """Tests for Direct API.""" import json -import logging import webob diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py index 6992773f5..393d71038 100644 --- a/nova/tests/test_localization.py +++ b/nova/tests/test_localization.py @@ -15,7 +15,6 @@ # under the License. import glob -import logging import os import re import sys diff --git a/nova/tests/test_log.py b/nova/tests/test_log.py index c2c9d7772..ada8d0a56 100644 --- a/nova/tests/test_log.py +++ b/nova/tests/test_log.py @@ -1,9 +1,12 @@ import cStringIO from nova import context +from nova import flags from nova import log from nova import test +FLAGS = flags.FLAGS + def _fake_context(): return context.RequestContext(1, 1) @@ -14,15 +17,11 @@ class RootLoggerTestCase(test.TestCase): super(RootLoggerTestCase, self).setUp() self.log = log.logging.root - def tearDown(self): - super(RootLoggerTestCase, self).tearDown() - log.NovaLogger.manager.loggerDict = {} - def test_is_nova_instance(self): self.assert_(isinstance(self.log, log.NovaLogger)) - def test_name_is_nova_root(self): - self.assertEqual("nova.root", self.log.name) + def test_name_is_nova(self): + self.assertEqual("nova", self.log.name) def test_handlers_have_nova_formatter(self): formatters = [] @@ -45,25 +44,38 @@ class RootLoggerTestCase(test.TestCase): log.audit("foo", context=_fake_context()) self.assert_(True) # didn't raise exception + def test_will_be_verbose_if_verbose_flag_set(self): + self.flags(verbose=True) + self.log.initialized = False + log.audit("foo", context=_fake_context()) + self.assertEqual(log.DEBUG, self.log.level) + + def test_will_not_be_verbose_if_verbose_flag_not_set(self): + self.flags(verbose=False) + self.log.initialized = False + log.audit("foo", context=_fake_context()) + self.assertEqual(log.INFO, self.log.level) + class LogHandlerTestCase(test.TestCase): def test_log_path_logdir(self): - self.flags(logdir='/some/path') - self.assertEquals(log.get_log_file_path(binary='foo-bar'), + self.flags(logdir='/some/path', logfile=None) + self.assertEquals(log._get_log_file_path(binary='foo-bar'), '/some/path/foo-bar.log') def test_log_path_logfile(self): self.flags(logfile='/some/path/foo-bar.log') - self.assertEquals(log.get_log_file_path(binary='foo-bar'), + self.assertEquals(log._get_log_file_path(binary='foo-bar'), '/some/path/foo-bar.log') def test_log_path_none(self): - self.assertTrue(log.get_log_file_path(binary='foo-bar') is None) + self.flags(logdir=None, logfile=None) + self.assertTrue(log._get_log_file_path(binary='foo-bar') is None) def test_log_path_logfile_overrides_logdir(self): self.flags(logdir='/some/other/path', logfile='/some/path/foo-bar.log') - self.assertEquals(log.get_log_file_path(binary='foo-bar'), + self.assertEquals(log._get_log_file_path(binary='foo-bar'), '/some/path/foo-bar.log') @@ -76,13 +88,15 @@ class NovaFormatterTestCase(test.TestCase): logging_debug_format_suffix="--DBG") self.log = log.logging.root self.stream = cStringIO.StringIO() - handler = log.StreamHandler(self.stream) - self.log.addHandler(handler) + self.handler = log.StreamHandler(self.stream) + self.log.addHandler(self.handler) + self.level = self.log.level self.log.setLevel(log.DEBUG) def tearDown(self): + self.log.setLevel(self.level) + self.log.removeHandler(self.handler) super(NovaFormatterTestCase, self).tearDown() - log.NovaLogger.manager.loggerDict = {} def test_uncontextualized_log(self): self.log.info("foo") @@ -102,30 +116,15 @@ class NovaFormatterTestCase(test.TestCase): class NovaLoggerTestCase(test.TestCase): def setUp(self): super(NovaLoggerTestCase, self).setUp() - self.flags(default_log_levels=["nova-test=AUDIT"], verbose=False) + levels = FLAGS.default_log_levels + levels.append("nova-test=AUDIT") + self.flags(default_log_levels=levels, + verbose=True) self.log = log.getLogger('nova-test') - def tearDown(self): - super(NovaLoggerTestCase, self).tearDown() - log.NovaLogger.manager.loggerDict = {} - def test_has_level_from_flags(self): self.assertEqual(log.AUDIT, self.log.level) def test_child_log_has_level_of_parent_flag(self): l = log.getLogger('nova-test.foo') self.assertEqual(log.AUDIT, l.level) - - -class VerboseLoggerTestCase(test.TestCase): - def setUp(self): - super(VerboseLoggerTestCase, self).setUp() - self.flags(default_log_levels=["nova.test=AUDIT"], verbose=True) - self.log = log.getLogger('nova.test') - - def tearDown(self): - super(VerboseLoggerTestCase, self).tearDown() - log.NovaLogger.manager.loggerDict = {} - - def test_will_be_verbose_if_named_nova_and_verbose_flag_set(self): - self.assertEqual(log.DEBUG, self.log.level) diff --git a/nova/utils.py b/nova/utils.py index 42efa0008..c2fd5f2ee 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -55,7 +55,7 @@ def import_class(import_str): __import__(mod_str) return getattr(sys.modules[mod_str], class_str) except (ImportError, ValueError, AttributeError), exc: - logging.debug(_('Inner Exception: %s'), exc) + LOG.info(_('Inner Exception: %s'), exc) raise exception.NotFound(_('Class %s cannot be found') % class_str) -- cgit From 98c2ef77e6018c0a6233e32ace435fba488175f5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 20 Feb 2011 23:18:09 -0800 Subject: move the fake initialized into fake flags --- nova/test.py | 2 -- nova/tests/fake_flags.py | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/test.py b/nova/test.py index a649b4c5f..a12cf9d32 100644 --- a/nova/test.py +++ b/nova/test.py @@ -60,8 +60,6 @@ class TestCase(unittest.TestCase): def setUp(self): """Run before each test method to initialize test environment""" super(TestCase, self).setUp() - # NOTE(vish): pretend like we've loaded flags from command line - flags.FlagValues.initialized = True # NOTE(vish): We need a better method for creating fixtures for tests # now that we have some required db setup for the system # to work properly. diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 68b14a46e..0a1011d86 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -42,4 +42,5 @@ FLAGS.verbose = True FLAGS.sql_connection = 'sqlite:///nova.sqlite' FLAGS.use_ipv6 = True FLAGS.logfile = 'run_tests.err' +# NOTE(vish): pretend like we've loaded flags from command line flags.FlagValues.initialized = True -- cgit From eaddb9ea529672549af28cab4aacd2f8243c62a3 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 20 Feb 2011 23:36:36 -0800 Subject: remove extra references to logging.basicConfig --- nova/log.py | 19 +++++++++++++------ nova/service.py | 1 - nova/twistd.py | 1 - nova/wsgi.py | 1 - 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 12b695a41..0a863c921 100644 --- a/nova/log.py +++ b/nova/log.py @@ -160,20 +160,20 @@ class NovaLogger(logging.Logger): logging.Logger.__init__(self, name, level) self.initialized = False if flags.FlagValues.initialized: - self._setup_from_flags() + self.setup_from_flags() - def _setup_from_flags(self): + def setup_from_flags(self): """Setup logger from flags""" level_name = _get_level_from_flags(self.name) self.setLevel(globals()[level_name]) self.initialized = True if not logging.root.initialized: - logging.root._setup_from_flags() + logging.root.setup_from_flags() def isEnabledFor(self, level): """Reset level after flags have been loaded""" if not self.initialized and flags.FlagValues.initialized: - self._setup_from_flags() + self.setup_from_flags() return logging.Logger.isEnabledFor(self, level) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): @@ -276,18 +276,24 @@ class NovaRootLogger(NovaLogger): NovaLogger.__init__(self, name, level) self.addHandler(_streamlog) - def _setup_from_flags(self): + def setup_from_flags(self): """Setup logger from flags""" global _filelog if FLAGS.use_syslog: self.addHandler(_syslog) + else: + self.removeHandler(_syslog) logpath = _get_log_file_path() if logpath: if not _filelog: _filelog = WatchedFileHandler(logpath) self.addHandler(_filelog) self.removeHandler(_streamlog) - return NovaLogger._setup_from_flags(self) + else: + self.removeHandler(_filelog) + self.addHandler(_streamlog) + + return NovaLogger.setup_from_flags(self) if not isinstance(logging.root, NovaRootLogger): @@ -296,6 +302,7 @@ if not isinstance(logging.root, NovaRootLogger): logging.root = NovaRootLogger("nova") NovaLogger.root = logging.root NovaLogger.manager.root = logging.root +root=logging.root def audit(msg, *args, **kwargs): diff --git a/nova/service.py b/nova/service.py index 59648adf2..02e86f6b3 100644 --- a/nova/service.py +++ b/nova/service.py @@ -215,7 +215,6 @@ class Service(object): def serve(*services): FLAGS(sys.argv) - logging.basicConfig() if not services: services = [Service.create()] diff --git a/nova/twistd.py b/nova/twistd.py index 60ff7879a..0e4db022c 100644 --- a/nova/twistd.py +++ b/nova/twistd.py @@ -258,7 +258,6 @@ def serve(filename): print 'usage: %s [options] [start|stop|restart]' % argv[0] sys.exit(1) - logging.basicConfig() logging.debug(_("Full set of FLAGS:")) for flag in FLAGS: logging.debug("%s : %s" % (flag, FLAGS.get(flag, None))) diff --git a/nova/wsgi.py b/nova/wsgi.py index e01cc1e1e..280baa80b 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -59,7 +59,6 @@ class Server(object): """Server class to manage multiple WSGI sockets and applications.""" def __init__(self, threads=1000): - logging.basicConfig() self.pool = eventlet.GreenPool(threads) def start(self, application, port, host='0.0.0.0', backlog=128): -- cgit From 2792e42a9c7da390b3db0b59b7dff357c440d3e5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Sun, 20 Feb 2011 23:45:43 -0800 Subject: clean up location of method --- nova/log.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 0a863c921..57a550a0b 100644 --- a/nova/log.py +++ b/nova/log.py @@ -117,21 +117,6 @@ def _get_binary_name(): return os.path.basename(inspect.stack()[-1][1]) -def _get_level_from_flags(name): - # if exactly "nova", or a child logger, honor the verbose flag - if (name == "nova" or name.startswith("nova.")) and FLAGS.verbose: - return 'DEBUG' - for pair in FLAGS.default_log_levels: - logger, _sep, level = pair.partition('=') - # NOTE(todd): if we set a.b, we want a.b.c to have the same level - # (but not a.bc, so we check the dot) - if name == logger: - return level - if name.startswith(logger) and name[len(logger)] == '.': - return level - return 'INFO' - - def _get_log_file_path(binary=None): if FLAGS.logfile: return FLAGS.logfile @@ -162,9 +147,24 @@ class NovaLogger(logging.Logger): if flags.FlagValues.initialized: self.setup_from_flags() + @staticmethod + def _get_level_from_flags(name): + # if exactly "nova", or a child logger, honor the verbose flag + if (name == "nova" or name.startswith("nova.")) and FLAGS.verbose: + return 'DEBUG' + for pair in FLAGS.default_log_levels: + logger, _sep, level = pair.partition('=') + # NOTE(todd): if we set a.b, we want a.b.c to have the same level + # (but not a.bc, so we check the dot) + if name == logger: + return level + if name.startswith(logger) and name[len(logger)] == '.': + return level + return 'INFO' + def setup_from_flags(self): """Setup logger from flags""" - level_name = _get_level_from_flags(self.name) + level_name = self._get_level_from_flags(self.name) self.setLevel(globals()[level_name]) self.initialized = True if not logging.root.initialized: @@ -302,7 +302,7 @@ if not isinstance(logging.root, NovaRootLogger): logging.root = NovaRootLogger("nova") NovaLogger.root = logging.root NovaLogger.manager.root = logging.root -root=logging.root +root = logging.root def audit(msg, *args, **kwargs): -- cgit From 7eab72b30cad9708e976f60e121569972b835b61 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 00:15:49 -0800 Subject: get rid of initialized flag --- nova/flags.py | 4 ++-- nova/log.py | 16 ++++------------ nova/test.py | 3 +++ nova/tests/fake_flags.py | 2 -- nova/tests/test_log.py | 6 ++---- 5 files changed, 11 insertions(+), 20 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index 2f3bdd675..72d123e21 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -29,7 +29,6 @@ import sys import gflags - class FlagValues(gflags.FlagValues): """Extension of gflags.FlagValues that allows undefined and runtime flags. @@ -93,7 +92,8 @@ class FlagValues(gflags.FlagValues): self.__dict__['__stored_argv'] = original_argv self.__dict__['__was_already_parsed'] = True self.ClearDirty() - FlagValues.initialized = True + from nova import log as logging + logging.reset() return args def Reset(self): diff --git a/nova/log.py b/nova/log.py index 57a550a0b..8d240782d 100644 --- a/nova/log.py +++ b/nova/log.py @@ -143,9 +143,7 @@ class NovaLogger(logging.Logger): """ def __init__(self, name, level=NOTSET): logging.Logger.__init__(self, name, level) - self.initialized = False - if flags.FlagValues.initialized: - self.setup_from_flags() + self.setup_from_flags() @staticmethod def _get_level_from_flags(name): @@ -166,15 +164,6 @@ class NovaLogger(logging.Logger): """Setup logger from flags""" level_name = self._get_level_from_flags(self.name) self.setLevel(globals()[level_name]) - self.initialized = True - if not logging.root.initialized: - logging.root.setup_from_flags() - - def isEnabledFor(self, level): - """Reset level after flags have been loaded""" - if not self.initialized and flags.FlagValues.initialized: - self.setup_from_flags() - return logging.Logger.isEnabledFor(self, level) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): """Extract context from any log call""" @@ -304,6 +293,9 @@ if not isinstance(logging.root, NovaRootLogger): NovaLogger.manager.root = logging.root root = logging.root +def reset(): + root.setup_from_flags() + def audit(msg, *args, **kwargs): """Shortcut for logging to root log with sevrity 'AUDIT'.""" diff --git a/nova/test.py b/nova/test.py index a12cf9d32..8022396cd 100644 --- a/nova/test.py +++ b/nova/test.py @@ -32,9 +32,12 @@ from nova import context from nova import db from nova import fakerabbit from nova import flags +from nova import log as logging from nova import rpc from nova.network import manager as network_manager + from nova.tests import fake_flags +logging.reset() FLAGS = flags.FLAGS diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 0a1011d86..59839b090 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -42,5 +42,3 @@ FLAGS.verbose = True FLAGS.sql_connection = 'sqlite:///nova.sqlite' FLAGS.use_ipv6 = True FLAGS.logfile = 'run_tests.err' -# NOTE(vish): pretend like we've loaded flags from command line -flags.FlagValues.initialized = True diff --git a/nova/tests/test_log.py b/nova/tests/test_log.py index ada8d0a56..122351ff6 100644 --- a/nova/tests/test_log.py +++ b/nova/tests/test_log.py @@ -46,14 +46,12 @@ class RootLoggerTestCase(test.TestCase): def test_will_be_verbose_if_verbose_flag_set(self): self.flags(verbose=True) - self.log.initialized = False - log.audit("foo", context=_fake_context()) + log.reset() self.assertEqual(log.DEBUG, self.log.level) def test_will_not_be_verbose_if_verbose_flag_not_set(self): self.flags(verbose=False) - self.log.initialized = False - log.audit("foo", context=_fake_context()) + log.reset() self.assertEqual(log.INFO, self.log.level) -- cgit From f9af5309cf50b3b1a4ef9799c071cbaa6b1b304f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 00:22:45 -0800 Subject: removed extra comments and initialized from flags --- nova/flags.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index 72d123e21..e2f7960ec 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -37,7 +37,6 @@ class FlagValues(gflags.FlagValues): defined after the initial parsing. """ - initialized = False def __init__(self, extra_context=None): gflags.FlagValues.__init__(self) @@ -45,8 +44,6 @@ class FlagValues(gflags.FlagValues): self.__dict__['__was_already_parsed'] = False self.__dict__['__stored_argv'] = [] self.__dict__['__extra_context'] = extra_context - # NOTE(vish): force a pseudo flag to keep track of whether - # flags have been parsed already def __call__(self, argv): # We're doing some hacky stuff here so that we don't have to copy -- cgit From f28ed7d95afd17e55e1db25a75e065f9da0f06e6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 00:24:35 -0800 Subject: add docstring to reset method --- nova/log.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 8d240782d..94eeecce0 100644 --- a/nova/log.py +++ b/nova/log.py @@ -294,6 +294,7 @@ if not isinstance(logging.root, NovaRootLogger): root = logging.root def reset(): + """Resets logging handlers. Should be called if FLAGS changes.""" root.setup_from_flags() -- cgit From bfba5b2cf8ade746d74485bd76f9d60238ccb2ea Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 00:48:33 -0800 Subject: reset all loggers on flag change, not just root --- nova/log.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 94eeecce0..2b43f7311 100644 --- a/nova/log.py +++ b/nova/log.py @@ -295,6 +295,9 @@ root = logging.root def reset(): """Resets logging handlers. Should be called if FLAGS changes.""" + for logger in logging.Logger.manager.loggerDict.itervalues(): + if isinstance(logger, NovaLogger): + logger.setup_from_flags() root.setup_from_flags() -- cgit From e773c16e1bce0e00b269394d1ed20d15884827ff Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 01:07:46 -0800 Subject: simplify logic for parsing log level flags --- nova/log.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 2b43f7311..0cd42d00e 100644 --- a/nova/log.py +++ b/nova/log.py @@ -145,25 +145,14 @@ class NovaLogger(logging.Logger): logging.Logger.__init__(self, name, level) self.setup_from_flags() - @staticmethod - def _get_level_from_flags(name): - # if exactly "nova", or a child logger, honor the verbose flag - if (name == "nova" or name.startswith("nova.")) and FLAGS.verbose: - return 'DEBUG' + def setup_from_flags(self): + """Setup logger from flags""" for pair in FLAGS.default_log_levels: logger, _sep, level = pair.partition('=') # NOTE(todd): if we set a.b, we want a.b.c to have the same level # (but not a.bc, so we check the dot) - if name == logger: - return level - if name.startswith(logger) and name[len(logger)] == '.': - return level - return 'INFO' - - def setup_from_flags(self): - """Setup logger from flags""" - level_name = self._get_level_from_flags(self.name) - self.setLevel(globals()[level_name]) + if self.name == logger or self.name.startswith("%s." % logger): + self.setLevel(globals()[level]) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): """Extract context from any log call""" @@ -281,8 +270,10 @@ class NovaRootLogger(NovaLogger): else: self.removeHandler(_filelog) self.addHandler(_streamlog) - - return NovaLogger.setup_from_flags(self) + if FLAGS.verbose: + self.setLevel(DEBUG) + else: + self.setLevel(INFO) if not isinstance(logging.root, NovaRootLogger): -- cgit From 753d3a6915ad8387ea29ad1a7fb4aed74c4b71fd Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 01:26:15 -0800 Subject: move exception hook into appropriate location and remove extra stuff from module namespace --- nova/log.py | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 0cd42d00e..5ffb52cde 100644 --- a/nova/log.py +++ b/nova/log.py @@ -130,9 +130,6 @@ def basicConfig(): logging.basicConfig = basicConfig -_syslog = SysLogHandler(address='/dev/log') -_filelog = None -_streamlog = StreamHandler() class NovaLogger(logging.Logger): @@ -193,16 +190,6 @@ class NovaLogger(logging.Logger): self.error(message, **kwargs) -def handle_exception(type, value, tb): - if len(logging.root.handlers) == 0: - logging.root.addHandler(_streamlog) - logging.root.critical(str(value), exc_info=(type, value, tb)) - - -sys.excepthook = handle_exception -logging.setLoggerClass(NovaLogger) - - class NovaFormatter(logging.Formatter): """ A nova.context.RequestContext aware formatter configured through flags. @@ -251,25 +238,30 @@ _formatter = NovaFormatter() class NovaRootLogger(NovaLogger): def __init__(self, name, level=NOTSET): + self.logpath = None + self.filelog = None + self.syslog = SysLogHandler(address='/dev/log') + self.streamlog = StreamHandler() NovaLogger.__init__(self, name, level) - self.addHandler(_streamlog) def setup_from_flags(self): """Setup logger from flags""" global _filelog if FLAGS.use_syslog: - self.addHandler(_syslog) + self.addHandler(self.syslog) else: - self.removeHandler(_syslog) + self.removeHandler(self.syslog) logpath = _get_log_file_path() if logpath: - if not _filelog: - _filelog = WatchedFileHandler(logpath) - self.addHandler(_filelog) - self.removeHandler(_streamlog) + self.removeHandler(self.streamlog) + if logpath != self.logpath: + self.removeHandler(self.filelog) + self.filelog = WatchedFileHandler(logpath) + self.addHandler(self.filelog) + self.logpath = logpath else: - self.removeHandler(_filelog) - self.addHandler(_streamlog) + self.removeHandler(self.filelog) + self.addHandler(self.streamlog) if FLAGS.verbose: self.setLevel(DEBUG) else: @@ -284,6 +276,15 @@ if not isinstance(logging.root, NovaRootLogger): NovaLogger.manager.root = logging.root root = logging.root + +def handle_exception(type, value, tb): + root.critical(str(value), exc_info=(type, value, tb)) + + +sys.excepthook = handle_exception +logging.setLoggerClass(NovaLogger) + + def reset(): """Resets logging handlers. Should be called if FLAGS changes.""" for logger in logging.Logger.manager.loggerDict.itervalues(): -- cgit From eebb9bb14edb6fd1d218b3aa18142ee739ddd715 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Mon, 21 Feb 2011 16:16:21 +0100 Subject: introducing a new flag timeout_nbd for manually setting the time in seconds for waiting for an upcoming NBD device --- nova/virt/disk.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/virt/disk.py b/nova/virt/disk.py index c5565abfa..cb639a102 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -38,6 +38,8 @@ flags.DEFINE_integer('minimum_root_size', 1024 * 1024 * 1024 * 10, 'minimum size in bytes of root partition') flags.DEFINE_integer('block_size', 1024 * 1024 * 256, 'block_size to use for dd') +flags.DEFINE_integer('timeout_nbd', 10, + 'time to wait for a NBD device coming up') def extend(image, size): @@ -117,7 +119,7 @@ def _link_device(image, nbd): utils.execute('sudo qemu-nbd -c %s %s' % (device, image)) # NOTE(vish): this forks into another process, so give it a chance # to set up before continuuing - for i in xrange(10): + for i in xrange(FLAGS.timeout_nbd): if os.path.exists("/sys/block/%s/pid" % os.path.basename(device)): return device time.sleep(1) -- cgit From 8b30a903a4d2c5c6ffe44e58b8531ddc889492c0 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Mon, 21 Feb 2011 13:10:45 -0500 Subject: PEP8 errors and remove check in authors file for nova-core, since nova-core owns the translation export branch --- nova/tests/test_misc.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova') diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py index 33c1777d5..7a4d512a4 100644 --- a/nova/tests/test_misc.py +++ b/nova/tests/test_misc.py @@ -46,6 +46,8 @@ class ProjectTestCase(test.TestCase): missing = set() for contributor in contributors: + if contributor == 'nova-core': + pass if not contributor in authors_file: missing.add(contributor) -- cgit From 5e02518d8ae5e7f57033e28ae85067d28c1ff3d8 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 10:52:28 -0800 Subject: reset to notset if level isn't in flags --- nova/log.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 5ffb52cde..61a279882 100644 --- a/nova/log.py +++ b/nova/log.py @@ -144,12 +144,14 @@ class NovaLogger(logging.Logger): def setup_from_flags(self): """Setup logger from flags""" + level = NOTSET for pair in FLAGS.default_log_levels: - logger, _sep, level = pair.partition('=') + logger, _sep, level_name = pair.partition('=') # NOTE(todd): if we set a.b, we want a.b.c to have the same level # (but not a.bc, so we check the dot) if self.name == logger or self.name.startswith("%s." % logger): - self.setLevel(globals()[level]) + level = globals()[level_name] + self.setLevel(level) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): """Extract context from any log call""" -- cgit From cf006cce87ce18cdf9d7705fcc2be05b912d4c3f Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Mon, 21 Feb 2011 13:55:25 -0500 Subject: Duh, continue skips iteration, not pass. #iamanidiot --- nova/tests/test_misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/tests/test_misc.py b/nova/tests/test_misc.py index 7a4d512a4..e6da6112a 100644 --- a/nova/tests/test_misc.py +++ b/nova/tests/test_misc.py @@ -47,7 +47,7 @@ class ProjectTestCase(test.TestCase): missing = set() for contributor in contributors: if contributor == 'nova-core': - pass + continue if not contributor in authors_file: missing.add(contributor) -- cgit From 8388144744849265b46d26735da01a11e35990b0 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 11:07:50 -0800 Subject: cleanup from review --- nova/log.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 61a279882..3a48c97ff 100644 --- a/nova/log.py +++ b/nova/log.py @@ -125,13 +125,6 @@ def _get_log_file_path(binary=None): return '%s.log' % (os.path.join(FLAGS.logdir, binary),) -def basicConfig(): - pass - - -logging.basicConfig = basicConfig - - class NovaLogger(logging.Logger): """ NovaLogger manages request context and formatting. @@ -176,7 +169,7 @@ class NovaLogger(logging.Logger): """Logging.exception doesn't handle kwargs, so breaks context""" if not kwargs.get('exc_info'): kwargs['exc_info'] = 1 - return self.error(msg, *args, **kwargs) + self.error(msg, *args, **kwargs) # NOTE(todd): does this really go here, or in _log ? extra = kwargs.get('extra') if not extra: @@ -271,11 +264,16 @@ class NovaRootLogger(NovaLogger): if not isinstance(logging.root, NovaRootLogger): + logging._acquireLock() for handler in logging.root.handlers: logging.root.removeHandler(handler) logging.root = NovaRootLogger("nova") + for logger in NovaLogger.manager.loggerDict.itervalues(): + logger.root = logging.root NovaLogger.root = logging.root NovaLogger.manager.root = logging.root + NovaLogger.manager.loggerDict["nova"] = logging.root + logging._releaseLock() root = logging.root @@ -289,14 +287,11 @@ logging.setLoggerClass(NovaLogger) def reset(): """Resets logging handlers. Should be called if FLAGS changes.""" - for logger in logging.Logger.manager.loggerDict.itervalues(): + for logger in NovaLogger.manager.loggerDict.itervalues(): if isinstance(logger, NovaLogger): logger.setup_from_flags() - root.setup_from_flags() def audit(msg, *args, **kwargs): """Shortcut for logging to root log with sevrity 'AUDIT'.""" - if len(logging.root.handlers) == 0: - basicConfig() logging.root.log(AUDIT, msg, *args, **kwargs) -- cgit From c7d83e26f7d6388857b4db4538602395b688aa7a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 11:42:46 -0800 Subject: use tests.sqlite so it doesn't conflict with running db --- nova/tests/fake_flags.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 59839b090..575fefff6 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -39,6 +39,6 @@ FLAGS.num_shelves = 2 FLAGS.blades_per_shelf = 4 FLAGS.iscsi_num_targets = 8 FLAGS.verbose = True -FLAGS.sql_connection = 'sqlite:///nova.sqlite' +FLAGS.sql_connection = 'sqlite:///tests.sqlite' FLAGS.use_ipv6 = True -FLAGS.logfile = 'run_tests.err' +FLAGS.logfile = 'tests.log' -- cgit From 29644fe5a9cf47ae33af31b848c0edc4567f3c09 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 13:46:41 -0800 Subject: switch to explicit call to logging.setup() --- nova/log.py | 44 +++++++++++++++++++++++++------------------- nova/service.py | 2 -- nova/twistd.py | 1 + nova/utils.py | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) (limited to 'nova') diff --git a/nova/log.py b/nova/log.py index 3a48c97ff..10c14d74b 100644 --- a/nova/log.py +++ b/nova/log.py @@ -65,6 +65,7 @@ flags.DEFINE_string('logging_exception_prefix', flags.DEFINE_list('default_log_levels', ['amqplib=WARN', 'sqlalchemy=WARN', + 'boto=WARN', 'eventlet.wsgi.server=WARN'], 'list of logger=LEVEL pairs') @@ -263,26 +264,8 @@ class NovaRootLogger(NovaLogger): self.setLevel(INFO) -if not isinstance(logging.root, NovaRootLogger): - logging._acquireLock() - for handler in logging.root.handlers: - logging.root.removeHandler(handler) - logging.root = NovaRootLogger("nova") - for logger in NovaLogger.manager.loggerDict.itervalues(): - logger.root = logging.root - NovaLogger.root = logging.root - NovaLogger.manager.root = logging.root - NovaLogger.manager.loggerDict["nova"] = logging.root - logging._releaseLock() -root = logging.root - - def handle_exception(type, value, tb): - root.critical(str(value), exc_info=(type, value, tb)) - - -sys.excepthook = handle_exception -logging.setLoggerClass(NovaLogger) + logging.root.critical(str(value), exc_info=(type, value, tb)) def reset(): @@ -292,6 +275,29 @@ def reset(): logger.setup_from_flags() +def setup(): + """Setup nova logging.""" + if not isinstance(logging.root, NovaRootLogger): + logging._acquireLock() + for handler in logging.root.handlers: + logging.root.removeHandler(handler) + logging.root = NovaRootLogger("nova") + NovaLogger.root = logging.root + NovaLogger.manager.root = logging.root + for logger in NovaLogger.manager.loggerDict.itervalues(): + logger.root = logging.root + if isinstance(logger, logging.Logger): + NovaLogger.manager._fixupParents(logger) + NovaLogger.manager.loggerDict["nova"] = logging.root + logging._releaseLock() + sys.excepthook = handle_exception + reset() + + +root = logging.root +logging.setLoggerClass(NovaLogger) + + def audit(msg, *args, **kwargs): """Shortcut for logging to root log with sevrity 'AUDIT'.""" logging.root.log(AUDIT, msg, *args, **kwargs) diff --git a/nova/service.py b/nova/service.py index 02e86f6b3..ddb4d7791 100644 --- a/nova/service.py +++ b/nova/service.py @@ -214,8 +214,6 @@ class Service(object): def serve(*services): - FLAGS(sys.argv) - if not services: services = [Service.create()] diff --git a/nova/twistd.py b/nova/twistd.py index 0e4db022c..c07ed991f 100644 --- a/nova/twistd.py +++ b/nova/twistd.py @@ -148,6 +148,7 @@ def WrapTwistedOptions(wrapped): options.insert(0, '') args = FLAGS(options) + logging.setup() argv = args[1:] # ignore subcommands diff --git a/nova/utils.py b/nova/utils.py index c2fd5f2ee..2a3acf042 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -55,7 +55,7 @@ def import_class(import_str): __import__(mod_str) return getattr(sys.modules[mod_str], class_str) except (ImportError, ValueError, AttributeError), exc: - LOG.info(_('Inner Exception: %s'), exc) + LOG.debug(_('Inner Exception: %s'), exc) raise exception.NotFound(_('Class %s cannot be found') % class_str) -- cgit From dbb071c8424871b6985c6b470d9eff522cdda660 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 13:59:46 -0800 Subject: fix pep8 and remove extra reference to reset --- nova/flags.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/flags.py b/nova/flags.py index e2f7960ec..f64a62da9 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -29,6 +29,7 @@ import sys import gflags + class FlagValues(gflags.FlagValues): """Extension of gflags.FlagValues that allows undefined and runtime flags. @@ -89,8 +90,6 @@ class FlagValues(gflags.FlagValues): self.__dict__['__stored_argv'] = original_argv self.__dict__['__was_already_parsed'] = True self.ClearDirty() - from nova import log as logging - logging.reset() return args def Reset(self): -- cgit From e5d030863eae7f997867350916adf0c721625d26 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 21 Feb 2011 14:55:06 -0800 Subject: add a test for rpc consumer isolation --- nova/tests/test_test.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 nova/tests/test_test.py (limited to 'nova') diff --git a/nova/tests/test_test.py b/nova/tests/test_test.py new file mode 100644 index 000000000..c1d96a148 --- /dev/null +++ b/nova/tests/test_test.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +"""Tests for the testing base code.""" + +from nova import rpc +from nova import test + + +class IsolationTestCase(test.TestCase): + """Ensure that things are cleaned up after failed tests. + + These tests don't really do much here, but if isolation fails a bunch + of other tests should fail. + + """ + def test_rpc_consumer_isolation(self): + connection = rpc.Connection.instance(new=True) + consumer = rpc.TopicConsumer(connection, topic='compute') + consumer.register_callback( + lambda x, y: self.fail('I should never be called')) + consumer.attach_to_eventlet() -- cgit From ab73d72d33369d47012437c022a0679fa4ca3b38 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 21 Feb 2011 14:55:06 -0800 Subject: add a start_service method to our test baseclass --- nova/service.py | 7 +++ nova/test.py | 53 +++++++++++++++++------ nova/tests/test_scheduler.py | 100 +++++++------------------------------------ nova/tests/test_test.py | 3 ++ 4 files changed, 67 insertions(+), 96 deletions(-) (limited to 'nova') diff --git a/nova/service.py b/nova/service.py index 59648adf2..45286cf94 100644 --- a/nova/service.py +++ b/nova/service.py @@ -181,6 +181,13 @@ class Service(object): pass self.timers = [] + def wait(self): + for x in self.timers: + try: + x.wait() + except Exception: + pass + def periodic_tasks(self): """Tasks to be run at a periodic interval""" self.manager.periodic_tasks(context.get_admin_context()) diff --git a/nova/test.py b/nova/test.py index a12cf9d32..9bff401a1 100644 --- a/nova/test.py +++ b/nova/test.py @@ -23,6 +23,7 @@ and some black magic for inline callbacks. """ import datetime +import uuid import unittest import mox @@ -33,6 +34,7 @@ from nova import db from nova import fakerabbit from nova import flags from nova import rpc +from nova import service from nova.network import manager as network_manager from nova.tests import fake_flags @@ -80,6 +82,7 @@ class TestCase(unittest.TestCase): self.stubs = stubout.StubOutForTesting() self.flag_overrides = {} self.injected = [] + self._services = [] self._monkey_patch_attach() self._original_flags = FLAGS.FlagValuesDict() @@ -91,25 +94,42 @@ class TestCase(unittest.TestCase): self.stubs.UnsetAll() self.stubs.SmartUnsetAll() self.mox.VerifyAll() - # NOTE(vish): Clean up any ips associated during the test. - ctxt = context.get_admin_context() - db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host, - self.start) - db.network_disassociate_all(ctxt) + super(TestCase, self).tearDown() + finally: + try: + # Clean up any ips associated during the test. + ctxt = context.get_admin_context() + db.fixed_ip_disassociate_all_by_timeout(ctxt, FLAGS.host, + self.start) + db.network_disassociate_all(ctxt) + + db.security_group_destroy_all(ctxt) + except Exception: + pass + + # Clean out fake_rabbit's queue if we used it + if FLAGS.fake_rabbit: + fakerabbit.reset_all() + + # Reset any overriden flags + self.reset_flags() + + # Reset our monkey-patches rpc.Consumer.attach_to_eventlet = self.originalAttach + + # Stop any timers for x in self.injected: try: x.stop() except AssertionError: pass - if FLAGS.fake_rabbit: - fakerabbit.reset_all() - - db.security_group_destroy_all(ctxt) - super(TestCase, self).tearDown() - finally: - self.reset_flags() + # Kill any services + for x in self._services: + try: + x.kill() + except Exception: + pass def flags(self, **kw): """Override flag variables for a test""" @@ -127,6 +147,15 @@ class TestCase(unittest.TestCase): for k, v in self._original_flags.iteritems(): setattr(FLAGS, k, v) + def start_service(self, name=None, host=None, **kwargs): + host = host and host or uuid.uuid4().hex + kwargs.setdefault('host', host) + kwargs.setdefault('binary', 'nova-%s' % name) + svc = service.Service.create(**kwargs) + svc.start() + self._services.append(svc) + return svc + def _monkey_patch_attach(self): self.originalAttach = rpc.Consumer.attach_to_eventlet diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index 9d458244b..250170072 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -176,18 +176,8 @@ class SimpleDriverTestCase(test.TestCase): def test_doesnt_report_disabled_hosts_as_up(self): """Ensures driver doesn't find hosts before they are enabled""" - # NOTE(vish): constructing service without create method - # because we are going to use it without queue - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() - compute2 = service.Service('host2', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute2.start() + compute1 = self.start_service('compute', host='host1') + compute2 = self.start_service('compute', host='host2') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') s2 = db.service_get_by_args(self.context, 'host2', 'nova-compute') db.service_update(self.context, s1['id'], {'disabled': True}) @@ -199,18 +189,8 @@ class SimpleDriverTestCase(test.TestCase): def test_reports_enabled_hosts_as_up(self): """Ensures driver can find the hosts that are up""" - # NOTE(vish): constructing service without create method - # because we are going to use it without queue - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() - compute2 = service.Service('host2', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute2.start() + compute1 = self.start_service('compute', host='host1') + compute2 = self.start_service('compute', host='host2') hosts = self.scheduler.driver.hosts_up(self.context, 'compute') self.assertEqual(2, len(hosts)) compute1.kill() @@ -218,16 +198,8 @@ class SimpleDriverTestCase(test.TestCase): def test_least_busy_host_gets_instance(self): """Ensures the host with less cores gets the next one""" - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() - compute2 = service.Service('host2', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute2.start() + compute1 = self.start_service('compute', host='host1') + compute2 = self.start_service('compute', host='host2') instance_id1 = self._create_instance() compute1.run_instance(self.context, instance_id1) instance_id2 = self._create_instance() @@ -241,16 +213,8 @@ class SimpleDriverTestCase(test.TestCase): def test_specific_host_gets_instance(self): """Ensures if you set availability_zone it launches on that zone""" - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() - compute2 = service.Service('host2', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute2.start() + compute1 = self.start_service('compute', host='host1') + compute2 = self.start_service('compute', host='host2') instance_id1 = self._create_instance() compute1.run_instance(self.context, instance_id1) instance_id2 = self._create_instance(availability_zone='nova:host1') @@ -263,11 +227,7 @@ class SimpleDriverTestCase(test.TestCase): compute2.kill() def test_wont_sechedule_if_specified_host_is_down(self): - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() + compute1 = self.start_service('compute', host='host1') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') now = datetime.datetime.utcnow() delta = datetime.timedelta(seconds=FLAGS.service_down_time * 2) @@ -282,11 +242,7 @@ class SimpleDriverTestCase(test.TestCase): compute1.kill() def test_will_schedule_on_disabled_host_if_specified(self): - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() + compute1 = self.start_service('compute', host='host1') s1 = db.service_get_by_args(self.context, 'host1', 'nova-compute') db.service_update(self.context, s1['id'], {'disabled': True}) instance_id2 = self._create_instance(availability_zone='nova:host1') @@ -298,16 +254,8 @@ class SimpleDriverTestCase(test.TestCase): def test_too_many_cores(self): """Ensures we don't go over max cores""" - compute1 = service.Service('host1', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute1.start() - compute2 = service.Service('host2', - 'nova-compute', - 'compute', - FLAGS.compute_manager) - compute2.start() + compute1 = self.start_service('compute', host='host1') + compute2 = self.start_service('compute', host='host2') instance_ids1 = [] instance_ids2 = [] for index in xrange(FLAGS.max_cores): @@ -331,16 +279,8 @@ class SimpleDriverTestCase(test.TestCase): def test_least_busy_host_gets_volume(self): """Ensures the host with less gigabytes gets the next one""" - volume1 = service.Service('host1', - 'nova-volume', - 'volume', - FLAGS.volume_manager) - volume1.start() - volume2 = service.Service('host2', - 'nova-volume', - 'volume', - FLAGS.volume_manager) - volume2.start() + volume1 = self.start_service('volume', host='host1') + volume2 = self.start_service('volume', host='host2') volume_id1 = self._create_volume() volume1.create_volume(self.context, volume_id1) volume_id2 = self._create_volume() @@ -354,16 +294,8 @@ class SimpleDriverTestCase(test.TestCase): def test_too_many_gigabytes(self): """Ensures we don't go over max gigabytes""" - volume1 = service.Service('host1', - 'nova-volume', - 'volume', - FLAGS.volume_manager) - volume1.start() - volume2 = service.Service('host2', - 'nova-volume', - 'volume', - FLAGS.volume_manager) - volume2.start() + volume1 = self.start_service('volume', host='host1') + volume2 = self.start_service('volume', host='host2') volume_ids1 = [] volume_ids2 = [] for index in xrange(FLAGS.max_gigabytes): diff --git a/nova/tests/test_test.py b/nova/tests/test_test.py index c1d96a148..e237674e6 100644 --- a/nova/tests/test_test.py +++ b/nova/tests/test_test.py @@ -29,6 +29,9 @@ class IsolationTestCase(test.TestCase): of other tests should fail. """ + def test_service_isolation(self): + self.start_service('compute') + def test_rpc_consumer_isolation(self): connection = rpc.Connection.instance(new=True) consumer = rpc.TopicConsumer(connection, topic='compute') -- cgit From 9003241814ab67817ea910943e932d7b2e542eb6 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 21 Feb 2011 14:55:06 -0800 Subject: move test_cloud to use start_service, too --- nova/tests/test_cloud.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 445cc6e8b..a174ea75d 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -65,10 +65,8 @@ class CloudTestCase(test.TestCase): self.cloud = cloud.CloudController() # set up services - self.compute = service.Service.create(binary='nova-compute') - self.compute.start() - self.network = service.Service.create(binary='nova-network') - self.network.start() + self.compute = self.start_service('compute') + self.network = self.start_service('network') self.manager = manager.AuthManager() self.user = self.manager.create_user('admin', 'admin', 'admin', True) -- cgit From 83e4dcb7184169d4d35769c2d56b21e66c908e75 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 21 Feb 2011 14:55:06 -0800 Subject: remove keyword argument, per review --- nova/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/test.py b/nova/test.py index 9bff401a1..4602f0313 100644 --- a/nova/test.py +++ b/nova/test.py @@ -147,7 +147,7 @@ class TestCase(unittest.TestCase): for k, v in self._original_flags.iteritems(): setattr(FLAGS, k, v) - def start_service(self, name=None, host=None, **kwargs): + def start_service(self, name, host=None, **kwargs): host = host and host or uuid.uuid4().hex kwargs.setdefault('host', host) kwargs.setdefault('binary', 'nova-%s' % name) -- cgit From 4b2a45aa5dc91b24aea53f748906d8a69e40f7c8 Mon Sep 17 00:00:00 2001 From: termie Date: Mon, 21 Feb 2011 15:42:16 -0800 Subject: modify tests to use specific hosts rather than default --- nova/tests/test_cloud.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index a174ea75d..1824d24bc 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -100,7 +100,7 @@ class CloudTestCase(test.TestCase): address = "10.10.10.10" db.floating_ip_create(self.context, {'address': address, - 'host': FLAGS.host}) + 'host': self.network.host}) self.cloud.allocate_address(self.context) self.cloud.describe_addresses(self.context) self.cloud.release_address(self.context, @@ -113,9 +113,9 @@ class CloudTestCase(test.TestCase): address = "10.10.10.10" db.floating_ip_create(self.context, {'address': address, - 'host': FLAGS.host}) + 'host': self.network.host}) self.cloud.allocate_address(self.context) - inst = db.instance_create(self.context, {'host': FLAGS.host}) + inst = db.instance_create(self.context, {'host': self.compute.host}) fixed = self.network.allocate_fixed_ip(self.context, inst['id']) ec2_id = cloud.id_to_ec2_id(inst['id']) self.cloud.associate_address(self.context, -- cgit From 71f7119910f16cb99c10f43a07ccb1e7c0ca473f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 16:05:28 -0800 Subject: remove changes to test db --- nova/tests/fake_flags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index 575fefff6..cfa65c137 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -39,6 +39,6 @@ FLAGS.num_shelves = 2 FLAGS.blades_per_shelf = 4 FLAGS.iscsi_num_targets = 8 FLAGS.verbose = True -FLAGS.sql_connection = 'sqlite:///tests.sqlite' +FLAGS.sql_connection = 'sqlite:///nova.sqlite' FLAGS.use_ipv6 = True FLAGS.logfile = 'tests.log' -- cgit From 11c57867ec18bd61dcc6bde0dc4b459318d54e70 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 21 Feb 2011 16:19:48 -0800 Subject: fixed newline and moved import fake_flags into run_tests where it makes more sense --- nova/test.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova') diff --git a/nova/test.py b/nova/test.py index 8022396cd..bff43b6c7 100644 --- a/nova/test.py +++ b/nova/test.py @@ -36,9 +36,6 @@ from nova import log as logging from nova import rpc from nova.network import manager as network_manager -from nova.tests import fake_flags -logging.reset() - FLAGS = flags.FLAGS flags.DEFINE_bool('flush_db', True, -- cgit