summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@yahoo.com>2010-10-30 17:42:40 -0700
committerVishvananda Ishaya <vishvananda@yahoo.com>2010-10-30 17:42:40 -0700
commit94e6b454183231b2e73b42d2e634889efd777587 (patch)
tree277fb492b068b2118b1ef2a65a968dd8ae23be6d
parent7c74613eb801679c67f551e307265b4af1dc12a6 (diff)
parent56c7e7763fc07f26be40bb8c0c702fc9afe8b1e3 (diff)
downloadnova-94e6b454183231b2e73b42d2e634889efd777587.tar.gz
nova-94e6b454183231b2e73b42d2e634889efd777587.tar.xz
nova-94e6b454183231b2e73b42d2e634889efd777587.zip
merged trunk, just in case
-rwxr-xr-xbin/nova-api9
-rw-r--r--doc/source/_ga/layout.html17
-rw-r--r--doc/source/_templates/.DS_Storebin0 -> 6148 bytes
-rw-r--r--doc/source/conf.py8
-rw-r--r--nova/api/__init__.py34
-rw-r--r--nova/api/ec2/cloud.py34
-rw-r--r--nova/api/openstack/servers.py25
-rw-r--r--nova/compute/manager.py40
-rw-r--r--nova/db/sqlalchemy/api.py66
-rw-r--r--nova/db/sqlalchemy/models.py10
-rw-r--r--nova/test.py156
-rw-r--r--nova/tests/api/__init__.py2
-rw-r--r--nova/tests/api/openstack/fakes.py5
-rw-r--r--nova/tests/api/openstack/test_api.py6
-rw-r--r--nova/tests/api/openstack/test_auth.py18
-rw-r--r--nova/tests/api/openstack/test_flavors.py2
-rw-r--r--nova/tests/api/openstack/test_images.py4
-rw-r--r--nova/tests/api/openstack/test_servers.py32
-rw-r--r--nova/tests/api_unittest.py10
-rw-r--r--nova/tests/service_unittest.py125
-rw-r--r--nova/utils.py5
-rw-r--r--nova/wsgi.py25
22 files changed, 278 insertions, 355 deletions
diff --git a/bin/nova-api b/bin/nova-api
index 20f1bd74f..a9002ae2d 100755
--- a/bin/nova-api
+++ b/bin/nova-api
@@ -37,13 +37,18 @@ from nova import utils
from nova import server
FLAGS = flags.FLAGS
-flags.DEFINE_integer('api_port', 8773, 'API port')
+flags.DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
+flags.DEFINE_integer('ec2api_port', 8773, 'EC2 API port')
def main(_args):
from nova import api
from nova import wsgi
- wsgi.run_server(api.API(), FLAGS.api_port)
+ server = wsgi.Server()
+ server.start(api.API('os'), FLAGS.osapi_port)
+ server.start(api.API('ec2'), FLAGS.ec2api_port)
+ server.wait()
+
if __name__ == '__main__':
utils.default_flagfile()
diff --git a/doc/source/_ga/layout.html b/doc/source/_ga/layout.html
new file mode 100644
index 000000000..0b72a77ac
--- /dev/null
+++ b/doc/source/_ga/layout.html
@@ -0,0 +1,17 @@
+{% extends "!layout.html" %}
+
+{% block footer %}
+{{ super() }}
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+try {
+var pageTracker = _gat._getTracker("UA-17511903-1");
+pageTracker._setDomainName("none");
+pageTracker._setAllowLinker(true);
+pageTracker._trackPageview();
+} catch(err) {}</script>
+{% endblock %}
+
diff --git a/doc/source/_templates/.DS_Store b/doc/source/_templates/.DS_Store
new file mode 100644
index 000000000..5008ddfcf
--- /dev/null
+++ b/doc/source/_templates/.DS_Store
Binary files differ
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 505771ff8..e137e728a 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -27,7 +27,13 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
todo_include_todos = True
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+# Changing the path so that the Hudson build output contains GA code and the source
+# docs do not contain the code so local, offline sphinx builds are "clean."
+templates_path = []
+if os.getenv('HUDSON_PUBLISH_DOCS'):
+ templates_path = ['_ga', '_templates']
+else:
+ templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
diff --git a/nova/api/__init__.py b/nova/api/__init__.py
index 8a1d9fe32..707c1623e 100644
--- a/nova/api/__init__.py
+++ b/nova/api/__init__.py
@@ -35,37 +35,31 @@ flags.DEFINE_string('osapi_subdomain', 'api',
'subdomain running the OpenStack API')
flags.DEFINE_string('ec2api_subdomain', 'ec2',
'subdomain running the EC2 API')
-flags.DEFINE_string('FAKE_subdomain', None,
- 'set to api or ec2 to fake the subdomain of the host '
- 'for testing')
FLAGS = flags.FLAGS
class API(wsgi.Router):
"""Routes top-level requests to the appropriate controller."""
- def __init__(self):
- osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]}
- ec2domain = {'sub_domain': [FLAGS.ec2api_subdomain]}
- # If someone wants to pretend they're hitting the OSAPI subdomain
- # on their local box, they can set FAKE_subdomain to 'api', which
- # removes subdomain restrictions from the OpenStack API routes below.
- if FLAGS.FAKE_subdomain == 'api':
- osapidomain = {}
- elif FLAGS.FAKE_subdomain == 'ec2':
- ec2domain = {}
+ def __init__(self, default_api):
+ osapi_subdomain = {'sub_domain': [FLAGS.osapi_subdomain]}
+ ec2api_subdomain = {'sub_domain': [FLAGS.ec2api_subdomain]}
+ if default_api == 'os':
+ osapi_subdomain = {}
+ elif default_api == 'ec2':
+ ec2api_subdomain = {}
mapper = routes.Mapper()
mapper.sub_domains = True
+
mapper.connect("/", controller=self.osapi_versions,
- conditions=osapidomain)
+ conditions=osapi_subdomain)
mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(),
- conditions=osapidomain)
+ conditions=osapi_subdomain)
mapper.connect("/", controller=self.ec2api_versions,
- conditions=ec2domain)
+ conditions=ec2api_subdomain)
mapper.connect("/services/{path_info:.*}", controller=ec2.API(),
- conditions=ec2domain)
- mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API())
+ conditions=ec2api_subdomain)
mrh = metadatarequesthandler.MetadataRequestHandler()
for s in ['/latest',
'/2009-04-04',
@@ -78,7 +72,9 @@ class API(wsgi.Router):
'/2007-01-19',
'/1.0']:
mapper.connect('%s/{path_info:.*}' % s, controller=mrh,
- conditions=ec2domain)
+ conditions=ec2api_subdomain)
+
+ mapper.connect("/cloudpipe/{path_info:.*}", controller=cloudpipe.API())
super(API, self).__init__(mapper)
@webob.dec.wsgify
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 8aed0763c..fbe4caa48 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -99,6 +99,7 @@ class CloudController(object):
"""
def __init__(self):
self.network_manager = utils.import_object(FLAGS.network_manager)
+ self.compute_manager = utils.import_object(FLAGS.compute_manager)
self.setup()
def __str__(self):
@@ -845,21 +846,21 @@ class CloudController(object):
elevated = context.elevated()
for num in range(num_instances):
- instance_ref = db.instance_create(context, base_options)
- inst_id = instance_ref['id']
- for security_group_id in security_groups:
- db.instance_add_security_group(elevated,
- inst_id,
- security_group_id)
+ instance_ref = self.compute_manager.create_instance(context,
+ security_groups,
+ mac_address=utils.generate_mac(),
+ launch_index=num,
+ **base_options)
+ inst_id = instance_ref['id']
- inst = {}
- inst['mac_address'] = utils.generate_mac()
- inst['launch_index'] = num
internal_id = instance_ref['internal_id']
ec2_id = internal_id_to_ec2_id(internal_id)
- inst['hostname'] = ec2_id
- db.instance_update(context, inst_id, inst)
+
+ self.compute_manager.update_instance(context,
+ inst_id,
+ hostname=ec2_id)
+
# TODO(vish): This probably should be done in the scheduler
# or in compute as a call. The network should be
# allocated after the host is assigned and setup
@@ -905,11 +906,12 @@ class CloudController(object):
id_str)
continue
now = datetime.datetime.utcnow()
- db.instance_update(context,
- instance_ref['id'],
- {'state_description': 'terminating',
- 'state': 0,
- 'terminated_at': now})
+ self.compute_manager.update_instance(context,
+ instance_ref['id'],
+ state_description='terminating',
+ state=0,
+ terminated_at=now)
+
# FIXME(ja): where should network deallocate occur?
address = db.instance_get_floating_address(context,
instance_ref['id'])
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index ef773c3be..1d8aa2fa4 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -95,6 +95,7 @@ class Controller(wsgi.Controller):
db_driver = FLAGS.db_driver
self.db_driver = utils.import_object(db_driver)
self.network_manager = utils.import_object(FLAGS.network_manager)
+ self.compute_manager = utils.import_object(FLAGS.compute_manager)
super(Controller, self).__init__()
def index(self, req):
@@ -242,34 +243,30 @@ class Controller(wsgi.Controller):
inst['memory_mb'] = flavor['memory_mb']
inst['vcpus'] = flavor['vcpus']
inst['local_gb'] = flavor['local_gb']
-
- ref = self.db_driver.instance_create(ctxt, inst)
- inst['id'] = ref.internal_id
-
inst['mac_address'] = utils.generate_mac()
-
- #TODO(dietz) is this necessary?
inst['launch_index'] = 0
- inst['hostname'] = str(ref.internal_id)
- self.db_driver.instance_update(ctxt, inst['id'], inst)
+ ref = self.compute_manager.create_instance(ctxt, **inst)
+ inst['id'] = ref['internal_id']
+
+ inst['hostname'] = str(ref['internal_id'])
+ self.compute_manager.update_instance(ctxt, inst['id'], **inst)
- network_manager = utils.import_object(FLAGS.network_manager)
- address = network_manager.allocate_fixed_ip(ctxt,
- inst['id'])
+ address = self.network_manager.allocate_fixed_ip(ctxt,
+ inst['id'])
# TODO(vish): This probably should be done in the scheduler
# network is setup when host is assigned
- network_topic = self._get_network_topic(ctxt, network_manager)
+ network_topic = self._get_network_topic(ctxt)
rpc.call(ctxt,
network_topic,
{"method": "setup_fixed_ip",
"args": {"address": address}})
return inst
- def _get_network_topic(self, context, network_manager):
+ def _get_network_topic(self, context):
"""Retrieves the network host for a project"""
- network_ref = network_manager.get_network(context)
+ network_ref = self.network_manager.get_network(context)
host = network_ref['host']
if not host:
host = rpc.call(context,
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b9ba6852a..d50607aca 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -69,6 +69,46 @@ class ComputeManager(manager.Manager):
def refresh_security_group(self, context, security_group_id, **_kwargs):
yield self.driver.refresh_security_group(security_group_id)
+ def create_instance(self, context, security_groups=[], **kwargs):
+ """Creates the instance in the datastore and returns the
+ new instance as a mapping
+
+ :param context: The security context
+ :param security_groups: list of security group ids to
+ attach to the instance
+ :param **kwargs: All additional keyword args are treated
+ as data fields of the instance to be
+ created
+
+ :retval Returns a mapping of the instance information
+ that has just been created
+
+ """
+ instance_ref = self.db.instance_create(context, kwargs)
+ inst_id = instance_ref['id']
+
+ elevated = context.elevated()
+ security_groups = kwargs.get('security_groups', [])
+ for security_group_id in security_groups:
+ self.db.instance_add_security_group(elevated,
+ inst_id,
+ security_group_id)
+ return instance_ref
+
+ def update_instance(self, context, instance_id, **kwargs):
+ """Updates the instance in the datastore
+
+ :param context: The security context
+ :param instance_id: ID of the instance to update
+ :param **kwargs: All additional keyword args are treated
+ as data fields of the instance to be
+ updated
+
+ :retval None
+
+ """
+ self.db.instance_update(context, instance_id, kwargs)
+
@defer.inlineCallbacks
@exception.wrap_exception
def run_instance(self, context, instance_id, **_kwargs):
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index b6bddd2a2..db4d9f68f 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -236,8 +236,7 @@ def service_get_by_args(context, host, binary):
@require_admin_context
def service_create(context, values):
service_ref = models.Service()
- for (key, value) in values.iteritems():
- service_ref[key] = value
+ service_ref.update(values)
service_ref.save()
return service_ref
@@ -247,8 +246,7 @@ def service_update(context, service_id, values):
session = get_session()
with session.begin():
service_ref = service_get(context, service_id, session=session)
- for (key, value) in values.iteritems():
- service_ref[key] = value
+ service_ref.update(values)
service_ref.save(session=session)
@@ -279,8 +277,7 @@ def floating_ip_allocate_address(context, host, project_id):
@require_context
def floating_ip_create(context, values):
floating_ip_ref = models.FloatingIp()
- for (key, value) in values.iteritems():
- floating_ip_ref[key] = value
+ floating_ip_ref.update(values)
floating_ip_ref.save()
return floating_ip_ref['address']
@@ -451,8 +448,7 @@ def fixed_ip_associate_pool(context, network_id, instance_id):
@require_context
def fixed_ip_create(_context, values):
fixed_ip_ref = models.FixedIp()
- for (key, value) in values.iteritems():
- fixed_ip_ref[key] = value
+ fixed_ip_ref.update(values)
fixed_ip_ref.save()
return fixed_ip_ref['address']
@@ -523,8 +519,7 @@ def fixed_ip_update(context, address, values):
fixed_ip_ref = fixed_ip_get_by_address(context,
address,
session=session)
- for (key, value) in values.iteritems():
- fixed_ip_ref[key] = value
+ fixed_ip_ref.update(values)
fixed_ip_ref.save(session=session)
@@ -537,8 +532,7 @@ def fixed_ip_update(context, address, values):
@require_context
def instance_create(context, values):
instance_ref = models.Instance()
- for (key, value) in values.iteritems():
- instance_ref[key] = value
+ instance_ref.update(values)
session = get_session()
with session.begin():
@@ -731,8 +725,7 @@ def instance_update(context, instance_id, values):
session = get_session()
with session.begin():
instance_ref = instance_get(context, instance_id, session=session)
- for (key, value) in values.iteritems():
- instance_ref[key] = value
+ instance_ref.update(values)
instance_ref.save(session=session)
@@ -754,8 +747,7 @@ def instance_add_security_group(context, instance_id, security_group_id):
@require_context
def key_pair_create(context, values):
key_pair_ref = models.KeyPair()
- for (key, value) in values.iteritems():
- key_pair_ref[key] = value
+ key_pair_ref.update(values)
key_pair_ref.save()
return key_pair_ref
@@ -870,8 +862,7 @@ def network_count_reserved_ips(context, network_id):
@require_admin_context
def network_create_safe(context, values):
network_ref = models.Network()
- for (key, value) in values.iteritems():
- network_ref[key] = value
+ network_ref.update(values)
try:
network_ref.save()
return network_ref
@@ -980,8 +971,7 @@ def network_update(context, network_id, values):
session = get_session()
with session.begin():
network_ref = network_get(context, network_id, session=session)
- for (key, value) in values.iteritems():
- network_ref[key] = value
+ network_ref.update(values)
network_ref.save(session=session)
@@ -1031,8 +1021,7 @@ def export_device_count(context):
@require_admin_context
def export_device_create_safe(context, values):
export_device_ref = models.ExportDevice()
- for (key, value) in values.iteritems():
- export_device_ref[key] = value
+ export_device_ref.update(values)
try:
export_device_ref.save()
return export_device_ref
@@ -1084,8 +1073,7 @@ def auth_get_token(_context, token_hash):
def auth_create_token(_context, token):
tk = models.AuthToken()
- for k, v in token.iteritems():
- tk[k] = v
+ tk.update(token)
tk.save()
return tk
@@ -1111,8 +1099,7 @@ def quota_get(context, project_id, session=None):
@require_admin_context
def quota_create(context, values):
quota_ref = models.Quota()
- for (key, value) in values.iteritems():
- quota_ref[key] = value
+ quota_ref.update(values)
quota_ref.save()
return quota_ref
@@ -1122,8 +1109,7 @@ def quota_update(context, project_id, values):
session = get_session()
with session.begin():
quota_ref = quota_get(context, project_id, session=session)
- for (key, value) in values.iteritems():
- quota_ref[key] = value
+ quota_ref.update(values)
quota_ref.save(session=session)
@@ -1191,8 +1177,7 @@ def volume_attached(context, volume_id, instance_id, mountpoint):
@require_context
def volume_create(context, values):
volume_ref = models.Volume()
- for (key, value) in values.iteritems():
- volume_ref[key] = value
+ volume_ref.update(values)
session = get_session()
with session.begin():
@@ -1377,8 +1362,7 @@ def volume_update(context, volume_id, values):
session = get_session()
with session.begin():
volume_ref = volume_get(context, volume_id, session=session)
- for (key, value) in values.iteritems():
- volume_ref[key] = value
+ volume_ref.update(values)
volume_ref.save(session=session)
@@ -1471,8 +1455,7 @@ def security_group_create(context, values):
# FIXME(devcamcar): Unless I do this, rules fails with lazy load exception
# once save() is called. This will get cleaned up in next orm pass.
security_group_ref.rules
- for (key, value) in values.iteritems():
- security_group_ref[key] = value
+ security_group_ref.update(values)
security_group_ref.save()
return security_group_ref
@@ -1526,8 +1509,7 @@ def security_group_rule_get(context, security_group_rule_id, session=None):
@require_context
def security_group_rule_create(context, values):
security_group_rule_ref = models.SecurityGroupIngressRule()
- for (key, value) in values.iteritems():
- security_group_rule_ref[key] = value
+ security_group_rule_ref.update(values)
security_group_rule_ref.save()
return security_group_rule_ref
@@ -1579,8 +1561,7 @@ def user_get_by_access_key(context, access_key, session=None):
@require_admin_context
def user_create(_context, values):
user_ref = models.User()
- for (key, value) in values.iteritems():
- user_ref[key] = value
+ user_ref.update(values)
user_ref.save()
return user_ref
@@ -1608,8 +1589,7 @@ def user_get_all(context):
def project_create(_context, values):
project_ref = models.Project()
- for (key, value) in values.iteritems():
- project_ref[key] = value
+ project_ref.update(values)
project_ref.save()
return project_ref
@@ -1671,8 +1651,7 @@ def user_update(context, user_id, values):
session = get_session()
with session.begin():
user_ref = user_get(context, user_id, session=session)
- for (key, value) in values.iteritems():
- user_ref[key] = value
+ user_ref.update(values)
user_ref.save(session=session)
@@ -1680,8 +1659,7 @@ def project_update(context, project_id, values):
session = get_session()
with session.begin():
project_ref = project_get(context, project_id, session=session)
- for (key, value) in values.iteritems():
- project_ref[key] = value
+ project_ref.update(values)
project_ref.save(session=session)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 7d65cd371..1111b5cbd 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -85,6 +85,16 @@ class NovaBase(object):
n = self._i.next().name
return n, getattr(self, n)
+ def update(self, values):
+ """Make the model object behave like a dict"""
+ for k, v in values.iteritems():
+ setattr(self, k, v)
+
+ def iteritems(self):
+ """Make the model object behave like a dict"""
+ return iter(self)
+
+
# TODO(vish): Store images in the database instead of file system
#class Image(BASE, NovaBase):
# """Represents an image in the datastore"""
diff --git a/nova/test.py b/nova/test.py
index 8ef7eca1a..5c2a72819 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -28,7 +28,6 @@ import time
import mox
import stubout
-from tornado import ioloop
from twisted.internet import defer
from twisted.trial import unittest
@@ -159,158 +158,3 @@ class TrialTestCase(unittest.TestCase):
_wrapped.func_name = self.originalAttach.func_name
rpc.Consumer.attach_to_twisted = _wrapped
-
-
-class BaseTestCase(TrialTestCase):
- # TODO(jaypipes): Can this be moved into the TrialTestCase class?
- """Base test case class for all unit tests.
-
- DEPRECATED: This is being removed once Tornado is gone, use TrialTestCase.
- """
- def setUp(self):
- """Run before each test method to initialize test environment"""
- super(BaseTestCase, self).setUp()
- # TODO(termie): we could possibly keep a more global registry of
- # the injected listeners... this is fine for now though
- self.ioloop = ioloop.IOLoop.instance()
-
- self._waiting = None
- self._done_waiting = False
- self._timed_out = False
-
- def _wait_for_test(self, timeout=60):
- """ Push the ioloop along to wait for our test to complete. """
- self._waiting = self.ioloop.add_timeout(time.time() + timeout,
- self._timeout)
-
- def _wait():
-
- """Wrapped wait function. Called on timeout."""
- if self._timed_out:
- self.fail('test timed out')
- self._done()
- if self._done_waiting:
- self.ioloop.stop()
- return
- # we can use add_callback here but this uses less cpu when testing
- self.ioloop.add_timeout(time.time() + 0.01, _wait)
-
- self.ioloop.add_callback(_wait)
- self.ioloop.start()
-
- def _done(self):
- """Callback used for cleaning up deferred test methods."""
- if self._waiting:
- try:
- self.ioloop.remove_timeout(self._waiting)
- except Exception: # pylint: disable-msg=W0703
- # TODO(jaypipes): This produces a pylint warning. Should
- # we really be catching Exception and then passing here?
- pass
- self._waiting = None
- self._done_waiting = True
-
- def _maybe_inline_callbacks(self, func):
- """ If we're doing async calls in our tests, wait on them.
-
- This is probably the most complicated hunk of code we have so far.
-
- First up, if the function is normal (not async) we just act normal
- and return.
-
- Async tests will use the "Inline Callbacks" pattern, which means
- you yield Deferreds at every "waiting" step of your code instead
- of making epic callback chains.
-
- Example (callback chain, ugly):
-
- # A deferred instance
- d = self.compute.terminate_instance(instance_id)
- def _describe(_):
- # Another deferred instance
- d_desc = self.compute.describe_instances()
- return d_desc
- def _checkDescribe(rv):
- self.assertEqual(rv, [])
- d.addCallback(_describe)
- d.addCallback(_checkDescribe)
- d.addCallback(lambda x: self._done())
- self._wait_for_test()
-
- Example (inline callbacks! yay!):
-
- yield self.compute.terminate_instance(instance_id)
- rv = yield self.compute.describe_instances()
- self.assertEqual(rv, [])
-
- If the test fits the Inline Callbacks pattern we will automatically
- handle calling wait and done.
- """
- # TODO(termie): this can be a wrapper function instead and
- # and we can make a metaclass so that we don't
- # have to copy all that "run" code below.
- g = func()
- if not hasattr(g, 'send'):
- self._done()
- return defer.succeed(g)
-
- inlined = defer.inlineCallbacks(func)
- d = inlined()
- return d
-
- def _catch_exceptions(self, result, failure):
- """Catches all exceptions and handles keyboard interrupts."""
- exc = (failure.type, failure.value, failure.getTracebackObject())
- if isinstance(failure.value, self.failureException):
- result.addFailure(self, exc)
- elif isinstance(failure.value, KeyboardInterrupt):
- raise
- else:
- result.addError(self, exc)
-
- self._done()
-
- def _timeout(self):
- """Helper method which trips the timeouts"""
- self._waiting = False
- self._timed_out = True
-
- def run(self, result=None):
- """Runs the test case"""
-
- result.startTest(self)
- test_method = getattr(self, self._testMethodName)
- try:
- try:
- self.setUp()
- except KeyboardInterrupt:
- raise
- except:
- result.addError(self, sys.exc_info())
- return
-
- ok = False
- try:
- d = self._maybe_inline_callbacks(test_method)
- d.addErrback(lambda x: self._catch_exceptions(result, x))
- d.addBoth(lambda x: self._done() and x)
- self._wait_for_test()
- ok = True
- except self.failureException:
- result.addFailure(self, sys.exc_info())
- except KeyboardInterrupt:
- raise
- except:
- result.addError(self, sys.exc_info())
-
- try:
- self.tearDown()
- except KeyboardInterrupt:
- raise
- except:
- result.addError(self, sys.exc_info())
- ok = False
- if ok:
- result.addSuccess(self)
- finally:
- result.stopTest(self)
diff --git a/nova/tests/api/__init__.py b/nova/tests/api/__init__.py
index 46f09e906..9caa8c9d0 100644
--- a/nova/tests/api/__init__.py
+++ b/nova/tests/api/__init__.py
@@ -42,7 +42,7 @@ class Test(unittest.TestCase):
environ_keys = {'HTTP_HOST': '%s.example.com' % subdomain}
environ_keys.update(kwargs)
req = webob.Request.blank(url, environ_keys)
- return req.get_response(api.API())
+ return req.get_response(api.API('ec2'))
def test_openstack(self):
self.stubs.Set(api.openstack, 'API', APIStub)
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index 7ecb72ab3..52b392601 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -30,12 +30,10 @@ from nova import exception as exc
import nova.api.openstack.auth
from nova.image import service
from nova.image.services import glance
+from nova.tests import fake_flags
from nova.wsgi import Router
-FLAGS = flags.FLAGS
-
-
class Context(object):
pass
@@ -107,7 +105,6 @@ def stub_out_networking(stubs):
def get_my_ip():
return '127.0.0.1'
stubs.Set(nova.utils, 'get_my_ip', get_my_ip)
- FLAGS.FAKE_subdomain = 'api'
def stub_out_glance(stubs, initial_fixtures=[]):
diff --git a/nova/tests/api/openstack/test_api.py b/nova/tests/api/openstack/test_api.py
index a8c0ff9f8..dd83991b9 100644
--- a/nova/tests/api/openstack/test_api.py
+++ b/nova/tests/api/openstack/test_api.py
@@ -24,22 +24,28 @@ from nova.api.openstack import API
from nova.api.openstack import faults
from webob import Request
+
class APITest(unittest.TestCase):
def test_exceptions_are_converted_to_faults(self):
+
@webob.dec.wsgify
def succeed(req):
return 'Succeeded'
+
@webob.dec.wsgify
def raise_webob_exc(req):
raise webob.exc.HTTPNotFound(explanation='Raised a webob.exc')
+
@webob.dec.wsgify
def fail(req):
raise Exception("Threw an exception")
+
@webob.dec.wsgify
def raise_api_fault(req):
exc = webob.exc.HTTPNotFound(explanation='Raised a webob.exc')
return faults.Fault(exc)
+
api = API()
api.application = succeed
diff --git a/nova/tests/api/openstack/test_auth.py b/nova/tests/api/openstack/test_auth.py
index b63da187f..29f4b8874 100644
--- a/nova/tests/api/openstack/test_auth.py
+++ b/nova/tests/api/openstack/test_auth.py
@@ -51,7 +51,7 @@ class Test(unittest.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'herp'
req.headers['X-Auth-Key'] = 'derp'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '204 No Content')
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
self.assertEqual(result.headers['X-CDN-Management-Url'],
@@ -65,7 +65,7 @@ class Test(unittest.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'herp'
req.headers['X-Auth-Key'] = 'derp'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '204 No Content')
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
self.assertEqual(result.headers['X-Server-Management-Url'],
@@ -79,7 +79,7 @@ class Test(unittest.TestCase):
fakes.FakeRouter)
req = webob.Request.blank('/v1.0/fake')
req.headers['X-Auth-Token'] = token
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '200 OK')
self.assertEqual(result.headers['X-Test-Success'], 'True')
@@ -103,7 +103,7 @@ class Test(unittest.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'bacon'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '401 Unauthorized')
self.assertEqual(self.destroy_called, True)
@@ -111,18 +111,18 @@ class Test(unittest.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'herp'
req.headers['X-Auth-Key'] = 'derp'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '401 Unauthorized')
def test_no_user(self):
req = webob.Request.blank('/v1.0/')
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '401 Unauthorized')
def test_bad_token(self):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-Token'] = 'baconbaconbacon'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '401 Unauthorized')
@@ -146,7 +146,7 @@ class TestLimiter(unittest.TestCase):
req = webob.Request.blank('/v1.0/')
req.headers['X-Auth-User'] = 'herp'
req.headers['X-Auth-Key'] = 'derp'
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
token = result.headers['X-Auth-Token']
@@ -155,7 +155,7 @@ class TestLimiter(unittest.TestCase):
req = webob.Request.blank('/v1.0/fake')
req.method = 'POST'
req.headers['X-Auth-Token'] = token
- result = req.get_response(nova.api.API())
+ result = req.get_response(nova.api.API('os'))
self.assertEqual(result.status, '200 OK')
self.assertEqual(result.headers['X-Test-Success'], 'True')
diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py
index 8dd4d1f29..41018afdf 100644
--- a/nova/tests/api/openstack/test_flavors.py
+++ b/nova/tests/api/openstack/test_flavors.py
@@ -39,7 +39,7 @@ class FlavorsTest(unittest.TestCase):
def test_get_flavor_list(self):
req = webob.Request.blank('/v1.0/flavors')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
def test_get_flavor_by_id(self):
pass
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index d61c3a99b..0f3941c29 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -203,7 +203,7 @@ class ImageControllerWithGlanceServiceTest(unittest.TestCase):
def test_get_image_index(self):
req = webob.Request.blank('/v1.0/images')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
res_dict = json.loads(res.body)
fixture_index = [dict(id=f['id'], name=f['name']) for f
@@ -215,7 +215,7 @@ class ImageControllerWithGlanceServiceTest(unittest.TestCase):
def test_get_image_details(self):
req = webob.Request.blank('/v1.0/images/detail')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
res_dict = json.loads(res.body)
for image in res_dict['images']:
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 55efcf733..8cfc6c45a 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -69,14 +69,14 @@ class ServersTest(unittest.TestCase):
def test_get_server_by_id(self):
req = webob.Request.blank('/v1.0/servers/1')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
res_dict = json.loads(res.body)
self.assertEqual(res_dict['server']['id'], 1)
self.assertEqual(res_dict['server']['name'], 'server1')
def test_get_server_list(self):
req = webob.Request.blank('/v1.0/servers')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
res_dict = json.loads(res.body)
i = 0
@@ -91,9 +91,7 @@ class ServersTest(unittest.TestCase):
pass
def instance_create(context, inst):
- class Foo(object):
- internal_id = 1
- return Foo()
+ return {'id': 1, 'internal_id': 1}
def fake_method(*args, **kwargs):
pass
@@ -121,14 +119,14 @@ class ServersTest(unittest.TestCase):
req.method = 'POST'
req.body = json.dumps(body)
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status_int, 200)
def test_update_no_body(self):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status_int, 422)
def test_update_bad_params(self):
@@ -147,7 +145,7 @@ class ServersTest(unittest.TestCase):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
req.body = self.body
- req.get_response(nova.api.API())
+ req.get_response(nova.api.API('os'))
def test_update_server(self):
inst_dict = dict(name='server_test', adminPass='bacon')
@@ -163,28 +161,28 @@ class ServersTest(unittest.TestCase):
req = webob.Request.blank('/v1.0/servers/1')
req.method = 'PUT'
req.body = self.body
- req.get_response(nova.api.API())
+ req.get_response(nova.api.API('os'))
def test_create_backup_schedules(self):
req = webob.Request.blank('/v1.0/servers/1/backup_schedules')
req.method = 'POST'
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status, '404 Not Found')
def test_delete_backup_schedules(self):
req = webob.Request.blank('/v1.0/servers/1/backup_schedules')
req.method = 'DELETE'
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status, '404 Not Found')
def test_get_server_backup_schedules(self):
req = webob.Request.blank('/v1.0/servers/1/backup_schedules')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status, '404 Not Found')
def test_get_all_server_details(self):
req = webob.Request.blank('/v1.0/servers/detail')
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
res_dict = json.loads(res.body)
i = 0
@@ -202,7 +200,7 @@ class ServersTest(unittest.TestCase):
req.method = 'POST'
req.content_type = 'application/json'
req.body = json.dumps(body)
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
def test_server_rebuild(self):
body = dict(server=dict(
@@ -212,7 +210,7 @@ class ServersTest(unittest.TestCase):
req.method = 'POST'
req.content_type = 'application/json'
req.body = json.dumps(body)
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
def test_server_resize(self):
body = dict(server=dict(
@@ -222,7 +220,7 @@ class ServersTest(unittest.TestCase):
req.method = 'POST'
req.content_type = 'application/json'
req.body = json.dumps(body)
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
def test_delete_server_instance(self):
req = webob.Request.blank('/v1.0/servers/1')
@@ -236,7 +234,7 @@ class ServersTest(unittest.TestCase):
self.stubs.Set(nova.db.api, 'instance_destroy',
instance_destroy_mock)
- res = req.get_response(nova.api.API())
+ res = req.get_response(nova.api.API('os'))
self.assertEqual(res.status, '202 Accepted')
self.assertEqual(self.server_delete_called, True)
diff --git a/nova/tests/api_unittest.py b/nova/tests/api_unittest.py
index 0b1c3e353..33d4cb294 100644
--- a/nova/tests/api_unittest.py
+++ b/nova/tests/api_unittest.py
@@ -34,10 +34,6 @@ from nova.api.ec2 import apirequest
from nova.auth import manager
-FLAGS = flags.FLAGS
-FLAGS.FAKE_subdomain = 'ec2'
-
-
class FakeHttplibSocket(object):
"""a fake socket implementation for httplib.HTTPResponse, trivial"""
def __init__(self, response_string):
@@ -83,7 +79,7 @@ class FakeHttplibConnection(object):
pass
-class XmlConversionTestCase(test.BaseTestCase):
+class XmlConversionTestCase(test.TrialTestCase):
"""Unit test api xml conversion"""
def test_number_conversion(self):
conv = apirequest._try_convert
@@ -100,7 +96,7 @@ class XmlConversionTestCase(test.BaseTestCase):
self.assertEqual(conv('-0'), 0)
-class ApiEc2TestCase(test.BaseTestCase):
+class ApiEc2TestCase(test.TrialTestCase):
"""Unit test for the cloud controller on an EC2 API"""
def setUp(self):
super(ApiEc2TestCase, self).setUp()
@@ -109,7 +105,7 @@ class ApiEc2TestCase(test.BaseTestCase):
self.host = '127.0.0.1'
- self.app = api.API()
+ self.app = api.API('ec2')
def expect_http(self, host=None, is_secure=False):
"""Returns a new EC2 connection"""
diff --git a/nova/tests/service_unittest.py b/nova/tests/service_unittest.py
index e74e0f726..a268bc4fe 100644
--- a/nova/tests/service_unittest.py
+++ b/nova/tests/service_unittest.py
@@ -23,8 +23,8 @@ Unit Tests for remote procedure calls using queue
import mox
from twisted.application.app import startApplication
+from twisted.internet import defer
-from nova import context
from nova import exception
from nova import flags
from nova import rpc
@@ -48,7 +48,7 @@ class ExtendedService(service.Service):
return 'service'
-class ServiceManagerTestCase(test.BaseTestCase):
+class ServiceManagerTestCase(test.TrialTestCase):
"""Test cases for Services"""
def test_attribute_error_for_no_manager(self):
@@ -75,13 +75,12 @@ class ServiceManagerTestCase(test.BaseTestCase):
self.assertEqual(serv.test_method(), 'service')
-class ServiceTestCase(test.BaseTestCase):
+class ServiceTestCase(test.TrialTestCase):
"""Test cases for Services"""
def setUp(self):
super(ServiceTestCase, self).setUp()
self.mox.StubOutWithMock(service, 'db')
- self.context = context.get_admin_context()
def test_create(self):
host = 'foo'
@@ -144,87 +143,103 @@ class ServiceTestCase(test.BaseTestCase):
# whether it is disconnected, it looks for a variable on itself called
# 'model_disconnected' and report_state doesn't really do much so this
# these are mostly just for coverage
- def test_report_state(self):
- host = 'foo'
- binary = 'bar'
- service_ref = {'host': host,
- 'binary': binary,
- 'report_count': 0,
- 'id': 1}
- service.db.__getattr__('report_state')
- service.db.service_get_by_args(self.context,
- host,
- binary).AndReturn(service_ref)
- service.db.service_update(self.context, service_ref['id'],
- mox.ContainsKeyValue('report_count', 1))
-
- self.mox.ReplayAll()
- s = service.Service()
- rv = yield s.report_state(host, binary)
-
+ @defer.inlineCallbacks
def test_report_state_no_service(self):
host = 'foo'
binary = 'bar'
+ topic = 'test'
service_create = {'host': host,
'binary': binary,
+ 'topic': topic,
'report_count': 0}
service_ref = {'host': host,
- 'binary': binary,
- 'report_count': 0,
- 'id': 1}
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0,
+ 'id': 1}
- service.db.__getattr__('report_state')
- service.db.service_get_by_args(self.context,
+ service.db.service_get_by_args(mox.IgnoreArg(),
host,
binary).AndRaise(exception.NotFound())
- service.db.service_create(self.context,
+ service.db.service_create(mox.IgnoreArg(),
service_create).AndReturn(service_ref)
- service.db.service_get(self.context,
+ service.db.service_get(mox.IgnoreArg(),
service_ref['id']).AndReturn(service_ref)
- service.db.service_update(self.context, service_ref['id'],
+ service.db.service_update(mox.IgnoreArg(), service_ref['id'],
mox.ContainsKeyValue('report_count', 1))
self.mox.ReplayAll()
- s = service.Service()
- rv = yield s.report_state(host, binary)
+ serv = service.Service(host,
+ binary,
+ topic,
+ 'nova.tests.service_unittest.FakeManager')
+ serv.startService()
+ yield serv.report_state()
+ @defer.inlineCallbacks
def test_report_state_newly_disconnected(self):
host = 'foo'
binary = 'bar'
+ topic = 'test'
+ service_create = {'host': host,
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0}
service_ref = {'host': host,
- 'binary': binary,
- 'report_count': 0,
- 'id': 1}
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0,
+ 'id': 1}
- service.db.__getattr__('report_state')
- service.db.service_get_by_args(self.context,
- host,
- binary).AndRaise(Exception())
+ service.db.service_get_by_args(mox.IgnoreArg(),
+ host,
+ binary).AndRaise(exception.NotFound())
+ service.db.service_create(mox.IgnoreArg(),
+ service_create).AndReturn(service_ref)
+ service.db.service_get(mox.IgnoreArg(),
+ mox.IgnoreArg()).AndRaise(Exception())
self.mox.ReplayAll()
- s = service.Service()
- rv = yield s.report_state(host, binary)
-
- self.assert_(s.model_disconnected)
+ serv = service.Service(host,
+ binary,
+ topic,
+ 'nova.tests.service_unittest.FakeManager')
+ serv.startService()
+ yield serv.report_state()
+ self.assert_(serv.model_disconnected)
+ @defer.inlineCallbacks
def test_report_state_newly_connected(self):
host = 'foo'
binary = 'bar'
+ topic = 'test'
+ service_create = {'host': host,
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0}
service_ref = {'host': host,
- 'binary': binary,
- 'report_count': 0,
- 'id': 1}
+ 'binary': binary,
+ 'topic': topic,
+ 'report_count': 0,
+ 'id': 1}
- service.db.__getattr__('report_state')
- service.db.service_get_by_args(self.context,
- host,
- binary).AndReturn(service_ref)
- service.db.service_update(self.context, service_ref['id'],
+ service.db.service_get_by_args(mox.IgnoreArg(),
+ host,
+ binary).AndRaise(exception.NotFound())
+ service.db.service_create(mox.IgnoreArg(),
+ service_create).AndReturn(service_ref)
+ service.db.service_get(mox.IgnoreArg(),
+ service_ref['id']).AndReturn(service_ref)
+ service.db.service_update(mox.IgnoreArg(), service_ref['id'],
mox.ContainsKeyValue('report_count', 1))
self.mox.ReplayAll()
- s = service.Service()
- s.model_disconnected = True
- rv = yield s.report_state(host, binary)
+ serv = service.Service(host,
+ binary,
+ topic,
+ 'nova.tests.service_unittest.FakeManager')
+ serv.startService()
+ serv.model_disconnected = True
+ yield serv.report_state()
- self.assert_(not s.model_disconnected)
+ self.assert_(not serv.model_disconnected)
diff --git a/nova/utils.py b/nova/utils.py
index 2c53b027e..bc495a691 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -213,10 +213,10 @@ def deferredToThread(f):
def xhtml_escape(value):
"""Escapes a string so it is valid within XML or XHTML.
-
+
Code is directly from the utf8 function in
http://github.com/facebook/tornado/blob/master/tornado/escape.py
-
+
"""
return saxutils.escape(value, {'"': "&quot;"})
@@ -232,4 +232,3 @@ def utf8(value):
return value.encode("utf-8")
assert isinstance(value, str)
return value
-
diff --git a/nova/wsgi.py b/nova/wsgi.py
index eb305a3d3..b04b487ea 100644
--- a/nova/wsgi.py
+++ b/nova/wsgi.py
@@ -39,10 +39,27 @@ import webob.exc
logging.getLogger("routes.middleware").addHandler(logging.StreamHandler())
-def run_server(application, port):
- """Run a WSGI server with the given application."""
- sock = eventlet.listen(('0.0.0.0', port))
- eventlet.wsgi.server(sock, application)
+class Server(object):
+ """Server class to manage multiple WSGI sockets and applications."""
+
+ def __init__(self, threads=1000):
+ self.pool = eventlet.GreenPool(threads)
+
+ def start(self, application, port, host='0.0.0.0', backlog=128):
+ """Run a WSGI server with the given application."""
+ socket = eventlet.listen((host, port), backlog=backlog)
+ self.pool.spawn_n(self._run, application, socket)
+
+ def wait(self):
+ """Wait until all servers have completed running."""
+ try:
+ self.pool.waitall()
+ except KeyboardInterrupt:
+ pass
+
+ def _run(self, application, socket):
+ """Start a WSGI server in a new green thread."""
+ eventlet.wsgi.server(socket, application, custom_pool=self.pool)
class Application(object):