summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/nova-ajax-console-proxy2
-rw-r--r--doc/source/devref/index.rst1
-rw-r--r--doc/source/devref/threading.rst17
-rw-r--r--nova/api/ec2/__init__.py4
-rw-r--r--nova/api/ec2/apirequest.py14
-rw-r--r--nova/api/ec2/cloud.py5
-rw-r--r--nova/api/openstack/contrib/createserverext.py10
-rw-r--r--nova/api/openstack/contrib/security_groups.py2
-rw-r--r--nova/api/openstack/servers.py11
-rw-r--r--nova/api/openstack/views/servers.py10
-rw-r--r--nova/compute/api.py35
-rw-r--r--nova/compute/manager.py2
-rw-r--r--nova/context.py3
-rw-r--r--nova/exception.py8
-rw-r--r--nova/flags.py2
-rw-r--r--nova/local.py37
-rw-r--r--nova/log.py9
-rw-r--r--nova/scheduler/driver.py3
-rw-r--r--nova/scheduler/simple.py28
-rw-r--r--nova/scheduler/zone.py77
-rw-r--r--nova/scheduler/zone_manager.py28
-rw-r--r--nova/tests/api/ec2/test_cloud.py5
-rw-r--r--nova/tests/api/openstack/contrib/test_security_groups.py1222
-rw-r--r--nova/tests/api/openstack/contrib/test_volumes.py3
-rw-r--r--nova/tests/api/openstack/test_servers.py49
-rw-r--r--nova/tests/integrated/test_servers.py4
-rw-r--r--nova/tests/scheduler/test_host_filter.py17
-rw-r--r--nova/tests/scheduler/test_least_cost.py1
-rw-r--r--nova/tests/scheduler/test_scheduler.py152
-rw-r--r--nova/tests/test_compute.py19
-rw-r--r--nova/utils.py22
-rw-r--r--nova/virt/xenapi/vm_utils.py10
32 files changed, 800 insertions, 1012 deletions
diff --git a/bin/nova-ajax-console-proxy b/bin/nova-ajax-console-proxy
index 23fb42fb5..4770a8a7e 100755
--- a/bin/nova-ajax-console-proxy
+++ b/bin/nova-ajax-console-proxy
@@ -141,4 +141,4 @@ if __name__ == '__main__':
server = wsgi.Server("AJAX Console Proxy", acp, port=acp_port)
service.serve(server)
service.wait()
- self.conn.close()
+ acp.conn.close()
diff --git a/doc/source/devref/index.rst b/doc/source/devref/index.rst
index c1c7aa80c..6a22b0e74 100644
--- a/doc/source/devref/index.rst
+++ b/doc/source/devref/index.rst
@@ -35,6 +35,7 @@ Background Concepts for Nova
.. toctree::
:maxdepth: 3
+ threading
distributed_scheduler
multinic
zone
diff --git a/doc/source/devref/threading.rst b/doc/source/devref/threading.rst
new file mode 100644
index 000000000..e499f47e1
--- /dev/null
+++ b/doc/source/devref/threading.rst
@@ -0,0 +1,17 @@
+Threading model
+===============
+
+All OpenStack services use *green thread* model of threading, implemented
+through using the Python `eventlet <http://eventlet.net/>`_ and
+`greenlet <http://packages.python.org/greenlet/>`_ libraries.
+
+Green threads use a cooperative model of threading: thread context
+switches can only occur when specific eventlet or greenlet library calls are
+made (e.g., sleep, certain I/O calls). From the operating system's point of
+view, each OpenStack service runs in a single thread.
+
+The use of green threads reduces the likelihood of race conditions, but does
+not completely eliminate them. In some cases, you may need to use the
+``@utils.synchronized(...)`` decorator to avoid races.
+
+
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index 4b4c0f536..fde1377db 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -391,6 +391,10 @@ class Executor(wsgi.Application):
LOG.info(_('NotAuthorized raised: %s'), unicode(ex),
context=context)
return self._error(req, context, type(ex).__name__, unicode(ex))
+ except exception.InvalidRequest as ex:
+ LOG.debug(_('InvalidRequest raised: %s'), unicode(ex),
+ context=context)
+ return self._error(req, context, type(ex).__name__, unicode(ex))
except Exception as ex:
extra = {'environment': req.environ}
LOG.exception(_('Unexpected error raised: %s'), unicode(ex),
diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py
index 9a3e55925..61b5ba3a5 100644
--- a/nova/api/ec2/apirequest.py
+++ b/nova/api/ec2/apirequest.py
@@ -24,10 +24,14 @@ import datetime
# TODO(termie): replace minidom with etree
from xml.dom import minidom
+from nova import flags
from nova import log as logging
+from nova import exception
from nova.api.ec2 import ec2utils
+from nova.api.ec2.admin import AdminController
LOG = logging.getLogger("nova.api.request")
+FLAGS = flags.FLAGS
def _underscore_to_camelcase(str):
@@ -53,6 +57,14 @@ class APIRequest(object):
def invoke(self, context):
try:
+ # Raise NotImplemented exception for Admin specific request if
+ # admin flag is set to false in nova.conf
+ if (isinstance(self.controller, AdminController) and
+ (not FLAGS.allow_ec2_admin_api)):
+ ## Raise InvalidRequest exception for EC2 Admin interface ##
+ LOG.exception("Unsupported API request")
+ raise exception.InvalidRequest()
+
method = getattr(self.controller,
ec2utils.camelcase_to_underscore(self.action))
except AttributeError:
@@ -63,7 +75,7 @@ class APIRequest(object):
LOG.exception(_error)
# TODO: Raise custom exception, trap in apiserver,
# and reraise as 400 error.
- raise Exception(_error)
+ raise exception.InvalidRequest()
args = ec2utils.dict_from_dotted_str(self.args.items())
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 16ea74025..b2aa120e6 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -1437,10 +1437,7 @@ class CloudController(object):
security_group=kwargs.get('security_group'),
availability_zone=kwargs.get('placement', {}).get(
'AvailabilityZone'),
- block_device_mapping=kwargs.get('block_device_mapping', {}),
- # NOTE(comstud): Unfortunately, EC2 requires that the
- # instance DB entries have been created..
- wait_for_instances=True)
+ block_device_mapping=kwargs.get('block_device_mapping', {}))
return self._format_run_instances(context, resv_id)
def _do_instance(self, action, context, ec2_id):
diff --git a/nova/api/openstack/contrib/createserverext.py b/nova/api/openstack/contrib/createserverext.py
index da95164e8..ab5037304 100644
--- a/nova/api/openstack/contrib/createserverext.py
+++ b/nova/api/openstack/contrib/createserverext.py
@@ -21,10 +21,12 @@ from nova.api.openstack import wsgi
class CreateServerController(servers.Controller):
- def _build_view(self, req, instance, is_detail=False):
- server = super(CreateServerController, self)._build_view(req,
- instance,
- is_detail)
+ def _build_view(self, req, instance, is_detail=False, is_create=False):
+ server = super(CreateServerController, self).\
+ _build_view(req,
+ instance,
+ is_detail=is_detail,
+ is_create=is_create)
if is_detail:
self._build_security_groups(server['server'], instance)
return server
diff --git a/nova/api/openstack/contrib/security_groups.py b/nova/api/openstack/contrib/security_groups.py
index 662711951..9072a34ee 100644
--- a/nova/api/openstack/contrib/security_groups.py
+++ b/nova/api/openstack/contrib/security_groups.py
@@ -251,7 +251,7 @@ class SecurityGroupRulesController(SecurityGroupController):
cidr=None, group_id=None):
values = {}
- if group_id:
+ if group_id is not None:
try:
parent_group_id = int(parent_group_id)
group_id = int(group_id)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 29160c5ce..b71e5df31 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -462,8 +462,7 @@ class Controller(object):
user_data=user_data,
availability_zone=availability_zone,
config_drive=config_drive,
- block_device_mapping=block_device_mapping,
- wait_for_instances=not ret_resv_id)
+ block_device_mapping=block_device_mapping)
except quota.QuotaError as error:
self._handle_quota_error(error)
except exception.InstanceTypeMemoryTooSmall as error:
@@ -497,7 +496,7 @@ class Controller(object):
instance['instance_type'] = inst_type
instance['image_ref'] = image_href
- server = self._build_view(req, instance, is_detail=True)
+ server = self._build_view(req, instance, is_create=True)
if '_is_precooked' in server['server']:
del server['server']['_is_precooked']
else:
@@ -748,7 +747,7 @@ class Controller(object):
return common.get_id_from_href(flavor_ref)
- def _build_view(self, req, instance, is_detail=False):
+ def _build_view(self, req, instance, is_detail=False, is_create=False):
context = req.environ['nova.context']
project_id = getattr(context, 'project_id', '')
base_url = req.application_url
@@ -757,7 +756,9 @@ class Controller(object):
addresses_builder = views_addresses.ViewBuilder()
builder = views_servers.ViewBuilder(context, addresses_builder,
flavor_builder, image_builder, base_url, project_id)
- return builder.build(instance, is_detail=is_detail)
+ return builder.build(instance,
+ is_detail=is_detail,
+ is_create=is_create)
def _build_list(self, req, instances, is_detail=False):
params = req.GET.copy()
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 288730efe..4a0be46c1 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -41,13 +41,15 @@ class ViewBuilder(object):
self.base_url = base_url
self.project_id = project_id
- def build(self, inst, is_detail=False):
+ def build(self, inst, is_detail=False, is_create=False):
"""Return a dict that represenst a server."""
if inst.get('_is_precooked', False):
server = dict(server=inst)
else:
if is_detail:
server = self._build_detail(inst)
+ elif is_create:
+ server = self._build_create(inst)
else:
server = self._build_simple(inst)
@@ -59,6 +61,12 @@ class ViewBuilder(object):
"""Return a simple model of a server."""
return dict(server=dict(id=inst['uuid'], name=inst['display_name']))
+ def _build_create(self, inst):
+ """Return data that should be returned from a server create."""
+ server = dict(server=dict(id=inst['uuid']))
+ self._build_links(server['server'], inst)
+ return server
+
def _build_detail(self, inst):
"""Returns a detailed model of a server."""
vm_state = inst.get('vm_state', vm_states.BUILDING)
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 436dc79b5..b6ba86eb3 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -45,6 +45,7 @@ LOG = logging.getLogger('nova.compute.api')
FLAGS = flags.FLAGS
+flags.DECLARE('enable_zone_routing', 'nova.scheduler.api')
flags.DECLARE('vncproxy_topic', 'nova.vnc')
flags.DEFINE_integer('find_host_timeout', 30,
'Timeout after NN seconds when looking for a host.')
@@ -189,8 +190,7 @@ class API(base.Base):
injected_files, admin_password, zone_blob,
reservation_id, access_ip_v4, access_ip_v6,
requested_networks, config_drive,
- block_device_mapping,
- wait_for_instances):
+ block_device_mapping, create_instance_here=False):
"""Verify all the input parameters regardless of the provisioning
strategy being performed and schedule the instance(s) for
creation."""
@@ -325,10 +325,18 @@ class API(base.Base):
LOG.debug(_("Going to run %s instances...") % num_instances)
- if wait_for_instances:
- rpc_method = rpc.call
- else:
+ if create_instance_here:
+ instance = self.create_db_entry_for_new_instance(
+ context, instance_type, image, base_options,
+ security_group, block_device_mapping)
+ # Tells scheduler we created the instance already.
+ base_options['id'] = instance['id']
rpc_method = rpc.cast
+ else:
+ # We need to wait for the scheduler to create the instance
+ # DB entries, because the instance *could* be # created in
+ # a child zone.
+ rpc_method = rpc.call
# TODO(comstud): We should use rpc.multicall when we can
# retrieve the full instance dictionary from the scheduler.
@@ -344,6 +352,8 @@ class API(base.Base):
num_instances, requested_networks,
block_device_mapping, security_group)
+ if create_instance_here:
+ return ([instance], reservation_id)
return (instances, reservation_id)
@staticmethod
@@ -534,8 +544,7 @@ class API(base.Base):
injected_files=None, admin_password=None, zone_blob=None,
reservation_id=None, block_device_mapping=None,
access_ip_v4=None, access_ip_v6=None,
- requested_networks=None, config_drive=None,
- wait_for_instances=True):
+ requested_networks=None, config_drive=None):
"""
Provision instances, sending instance information to the
scheduler. The scheduler will determine where the instance(s)
@@ -546,6 +555,13 @@ class API(base.Base):
we waited for information from the scheduler or not.
"""
+ # We can create the DB entry for the instance here if we're
+ # only going to create 1 instance and we're in a single
+ # zone deployment. This speeds up API responses for builds
+ # as we don't need to wait for the scheduler.
+ create_instance_here = (max_count == 1 and
+ not FLAGS.enable_zone_routing)
+
(instances, reservation_id) = self._create_instance(
context, instance_type,
image_href, kernel_id, ramdisk_id,
@@ -557,10 +573,9 @@ class API(base.Base):
reservation_id, access_ip_v4, access_ip_v6,
requested_networks, config_drive,
block_device_mapping,
- wait_for_instances)
+ create_instance_here=create_instance_here)
- if instances is None:
- # wait_for_instances must have been False
+ if create_instance_here or instances is None:
return (instances, reservation_id)
inst_ret_list = []
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b1e75cd9a..ddd878664 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -470,7 +470,7 @@ class ComputeManager(manager.SchedulerDependentManager):
# be fixed once we have no-db-messaging
pass
except:
- with utils.original_exception_raised():
+ with utils.save_and_reraise_exception():
_deallocate_network()
def _get_instance_volume_bdms(self, context, instance_id):
diff --git a/nova/context.py b/nova/context.py
index de5b791c4..36d15ba08 100644
--- a/nova/context.py
+++ b/nova/context.py
@@ -1,5 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright 2011 OpenStack LLC.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
@@ -20,6 +21,7 @@
import uuid
+from nova import local
from nova import utils
@@ -51,6 +53,7 @@ class RequestContext(object):
self.request_id = request_id
self.auth_token = auth_token
self.strategy = strategy
+ local.store.context = self
def to_dict(self):
return {'user_id': self.user_id,
diff --git a/nova/exception.py b/nova/exception.py
index 998fece1e..1b80a0f56 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -107,6 +107,8 @@ def wrap_exception(notifier=None, publisher_id=None, event_type=None,
# TODO(sandy): Find a way to import nova.notifier.api so we don't have
# to pass it in as a parameter. Otherwise we get a cyclic import of
# nova.notifier.api -> nova.utils -> nova.exception :(
+ # TODO(johannes): Also, it would be nice to use
+ # utils.save_and_reraise_exception() without an import loop
def inner(f):
def wrapped(*args, **kw):
try:
@@ -206,6 +208,10 @@ class Invalid(NovaException):
message = _("Unacceptable parameters.")
+class InvalidRequest(Invalid):
+ message = _("The request is invalid.")
+
+
class InvalidSignature(Invalid):
message = _("Invalid signature %(signature)s for user %(user)s.")
@@ -567,7 +573,7 @@ class NoFloatingIpsDefined(NotFound):
class KeypairNotFound(NotFound):
- message = _("Keypair %(keypair_name)s not found for user %(user_id)s")
+ message = _("Keypair %(name)s not found for user %(user_id)s")
class CertificateNotFound(NotFound):
diff --git a/nova/flags.py b/nova/flags.py
index 20225eba5..bc4fd475d 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -474,3 +474,5 @@ DEFINE_integer('reclaim_instance_interval', 0,
DEFINE_integer('zombie_instance_updated_at_window', 172800,
'Limit in seconds that a zombie instance can exist before '
'being cleaned up.')
+
+DEFINE_boolean('allow_ec2_admin_api', False, 'Enable/Disable EC2 Admin API')
diff --git a/nova/local.py b/nova/local.py
new file mode 100644
index 000000000..19d962732
--- /dev/null
+++ b/nova/local.py
@@ -0,0 +1,37 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 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.
+
+"""Greenthread local storage of variables using weak references"""
+
+import weakref
+
+from eventlet import corolocal
+
+
+class WeakLocal(corolocal.local):
+ def __getattribute__(self, attr):
+ rval = corolocal.local.__getattribute__(self, attr)
+ if rval:
+ rval = rval()
+ return rval
+
+ def __setattr__(self, attr, value):
+ value = weakref.ref(value)
+ return corolocal.local.__setattr__(self, attr, value)
+
+
+store = WeakLocal()
diff --git a/nova/log.py b/nova/log.py
index 1e04f755d..23b83ab5b 100644
--- a/nova/log.py
+++ b/nova/log.py
@@ -1,5 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright 2011 OpenStack LLC.
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
@@ -38,6 +39,7 @@ import traceback
import nova
from nova import flags
+from nova import local
from nova import version
@@ -152,6 +154,8 @@ class NovaLogger(logging.Logger):
"""Extract context from any log call."""
if not extra:
extra = {}
+ if context is None:
+ context = getattr(local.store, 'context', None)
if context:
extra.update(_dictify_context(context))
extra.update({"nova_version": version.version_string_with_vcs()})
@@ -245,11 +249,12 @@ class NovaRootLogger(NovaLogger):
def setup_from_flags(self):
"""Setup logger from flags."""
global _filelog
+ if self.syslog:
+ self.removeHandler(self.syslog)
+ self.syslog = None
if FLAGS.use_syslog:
self.syslog = SysLogHandler(address='/dev/log')
self.addHandler(self.syslog)
- elif self.syslog:
- self.removeHandler(self.syslog)
logpath = _get_log_file_path()
if logpath:
self.removeHandler(self.streamlog)
diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py
index 7c79d28c9..af39b2edb 100644
--- a/nova/scheduler/driver.py
+++ b/nova/scheduler/driver.py
@@ -155,6 +155,9 @@ class Scheduler(object):
def create_instance_db_entry(self, context, request_spec):
"""Create instance DB entry based on request_spec"""
base_options = request_spec['instance_properties']
+ if base_options.get('id'):
+ # Instance was already created before calling scheduler
+ return db.instance_get(context, base_options['id'])
image = request_spec['image']
instance_type = request_spec.get('instance_type')
security_group = request_spec.get('security_group', 'default')
diff --git a/nova/scheduler/simple.py b/nova/scheduler/simple.py
index cce1509b8..6768205ad 100644
--- a/nova/scheduler/simple.py
+++ b/nova/scheduler/simple.py
@@ -23,7 +23,6 @@ Simple Scheduler
from nova import db
from nova import flags
-from nova import utils
from nova.scheduler import driver
from nova.scheduler import chance
@@ -44,9 +43,11 @@ class SimpleScheduler(chance.ChanceScheduler):
availability_zone = instance_opts.get('availability_zone')
- if availability_zone and context.is_admin and \
- (':' in availability_zone):
- zone, host = availability_zone.split(':', 1)
+ zone, host = None, None
+ if availability_zone:
+ zone, _x, host = availability_zone.partition(':')
+
+ if host and context.is_admin:
service = db.service_get_by_args(context.elevated(), host,
'nova-compute')
if not self.service_is_up(service):
@@ -54,6 +55,9 @@ class SimpleScheduler(chance.ChanceScheduler):
return host
results = db.service_get_all_compute_sorted(context)
+ if zone:
+ results = [(service, cores) for (service, cores) in results
+ if service['availability_zone'] == zone]
for result in results:
(service, instance_cores) = result
if instance_cores + instance_opts['vcpus'] > FLAGS.max_cores:
@@ -82,15 +86,17 @@ class SimpleScheduler(chance.ChanceScheduler):
host = self._schedule_instance(context, instance_ref,
*_args, **_kwargs)
driver.cast_to_compute_host(context, host, 'start_instance',
- instance_id=intance_id, **_kwargs)
+ instance_id=instance_id, **_kwargs)
def schedule_create_volume(self, context, volume_id, *_args, **_kwargs):
"""Picks a host that is up and has the fewest volumes."""
volume_ref = db.volume_get(context, volume_id)
- if (volume_ref['availability_zone']
- and ':' in volume_ref['availability_zone']
- and context.is_admin):
- zone, _x, host = volume_ref['availability_zone'].partition(':')
+ availability_zone = volume_ref.get('availability_zone')
+
+ zone, host = None, None
+ if availability_zone:
+ zone, _x, host = availability_zone.partition(':')
+ if host and context.is_admin:
service = db.service_get_by_args(context.elevated(), host,
'nova-volume')
if not self.service_is_up(service):
@@ -98,7 +104,11 @@ class SimpleScheduler(chance.ChanceScheduler):
driver.cast_to_volume_host(context, host, 'create_volume',
volume_id=volume_id, **_kwargs)
return None
+
results = db.service_get_all_volume_sorted(context)
+ if zone:
+ results = [(service, gigs) for (service, gigs) in results
+ if service['availability_zone'] == zone]
for result in results:
(service, volume_gigabytes) = result
if volume_gigabytes + volume_ref['size'] > FLAGS.max_gigabytes:
diff --git a/nova/scheduler/zone.py b/nova/scheduler/zone.py
deleted file mode 100644
index c369477f8..000000000
--- a/nova/scheduler/zone.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright (c) 2010 Openstack, LLC.
-# 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.
-
-"""
-Availability Zone Scheduler implementation
-"""
-
-import random
-
-from nova.scheduler import driver
-from nova import db
-
-
-class ZoneScheduler(driver.Scheduler):
- """Implements Scheduler as a random node selector."""
-
- def hosts_up_with_zone(self, context, topic, zone):
- """Return the list of hosts that have a running service
- for topic and availability zone (if defined).
- """
-
- if not zone:
- return self.hosts_up(context, topic)
-
- services = db.service_get_all_by_topic(context, topic)
- return [service.host
- for service in services
- if self.service_is_up(service)
- and service.availability_zone == zone]
-
- def _schedule(self, context, topic, request_spec, **kwargs):
- """Picks a host that is up at random in selected
- availability zone (if defined).
- """
-
- zone = kwargs.get('availability_zone')
- if not zone and request_spec:
- zone = request_spec['instance_properties'].get(
- 'availability_zone')
- hosts = self.hosts_up_with_zone(context.elevated(), topic, zone)
- if not hosts:
- raise driver.NoValidHost(_("Scheduler was unable to locate a host"
- " for this request. Is the appropriate"
- " service running?"))
- return hosts[int(random.random() * len(hosts))]
-
- def schedule(self, context, topic, method, *_args, **kwargs):
- host = self._schedule(context, topic, None, **kwargs)
- driver.cast_to_host(context, topic, host, method, **kwargs)
-
- def schedule_run_instance(self, context, request_spec, *_args, **kwargs):
- """Builds and starts instances on selected hosts"""
- num_instances = request_spec.get('num_instances', 1)
- instances = []
- for num in xrange(num_instances):
- host = self._schedule(context, 'compute', request_spec, **kwargs)
- instance = self.create_instance_db_entry(context, request_spec)
- driver.cast_to_compute_host(context, host,
- 'run_instance', instance_id=instance['id'], **kwargs)
- instances.append(driver.encode_instance(instance))
- return instances
diff --git a/nova/scheduler/zone_manager.py b/nova/scheduler/zone_manager.py
index 3ccd5015e..f6d895a55 100644
--- a/nova/scheduler/zone_manager.py
+++ b/nova/scheduler/zone_manager.py
@@ -22,9 +22,8 @@ import thread
import traceback
import UserDict
-from novaclient import v1_1 as novaclient
-
from eventlet import greenpool
+from novaclient import v1_1 as novaclient
from nova import db
from nova import flags
@@ -33,9 +32,13 @@ from nova import utils
FLAGS = flags.FLAGS
flags.DEFINE_integer('zone_db_check_interval', 60,
- 'Seconds between getting fresh zone info from db.')
+ 'Seconds between getting fresh zone info from db.')
flags.DEFINE_integer('zone_failures_to_offline', 3,
- 'Number of consecutive errors before marking zone offline')
+ 'Number of consecutive errors before marking zone offline')
+flags.DEFINE_integer('reserved_host_disk_mb', 0,
+ 'Amount of disk in MB to reserve for host/dom0')
+flags.DEFINE_integer('reserved_host_memory_mb', 512,
+ 'Amount of memory in MB to reserve for host/dom0')
class ZoneState(object):
@@ -228,17 +231,26 @@ class ZoneManager(object):
for compute in compute_nodes:
all_disk = compute['local_gb']
all_ram = compute['memory_mb']
- host = compute['service']['host']
+ service = compute['service']
+ if not service:
+ LOG.warn(_("No service for compute ID %s") % compute['id'])
+ continue
+ host = service['host']
caps = self.service_states.get(host, None)
- host_info_map[host] = HostInfo(host, caps=caps,
- free_disk_gb=all_disk,
- free_ram_mb=all_ram)
+ host_info = HostInfo(host, caps=caps,
+ free_disk_gb=all_disk, free_ram_mb=all_ram)
+ # Reserve resources for host/dom0
+ host_info.consume_resources(FLAGS.reserved_host_disk_mb * 1024,
+ FLAGS.reserved_host_memory_mb)
+ host_info_map[host] = host_info
# "Consume" resources from the host the instance resides on.
instances = self._instance_get_all(context)
for instance in instances:
host = instance['host']
+ if not host:
+ continue
host_info = host_info_map.get(host, None)
if not host_info:
continue
diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
index c0f3d44d7..f76690831 100644
--- a/nova/tests/api/ec2/test_cloud.py
+++ b/nova/tests/api/ec2/test_cloud.py
@@ -1013,8 +1013,6 @@ class CloudTestCase(test.TestCase):
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
self._expected_bdms2, 'deviceName')
- self.stubs.UnsetAll()
-
def test_describe_image_attribute(self):
describe_image_attribute = self.cloud.describe_image_attribute
@@ -1216,6 +1214,9 @@ class CloudTestCase(test.TestCase):
self.stubs.UnsetAll()
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
+ # NOTE(comstud): Make 'cast' behave like a 'call' which will
+ # ensure that operations complete
+ self.stubs.Set(rpc, 'cast', rpc.call)
result = run_instances(self.context, **kwargs)
instance = result['instancesSet'][0]
diff --git a/nova/tests/api/openstack/contrib/test_security_groups.py b/nova/tests/api/openstack/contrib/test_security_groups.py
index 65e60df7f..f55ce4a55 100644
--- a/nova/tests/api/openstack/contrib/test_security_groups.py
+++ b/nova/tests/api/openstack/contrib/test_security_groups.py
@@ -30,31 +30,44 @@ from nova.tests.api.openstack import fakes
FAKE_UUID = 'a47ae74e-ab08-447f-8eee-ffd43fc46c16'
-def _get_create_request_json(body_dict):
- req = webob.Request.blank('/v1.1/123/os-security-groups')
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body_dict)
- return req
+class AttrDict(dict):
+ def __getattr__(self, k):
+ return self[k]
-def _create_security_group_json(security_group):
- body_dict = _create_security_group_request_dict(security_group)
- request = _get_create_request_json(body_dict)
- response = request.get_response(fakes.wsgi_app())
- return response
+def security_group_template(**kwargs):
+ sg = kwargs.copy()
+ sg.setdefault('tenant_id', '123')
+ sg.setdefault('name', 'test')
+ sg.setdefault('description', 'test-description')
+ return sg
-def _create_security_group_request_dict(security_group):
- sg = {}
- if security_group is not None:
- name = security_group.get('name', None)
- description = security_group.get('description', None)
- if name:
- sg['name'] = security_group['name']
- if description:
- sg['description'] = security_group['description']
- return {'security_group': sg}
+def security_group_db(security_group, id=None):
+ attrs = security_group.copy()
+ if 'tenant_id' in attrs:
+ attrs['project_id'] = attrs.pop('tenant_id')
+ if id is not None:
+ attrs['id'] = id
+ attrs.setdefault('rules', [])
+ attrs.setdefault('instances', [])
+ return AttrDict(attrs)
+
+
+def security_group_rule_template(**kwargs):
+ rule = kwargs.copy()
+ rule.setdefault('ip_protocol', 'tcp')
+ rule.setdefault('from_port', 22)
+ rule.setdefault('to_port', 22)
+ rule.setdefault('parent_group_id', 2)
+ return rule
+
+
+def security_group_rule_db(rule, id=None):
+ attrs = rule.copy()
+ if 'ip_protocol' in attrs:
+ attrs['protocol'] = attrs.pop('ip_protocol')
+ return AttrDict(attrs)
def return_server(context, server_id):
@@ -72,13 +85,11 @@ def return_server_by_uuid(context, server_uuid):
def return_non_running_server(context, server_id):
- return {'id': server_id, 'state': 0x02,
- 'host': "localhost"}
+ return {'id': server_id, 'state': 0x02, 'host': "localhost"}
-def return_security_group(context, project_id, group_name):
- return {'id': 1, 'name': group_name, "instances": [
- {'id': 1}]}
+def return_security_group_by_name(context, project_id, group_name):
+ return {'id': 1, 'name': group_name, "instances": [{'id': 1}]}
def return_security_group_without_instances(context, project_id, group_name):
@@ -89,328 +100,251 @@ def return_server_nonexistent(context, server_id):
raise exception.InstanceNotFound(instance_id=server_id)
+class StubExtensionManager(object):
+ def register(self, *args):
+ pass
+
+
class TestSecurityGroups(test.TestCase):
def setUp(self):
super(TestSecurityGroups, self).setUp()
+ self.controller = security_groups.SecurityGroupController()
+ self.manager = security_groups.Security_groups(StubExtensionManager())
+
def tearDown(self):
super(TestSecurityGroups, self).tearDown()
- def _create_security_group_request_dict(self, security_group):
- sg = {}
- if security_group is not None:
- name = security_group.get('name', None)
- description = security_group.get('description', None)
- if name:
- sg['name'] = security_group['name']
- if description:
- sg['description'] = security_group['description']
- return {'security_group': sg}
-
- def _format_create_xml_request_body(self, body_dict):
- sg = body_dict['security_group']
- body_parts = []
- body_parts.extend([
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<security_group xmlns="http://docs.openstack.org/ext/'
- 'securitygroups/api/v1.1"',
- ' name="%s">' % (sg['name'])])
- if 'description' in sg:
- body_parts.append('<description>%s</description>'
- % sg['description'])
- body_parts.append('</security_group>')
- return ''.join(body_parts)
-
- def _get_create_request_xml(self, body_dict):
- req = webob.Request.blank('/v1.1/123/os-security-groups')
- req.headers['Content-Type'] = 'application/xml'
- req.content_type = 'application/xml'
- req.accept = 'application/xml'
- req.method = 'POST'
- req.body = self._format_create_xml_request_body(body_dict)
- return req
-
- def _create_security_group_xml(self, security_group):
- body_dict = self._create_security_group_request_dict(security_group)
- request = self._get_create_request_xml(body_dict)
- response = request.get_response(fakes.wsgi_app())
- return response
-
- def _delete_security_group(self, id):
- request = webob.Request.blank('/v1.1/123/os-security-groups/%s'
- % id)
- request.method = 'DELETE'
- response = request.get_response(fakes.wsgi_app())
- return response
-
- def test_create_security_group_json(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- res_dict = json.loads(response.body)
- self.assertEqual(res_dict['security_group']['name'], "test")
+ def test_create_security_group(self):
+ sg = security_group_template()
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ res_dict = self.controller.create(req, {'security_group': sg})
+ self.assertEqual(res_dict['security_group']['name'], 'test')
self.assertEqual(res_dict['security_group']['description'],
- "group-description")
- self.assertEquals(response.status_int, 200)
-
- def test_create_security_group_xml(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = \
- self._create_security_group_xml(security_group)
-
- self.assertEquals(response.status_int, 200)
- dom = minidom.parseString(response.body)
- sg = dom.childNodes[0]
- self.assertEquals(sg.nodeName, 'security_group')
- self.assertEqual(security_group['name'], sg.getAttribute('name'))
-
- def test_create_security_group_with_no_name_json(self):
- security_group = {}
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_no_description_json(self):
- security_group = {}
- security_group['name'] = "test"
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_blank_name_json(self):
- security_group = {}
- security_group['name'] = ""
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_whitespace_name_json(self):
- security_group = {}
- security_group['name'] = " "
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_blank_description_json(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = ""
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_whitespace_description_json(self):
- security_group = {}
- security_group['name'] = "name"
- security_group['description'] = " "
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_duplicate_name_json(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
-
- self.assertEquals(response.status_int, 200)
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_with_no_body_json(self):
- request = _get_create_request_json(body_dict=None)
- response = request.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 422)
+ 'test-description')
+
+ def test_create_security_group_with_no_name(self):
+ sg = security_group_template()
+ del sg['name']
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, sg)
+
+ def test_create_security_group_with_no_description(self):
+ sg = security_group_template()
+ del sg['description']
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_blank_name(self):
+ sg = security_group_template(name='')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_whitespace_name(self):
+ sg = security_group_template(name=' ')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_blank_description(self):
+ sg = security_group_template(description='')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_whitespace_description(self):
+ sg = security_group_template(description=' ')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_duplicate_name(self):
+ sg = security_group_template()
+
+ # FIXME: Stub out _get instead of creating twice
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.controller.create(req, {'security_group': sg})
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_with_no_body(self):
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, None)
def test_create_security_group_with_no_security_group(self):
- body_dict = {}
- body_dict['no-securityGroup'] = None
- request = _get_create_request_json(body_dict)
- response = request.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 422)
-
- def test_create_security_group_above_255_characters_name_json(self):
- security_group = {}
- security_group['name'] = ("1234567890123456"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890")
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
-
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_above_255_characters_description_json(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = ("1234567890123456"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890"
- "1234567890123456789012345678901234567890")
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_non_string_name_json(self):
- security_group = {}
- security_group['name'] = 12
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
-
- def test_create_security_group_non_string_description_json(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = 12
- response = _create_security_group_json(security_group)
- self.assertEquals(response.status_int, 400)
+ body = {'no-securityGroup': None}
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, body)
+
+ def test_create_security_group_above_255_characters_name(self):
+ sg = security_group_template(name='1234567890' * 26)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_above_255_characters_description(self):
+ sg = security_group_template(description='1234567890' * 26)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_non_string_name(self):
+ sg = security_group_template(name=12)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
+
+ def test_create_security_group_non_string_description(self):
+ sg = security_group_template(description=12)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group': sg})
def test_get_security_group_list(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
-
- req = webob.Request.blank('/v1.1/123/os-security-groups')
- req.headers['Content-Type'] = 'application/json'
- req.method = 'GET'
- response = req.get_response(fakes.wsgi_app())
- res_dict = json.loads(response.body)
-
- expected = {'security_groups': [
- {'id': 1,
- 'name':"default",
- 'tenant_id': "123",
- "description":"default",
- "rules": []
- },
- ]
- }
- expected['security_groups'].append(
- {
- 'id': 2,
- 'name': "test",
- 'tenant_id': "123",
- "description": "group-description",
- "rules": []
- }
- )
- self.assertEquals(response.status_int, 200)
+ groups = []
+ for i, name in enumerate(['default', 'test']):
+ sg = security_group_template(id=i + 1,
+ name=name,
+ description=name + '-desc',
+ rules=[])
+ groups.append(sg)
+ expected = {'security_groups': groups}
+
+ def return_security_groups(context, project_id):
+ return [security_group_db(sg) for sg in groups]
+
+ self.stubs.Set(nova.db, 'security_group_get_by_project',
+ return_security_groups)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups')
+ res_dict = self.controller.index(req)
+
self.assertEquals(res_dict, expected)
def test_get_security_group_by_id(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
-
- res_dict = json.loads(response.body)
- req = webob.Request.blank('/v1.1/123/os-security-groups/%s' %
- res_dict['security_group']['id'])
- req.headers['Content-Type'] = 'application/json'
- req.method = 'GET'
- response = req.get_response(fakes.wsgi_app())
- res_dict = json.loads(response.body)
+ sg = security_group_template(id=2, rules=[])
- expected = {
- 'security_group': {
- 'id': 2,
- 'name': "test",
- 'tenant_id': "123",
- 'description': "group-description",
- 'rules': []
- }
- }
+ def return_security_group(context, group_id):
+ self.assertEquals(sg['id'], group_id)
+ return security_group_db(sg)
+
+ self.stubs.Set(nova.db, 'security_group_get',
+ return_security_group)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/2')
+ res_dict = self.controller.show(req, '2')
+
+ expected = {'security_group': sg}
self.assertEquals(res_dict, expected)
def test_get_security_group_by_invalid_id(self):
- req = webob.Request.blank('/v1.1/123/os-security-groups/invalid')
- req.headers['Content-Type'] = 'application/json'
- req.method = 'GET'
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/invalid')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete,
+ req, 'invalid')
def test_get_security_group_by_non_existing_id(self):
- req = webob.Request.blank('/v1.1/123/os-security-groups/111111111')
- req.headers['Content-Type'] = 'application/json'
- req.method = 'GET'
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 404)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/111111111')
+ self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
+ req, '111111111')
def test_delete_security_group_by_id(self):
- security_group = {}
- security_group['name'] = "test"
- security_group['description'] = "group-description"
- response = _create_security_group_json(security_group)
- security_group = json.loads(response.body)['security_group']
- response = self._delete_security_group(security_group['id'])
- self.assertEquals(response.status_int, 202)
+ sg = security_group_template(id=1, rules=[])
+
+ self.called = False
+
+ def security_group_destroy(context, id):
+ self.called = True
+
+ def return_security_group(context, group_id):
+ self.assertEquals(sg['id'], group_id)
+ return security_group_db(sg)
+
+ self.stubs.Set(nova.db, 'security_group_destroy',
+ security_group_destroy)
+ self.stubs.Set(nova.db, 'security_group_get',
+ return_security_group)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/1')
+ self.controller.delete(req, '1')
- response = self._delete_security_group(security_group['id'])
- self.assertEquals(response.status_int, 404)
+ self.assertTrue(self.called)
def test_delete_security_group_by_invalid_id(self):
- response = self._delete_security_group('invalid')
- self.assertEquals(response.status_int, 400)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/invalid')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete,
+ req, 'invalid')
def test_delete_security_group_by_non_existing_id(self):
- response = self._delete_security_group(11111111)
- self.assertEquals(response.status_int, 404)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-groups/11111111')
+ self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
+ req, '11111111')
def test_associate_by_non_existing_security_group_name(self):
body = dict(addSecurityGroup=dict(name='non-existing'))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 404)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._addSecurityGroup, body, req, '1')
+
+ def test_associate_by_invalid_server_id(self):
+ body = dict(addSecurityGroup=dict(name='test'))
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/invalid/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._addSecurityGroup, body, req, 'invalid')
def test_associate_without_body(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(addSecurityGroup=None)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate_no_security_group_name(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(addSecurityGroup=dict())
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate_security_group_name_with_whitespaces(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(addSecurityGroup=dict(name=" "))
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate_non_existing_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_server_nonexistent)
self.stubs.Set(nova.db, 'instance_get_by_uuid',
return_server_nonexistent)
body = dict(addSecurityGroup=dict(name="test"))
- self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 404)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate_non_running_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_non_running_server)
@@ -419,26 +353,22 @@ class TestSecurityGroups(test.TestCase):
self.stubs.Set(nova.db, 'security_group_get_by_name',
return_security_group_without_instances)
body = dict(addSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate_already_associated_security_group_to_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_server)
self.stubs.Set(nova.db, 'instance_get_by_uuid',
return_server_by_uuid)
self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
+ return_security_group_by_name)
body = dict(addSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._addSecurityGroup, body, req, '1')
def test_associate(self):
self.stubs.Set(nova.db, 'instance_get', return_server)
@@ -446,104 +376,79 @@ class TestSecurityGroups(test.TestCase):
return_server_by_uuid)
self.mox.StubOutWithMock(nova.db, 'instance_add_security_group')
nova.db.instance_add_security_group(mox.IgnoreArg(),
- mox.IgnoreArg(),
- mox.IgnoreArg())
+ mox.IgnoreArg(),
+ mox.IgnoreArg())
self.stubs.Set(nova.db, 'security_group_get_by_name',
return_security_group_without_instances)
self.mox.ReplayAll()
body = dict(addSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 202)
-
- def test_associate_xml(self):
- self.stubs.Set(nova.db, 'instance_get', return_server)
- self.stubs.Set(nova.db, 'instance_get_by_uuid',
- return_server_by_uuid)
- self.mox.StubOutWithMock(nova.db, 'instance_add_security_group')
- nova.db.instance_add_security_group(mox.IgnoreArg(),
- mox.IgnoreArg(),
- mox.IgnoreArg())
- self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group_without_instances)
- self.mox.ReplayAll()
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/xml'
- req.method = 'POST'
- req.body = """<addSecurityGroup>
- <name>test</name>
- </addSecurityGroup>"""
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 202)
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.manager._addSecurityGroup(body, req, '1')
def test_disassociate_by_non_existing_security_group_name(self):
body = dict(removeSecurityGroup=dict(name='non-existing'))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 404)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._removeSecurityGroup, body, req, '1')
+
+ def test_disassociate_by_invalid_server_id(self):
+ self.stubs.Set(nova.db, 'security_group_get_by_name',
+ return_security_group_by_name)
+ body = dict(removeSecurityGroup=dict(name='test'))
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/invalid/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._removeSecurityGroup, body, req,
+ 'invalid')
def test_disassociate_without_body(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(removeSecurityGroup=None)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate_no_security_group_name(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(removeSecurityGroup=dict())
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate_security_group_name_with_whitespaces(self):
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
+ self.stubs.Set(nova.db, 'instance_get', return_server)
body = dict(removeSecurityGroup=dict(name=" "))
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate_non_existing_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_server_nonexistent)
- self.stubs.Set(nova.db, 'instance_get_by_uuid',
- return_server_nonexistent)
- body = dict(removeSecurityGroup=dict(name="test"))
self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 404)
+ return_security_group_by_name)
+ body = dict(removeSecurityGroup=dict(name="test"))
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPNotFound,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate_non_running_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_non_running_server)
self.stubs.Set(nova.db, 'instance_get_by_uuid',
return_non_running_server)
self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
+ return_security_group_by_name)
body = dict(removeSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate_already_associated_security_group_to_instance(self):
self.stubs.Set(nova.db, 'instance_get', return_server)
@@ -552,12 +457,10 @@ class TestSecurityGroups(test.TestCase):
self.stubs.Set(nova.db, 'security_group_get_by_name',
return_security_group_without_instances)
body = dict(removeSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 400)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.manager._removeSecurityGroup, body, req, '1')
def test_disassociate(self):
self.stubs.Set(nova.db, 'instance_get', return_server)
@@ -568,377 +471,242 @@ class TestSecurityGroups(test.TestCase):
mox.IgnoreArg(),
mox.IgnoreArg())
self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
+ return_security_group_by_name)
self.mox.ReplayAll()
body = dict(removeSecurityGroup=dict(name="test"))
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/json'
- req.method = 'POST'
- req.body = json.dumps(body)
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 202)
-
- def test_disassociate_xml(self):
- self.stubs.Set(nova.db, 'instance_get', return_server)
- self.stubs.Set(nova.db, 'instance_get_by_uuid',
- return_server_by_uuid)
- self.mox.StubOutWithMock(nova.db, 'instance_remove_security_group')
- nova.db.instance_remove_security_group(mox.IgnoreArg(),
- mox.IgnoreArg(),
- mox.IgnoreArg())
- self.stubs.Set(nova.db, 'security_group_get_by_name',
- return_security_group)
- self.mox.ReplayAll()
- req = webob.Request.blank('/v1.1/123/servers/%s/action' % FAKE_UUID)
- req.headers['Content-Type'] = 'application/xml'
- req.method = 'POST'
- req.body = """<removeSecurityGroup>
- <name>test</name>
- </removeSecurityGroup>"""
- response = req.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 202)
+ req = fakes.HTTPRequest.blank('/v1.1/123/servers/1/action')
+ self.manager._removeSecurityGroup(body, req, '1')
class TestSecurityGroupRules(test.TestCase):
def setUp(self):
super(TestSecurityGroupRules, self).setUp()
- security_group = {}
- security_group['name'] = "authorize-revoke"
- security_group['description'] = ("Security group created for "
- " authorize-revoke testing")
- response = _create_security_group_json(security_group)
- security_group = json.loads(response.body)
- self.parent_security_group = security_group['security_group']
-
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "parent_group_id": self.parent_security_group['id'],
- "cidr": "10.0.0.0/24"
- }
- }
- res = self._create_security_group_rule_json(rules)
- self.assertEquals(res.status_int, 200)
- self.security_group_rule = json.loads(res.body)['security_group_rule']
+
+ controller = security_groups.SecurityGroupController()
+
+ sg1 = security_group_template(id=1)
+ sg2 = security_group_template(id=2,
+ name='authorize_revoke',
+ description='authorize-revoke testing')
+ db1 = security_group_db(sg1)
+ db2 = security_group_db(sg2)
+
+ def return_security_group(context, group_id):
+ if group_id == db1['id']:
+ return db1
+ if group_id == db2['id']:
+ return db2
+ raise exception.NotFound()
+
+ self.stubs.Set(nova.db, 'security_group_get',
+ return_security_group)
+
+ self.parent_security_group = db2
+
+ self.controller = security_groups.SecurityGroupRulesController()
def tearDown(self):
super(TestSecurityGroupRules, self).tearDown()
- def _create_security_group_rule_json(self, rules):
- request = webob.Request.blank('/v1.1/123/os-security-group-rules')
- request.headers['Content-Type'] = 'application/json'
- request.method = 'POST'
- request.body = json.dumps(rules)
- response = request.get_response(fakes.wsgi_app())
- return response
-
- def _delete_security_group_rule(self, id):
- request = webob.Request.blank('/v1.1/123/os-security-group-rules/%s'
- % id)
- request.method = 'DELETE'
- response = request.get_response(fakes.wsgi_app())
- return response
-
- def test_create_by_cidr_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "parent_group_id": 2,
- "cidr": "10.2.3.124/24"
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- security_group_rule = json.loads(response.body)['security_group_rule']
- self.assertEquals(response.status_int, 200)
+ def test_create_by_cidr(self):
+ rule = security_group_rule_template(cidr='10.2.3.124/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ res_dict = self.controller.create(req, {'security_group_rule': rule})
+
+ security_group_rule = res_dict['security_group_rule']
self.assertNotEquals(security_group_rule['id'], 0)
self.assertEquals(security_group_rule['parent_group_id'], 2)
self.assertEquals(security_group_rule['ip_range']['cidr'],
"10.2.3.124/24")
- def test_create_by_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "1",
- "parent_group_id": "%s"
- % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 200)
- security_group_rule = json.loads(response.body)['security_group_rule']
+ def test_create_by_group_id(self):
+ rule = security_group_rule_template(group_id='1')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ res_dict = self.controller.create(req, {'security_group_rule': rule})
+
+ security_group_rule = res_dict['security_group_rule']
self.assertNotEquals(security_group_rule['id'], 0)
self.assertEquals(security_group_rule['parent_group_id'], 2)
- def test_create_add_existing_rules_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "cidr": "10.0.0.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_no_body_json(self):
- request = webob.Request.blank('/v1.1/123/os-security-group-rules')
- request.headers['Content-Type'] = 'application/json'
- request.method = 'POST'
- request.body = json.dumps(None)
- response = request.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 422)
-
- def test_create_with_no_security_group_rule_in_body_json(self):
- request = webob.Request.blank('/v1.1/123/os-security-group-rules')
- request.headers['Content-Type'] = 'application/json'
- request.method = 'POST'
- body_dict = {'test': "test"}
- request.body = json.dumps(body_dict)
- response = request.get_response(fakes.wsgi_app())
- self.assertEquals(response.status_int, 422)
-
- def test_create_with_invalid_parent_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "parent_group_id": "invalid"
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_non_existing_parent_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "invalid",
- "parent_group_id": "1111111111111"
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 404)
-
- def test_create_with_invalid_protocol_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "invalid-protocol",
- "from_port": "22",
- "to_port": "22",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_no_protocol_json(self):
- rules = {
- "security_group_rule": {
- "from_port": "22",
- "to_port": "22",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_invalid_from_port_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "666666",
- "to_port": "22",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_invalid_to_port_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "666666",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_non_numerical_from_port_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "invalid",
- "to_port": "22",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_non_numerical_to_port_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "invalid",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_no_to_port_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "cidr": "10.2.2.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_invalid_cidr_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "cidr": "10.2.22222.0/24",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_no_cidr_group_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- security_group_rule = json.loads(response.body)['security_group_rule']
- self.assertEquals(response.status_int, 200)
+ def test_create_add_existing_rules(self):
+ rule = security_group_rule_template(cidr='10.0.0.0/24')
+
+ self.parent_security_group['rules'] = [security_group_rule_db(rule)]
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_no_body(self):
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, None)
+
+ def test_create_with_no_security_group_rule_in_body(self):
+ rules = {'test': 'test'}
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPUnprocessableEntity,
+ self.controller.create, req, rules)
+
+ def test_create_with_invalid_parent_group_id(self):
+ rule = security_group_rule_template(parent_group_id='invalid')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_non_existing_parent_group_id(self):
+ rule = security_group_rule_template(group_id='invalid',
+ parent_group_id='1111111111111')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPNotFound, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_invalid_protocol(self):
+ rule = security_group_rule_template(ip_protocol='invalid-protocol',
+ cidr='10.2.2.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_no_protocol(self):
+ rule = security_group_rule_template(cidr='10.2.2.0/24')
+ del rule['ip_protocol']
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_invalid_from_port(self):
+ rule = security_group_rule_template(from_port='666666',
+ cidr='10.2.2.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_invalid_to_port(self):
+ rule = security_group_rule_template(to_port='666666',
+ cidr='10.2.2.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_non_numerical_from_port(self):
+ rule = security_group_rule_template(from_port='invalid',
+ cidr='10.2.2.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_non_numerical_to_port(self):
+ rule = security_group_rule_template(to_port='invalid',
+ cidr='10.2.2.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_no_from_port(self):
+ rule = security_group_rule_template(cidr='10.2.2.0/24')
+ del rule['from_port']
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_no_to_port(self):
+ rule = security_group_rule_template(cidr='10.2.2.0/24')
+ del rule['to_port']
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_invalid_cidr(self):
+ rule = security_group_rule_template(cidr='10.2.2222.0/24')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_no_cidr_group(self):
+ rule = security_group_rule_template()
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ res_dict = self.controller.create(req, {'security_group_rule': rule})
+
+ security_group_rule = res_dict['security_group_rule']
self.assertNotEquals(security_group_rule['id'], 0)
self.assertEquals(security_group_rule['parent_group_id'],
self.parent_security_group['id'])
self.assertEquals(security_group_rule['ip_range']['cidr'],
"0.0.0.0/0")
- def test_create_with_invalid_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "invalid",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_empty_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "invalid",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_with_invalid_group_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "222222",
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
-
- def test_create_rule_with_same_group_parent_id_json(self):
- rules = {
- "security_group_rule": {
- "ip_protocol": "tcp",
- "from_port": "22",
- "to_port": "22",
- "group_id": "%s" % self.parent_security_group['id'],
- "parent_group_id": "%s" % self.parent_security_group['id'],
- }
- }
-
- response = self._create_security_group_rule_json(rules)
- self.assertEquals(response.status_int, 400)
+ def test_create_with_invalid_group_id(self):
+ rule = security_group_rule_template(group_id='invalid')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_empty_group_id(self):
+ rule = security_group_rule_template(group_id='')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_with_nonexist_group_id(self):
+ rule = security_group_rule_template(group_id='222222')
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
+ def test_create_rule_with_same_group_parent_id(self):
+ rule = security_group_rule_template(group_id=2)
+
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
def test_delete(self):
- response = self._delete_security_group_rule(
- self.security_group_rule['id'])
- self.assertEquals(response.status_int, 202)
+ rule = security_group_rule_template(id=10)
+
+ def security_group_rule_get(context, id):
+ return security_group_rule_db(rule)
+
+ def security_group_rule_destroy(context, id):
+ pass
+
+ self.stubs.Set(nova.db, 'security_group_rule_get',
+ security_group_rule_get)
+ self.stubs.Set(nova.db, 'security_group_rule_destroy',
+ security_group_rule_destroy)
- response = self._delete_security_group_rule(
- self.security_group_rule['id'])
- self.assertEquals(response.status_int, 404)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules/10')
+ self.controller.delete(req, '10')
def test_delete_invalid_rule_id(self):
- response = self._delete_security_group_rule('invalid')
- self.assertEquals(response.status_int, 400)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules' +
+ '/invalid')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete,
+ req, 'invalid')
def test_delete_non_existing_rule_id(self):
- response = self._delete_security_group_rule(22222222222222)
- self.assertEquals(response.status_int, 404)
+ req = fakes.HTTPRequest.blank('/v1.1/123/os-security-group-rules' +
+ '/22222222222222')
+ self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
+ req, '22222222222222')
class TestSecurityGroupRulesXMLDeserializer(unittest.TestCase):
diff --git a/nova/tests/api/openstack/contrib/test_volumes.py b/nova/tests/api/openstack/contrib/test_volumes.py
index 0a3023e48..a130d1140 100644
--- a/nova/tests/api/openstack/contrib/test_volumes.py
+++ b/nova/tests/api/openstack/contrib/test_volumes.py
@@ -81,9 +81,6 @@ class BootFromVolumeTest(test.TestCase):
self.assertEqual(res.status_int, 200)
server = json.loads(res.body)['server']
self.assertEqual(FAKE_UUID, server['id'])
- self.assertEqual(2, int(server['flavor']['id']))
- self.assertEqual(u'test_server', server['name'])
- self.assertEqual(IMAGE_UUID, server['image']['id'])
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self.assertEqual(len(_block_device_mapping_seen), 1)
self.assertEqual(_block_device_mapping_seen[0]['volume_id'], 1)
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index e6e528535..31c87e630 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -1354,7 +1354,7 @@ class ServersControllerCreateTest(test.TestCase):
self.instance_cache_num += 1
instance = {
'id': self.instance_cache_num,
- 'display_name': 'server_test',
+ 'display_name': inst['display_name'] or 'test',
'uuid': FAKE_UUID,
'instance_type': dict(inst_type),
'access_ip_v4': '1.2.3.4',
@@ -1390,8 +1390,10 @@ class ServersControllerCreateTest(test.TestCase):
request_spec['instance_properties']))
return instances
- def server_update(context, id, params):
- return instance_create(context, id)
+ def server_update(context, instance_id, params):
+ inst = self.instance_cache[instance_id]
+ inst.update(params)
+ return inst
def fake_method(*args, **kwargs):
pass
@@ -1441,10 +1443,7 @@ class ServersControllerCreateTest(test.TestCase):
server = self.controller.create(req, body)['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
- self.assertEqual('server_test', server['name'])
self.assertEqual(FAKE_UUID, server['id'])
- self.assertEqual('2', server['flavor']['id'])
- self.assertEqual(image_uuid, server['image']['id'])
def test_create_multiple_instances(self):
"""Test creating multiple instances but not asking for
@@ -1613,12 +1612,6 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self.assertEqual(FAKE_UUID, server['id'])
- self.assertEqual(0, server['progress'])
- self.assertEqual('server_test', server['name'])
- self.assertEqual(expected_flavor, server['flavor'])
- self.assertEqual(expected_image, server['image'])
- self.assertEqual(access_ipv4, server['accessIPv4'])
- self.assertEqual(access_ipv6, server['accessIPv6'])
def test_create_instance(self):
# proper local hrefs must start with 'http://localhost/v1.1/'
@@ -1670,13 +1663,6 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self.assertEqual(FAKE_UUID, server['id'])
- self.assertEqual("BUILD", server["status"])
- self.assertEqual(0, server['progress'])
- self.assertEqual('server_test', server['name'])
- self.assertEqual(expected_flavor, server['flavor'])
- self.assertEqual(expected_image, server['image'])
- self.assertEqual('1.2.3.4', server['accessIPv4'])
- self.assertEqual('fead::1234', server['accessIPv6'])
def test_create_instance_invalid_key_name(self):
image_href = 'http://localhost/v1.1/images/2'
@@ -1777,7 +1763,6 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(FAKE_UUID, server['id'])
- self.assertTrue(server['config_drive'])
def test_create_instance_with_config_drive_as_id(self):
self.config_drive = 2
@@ -1805,8 +1790,6 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(FAKE_UUID, server['id'])
- self.assertTrue(server['config_drive'])
- self.assertEqual(2, server['config_drive'])
def test_create_instance_with_bad_config_drive(self):
self.config_drive = "asdf"
@@ -1859,7 +1842,6 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(FAKE_UUID, server['id'])
- self.assertFalse(server['config_drive'])
def test_create_instance_bad_href(self):
image_href = 'asdf'
@@ -1879,24 +1861,6 @@ class ServersControllerCreateTest(test.TestCase):
def test_create_instance_local_href(self):
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
flavor_ref = 'http://localhost/v1.1/flavors/3'
- expected_flavor = {
- "id": "3",
- "links": [
- {
- "rel": "bookmark",
- "href": 'http://localhost/fake/flavors/3',
- },
- ],
- }
- expected_image = {
- "id": image_uuid,
- "links": [
- {
- "rel": "bookmark",
- "href": 'http://localhost/fake/images/%s' % image_uuid,
- },
- ],
- }
body = {
'server': {
'name': 'server_test',
@@ -1912,8 +1876,7 @@ class ServersControllerCreateTest(test.TestCase):
res = self.controller.create(req, body)
server = res['server']
- self.assertEqual(expected_flavor, server['flavor'])
- self.assertEqual(expected_image, server['image'])
+ self.assertEqual(FAKE_UUID, server['id'])
def test_create_instance_admin_pass(self):
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py
index 36f62ac01..58aca5778 100644
--- a/nova/tests/integrated/test_servers.py
+++ b/nova/tests/integrated/test_servers.py
@@ -292,10 +292,6 @@ class ServersTest(integrated_helpers._IntegratedTestBase):
self.assertTrue(created_server['id'])
created_server_id = created_server['id']
- # Reenable when bug fixed
- self.assertEqual(metadata, created_server.get('metadata'))
- # Check it's there
-
found_server = self.api.get_server(created_server_id)
self.assertEqual(created_server_id, found_server['id'])
self.assertEqual(metadata, found_server.get('metadata'))
diff --git a/nova/tests/scheduler/test_host_filter.py b/nova/tests/scheduler/test_host_filter.py
index 96f26b23c..b5b5aadef 100644
--- a/nova/tests/scheduler/test_host_filter.py
+++ b/nova/tests/scheduler/test_host_filter.py
@@ -56,7 +56,8 @@ class HostFilterTestCase(test.TestCase):
def setUp(self):
super(HostFilterTestCase, self).setUp()
default_host_filters = ['AllHostsFilter']
- self.flags(default_host_filters=default_host_filters)
+ self.flags(default_host_filters=default_host_filters,
+ reserved_host_disk_mb=0, reserved_host_memory_mb=0)
self.instance_type = dict(name='tiny',
memory_mb=30,
vcpus=10,
@@ -139,6 +140,20 @@ class HostFilterTestCase(test.TestCase):
self.assertEquals('host3', just_hosts[1])
self.assertEquals('host2', just_hosts[0])
+ def test_instance_type_filter_reserved_memory(self):
+ self.flags(reserved_host_memory_mb=2048)
+ hf = nova.scheduler.filters.InstanceTypeFilter()
+ # filter all hosts that can support 30 ram and 300 disk after
+ # reserving 2048 ram
+ cooked = hf.instance_type_to_filter(self.instance_type)
+ all_hosts = self._get_all_hosts()
+ hosts = hf.filter_hosts(all_hosts, cooked)
+ self.assertEquals(2, len(hosts))
+ just_hosts = [host for host, hostinfo in hosts]
+ just_hosts.sort()
+ self.assertEquals('host4', just_hosts[1])
+ self.assertEquals('host3', just_hosts[0])
+
def test_instance_type_filter_extra_specs(self):
hf = nova.scheduler.filters.InstanceTypeFilter()
# filter all hosts that can support 30 ram and 300 disk
diff --git a/nova/tests/scheduler/test_least_cost.py b/nova/tests/scheduler/test_least_cost.py
index ba6cdb686..a45e95181 100644
--- a/nova/tests/scheduler/test_least_cost.py
+++ b/nova/tests/scheduler/test_least_cost.py
@@ -32,6 +32,7 @@ def scale(hostinfo):
class LeastCostTestCase(test.TestCase):
def setUp(self):
super(LeastCostTestCase, self).setUp()
+ self.flags(reserved_host_disk_mb=0, reserved_host_memory_mb=0)
self.zone_manager = fake_zone_manager.FakeZoneManager()
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index df1ccce61..472def879 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -21,12 +21,10 @@ Tests For Scheduler
import datetime
import mox
-import stubout
from novaclient import v1_1 as novaclient
from novaclient import exceptions as novaclient_exceptions
-from mox import IgnoreArg
from nova import context
from nova import db
from nova import exception
@@ -35,13 +33,10 @@ from nova import service
from nova import test
from nova import rpc
from nova import utils
-from nova.db.sqlalchemy import models
from nova.scheduler import api
from nova.scheduler import driver
from nova.scheduler import manager
-from nova.scheduler import multi
from nova.scheduler.simple import SimpleScheduler
-from nova.scheduler.zone import ZoneScheduler
from nova.compute import power_state
from nova.compute import vm_states
@@ -84,7 +79,7 @@ def _create_volume():
"""Create a test volume"""
vol = {}
vol['size'] = 1
- vol['availability_zone'] = 'test'
+ vol['availability_zone'] = 'nova'
ctxt = context.get_admin_context()
return db.volume_create(ctxt, vol)['id']
@@ -250,77 +245,6 @@ class SchedulerTestCase(test.TestCase):
db.instance_destroy(ctxt, i_ref2['id'])
-class ZoneSchedulerTestCase(test.TestCase):
- """Test case for zone scheduler"""
- def setUp(self):
- super(ZoneSchedulerTestCase, self).setUp()
- self.flags(
- scheduler_driver='nova.scheduler.multi.MultiScheduler',
- compute_scheduler_driver='nova.scheduler.zone.ZoneScheduler',
- volume_scheduler_driver='nova.scheduler.zone.ZoneScheduler')
-
- def _create_service_model(self, **kwargs):
- service = db.sqlalchemy.models.Service()
- service.host = kwargs['host']
- service.disabled = False
- service.deleted = False
- service.report_count = 0
- service.binary = 'nova-compute'
- service.topic = 'compute'
- service.id = kwargs['id']
- service.availability_zone = kwargs['zone']
- service.created_at = utils.utcnow()
- return service
-
- def test_with_two_zones(self):
- scheduler = manager.SchedulerManager()
- ctxt = context.RequestContext('user', 'project')
- service_list = [self._create_service_model(id=1,
- host='host1',
- zone='zone1'),
- self._create_service_model(id=2,
- host='host2',
- zone='zone2'),
- self._create_service_model(id=3,
- host='host3',
- zone='zone2'),
- self._create_service_model(id=4,
- host='host4',
- zone='zone2'),
- self._create_service_model(id=5,
- host='host5',
- zone='zone2')]
-
- request_spec = _create_request_spec(availability_zone='zone1')
-
- fake_instance = _create_instance_dict(
- **request_spec['instance_properties'])
- fake_instance['id'] = 100
- fake_instance['uuid'] = FAKE_UUID
-
- self.mox.StubOutWithMock(db, 'service_get_all_by_topic')
- self.mox.StubOutWithMock(db, 'instance_update')
- # Assumes we're testing with MultiScheduler
- compute_sched_driver = scheduler.driver.drivers['compute']
- self.mox.StubOutWithMock(compute_sched_driver,
- 'create_instance_db_entry')
- self.mox.StubOutWithMock(rpc, 'cast', use_mock_anything=True)
-
- arg = IgnoreArg()
- db.service_get_all_by_topic(arg, arg).AndReturn(service_list)
- compute_sched_driver.create_instance_db_entry(arg,
- request_spec).AndReturn(fake_instance)
- db.instance_update(arg, 100, {'host': 'host1', 'scheduled_at': arg})
- rpc.cast(arg,
- 'compute.host1',
- {'method': 'run_instance',
- 'args': {'instance_id': 100}})
- self.mox.ReplayAll()
- scheduler.run_instance(ctxt,
- 'compute',
- request_spec=request_spec)
-
-
class SimpleDriverTestCase(test.TestCase):
"""Test case for simple driver"""
def setUp(self):
@@ -444,7 +368,7 @@ class SimpleDriverTestCase(test.TestCase):
compute2.kill()
def test_specific_host_gets_instance_no_queue(self):
- """Ensures if you set availability_zone it launches on that zone"""
+ """Ensures if you set zone:host it launches on that host"""
compute1 = service.Service('host1',
'nova-compute',
'compute',
@@ -533,6 +457,78 @@ class SimpleDriverTestCase(test.TestCase):
compute1.terminate_instance(self.context, instance_ids[0])
compute1.kill()
+ def test_specific_zone_gets_instance_no_queue(self):
+ """Ensures if you set availability_zone it launches on that zone"""
+ self.flags(node_availability_zone='zone1')
+ compute1 = service.Service('host1',
+ 'nova-compute',
+ 'compute',
+ FLAGS.compute_manager)
+ compute1.start()
+ self.flags(node_availability_zone='zone2')
+ compute2 = service.Service('host2',
+ 'nova-compute',
+ 'compute',
+ FLAGS.compute_manager)
+ compute2.start()
+
+ global instance_ids
+ instance_ids = []
+ instance_ids.append(_create_instance()['id'])
+ compute1.run_instance(self.context, instance_ids[0])
+
+ self.stubs.Set(SimpleScheduler,
+ 'create_instance_db_entry', _fake_create_instance_db_entry)
+ global _picked_host
+ _picked_host = None
+ self.stubs.Set(driver,
+ 'cast_to_compute_host', _fake_cast_to_compute_host)
+
+ request_spec = _create_request_spec(availability_zone='zone1')
+ instances = self.scheduler.driver.schedule_run_instance(
+ self.context, request_spec)
+ self.assertEqual(_picked_host, 'host1')
+ self.assertEqual(len(instance_ids), 2)
+
+ compute1.terminate_instance(self.context, instance_ids[0])
+ compute1.terminate_instance(self.context, instance_ids[1])
+ compute1.kill()
+ compute2.kill()
+
+ def test_bad_instance_zone_fails(self):
+ self.flags(node_availability_zone='zone1')
+ compute1 = service.Service('host1',
+ 'nova-compute',
+ 'compute',
+ FLAGS.compute_manager)
+ compute1.start()
+ request_spec = _create_request_spec(availability_zone='zone2')
+ try:
+ self.assertRaises(driver.NoValidHost,
+ self.scheduler.driver.schedule_run_instance,
+ self.context,
+ request_spec)
+ finally:
+ compute1.kill()
+
+ def test_bad_volume_zone_fails(self):
+ self.flags(node_availability_zone='zone1')
+ volume1 = service.Service('host1',
+ 'nova-volume',
+ 'volume',
+ FLAGS.volume_manager)
+ volume1.start()
+ # uses 'nova' for zone
+ volume_id = _create_volume()
+ try:
+ self.assertRaises(driver.NoValidHost,
+ self.scheduler.driver.schedule_create_volume,
+ self.context,
+ volume_id)
+ finally:
+ db.volume_destroy(self.context, volume_id)
+ volume1.kill()
+
def test_too_many_cores_no_queue(self):
"""Ensures we don't go over max cores"""
compute1 = service.Service('host1',
diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py
index addb6084d..7295c9f1f 100644
--- a/nova/tests/test_compute.py
+++ b/nova/tests/test_compute.py
@@ -1409,25 +1409,6 @@ class ComputeTestCase(test.TestCase):
self.assertEqual(instance['reservation_id'], resv_id)
db.instance_destroy(self.context, instance['id'])
- def test_reservation_ids_two_instances_no_wait(self):
- """Verify building 2 instances at once without waiting for
- instance IDs results in a reservation_id being returned equal
- to reservation id set in both instances
- """
- (refs, resv_id) = self.compute_api.create(self.context,
- instance_types.get_default_instance_type(), None,
- min_count=2, max_count=2, wait_for_instances=False)
- try:
- self.assertEqual(refs, None)
- self.assertNotEqual(resv_id, None)
- finally:
- instances = self.compute_api.get_all(self.context,
- search_opts={'reservation_id': resv_id})
- self.assertEqual(len(instances), 2)
- for instance in instances:
- self.assertEqual(instance['reservation_id'], resv_id)
- db.instance_destroy(self.context, instance['id'])
-
def test_create_with_specified_reservation_id(self):
"""Verify building instances with a specified
reservation_id results in the correct reservation_id
diff --git a/nova/utils.py b/nova/utils.py
index 9a01a6fb8..655be744d 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -979,21 +979,27 @@ def generate_glance_url():
@contextlib.contextmanager
-def original_exception_raised():
- """Run some code, then re-raise the original exception.
+def save_and_reraise_exception():
+ """Save current exception, run some code and then re-raise.
- This is needed because when Eventlet switches greenthreads, it clears the
- exception context. This means if exception handler code blocks, we'll lose
- the helpful exception traceback information.
+ In some cases the exception context can be cleared, resulting in None
+ being attempted to be reraised after an exception handler is run. This
+ can happen when eventlet switches greenthreads or when running an
+ exception handler, code raises and catches and exception. In both
+ cases the exception context will be cleared.
To work around this, we save the exception state, run handler code, and
- then re-raise the original exception.
+ then re-raise the original exception. If another exception occurs, the
+ saved exception is logged and the new exception is reraised.
"""
type_, value, traceback = sys.exc_info()
try:
yield
- finally:
- raise type_, value, traceback
+ except:
+ LOG.exception(_('Original exception being dropped'),
+ exc_info=(type_, value, traceback))
+ raise
+ raise type_, value, traceback
def make_dev_path(dev, partition=None, base='/dev'):
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 2778c5bf4..296f9b0e4 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -483,6 +483,12 @@ w
# 2. Attach VDI to compute worker (VBD hotplug)
with vdi_attached_here(session, vdi_ref, read_only=False) as dev:
# 3. Create swap partition
+
+ # NOTE(jk0): We use a FAT32 filesystem for the Windows swap
+ # partition because that is what parted supports.
+ is_windows = instance.os_type == "windows"
+ fs_type = "fat32" if is_windows else "linux-swap"
+
dev_path = utils.make_dev_path(dev)
utils.execute('parted', '--script', dev_path,
'mklabel', 'msdos', run_as_root=True)
@@ -490,7 +496,7 @@ w
partition_start = 0
partition_end = swap_mb
utils.execute('parted', '--script', dev_path, 'mkpartfs',
- 'primary', 'linux-swap',
+ 'primary', fs_type,
str(partition_start),
str(partition_end),
run_as_root=True)
@@ -499,7 +505,7 @@ w
cls.create_vbd(session, vm_ref, vdi_ref, userdevice,
bootable=False)
except:
- with utils.original_exception_raised():
+ with utils.save_and_reraise_exception():
cls.destroy_vdi(session, vdi_ref)
@classmethod