summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/nova-api-os-compute47
-rwxr-xr-xbin/nova-api-os-volume (renamed from bin/nova-api-os)2
-rw-r--r--etc/nova/api-paste.ini62
-rw-r--r--nova/api/mapper.py76
-rw-r--r--nova/api/openstack/__init__.py69
-rw-r--r--nova/api/openstack/auth.py (renamed from nova/api/openstack/v2/auth.py)2
-rw-r--r--nova/api/openstack/compute/__init__.py (renamed from nova/api/openstack/v2/__init__.py)62
-rw-r--r--nova/api/openstack/compute/consoles.py (renamed from nova/api/openstack/v2/consoles.py)0
-rw-r--r--nova/api/openstack/compute/contrib/__init__.py32
-rw-r--r--nova/api/openstack/compute/contrib/accounts.py (renamed from nova/api/openstack/v2/contrib/accounts.py)4
-rw-r--r--nova/api/openstack/compute/contrib/admin_actions.py (renamed from nova/api/openstack/v2/contrib/admin_actions.py)4
-rw-r--r--nova/api/openstack/compute/contrib/cloudpipe.py (renamed from nova/api/openstack/v2/contrib/cloudpipe.py)4
-rw-r--r--nova/api/openstack/compute/contrib/console_output.py (renamed from nova/api/openstack/v2/contrib/console_output.py)4
-rw-r--r--nova/api/openstack/compute/contrib/createserverext.py (renamed from nova/api/openstack/v2/contrib/createserverext.py)6
-rw-r--r--nova/api/openstack/compute/contrib/deferred_delete.py (renamed from nova/api/openstack/v2/contrib/deferred_delete.py)6
-rw-r--r--nova/api/openstack/compute/contrib/disk_config.py (renamed from nova/api/openstack/v2/contrib/disk_config.py)2
-rw-r--r--nova/api/openstack/compute/contrib/extended_status.py (renamed from nova/api/openstack/v2/contrib/extended_status.py)4
-rw-r--r--nova/api/openstack/compute/contrib/flavorextradata.py (renamed from nova/api/openstack/v2/contrib/flavorextradata.py)2
-rw-r--r--nova/api/openstack/compute/contrib/flavorextraspecs.py (renamed from nova/api/openstack/v2/contrib/flavorextraspecs.py)2
-rw-r--r--nova/api/openstack/compute/contrib/floating_ip_dns.py (renamed from nova/api/openstack/v2/contrib/floating_ip_dns.py)4
-rw-r--r--nova/api/openstack/compute/contrib/floating_ip_pools.py (renamed from nova/api/openstack/v2/contrib/floating_ip_pools.py)4
-rw-r--r--nova/api/openstack/compute/contrib/floating_ips.py (renamed from nova/api/openstack/v2/contrib/floating_ips.py)4
-rw-r--r--nova/api/openstack/compute/contrib/hosts.py (renamed from nova/api/openstack/v2/contrib/hosts.py)4
-rw-r--r--nova/api/openstack/compute/contrib/keypairs.py (renamed from nova/api/openstack/v2/contrib/keypairs.py)2
-rw-r--r--nova/api/openstack/compute/contrib/multinic.py (renamed from nova/api/openstack/v2/contrib/multinic.py)4
-rw-r--r--nova/api/openstack/compute/contrib/networks.py (renamed from nova/api/openstack/v2/contrib/networks.py)4
-rw-r--r--nova/api/openstack/compute/contrib/quotas.py (renamed from nova/api/openstack/v2/contrib/quotas.py)2
-rw-r--r--nova/api/openstack/compute/contrib/rescue.py (renamed from nova/api/openstack/v2/contrib/rescue.py)4
-rw-r--r--nova/api/openstack/compute/contrib/security_groups.py (renamed from nova/api/openstack/v2/contrib/security_groups.py)4
-rw-r--r--nova/api/openstack/compute/contrib/server_action_list.py (renamed from nova/api/openstack/v2/contrib/server_action_list.py)2
-rw-r--r--nova/api/openstack/compute/contrib/server_diagnostics.py (renamed from nova/api/openstack/v2/contrib/server_diagnostics.py)2
-rw-r--r--nova/api/openstack/compute/contrib/simple_tenant_usage.py (renamed from nova/api/openstack/v2/contrib/simple_tenant_usage.py)2
-rw-r--r--nova/api/openstack/compute/contrib/users.py (renamed from nova/api/openstack/v2/contrib/users.py)2
-rw-r--r--nova/api/openstack/compute/contrib/virtual_interfaces.py (renamed from nova/api/openstack/v2/contrib/virtual_interfaces.py)5
-rw-r--r--nova/api/openstack/compute/contrib/virtual_storage_arrays.py (renamed from nova/api/openstack/v2/contrib/virtual_storage_arrays.py)8
-rw-r--r--nova/api/openstack/compute/contrib/volumes.py (renamed from nova/api/openstack/v2/contrib/volumes.py)6
-rw-r--r--nova/api/openstack/compute/contrib/volumetypes.py (renamed from nova/api/openstack/v2/contrib/volumetypes.py)2
-rw-r--r--nova/api/openstack/compute/contrib/zones.py (renamed from nova/api/openstack/v2/contrib/zones.py)6
-rw-r--r--nova/api/openstack/compute/extensions.py45
-rw-r--r--nova/api/openstack/compute/flavors.py (renamed from nova/api/openstack/v2/flavors.py)2
-rw-r--r--nova/api/openstack/compute/image_metadata.py (renamed from nova/api/openstack/v2/image_metadata.py)0
-rw-r--r--nova/api/openstack/compute/images.py (renamed from nova/api/openstack/v2/images.py)4
-rw-r--r--nova/api/openstack/compute/ips.py (renamed from nova/api/openstack/v2/ips.py)4
-rw-r--r--nova/api/openstack/compute/limits.py (renamed from nova/api/openstack/v2/limits.py)2
-rw-r--r--nova/api/openstack/compute/ratelimiting/__init__.py (renamed from nova/api/openstack/v2/ratelimiting/__init__.py)0
-rw-r--r--nova/api/openstack/compute/schemas/atom-link.rng (renamed from nova/api/openstack/v2/schemas/atom-link.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/atom.rng (renamed from nova/api/openstack/v2/schemas/atom.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/addresses.rng (renamed from nova/api/openstack/v2/schemas/v1.1/addresses.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/extension.rng (renamed from nova/api/openstack/v2/schemas/v1.1/extension.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/extensions.rng (renamed from nova/api/openstack/v2/schemas/v1.1/extensions.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/flavor.rng (renamed from nova/api/openstack/v2/schemas/v1.1/flavor.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/flavors.rng (renamed from nova/api/openstack/v2/schemas/v1.1/flavors.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/flavors_index.rng (renamed from nova/api/openstack/v2/schemas/v1.1/flavors_index.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/image.rng (renamed from nova/api/openstack/v2/schemas/v1.1/image.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/images.rng (renamed from nova/api/openstack/v2/schemas/v1.1/images.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/images_index.rng (renamed from nova/api/openstack/v2/schemas/v1.1/images_index.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/limits.rng (renamed from nova/api/openstack/v2/schemas/v1.1/limits.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/metadata.rng (renamed from nova/api/openstack/v2/schemas/v1.1/metadata.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/server.rng (renamed from nova/api/openstack/v2/schemas/v1.1/server.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/servers.rng (renamed from nova/api/openstack/v2/schemas/v1.1/servers.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/servers_index.rng (renamed from nova/api/openstack/v2/schemas/v1.1/servers_index.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/version.rng (renamed from nova/api/openstack/v2/schemas/v1.1/version.rng)0
-rw-r--r--nova/api/openstack/compute/schemas/v1.1/versions.rng (renamed from nova/api/openstack/v2/schemas/v1.1/versions.rng)0
-rw-r--r--nova/api/openstack/compute/server_metadata.py (renamed from nova/api/openstack/v2/server_metadata.py)0
-rw-r--r--nova/api/openstack/compute/servers.py (renamed from nova/api/openstack/v2/servers.py)6
-rw-r--r--nova/api/openstack/compute/versions.py (renamed from nova/api/openstack/v2/versions.py)2
-rw-r--r--nova/api/openstack/compute/views/__init__.py (renamed from nova/api/openstack/v2/views/__init__.py)0
-rw-r--r--nova/api/openstack/compute/views/addresses.py (renamed from nova/api/openstack/v2/views/addresses.py)2
-rw-r--r--nova/api/openstack/compute/views/flavors.py (renamed from nova/api/openstack/v2/views/flavors.py)0
-rw-r--r--nova/api/openstack/compute/views/images.py (renamed from nova/api/openstack/v2/views/images.py)0
-rw-r--r--nova/api/openstack/compute/views/limits.py (renamed from nova/api/openstack/v2/views/limits.py)0
-rw-r--r--nova/api/openstack/compute/views/servers.py (renamed from nova/api/openstack/v2/views/servers.py)8
-rw-r--r--nova/api/openstack/compute/views/versions.py (renamed from nova/api/openstack/v2/views/versions.py)0
-rw-r--r--nova/api/openstack/extensions.py (renamed from nova/api/openstack/v2/extensions.py)80
-rw-r--r--nova/api/openstack/urlmap.py (renamed from nova/api/openstack/v2/urlmap.py)2
-rw-r--r--nova/api/openstack/v2/contrib/__init__.py90
-rw-r--r--nova/api/openstack/volume/__init__.py99
-rw-r--r--nova/api/openstack/volume/contrib/__init__.py32
-rw-r--r--nova/api/openstack/volume/extensions.py44
-rw-r--r--nova/api/openstack/volume/snapshots.py183
-rw-r--r--nova/api/openstack/volume/types.py89
-rw-r--r--nova/api/openstack/volume/versions.py83
-rw-r--r--nova/api/openstack/volume/views/__init__.py16
-rw-r--r--nova/api/openstack/volume/views/versions.py37
-rw-r--r--nova/api/openstack/volume/volumes.py254
-rw-r--r--nova/api/openstack/xmlutil.py4
-rw-r--r--nova/auth/manager.py2
-rw-r--r--nova/common/cfg.py8
-rw-r--r--nova/flags.py14
-rw-r--r--nova/service.py9
-rw-r--r--nova/tests/api/openstack/compute/__init__.py (renamed from nova/tests/api/openstack/v2/__init__.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/__init__.py (renamed from nova/tests/api/openstack/v2/contrib/__init__.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_accounts.py (renamed from nova/tests/api/openstack/v2/contrib/test_accounts.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_admin_actions.py (renamed from nova/tests/api/openstack/v2/contrib/test_admin_actions.py)6
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_cloudpipe.py (renamed from nova/tests/api/openstack/v2/contrib/test_cloudpipe.py)8
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_console_output.py (renamed from nova/tests/api/openstack/v2/contrib/test_console_output.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_createserverext.py (renamed from nova/tests/api/openstack/v2/contrib/test_createserverext.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_deferred_delete.py (renamed from nova/tests/api/openstack/v2/contrib/test_deferred_delete.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_disk_config.py (renamed from nova/tests/api/openstack/v2/contrib/test_disk_config.py)6
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_extendedstatus.py (renamed from nova/tests/api/openstack/v2/contrib/test_extendedstatus.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_flavors_extra_specs.py (renamed from nova/tests/api/openstack/v2/contrib/test_flavors_extra_specs.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_floating_ip_dns.py (renamed from nova/tests/api/openstack/v2/contrib/test_floating_ip_dns.py)4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_floating_ip_pools.py (renamed from nova/tests/api/openstack/v2/contrib/test_floating_ip_pools.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_floating_ips.py (renamed from nova/tests/api/openstack/v2/contrib/test_floating_ips.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_hosts.py (renamed from nova/tests/api/openstack/v2/contrib/test_hosts.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_keypairs.py (renamed from nova/tests/api/openstack/v2/contrib/test_keypairs.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_multinic_xs.py (renamed from nova/tests/api/openstack/v2/contrib/test_multinic_xs.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_networks.py (renamed from nova/tests/api/openstack/v2/contrib/test_networks.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_quotas.py (renamed from nova/tests/api/openstack/v2/contrib/test_quotas.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_rescue.py (renamed from nova/tests/api/openstack/v2/contrib/test_rescue.py)0
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_security_groups.py (renamed from nova/tests/api/openstack/v2/contrib/test_security_groups.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_server_action_list.py (renamed from nova/tests/api/openstack/v2/contrib/test_server_action_list.py)8
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py (renamed from nova/tests/api/openstack/v2/contrib/test_server_diagnostics.py)8
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py (renamed from nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_snapshots.py (renamed from nova/tests/api/openstack/v2/contrib/test_snapshots.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_users.py (renamed from nova/tests/api/openstack/v2/contrib/test_users.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_virtual_interfaces.py (renamed from nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_volume_types.py (renamed from nova/tests/api/openstack/v2/contrib/test_volume_types.py)4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py (renamed from nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_volumes.py (renamed from nova/tests/api/openstack/v2/contrib/test_volumes.py)2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_vsa.py (renamed from nova/tests/api/openstack/v2/contrib/test_vsa.py)5
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_zones.py (renamed from nova/tests/api/openstack/v2/contrib/test_zones.py)2
-rw-r--r--nova/tests/api/openstack/compute/extensions/__init__.py (renamed from nova/tests/api/openstack/v2/extensions/__init__.py)0
-rw-r--r--nova/tests/api/openstack/compute/extensions/foxinsocks.py (renamed from nova/tests/api/openstack/v2/extensions/foxinsocks.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_api.py (renamed from nova/tests/api/openstack/v2/test_api.py)7
-rw-r--r--nova/tests/api/openstack/compute/test_auth.py (renamed from nova/tests/api/openstack/v2/test_auth.py)23
-rw-r--r--nova/tests/api/openstack/compute/test_consoles.py (renamed from nova/tests/api/openstack/v2/test_consoles.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py (renamed from nova/tests/api/openstack/v2/test_extensions.py)109
-rw-r--r--nova/tests/api/openstack/compute/test_flavors.py (renamed from nova/tests/api/openstack/v2/test_flavors.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_image_metadata.py (renamed from nova/tests/api/openstack/v2/test_image_metadata.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_images.py (renamed from nova/tests/api/openstack/v2/test_images.py)4
-rw-r--r--nova/tests/api/openstack/compute/test_limits.py (renamed from nova/tests/api/openstack/v2/test_limits.py)4
-rw-r--r--nova/tests/api/openstack/compute/test_server_actions.py (renamed from nova/tests/api/openstack/v2/test_server_actions.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_server_metadata.py (renamed from nova/tests/api/openstack/v2/test_server_metadata.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py (renamed from nova/tests/api/openstack/v2/test_servers.py)13
-rw-r--r--nova/tests/api/openstack/compute/test_urlmap.py (renamed from nova/tests/api/openstack/v2/test_urlmap.py)2
-rw-r--r--nova/tests/api/openstack/compute/test_versions.py (renamed from nova/tests/api/openstack/v2/test_versions.py)4
-rw-r--r--nova/tests/api/openstack/fakes.py32
-rw-r--r--nova/tests/api/openstack/volume/__init__.py16
-rw-r--r--nova/tests/api/openstack/volume/test_snapshots.py299
-rw-r--r--nova/tests/api/openstack/volume/test_types.py166
-rw-r--r--nova/tests/api/openstack/volume/test_volumes.py179
-rw-r--r--nova/tests/integrated/api/client.py8
-rw-r--r--nova/tests/integrated/integrated_helpers.py10
-rw-r--r--nova/tests/integrated/test_extensions.py9
-rw-r--r--nova/tests/integrated/test_volumes.py158
-rw-r--r--setup.py3
147 files changed, 2157 insertions, 566 deletions
diff --git a/bin/nova-api-os-compute b/bin/nova-api-os-compute
new file mode 100755
index 000000000..7bfff2a42
--- /dev/null
+++ b/bin/nova-api-os-compute
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Starter script for Nova OS API."""
+
+import eventlet
+eventlet.monkey_patch()
+
+import os
+import sys
+
+
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
+ sys.argv[0]), os.pardir, os.pardir))
+if os.path.exists(os.path.join(possible_topdir, "nova", "__init__.py")):
+ sys.path.insert(0, possible_topdir)
+
+
+from nova import flags
+from nova import log as logging
+from nova import service
+from nova import utils
+
+if __name__ == '__main__':
+ utils.default_flagfile()
+ flags.FLAGS(sys.argv)
+ logging.setup()
+ utils.monkey_patch()
+ server = service.WSGIService('osapi_compute')
+ service.serve(server)
+ service.wait()
diff --git a/bin/nova-api-os b/bin/nova-api-os-volume
index 83a808987..33909c5b5 100755
--- a/bin/nova-api-os
+++ b/bin/nova-api-os-volume
@@ -42,6 +42,6 @@ if __name__ == '__main__':
flags.FLAGS(sys.argv)
logging.setup()
utils.monkey_patch()
- server = service.WSGIService('osapi')
+ server = service.WSGIService('osapi_volume')
service.serve(server)
service.wait()
diff --git a/etc/nova/api-paste.ini b/etc/nova/api-paste.ini
index 145044df7..c2de4b484 100644
--- a/etc/nova/api-paste.ini
+++ b/etc/nova/api-paste.ini
@@ -78,40 +78,60 @@ paste.app_factory = nova.api.ec2:Executor.factory
# Openstack #
#############
-[composite:osapi]
-use = call:nova.api.openstack.v2.urlmap:urlmap_factory
-/: osversions
-/v1.1: openstack_api_v2
-/v2: openstack_api_v2
-
-[pipeline:openstack_api_v2]
-pipeline = faultwrap noauth ratelimit serialize extensions osapi_app_v2
+[composite:osapi_compute]
+use = call:nova.api.openstack.urlmap:urlmap_factory
+/: oscomputeversions
+/v1.1: openstack_compute_api_v2
+/v2: openstack_compute_api_v2
+
+[composite:osapi_volume]
+use = call:nova.api.openstack.urlmap:urlmap_factory
+/: osvolumeversions
+/v1: openstack_volume_api_v1
+
+[pipeline:openstack_compute_api_v2]
+pipeline = faultwrap noauth ratelimit serialize compute_extensions osapi_compute_app_v2
# NOTE(vish): use the following pipeline for deprecated auth
-# pipeline = faultwrap auth ratelimit serialize extensions osapi_app_v2
+# pipeline = faultwrap auth ratelimit serialize extensions osapi_compute_app_v2
+
+[pipeline:openstack_volume_api_v1]
+pipeline = faultwrap noauth ratelimit serialize volume_extensions osapi_volume_app_v1
[filter:faultwrap]
-paste.filter_factory = nova.api.openstack.v2:FaultWrapper.factory
+paste.filter_factory = nova.api.openstack:FaultWrapper.factory
[filter:auth]
-paste.filter_factory = nova.api.openstack.v2.auth:AuthMiddleware.factory
+paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory
[filter:noauth]
-paste.filter_factory = nova.api.openstack.v2.auth:NoAuthMiddleware.factory
+paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory
[filter:ratelimit]
-paste.filter_factory = nova.api.openstack.v2.limits:RateLimitingMiddleware.factory
+paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory
[filter:serialize]
paste.filter_factory = nova.api.openstack.wsgi:LazySerializationMiddleware.factory
-[filter:extensions]
-paste.filter_factory = nova.api.openstack.v2.extensions:ExtensionMiddleware.factory
+[filter:compute_extensions]
+paste.filter_factory = nova.api.openstack.compute.extensions:ExtensionMiddleware.factory
+
+[filter:volume_extensions]
+paste.filter_factory = nova.api.openstack.volume.extensions:ExtensionMiddleware.factory
+
+[app:osapi_compute_app_v2]
+paste.app_factory = nova.api.openstack.compute:APIRouter.factory
+
+[pipeline:oscomputeversions]
+pipeline = faultwrap oscomputeversionapp
+
+[app:osapi_volume_app_v1]
+paste.app_factory = nova.api.openstack.volume:APIRouter.factory
-[app:osapi_app_v2]
-paste.app_factory = nova.api.openstack.v2:APIRouter.factory
+[app:oscomputeversionapp]
+paste.app_factory = nova.api.openstack.compute.versions:Versions.factory
-[pipeline:osversions]
-pipeline = faultwrap osversionapp
+[pipeline:osvolumeversions]
+pipeline = faultwrap osvolumeversionapp
-[app:osversionapp]
-paste.app_factory = nova.api.openstack.v2.versions:Versions.factory
+[app:osvolumeversionapp]
+paste.app_factory = nova.api.openstack.volume.versions:Versions.factory
diff --git a/nova/api/mapper.py b/nova/api/mapper.py
new file mode 100644
index 000000000..cd26e06ee
--- /dev/null
+++ b/nova/api/mapper.py
@@ -0,0 +1,76 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+WSGI middleware for OpenStack API controllers.
+"""
+
+import routes
+import webob.dec
+import webob.exc
+
+from nova.api.openstack import wsgi
+from nova import flags
+from nova import log as logging
+from nova import wsgi as base_wsgi
+
+
+LOG = logging.getLogger('nova.api.openstack.compute')
+FLAGS = flags.FLAGS
+flags.DEFINE_bool('allow_admin_api',
+ False,
+ 'When True, this API service will accept admin operations.')
+flags.DEFINE_bool('allow_instance_snapshots',
+ True,
+ 'When True, this API service will permit instance snapshot operations.')
+
+
+class FaultWrapper(base_wsgi.Middleware):
+ """Calls down the middleware stack, making exceptions into faults."""
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ try:
+ return req.get_response(self.application)
+ except Exception as ex:
+ LOG.exception(_("Caught error: %s"), unicode(ex))
+ exc = webob.exc.HTTPInternalServerError()
+ return wsgi.Fault(exc)
+
+
+class APIMapper(routes.Mapper):
+ def routematch(self, url=None, environ=None):
+ if url is "":
+ result = self._match("", environ)
+ return result[0], result[1]
+ return routes.Mapper.routematch(self, url, environ)
+
+
+class ProjectMapper(APIMapper):
+ def resource(self, member_name, collection_name, **kwargs):
+ if not ('parent_resource' in kwargs):
+ kwargs['path_prefix'] = '{project_id}/'
+ else:
+ parent_resource = kwargs['parent_resource']
+ p_collection = parent_resource['collection_name']
+ p_member = parent_resource['member_name']
+ kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection,
+ p_member)
+ routes.Mapper.resource(self, member_name,
+ collection_name,
+ **kwargs)
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index e69de29bb..dfc174a58 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+WSGI middleware for OpenStack API controllers.
+"""
+
+import routes
+import webob.dec
+import webob.exc
+
+from nova.api.openstack import wsgi
+from nova import flags
+from nova import log as logging
+from nova import wsgi as base_wsgi
+
+
+LOG = logging.getLogger('nova.api.openstack')
+
+
+class FaultWrapper(base_wsgi.Middleware):
+ """Calls down the middleware stack, making exceptions into faults."""
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ try:
+ return req.get_response(self.application)
+ except Exception as ex:
+ LOG.exception(_("Caught error: %s"), unicode(ex))
+ exc = webob.exc.HTTPInternalServerError()
+ return wsgi.Fault(exc)
+
+
+class APIMapper(routes.Mapper):
+ def routematch(self, url=None, environ=None):
+ if url is "":
+ result = self._match("", environ)
+ return result[0], result[1]
+ return routes.Mapper.routematch(self, url, environ)
+
+
+class ProjectMapper(APIMapper):
+ def resource(self, member_name, collection_name, **kwargs):
+ if not ('parent_resource' in kwargs):
+ kwargs['path_prefix'] = '{project_id}/'
+ else:
+ parent_resource = kwargs['parent_resource']
+ p_collection = parent_resource['collection_name']
+ p_member = parent_resource['member_name']
+ kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection,
+ p_member)
+ routes.Mapper.resource(self, member_name,
+ collection_name,
+ **kwargs)
diff --git a/nova/api/openstack/v2/auth.py b/nova/api/openstack/auth.py
index ba5fb603f..9a0432d51 100644
--- a/nova/api/openstack/v2/auth.py
+++ b/nova/api/openstack/auth.py
@@ -32,7 +32,7 @@ from nova import log as logging
from nova import utils
from nova import wsgi as base_wsgi
-LOG = logging.getLogger('nova.api.openstack.v2.auth')
+LOG = logging.getLogger('nova.api.openstack.compute.auth')
FLAGS = flags.FLAGS
flags.DECLARE('use_forwarded_for', 'nova.api.auth')
diff --git a/nova/api/openstack/v2/__init__.py b/nova/api/openstack/compute/__init__.py
index c211cd2f9..2f6e92a42 100644
--- a/nova/api/openstack/v2/__init__.py
+++ b/nova/api/openstack/compute/__init__.py
@@ -24,23 +24,24 @@ import routes
import webob.dec
import webob.exc
-from nova.api.openstack.v2 import consoles
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import flavors
-from nova.api.openstack.v2 import images
-from nova.api.openstack.v2 import image_metadata
-from nova.api.openstack.v2 import ips
-from nova.api.openstack.v2 import limits
-from nova.api.openstack.v2 import servers
-from nova.api.openstack.v2 import server_metadata
-from nova.api.openstack.v2 import versions
+import nova.api.openstack
+from nova.api.openstack.compute import consoles
+from nova.api.openstack.compute import extensions
+from nova.api.openstack.compute import flavors
+from nova.api.openstack.compute import images
+from nova.api.openstack.compute import image_metadata
+from nova.api.openstack.compute import ips
+from nova.api.openstack.compute import limits
+from nova.api.openstack.compute import servers
+from nova.api.openstack.compute import server_metadata
+from nova.api.openstack.compute import versions
from nova.api.openstack import wsgi
from nova import flags
from nova import log as logging
from nova import wsgi as base_wsgi
-LOG = logging.getLogger('nova.api.openstack.v2')
+LOG = logging.getLogger('nova.api.openstack.compute')
FLAGS = flags.FLAGS
flags.DEFINE_bool('allow_admin_api',
False,
@@ -50,43 +51,6 @@ flags.DEFINE_bool('allow_instance_snapshots',
'When True, this API service will permit instance snapshot operations.')
-class FaultWrapper(base_wsgi.Middleware):
- """Calls down the middleware stack, making exceptions into faults."""
-
- @webob.dec.wsgify(RequestClass=wsgi.Request)
- def __call__(self, req):
- try:
- return req.get_response(self.application)
- except Exception as ex:
- LOG.exception(_("Caught error: %s"), unicode(ex))
- exc = webob.exc.HTTPInternalServerError()
- return wsgi.Fault(exc)
-
-
-class APIMapper(routes.Mapper):
- def routematch(self, url=None, environ=None):
- if url is "":
- result = self._match("", environ)
- return result[0], result[1]
- return routes.Mapper.routematch(self, url, environ)
-
-
-class ProjectMapper(APIMapper):
-
- def resource(self, member_name, collection_name, **kwargs):
- if not ('parent_resource' in kwargs):
- kwargs['path_prefix'] = '{project_id}/'
- else:
- parent_resource = kwargs['parent_resource']
- p_collection = parent_resource['collection_name']
- p_member = parent_resource['member_name']
- kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection,
- p_member)
- routes.Mapper.resource(self, member_name,
- collection_name,
- **kwargs)
-
-
class APIRouter(base_wsgi.Router):
"""
Routes requests on the OpenStack API to the appropriate controller
@@ -102,7 +66,7 @@ class APIRouter(base_wsgi.Router):
if ext_mgr is None:
ext_mgr = extensions.ExtensionManager()
- mapper = ProjectMapper()
+ mapper = nova.api.openstack.ProjectMapper()
self._setup_routes(mapper)
self._setup_ext_routes(mapper, ext_mgr)
super(APIRouter, self).__init__(mapper)
diff --git a/nova/api/openstack/v2/consoles.py b/nova/api/openstack/compute/consoles.py
index e9eee4c75..e9eee4c75 100644
--- a/nova/api/openstack/v2/consoles.py
+++ b/nova/api/openstack/compute/consoles.py
diff --git a/nova/api/openstack/compute/contrib/__init__.py b/nova/api/openstack/compute/contrib/__init__.py
new file mode 100644
index 000000000..2713a82f4
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/__init__.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Contrib contains extensions that are shipped with nova.
+
+It can't be called 'extensions' because that causes namespacing problems.
+
+"""
+
+from nova import log as logging
+from nova.api.openstack import extensions
+
+
+LOG = logging.getLogger('nova.api.openstack.compute.contrib')
+
+
+def standard_extensions(ext_mgr):
+ extensions.load_standard_extensions(ext_mgr, LOG, __path__, __package__)
diff --git a/nova/api/openstack/v2/contrib/accounts.py b/nova/api/openstack/compute/contrib/accounts.py
index 9bfff31d7..9253c037d 100644
--- a/nova/api/openstack/v2/contrib/accounts.py
+++ b/nova/api/openstack/compute/contrib/accounts.py
@@ -15,7 +15,7 @@
import webob.exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.auth import manager
@@ -25,7 +25,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.accounts')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.accounts')
class AccountTemplate(xmlutil.TemplateBuilder):
diff --git a/nova/api/openstack/v2/contrib/admin_actions.py b/nova/api/openstack/compute/contrib/admin_actions.py
index 5479f88c4..dedef3061 100644
--- a/nova/api/openstack/v2/contrib/admin_actions.py
+++ b/nova/api/openstack/compute/contrib/admin_actions.py
@@ -19,7 +19,7 @@ import webob
from webob import exc
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import compute
from nova import exception
from nova import flags
@@ -28,7 +28,7 @@ from nova.scheduler import api as scheduler_api
FLAGS = flags.FLAGS
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.admin_actions")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.admin_actions")
class Admin_actions(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/cloudpipe.py b/nova/api/openstack/compute/contrib/cloudpipe.py
index 9327e3987..17bfa810b 100644
--- a/nova/api/openstack/v2/contrib/cloudpipe.py
+++ b/nova/api/openstack/compute/contrib/cloudpipe.py
@@ -18,7 +18,7 @@ import os
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.auth import manager
from nova.cloudpipe import pipelib
from nova import compute
@@ -31,7 +31,7 @@ from nova import utils
FLAGS = flags.FLAGS
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.cloudpipe")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.cloudpipe")
class CloudpipeTemplate(xmlutil.TemplateBuilder):
diff --git a/nova/api/openstack/v2/contrib/console_output.py b/nova/api/openstack/compute/contrib/console_output.py
index 0c9196398..a27d8663b 100644
--- a/nova/api/openstack/v2/contrib/console_output.py
+++ b/nova/api/openstack/compute/contrib/console_output.py
@@ -21,10 +21,10 @@ import webob
from nova import compute
from nova import exception
from nova import log as logging
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.console_output')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.console_output')
class Console_output(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/createserverext.py b/nova/api/openstack/compute/contrib/createserverext.py
index 70fe2796f..25b53a0d6 100644
--- a/nova/api/openstack/v2/contrib/createserverext.py
+++ b/nova/api/openstack/compute/contrib/createserverext.py
@@ -14,9 +14,9 @@
# License for the specific language governing permissions and limitations
# under the License
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import servers
-from nova.api.openstack.v2 import views
+from nova.api.openstack import extensions
+from nova.api.openstack.compute import servers
+from nova.api.openstack.compute import views
from nova.api.openstack import wsgi
diff --git a/nova/api/openstack/v2/contrib/deferred_delete.py b/nova/api/openstack/compute/contrib/deferred_delete.py
index 0b7c60073..312c22c80 100644
--- a/nova/api/openstack/v2/contrib/deferred_delete.py
+++ b/nova/api/openstack/compute/contrib/deferred_delete.py
@@ -18,14 +18,14 @@
import webob
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import servers
+from nova.api.openstack import extensions
+from nova.api.openstack.compute import servers
from nova import compute
from nova import exception
from nova import log as logging
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.deferred-delete")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.deferred-delete")
class Deferred_delete(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/disk_config.py b/nova/api/openstack/compute/contrib/disk_config.py
index 7ce24a3fd..392291652 100644
--- a/nova/api/openstack/v2/contrib/disk_config.py
+++ b/nova/api/openstack/compute/contrib/disk_config.py
@@ -20,7 +20,7 @@ from xml.dom import minidom
from webob import exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import xmlutil
from nova import compute
from nova import db
diff --git a/nova/api/openstack/v2/contrib/extended_status.py b/nova/api/openstack/compute/contrib/extended_status.py
index a3b0410f6..7f9301b93 100644
--- a/nova/api/openstack/v2/contrib/extended_status.py
+++ b/nova/api/openstack/compute/contrib/extended_status.py
@@ -16,7 +16,7 @@
from webob import exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
@@ -25,7 +25,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.extendedstatus")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.extendedstatus")
class Extended_status(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/flavorextradata.py b/nova/api/openstack/compute/contrib/flavorextradata.py
index 462ad1aba..bf6fa8040 100644
--- a/nova/api/openstack/v2/contrib/flavorextradata.py
+++ b/nova/api/openstack/compute/contrib/flavorextradata.py
@@ -24,7 +24,7 @@ attributes. This extension adds to that list:
swap
"""
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
class Flavorextradata(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/flavorextraspecs.py b/nova/api/openstack/compute/contrib/flavorextraspecs.py
index cb5b572fa..eafea5d1f 100644
--- a/nova/api/openstack/v2/contrib/flavorextraspecs.py
+++ b/nova/api/openstack/compute/contrib/flavorextraspecs.py
@@ -21,7 +21,7 @@ from webob import exc
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import db
from nova import exception
diff --git a/nova/api/openstack/v2/contrib/floating_ip_dns.py b/nova/api/openstack/compute/contrib/floating_ip_dns.py
index de1a0a27e..032d5bd7e 100644
--- a/nova/api/openstack/v2/contrib/floating_ip_dns.py
+++ b/nova/api/openstack/compute/contrib/floating_ip_dns.py
@@ -20,13 +20,13 @@ import webob
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import exception
from nova import log as logging
from nova import network
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.floating_ip_dns')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ip_dns')
def make_dns_entry(elem):
diff --git a/nova/api/openstack/v2/contrib/floating_ip_pools.py b/nova/api/openstack/compute/contrib/floating_ip_pools.py
index 9d6386f25..01b9a3645 100644
--- a/nova/api/openstack/v2/contrib/floating_ip_pools.py
+++ b/nova/api/openstack/compute/contrib/floating_ip_pools.py
@@ -16,12 +16,12 @@
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import log as logging
from nova import network
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.floating_ip_poolss')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ip_pools')
def _translate_floating_ip_view(pool):
diff --git a/nova/api/openstack/v2/contrib/floating_ips.py b/nova/api/openstack/compute/contrib/floating_ips.py
index 3a6f4ee34..2400f6c83 100644
--- a/nova/api/openstack/v2/contrib/floating_ips.py
+++ b/nova/api/openstack/compute/contrib/floating_ips.py
@@ -21,7 +21,7 @@ import webob
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import compute
from nova import exception
from nova import log as logging
@@ -29,7 +29,7 @@ from nova import network
from nova import rpc
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.floating_ips')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ips')
def make_float_ip(elem):
diff --git a/nova/api/openstack/v2/contrib/hosts.py b/nova/api/openstack/compute/contrib/hosts.py
index 2bb61696e..66dd64def 100644
--- a/nova/api/openstack/v2/contrib/hosts.py
+++ b/nova/api/openstack/compute/contrib/hosts.py
@@ -21,7 +21,7 @@ from xml.parsers import expat
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import compute
from nova import exception
from nova import flags
@@ -29,7 +29,7 @@ from nova import log as logging
from nova.scheduler import api as scheduler_api
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.hosts")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.hosts")
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/v2/contrib/keypairs.py b/nova/api/openstack/compute/contrib/keypairs.py
index 2dc9b063d..5ac205df5 100644
--- a/nova/api/openstack/v2/contrib/keypairs.py
+++ b/nova/api/openstack/compute/contrib/keypairs.py
@@ -26,7 +26,7 @@ from webob import exc
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import crypto
from nova import db
from nova import exception
diff --git a/nova/api/openstack/v2/contrib/multinic.py b/nova/api/openstack/compute/contrib/multinic.py
index 6719fb18a..18b95e63d 100644
--- a/nova/api/openstack/v2/contrib/multinic.py
+++ b/nova/api/openstack/compute/contrib/multinic.py
@@ -18,13 +18,13 @@
import webob
from webob import exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import compute
from nova import exception
from nova import log as logging
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.multinic")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.multinic")
# Note: The class name is as it has to be for this to be loaded as an
diff --git a/nova/api/openstack/v2/contrib/networks.py b/nova/api/openstack/compute/contrib/networks.py
index 4a96e534f..f2381a19d 100644
--- a/nova/api/openstack/v2/contrib/networks.py
+++ b/nova/api/openstack/compute/contrib/networks.py
@@ -19,7 +19,7 @@
from webob import exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import exception
from nova import flags
from nova import log as logging
@@ -27,7 +27,7 @@ import nova.network.api
FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.api.openstack.v2.contrib.networks')
+LOG = logging.getLogger('nova.api.openstack.compute.contrib.networks')
def network_dict(network):
diff --git a/nova/api/openstack/v2/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py
index 191553a02..5e4a20568 100644
--- a/nova/api/openstack/v2/contrib/quotas.py
+++ b/nova/api/openstack/compute/contrib/quotas.py
@@ -19,7 +19,7 @@ import webob
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova import db
from nova import exception
from nova import quota
diff --git a/nova/api/openstack/v2/contrib/rescue.py b/nova/api/openstack/compute/contrib/rescue.py
index 20c18028d..0ea77cc6a 100644
--- a/nova/api/openstack/v2/contrib/rescue.py
+++ b/nova/api/openstack/compute/contrib/rescue.py
@@ -17,7 +17,7 @@
import webob
from webob import exc
-from nova.api.openstack.v2 import extensions as exts
+from nova.api.openstack import extensions as exts
from nova import compute
from nova import exception
from nova import flags
@@ -26,7 +26,7 @@ from nova import utils
FLAGS = flags.FLAGS
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.rescue")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.rescue")
class Rescue(exts.ExtensionDescriptor):
diff --git a/nova/api/openstack/v2/contrib/security_groups.py b/nova/api/openstack/compute/contrib/security_groups.py
index f4abbcd51..f0d3dfe16 100644
--- a/nova/api/openstack/v2/contrib/security_groups.py
+++ b/nova/api/openstack/compute/contrib/security_groups.py
@@ -22,7 +22,7 @@ from webob import exc
import webob
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
@@ -33,7 +33,7 @@ from nova import log as logging
from nova import utils
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.security_groups")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.security_groups")
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/v2/contrib/server_action_list.py b/nova/api/openstack/compute/contrib/server_action_list.py
index 90573043e..436758572 100644
--- a/nova/api/openstack/v2/contrib/server_action_list.py
+++ b/nova/api/openstack/compute/contrib/server_action_list.py
@@ -15,7 +15,7 @@
import webob.exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
diff --git a/nova/api/openstack/v2/contrib/server_diagnostics.py b/nova/api/openstack/compute/contrib/server_diagnostics.py
index daeda5081..11d1affaf 100644
--- a/nova/api/openstack/v2/contrib/server_diagnostics.py
+++ b/nova/api/openstack/compute/contrib/server_diagnostics.py
@@ -15,7 +15,7 @@
import webob.exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
diff --git a/nova/api/openstack/v2/contrib/simple_tenant_usage.py b/nova/api/openstack/compute/contrib/simple_tenant_usage.py
index 7b07dfae1..f34581f6c 100644
--- a/nova/api/openstack/v2/contrib/simple_tenant_usage.py
+++ b/nova/api/openstack/compute/contrib/simple_tenant_usage.py
@@ -20,7 +20,7 @@ import urlparse
import webob
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import api
diff --git a/nova/api/openstack/v2/contrib/users.py b/nova/api/openstack/compute/contrib/users.py
index e24c7c068..55dba02e4 100644
--- a/nova/api/openstack/v2/contrib/users.py
+++ b/nova/api/openstack/compute/contrib/users.py
@@ -16,7 +16,7 @@
from webob import exc
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.auth import manager
diff --git a/nova/api/openstack/v2/contrib/virtual_interfaces.py b/nova/api/openstack/compute/contrib/virtual_interfaces.py
index 401c7133e..ea37c4d97 100644
--- a/nova/api/openstack/v2/contrib/virtual_interfaces.py
+++ b/nova/api/openstack/compute/contrib/virtual_interfaces.py
@@ -16,14 +16,15 @@
"""The virtual interfaces extension."""
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import log as logging
from nova import network
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.virtual_interfaces")
+LOG = logging.getLogger("nova.api.openstack.compute."
+ "contrib.virtual_interfaces")
vif_nsmap = {None: wsgi.XMLNS_V11}
diff --git a/nova/api/openstack/v2/contrib/virtual_storage_arrays.py b/nova/api/openstack/compute/contrib/virtual_storage_arrays.py
index 0dee3f1b4..39edd155b 100644
--- a/nova/api/openstack/v2/contrib/virtual_storage_arrays.py
+++ b/nova/api/openstack/compute/contrib/virtual_storage_arrays.py
@@ -22,9 +22,9 @@ import webob
from webob import exc
from nova.api.openstack import common
-from nova.api.openstack.v2.contrib import volumes
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import servers
+from nova.api.openstack.compute.contrib import volumes
+from nova.api.openstack import extensions
+from nova.api.openstack.compute import servers
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
@@ -40,7 +40,7 @@ from nova import volume
FLAGS = flags.FLAGS
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.vsa")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.vsa")
def _vsa_view(context, vsa, details=False, instances=None):
diff --git a/nova/api/openstack/v2/contrib/volumes.py b/nova/api/openstack/compute/contrib/volumes.py
index 0ca50b288..972c000ef 100644
--- a/nova/api/openstack/v2/contrib/volumes.py
+++ b/nova/api/openstack/compute/contrib/volumes.py
@@ -19,8 +19,8 @@ from webob import exc
import webob
from nova.api.openstack import common
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import servers
+from nova.api.openstack import extensions
+from nova.api.openstack.compute import servers
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
@@ -31,7 +31,7 @@ from nova import volume
from nova.volume import volume_types
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.volumes")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.volumes")
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/v2/contrib/volumetypes.py b/nova/api/openstack/compute/contrib/volumetypes.py
index 231c86b1b..bf249f3f8 100644
--- a/nova/api/openstack/v2/contrib/volumetypes.py
+++ b/nova/api/openstack/compute/contrib/volumetypes.py
@@ -19,7 +19,7 @@
from webob import exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import db
diff --git a/nova/api/openstack/v2/contrib/zones.py b/nova/api/openstack/compute/contrib/zones.py
index adbc6580f..28e6f0772 100644
--- a/nova/api/openstack/v2/contrib/zones.py
+++ b/nova/api/openstack/compute/contrib/zones.py
@@ -20,8 +20,8 @@
import json
from nova.api.openstack import common
-from nova.api.openstack.v2 import servers
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack.compute import servers
+from nova.api.openstack import extensions
from nova.api.openstack import xmlutil
from nova.api.openstack import wsgi
from nova.compute import api as compute
@@ -32,7 +32,7 @@ from nova import log as logging
import nova.scheduler.api
-LOG = logging.getLogger("nova.api.openstack.v2.contrib.zones")
+LOG = logging.getLogger("nova.api.openstack.compute.contrib.zones")
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/compute/extensions.py b/nova/api/openstack/compute/extensions.py
new file mode 100644
index 000000000..39849e802
--- /dev/null
+++ b/nova/api/openstack/compute/extensions.py
@@ -0,0 +1,45 @@
+# 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.
+
+from nova.api.openstack import extensions as base_extensions
+from nova import flags
+from nova import log as logging
+
+
+LOG = logging.getLogger('nova.api.openstack.compute.extensions')
+FLAGS = flags.FLAGS
+
+
+class ExtensionManager(base_extensions.ExtensionManager):
+ def __new__(cls):
+ if cls._ext_mgr is None:
+ LOG.audit(_('Initializing extension manager.'))
+
+ cls._ext_mgr = super(ExtensionManager, cls).__new__(cls)
+
+ cls.cls_list = FLAGS.osapi_compute_extension
+ cls._ext_mgr.extensions = {}
+ cls._ext_mgr._load_extensions()
+
+ return cls._ext_mgr
+
+
+class ExtensionMiddleware(base_extensions.ExtensionMiddleware):
+ def __init__(self, application, ext_mgr=None):
+ if not ext_mgr:
+ ext_mgr = ExtensionManager()
+ super(ExtensionMiddleware, self).__init__(application, ext_mgr)
diff --git a/nova/api/openstack/v2/flavors.py b/nova/api/openstack/compute/flavors.py
index 21c2a8120..b5212e703 100644
--- a/nova/api/openstack/v2/flavors.py
+++ b/nova/api/openstack/compute/flavors.py
@@ -17,7 +17,7 @@
import webob
-from nova.api.openstack.v2.views import flavors as flavors_view
+from nova.api.openstack.compute.views import flavors as flavors_view
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import instance_types
diff --git a/nova/api/openstack/v2/image_metadata.py b/nova/api/openstack/compute/image_metadata.py
index 1e29d23ce..1e29d23ce 100644
--- a/nova/api/openstack/v2/image_metadata.py
+++ b/nova/api/openstack/compute/image_metadata.py
diff --git a/nova/api/openstack/v2/images.py b/nova/api/openstack/compute/images.py
index 96a2275e6..194c5071e 100644
--- a/nova/api/openstack/v2/images.py
+++ b/nova/api/openstack/compute/images.py
@@ -16,7 +16,7 @@
import webob.exc
from nova.api.openstack import common
-from nova.api.openstack.v2.views import images as views_images
+from nova.api.openstack.compute.views import images as views_images
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
@@ -26,7 +26,7 @@ import nova.image
from nova import log
-LOG = log.getLogger('nova.api.openstack.v2.images')
+LOG = log.getLogger('nova.api.openstack.compute.images')
FLAGS = flags.FLAGS
SUPPORTED_FILTERS = {
diff --git a/nova/api/openstack/v2/ips.py b/nova/api/openstack/compute/ips.py
index 3dc9cf928..ec107914a 100644
--- a/nova/api/openstack/v2/ips.py
+++ b/nova/api/openstack/compute/ips.py
@@ -19,14 +19,14 @@ from webob import exc
import nova
from nova.api.openstack import common
-from nova.api.openstack.v2.views import addresses as view_addresses
+from nova.api.openstack.compute.views import addresses as view_addresses
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import log as logging
from nova import flags
-LOG = logging.getLogger('nova.api.openstack.v2.ips')
+LOG = logging.getLogger('nova.api.openstack.compute.ips')
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/v2/limits.py b/nova/api/openstack/compute/limits.py
index e1f5ff836..0a1b80057 100644
--- a/nova/api/openstack/v2/limits.py
+++ b/nova/api/openstack/compute/limits.py
@@ -28,7 +28,7 @@ import time
from webob.dec import wsgify
import webob.exc
-from nova.api.openstack.v2.views import limits as limits_views
+from nova.api.openstack.compute.views import limits as limits_views
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import quota
diff --git a/nova/api/openstack/v2/ratelimiting/__init__.py b/nova/api/openstack/compute/ratelimiting/__init__.py
index 78dc465a7..78dc465a7 100644
--- a/nova/api/openstack/v2/ratelimiting/__init__.py
+++ b/nova/api/openstack/compute/ratelimiting/__init__.py
diff --git a/nova/api/openstack/v2/schemas/atom-link.rng b/nova/api/openstack/compute/schemas/atom-link.rng
index edba5eee6..edba5eee6 100644
--- a/nova/api/openstack/v2/schemas/atom-link.rng
+++ b/nova/api/openstack/compute/schemas/atom-link.rng
diff --git a/nova/api/openstack/v2/schemas/atom.rng b/nova/api/openstack/compute/schemas/atom.rng
index c2df4e410..c2df4e410 100644
--- a/nova/api/openstack/v2/schemas/atom.rng
+++ b/nova/api/openstack/compute/schemas/atom.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/addresses.rng b/nova/api/openstack/compute/schemas/v1.1/addresses.rng
index b498e8a63..b498e8a63 100644
--- a/nova/api/openstack/v2/schemas/v1.1/addresses.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/addresses.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/extension.rng b/nova/api/openstack/compute/schemas/v1.1/extension.rng
index 336659755..336659755 100644
--- a/nova/api/openstack/v2/schemas/v1.1/extension.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/extension.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/extensions.rng b/nova/api/openstack/compute/schemas/v1.1/extensions.rng
index 4d8bff646..4d8bff646 100644
--- a/nova/api/openstack/v2/schemas/v1.1/extensions.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/extensions.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/flavor.rng b/nova/api/openstack/compute/schemas/v1.1/flavor.rng
index 08746ce3d..08746ce3d 100644
--- a/nova/api/openstack/v2/schemas/v1.1/flavor.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/flavor.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/flavors.rng b/nova/api/openstack/compute/schemas/v1.1/flavors.rng
index b7a3acc01..b7a3acc01 100644
--- a/nova/api/openstack/v2/schemas/v1.1/flavors.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/flavors.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/flavors_index.rng b/nova/api/openstack/compute/schemas/v1.1/flavors_index.rng
index d1a4fedb1..d1a4fedb1 100644
--- a/nova/api/openstack/v2/schemas/v1.1/flavors_index.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/flavors_index.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/image.rng b/nova/api/openstack/compute/schemas/v1.1/image.rng
index 505081fba..505081fba 100644
--- a/nova/api/openstack/v2/schemas/v1.1/image.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/image.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/images.rng b/nova/api/openstack/compute/schemas/v1.1/images.rng
index 064d4d9cc..064d4d9cc 100644
--- a/nova/api/openstack/v2/schemas/v1.1/images.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/images.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/images_index.rng b/nova/api/openstack/compute/schemas/v1.1/images_index.rng
index 3db0b2672..3db0b2672 100644
--- a/nova/api/openstack/v2/schemas/v1.1/images_index.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/images_index.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/limits.rng b/nova/api/openstack/compute/schemas/v1.1/limits.rng
index 1af8108ec..1af8108ec 100644
--- a/nova/api/openstack/v2/schemas/v1.1/limits.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/limits.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/metadata.rng b/nova/api/openstack/compute/schemas/v1.1/metadata.rng
index b2f5d702a..b2f5d702a 100644
--- a/nova/api/openstack/v2/schemas/v1.1/metadata.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/metadata.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/server.rng b/nova/api/openstack/compute/schemas/v1.1/server.rng
index 07fa16daa..07fa16daa 100644
--- a/nova/api/openstack/v2/schemas/v1.1/server.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/server.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/servers.rng b/nova/api/openstack/compute/schemas/v1.1/servers.rng
index 4e2bb8853..4e2bb8853 100644
--- a/nova/api/openstack/v2/schemas/v1.1/servers.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/servers.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/servers_index.rng b/nova/api/openstack/compute/schemas/v1.1/servers_index.rng
index 023e4b66a..023e4b66a 100644
--- a/nova/api/openstack/v2/schemas/v1.1/servers_index.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/servers_index.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/version.rng b/nova/api/openstack/compute/schemas/v1.1/version.rng
index ae76270ba..ae76270ba 100644
--- a/nova/api/openstack/v2/schemas/v1.1/version.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/version.rng
diff --git a/nova/api/openstack/v2/schemas/v1.1/versions.rng b/nova/api/openstack/compute/schemas/v1.1/versions.rng
index 8b2cc7f71..8b2cc7f71 100644
--- a/nova/api/openstack/v2/schemas/v1.1/versions.rng
+++ b/nova/api/openstack/compute/schemas/v1.1/versions.rng
diff --git a/nova/api/openstack/v2/server_metadata.py b/nova/api/openstack/compute/server_metadata.py
index 52a90f96e..52a90f96e 100644
--- a/nova/api/openstack/v2/server_metadata.py
+++ b/nova/api/openstack/compute/server_metadata.py
diff --git a/nova/api/openstack/v2/servers.py b/nova/api/openstack/compute/servers.py
index c2655a73e..60b85f591 100644
--- a/nova/api/openstack/v2/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -22,8 +22,8 @@ from webob import exc
import webob
from nova.api.openstack import common
-from nova.api.openstack.v2 import ips
-from nova.api.openstack.v2.views import servers as views_servers
+from nova.api.openstack.compute import ips
+from nova.api.openstack.compute.views import servers as views_servers
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
@@ -36,7 +36,7 @@ from nova.scheduler import api as scheduler_api
from nova import utils
-LOG = logging.getLogger('nova.api.openstack.v2.servers')
+LOG = logging.getLogger('nova.api.openstack.compute.servers')
FLAGS = flags.FLAGS
diff --git a/nova/api/openstack/v2/versions.py b/nova/api/openstack/compute/versions.py
index 45b84f7c2..ddc31e9f0 100644
--- a/nova/api/openstack/v2/versions.py
+++ b/nova/api/openstack/compute/versions.py
@@ -19,7 +19,7 @@ from datetime import datetime
from lxml import etree
-from nova.api.openstack.v2.views import versions as views_versions
+from nova.api.openstack.compute.views import versions as views_versions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
diff --git a/nova/api/openstack/v2/views/__init__.py b/nova/api/openstack/compute/views/__init__.py
index e69de29bb..e69de29bb 100644
--- a/nova/api/openstack/v2/views/__init__.py
+++ b/nova/api/openstack/compute/views/__init__.py
diff --git a/nova/api/openstack/v2/views/addresses.py b/nova/api/openstack/compute/views/addresses.py
index 6f518b11a..776ba9e59 100644
--- a/nova/api/openstack/v2/views/addresses.py
+++ b/nova/api/openstack/compute/views/addresses.py
@@ -23,7 +23,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.api.openstack.v2.views.addresses')
+LOG = logging.getLogger('nova.api.openstack.compute.views.addresses')
class ViewBuilder(common.ViewBuilder):
diff --git a/nova/api/openstack/v2/views/flavors.py b/nova/api/openstack/compute/views/flavors.py
index 64284e406..64284e406 100644
--- a/nova/api/openstack/v2/views/flavors.py
+++ b/nova/api/openstack/compute/views/flavors.py
diff --git a/nova/api/openstack/v2/views/images.py b/nova/api/openstack/compute/views/images.py
index c4cfe8031..c4cfe8031 100644
--- a/nova/api/openstack/v2/views/images.py
+++ b/nova/api/openstack/compute/views/images.py
diff --git a/nova/api/openstack/v2/views/limits.py b/nova/api/openstack/compute/views/limits.py
index cff6781be..cff6781be 100644
--- a/nova/api/openstack/v2/views/limits.py
+++ b/nova/api/openstack/compute/views/limits.py
diff --git a/nova/api/openstack/v2/views/servers.py b/nova/api/openstack/compute/views/servers.py
index 859bd48ab..6a1622a66 100644
--- a/nova/api/openstack/v2/views/servers.py
+++ b/nova/api/openstack/compute/views/servers.py
@@ -19,14 +19,14 @@
import hashlib
from nova.api.openstack import common
-from nova.api.openstack.v2.views import addresses as views_addresses
-from nova.api.openstack.v2.views import flavors as views_flavors
-from nova.api.openstack.v2.views import images as views_images
+from nova.api.openstack.compute.views import addresses as views_addresses
+from nova.api.openstack.compute.views import flavors as views_flavors
+from nova.api.openstack.compute.views import images as views_images
from nova import log as logging
from nova import utils
-LOG = logging.getLogger('nova.api.openstack.v2.views.servers')
+LOG = logging.getLogger('nova.api.openstack.compute.views.servers')
class ViewBuilder(common.ViewBuilder):
diff --git a/nova/api/openstack/v2/views/versions.py b/nova/api/openstack/compute/views/versions.py
index cb2fd9f4a..cb2fd9f4a 100644
--- a/nova/api/openstack/v2/views/versions.py
+++ b/nova/api/openstack/compute/views/versions.py
diff --git a/nova/api/openstack/v2/extensions.py b/nova/api/openstack/extensions.py
index 0aa3146a9..6c49e8ace 100644
--- a/nova/api/openstack/v2/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -16,11 +16,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
import routes
import webob.dec
import webob.exc
-import nova.api.openstack.v2
+import nova.api.openstack
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
@@ -30,7 +31,7 @@ from nova import utils
from nova import wsgi as base_wsgi
-LOG = logging.getLogger('nova.api.openstack.v2.extensions')
+LOG = logging.getLogger('nova.api.openstack.extensions')
FLAGS = flags.FLAGS
@@ -326,7 +327,7 @@ class ExtensionMiddleware(base_wsgi.Middleware):
ext_mgr = ExtensionManager()
self.ext_mgr = ext_mgr
- mapper = nova.api.openstack.v2.ProjectMapper()
+ mapper = nova.api.openstack.ProjectMapper()
# extended actions
action_resources = self._action_ext_resources(application, ext_mgr,
@@ -388,17 +389,6 @@ class ExtensionManager(object):
def reset(cls):
cls._ext_mgr = None
- def __new__(cls):
- if cls._ext_mgr is None:
- LOG.audit(_('Initializing extension manager.'))
-
- cls._ext_mgr = super(ExtensionManager, cls).__new__(cls)
-
- cls._ext_mgr.extensions = {}
- cls._ext_mgr._load_extensions()
-
- return cls._ext_mgr
-
def register(self, ext):
# Do nothing if the extension doesn't check out
if not self._check_extension(ext):
@@ -483,7 +473,6 @@ class ExtensionManager(object):
LOG.debug(_("Loading extension %s"), ext_factory)
# Load the factory
-
factory = utils.import_class(ext_factory)
# Call it
@@ -493,7 +482,7 @@ class ExtensionManager(object):
def _load_extensions(self):
"""Load extensions specified on the command line."""
- extensions = list(FLAGS.osapi_extension)
+ extensions = list(self.cls_list)
for ext_factory in extensions:
try:
@@ -573,3 +562,62 @@ def wrap_errors(fn):
except Exception, e:
raise webob.exc.HTTPInternalServerError()
return wrapped
+
+
+def load_standard_extensions(ext_mgr, logger, path, package):
+ """Registers all standard API extensions."""
+
+ # Walk through all the modules in our directory...
+ our_dir = path[0]
+ for dirpath, dirnames, filenames in os.walk(our_dir):
+ # Compute the relative package name from the dirpath
+ relpath = os.path.relpath(dirpath, our_dir)
+ if relpath == '.':
+ relpkg = ''
+ else:
+ relpkg = '.%s' % '.'.join(relpath.split(os.sep))
+
+ # Now, consider each file in turn, only considering .py files
+ for fname in filenames:
+ root, ext = os.path.splitext(fname)
+
+ # Skip __init__ and anything that's not .py
+ if ext != '.py' or root == '__init__':
+ continue
+
+ # Try loading it
+ classname = ("%s%s.%s.%s%s" %
+ (package, relpkg, root,
+ root[0].upper(), root[1:]))
+ try:
+ ext_mgr.load_extension(classname)
+ except Exception as exc:
+ logger.warn(_('Failed to load extension %(classname)s: '
+ '%(exc)s') % locals())
+
+ # Now, let's consider any subdirectories we may have...
+ subdirs = []
+ for dname in dirnames:
+ # Skip it if it does not have __init__.py
+ if not os.path.exists(os.path.join(dirpath, dname,
+ '__init__.py')):
+ continue
+
+ # If it has extension(), delegate...
+ ext_name = ("%s%s.%s.extension" %
+ (package, relpkg, dname))
+ try:
+ ext = utils.import_class(ext_name)
+ except exception.ClassNotFound:
+ # extension() doesn't exist on it, so we'll explore
+ # the directory for ourselves
+ subdirs.append(dname)
+ else:
+ try:
+ ext(ext_mgr)
+ except Exception as exc:
+ logger.warn(_('Failed to load extension %(ext_name)s: '
+ '%(exc)s') % locals())
+
+ # Update the list of directories we'll explore...
+ dirnames[:] = subdirs
diff --git a/nova/api/openstack/v2/urlmap.py b/nova/api/openstack/urlmap.py
index bae69198e..825a12af2 100644
--- a/nova/api/openstack/v2/urlmap.py
+++ b/nova/api/openstack/urlmap.py
@@ -28,7 +28,7 @@ _option_header_piece_re = re.compile(r';\s*([^\s;=]+|%s)\s*'
r'(?:=\s*([^;]+|%s))?\s*' %
(_quoted_string_re, _quoted_string_re))
-LOG = logging.getLogger('nova.api.openstack.v2.map')
+LOG = logging.getLogger('nova.api.openstack.compute.map')
def unquote_header_value(value):
diff --git a/nova/api/openstack/v2/contrib/__init__.py b/nova/api/openstack/v2/contrib/__init__.py
deleted file mode 100644
index d361dac9c..000000000
--- a/nova/api/openstack/v2/contrib/__init__.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Justin Santa Barbara
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""Contrib contains extensions that are shipped with nova.
-
-It can't be called 'extensions' because that causes namespacing problems.
-
-"""
-
-import os
-
-from nova import exception
-from nova import log as logging
-from nova import utils
-
-
-LOG = logging.getLogger('nova.api.openstack.v2.contrib')
-
-
-def standard_extensions(ext_mgr):
- """Registers all standard API extensions."""
-
- # Walk through all the modules in our directory...
- our_dir = __path__[0]
- for dirpath, dirnames, filenames in os.walk(our_dir):
- # Compute the relative package name from the dirpath
- relpath = os.path.relpath(dirpath, our_dir)
- if relpath == '.':
- relpkg = ''
- else:
- relpkg = '.%s' % '.'.join(relpath.split(os.sep))
-
- # Now, consider each file in turn, only considering .py files
- for fname in filenames:
- root, ext = os.path.splitext(fname)
-
- # Skip __init__ and anything that's not .py
- if ext != '.py' or root == '__init__':
- continue
-
- # Try loading it
- classname = ("%s%s.%s.%s%s" %
- (__package__, relpkg, root,
- root[0].upper(), root[1:]))
- try:
- ext_mgr.load_extension(classname)
- except Exception as exc:
- LOG.warn(_('Failed to load extension %(classname)s: '
- '%(exc)s') % locals())
-
- # Now, let's consider any subdirectories we may have...
- subdirs = []
- for dname in dirnames:
- # Skip it if it does not have __init__.py
- if not os.path.exists(os.path.join(dirpath, dname,
- '__init__.py')):
- continue
-
- # If it has extension(), delegate...
- ext_name = ("%s%s.%s.extension" %
- (__package__, relpkg, dname))
- try:
- ext = utils.import_class(ext_name)
- except exception.ClassNotFound:
- # extension() doesn't exist on it, so we'll explore
- # the directory for ourselves
- subdirs.append(dname)
- else:
- try:
- ext(ext_mgr)
- except Exception as exc:
- LOG.warn(_('Failed to load extension %(ext_name)s: '
- '%(exc)s') % locals())
-
- # Update the list of directories we'll explore...
- dirnames[:] = subdirs
diff --git a/nova/api/openstack/volume/__init__.py b/nova/api/openstack/volume/__init__.py
new file mode 100644
index 000000000..075b53c29
--- /dev/null
+++ b/nova/api/openstack/volume/__init__.py
@@ -0,0 +1,99 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+WSGI middleware for OpenStack Volume API.
+"""
+
+import routes
+import webob.dec
+import webob.exc
+
+import nova.api.openstack
+from nova.api.openstack.volume import extensions
+from nova.api.openstack.volume import snapshots
+from nova.api.openstack.volume import types
+from nova.api.openstack.volume import volumes
+from nova.api.openstack.volume import versions
+from nova.api.openstack import wsgi
+from nova import flags
+from nova import log as logging
+from nova import wsgi as base_wsgi
+
+
+LOG = logging.getLogger('nova.api.openstack.volume')
+FLAGS = flags.FLAGS
+
+
+class APIRouter(base_wsgi.Router):
+ """
+ Routes requests on the OpenStack API to the appropriate controller
+ and method.
+ """
+
+ @classmethod
+ def factory(cls, global_config, **local_config):
+ """Simple paste factory, :class:`nova.wsgi.Router` doesn't have one"""
+ return cls()
+
+ def __init__(self, ext_mgr=None):
+ if ext_mgr is None:
+ ext_mgr = extensions.ExtensionManager()
+
+ mapper = nova.api.openstack.ProjectMapper()
+ self._setup_routes(mapper)
+ self._setup_ext_routes(mapper, ext_mgr)
+ super(APIRouter, self).__init__(mapper)
+
+ def _setup_ext_routes(self, mapper, ext_mgr):
+ serializer = wsgi.ResponseSerializer(
+ {'application/xml': wsgi.XMLDictSerializer()})
+ for resource in ext_mgr.get_resources():
+ LOG.debug(_('Extended resource: %s'),
+ resource.collection)
+ if resource.serializer is None:
+ resource.serializer = serializer
+
+ kargs = dict(
+ controller=wsgi.Resource(
+ resource.controller, resource.deserializer,
+ resource.serializer),
+ collection=resource.collection_actions,
+ member=resource.member_actions)
+
+ if resource.parent:
+ kargs['parent_resource'] = resource.parent
+
+ mapper.resource(resource.collection, resource.collection, **kargs)
+
+ def _setup_routes(self, mapper):
+ mapper.connect("versions", "/",
+ controller=versions.create_resource(),
+ action='show')
+
+ mapper.redirect("", "/")
+
+ mapper.resource("volume", "volumes",
+ controller=volumes.create_resource(),
+ collection={'detail': 'GET'})
+
+ mapper.resource("type", "types",
+ controller=types.create_resource())
+
+ mapper.resource("snapshot", "snapshots",
+ controller=snapshots.create_resource())
diff --git a/nova/api/openstack/volume/contrib/__init__.py b/nova/api/openstack/volume/contrib/__init__.py
new file mode 100644
index 000000000..58c0413ab
--- /dev/null
+++ b/nova/api/openstack/volume/contrib/__init__.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Contrib contains extensions that are shipped with nova.
+
+It can't be called 'extensions' because that causes namespacing problems.
+
+"""
+
+from nova import log as logging
+from nova.api.openstack import extensions
+
+
+LOG = logging.getLogger('nova.api.openstack.volume.contrib')
+
+
+def standard_extensions(ext_mgr):
+ extensions.load_standard_extensions(ext_mgr, LOG, __path__, __package__)
diff --git a/nova/api/openstack/volume/extensions.py b/nova/api/openstack/volume/extensions.py
new file mode 100644
index 000000000..d1007629e
--- /dev/null
+++ b/nova/api/openstack/volume/extensions.py
@@ -0,0 +1,44 @@
+# 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.
+
+from nova.api.openstack import extensions as base_extensions
+from nova import flags
+from nova import log as logging
+
+
+LOG = logging.getLogger('nova.api.openstack.volume.extensions')
+FLAGS = flags.FLAGS
+
+
+class ExtensionManager(base_extensions.ExtensionManager):
+ def __new__(cls):
+ if cls._ext_mgr is None:
+ LOG.audit(_('Initializing extension manager.'))
+
+ cls._ext_mgr = super(ExtensionManager, cls).__new__(cls)
+
+ cls.cls_list = FLAGS.osapi_volume_extension
+ cls._ext_mgr.extensions = {}
+ cls._ext_mgr._load_extensions()
+
+ return cls._ext_mgr
+
+
+class ExtensionMiddleware(base_extensions.ExtensionMiddleware):
+ def __init__(self, application, ext_mgr=None):
+ ext_mgr = ExtensionManager()
+ super(ExtensionMiddleware, self).__init__(application, ext_mgr)
diff --git a/nova/api/openstack/volume/snapshots.py b/nova/api/openstack/volume/snapshots.py
new file mode 100644
index 000000000..f6ec3dc5f
--- /dev/null
+++ b/nova/api/openstack/volume/snapshots.py
@@ -0,0 +1,183 @@
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""The volumes snapshots api."""
+
+from webob import exc
+import webob
+
+from nova.api.openstack import common
+from nova.api.openstack import extensions
+from nova.api.openstack.compute import servers
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+from nova import compute
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import volume
+from nova.volume import volume_types
+
+
+LOG = logging.getLogger("nova.api.openstack.volume.snapshots")
+
+
+FLAGS = flags.FLAGS
+
+
+def _translate_snapshot_detail_view(context, vol):
+ """Maps keys for snapshots details view."""
+
+ d = _translate_snapshot_summary_view(context, vol)
+
+ # NOTE(gagupta): No additional data / lookups at the moment
+ return d
+
+
+def _translate_snapshot_summary_view(context, vol):
+ """Maps keys for snapshots summary view."""
+ d = {}
+
+ d['id'] = vol['id']
+ d['volumeId'] = vol['volume_id']
+ d['status'] = vol['status']
+ # NOTE(gagupta): We map volume_size as the snapshot size
+ d['size'] = vol['volume_size']
+ d['createdAt'] = vol['created_at']
+ d['displayName'] = vol['display_name']
+ d['displayDescription'] = vol['display_description']
+ return d
+
+
+class SnapshotsController(object):
+ """The Volumes API controller for the OpenStack API."""
+
+ def __init__(self):
+ self.volume_api = volume.API()
+ super(SnapshotsController, self).__init__()
+
+ def show(self, req, id):
+ """Return data about the given snapshot."""
+ context = req.environ['nova.context']
+
+ try:
+ vol = self.volume_api.get_snapshot(context, id)
+ except exception.NotFound:
+ return exc.HTTPNotFound()
+
+ return {'snapshot': _translate_snapshot_detail_view(context, vol)}
+
+ def delete(self, req, id):
+ """Delete a snapshot."""
+ context = req.environ['nova.context']
+
+ LOG.audit(_("Delete snapshot with id: %s"), id, context=context)
+
+ try:
+ self.volume_api.delete_snapshot(context, snapshot_id=id)
+ except exception.NotFound:
+ return exc.HTTPNotFound()
+ return webob.Response(status_int=202)
+
+ def index(self, req):
+ """Returns a summary list of snapshots."""
+ return self._items(req, entity_maker=_translate_snapshot_summary_view)
+
+ def detail(self, req):
+ """Returns a detailed list of snapshots."""
+ return self._items(req, entity_maker=_translate_snapshot_detail_view)
+
+ def _items(self, req, entity_maker):
+ """Returns a list of snapshots, transformed through entity_maker."""
+ context = req.environ['nova.context']
+
+ snapshots = self.volume_api.get_all_snapshots(context)
+ limited_list = common.limited(snapshots, req)
+ res = [entity_maker(context, snapshot) for snapshot in limited_list]
+ return {'snapshots': res}
+
+ def create(self, req, body):
+ """Creates a new snapshot."""
+ context = req.environ['nova.context']
+
+ if not body:
+ return exc.HTTPUnprocessableEntity()
+
+ snapshot = body['snapshot']
+ volume_id = snapshot['volume_id']
+ force = snapshot.get('force', False)
+ LOG.audit(_("Create snapshot from volume %s"), volume_id,
+ context=context)
+
+ if force:
+ new_snapshot = self.volume_api.create_snapshot_force(context,
+ volume_id,
+ snapshot.get('display_name'),
+ snapshot.get('display_description'))
+ else:
+ new_snapshot = self.volume_api.create_snapshot(context,
+ volume_id,
+ snapshot.get('display_name'),
+ snapshot.get('display_description'))
+
+ retval = _translate_snapshot_detail_view(context, new_snapshot)
+
+ return {'snapshot': retval}
+
+
+def make_snapshot(elem):
+ elem.set('id')
+ elem.set('status')
+ elem.set('size')
+ elem.set('createdAt')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('volumeId')
+
+
+class SnapshotTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('snapshot', selector='snapshot')
+ make_snapshot(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SnapshotsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('snapshots')
+ elem = xmlutil.SubTemplateElement(root, 'snapshot',
+ selector='snapshots')
+ make_snapshot(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SnapshotSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return SnapshotTemplate()
+
+ def index(self):
+ return SnapshotsTemplate()
+
+ def detail(self):
+ return SnapshotsTemplate()
+
+
+def create_resource():
+ body_serializers = {
+ 'application/xml': SnapshotSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
+ return wsgi.Resource(SnapshotsController(), serializer=serializer)
diff --git a/nova/api/openstack/volume/types.py b/nova/api/openstack/volume/types.py
new file mode 100644
index 000000000..1c6a68b58
--- /dev/null
+++ b/nova/api/openstack/volume/types.py
@@ -0,0 +1,89 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Zadara Storage Inc.
+# Copyright (c) 2011 OpenStack LLC.
+#
+# 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.
+
+""" The volume type & volume types extra specs extension"""
+
+from webob import exc
+
+from nova.api.openstack import extensions
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+from nova import db
+from nova import exception
+from nova.volume import volume_types
+
+
+class VolumeTypesController(object):
+ """ The volume types API controller for the Openstack API """
+
+ def index(self, req):
+ """ Returns the list of volume types """
+ context = req.environ['nova.context']
+ return volume_types.get_all_types(context)
+
+ def show(self, req, id):
+ """ Return a single volume type item """
+ context = req.environ['nova.context']
+
+ try:
+ vol_type = volume_types.get_volume_type(context, id)
+ except exception.NotFound or exception.ApiError:
+ raise exc.HTTPNotFound()
+
+ return {'volume_type': vol_type}
+
+
+def make_voltype(elem):
+ elem.set('id')
+ elem.set('name')
+ extra_specs = xmlutil.make_flat_dict('extra_specs', selector='extra_specs')
+ elem.append(extra_specs)
+
+
+class VolumeTypeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume_type', selector='volume_type')
+ make_voltype(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume_types')
+ sel = lambda obj, do_raise=False: obj.values()
+ elem = xmlutil.SubTemplateElement(root, 'volume_type', selector=sel)
+ make_voltype(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypesSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return VolumeTypesTemplate()
+
+ def default(self):
+ return VolumeTypeTemplate()
+
+
+def create_resource():
+ body_serializers = {
+ 'application/xml': VolumeTypesSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
+ deserializer = wsgi.RequestDeserializer()
+
+ return wsgi.Resource(VolumeTypesController(), serializer=serializer)
diff --git a/nova/api/openstack/volume/versions.py b/nova/api/openstack/volume/versions.py
new file mode 100644
index 000000000..9a29e4adf
--- /dev/null
+++ b/nova/api/openstack/volume/versions.py
@@ -0,0 +1,83 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from datetime import datetime
+
+from lxml import etree
+
+from nova.api.openstack.compute import versions
+from nova.api.openstack.volume.views import versions as views_versions
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+
+
+VERSIONS = {
+ "v1": {
+ "id": "v1",
+ "status": "CURRENT",
+ "updated": "2012-01-04T11:33:21Z",
+ "links": [
+ {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://jorgew.github.com/block-storage-api/"
+ "content/os-block-storage-1.0.pdf",
+ },
+ {
+ "rel": "describedby",
+ "type": "application/vnd.sun.wadl+xml",
+ #(anthony) FIXME
+ "href": "http://docs.rackspacecloud.com/"
+ "servers/api/v1.1/application.wadl",
+ },
+ ],
+ "media-types": [
+ {
+ "base": "application/xml",
+ "type": "application/vnd.openstack.volume+xml;version=1",
+ },
+ {
+ "base": "application/json",
+ "type": "application/vnd.openstack.volume+json;version=1",
+ }
+ ],
+ }
+}
+
+
+class Versions(versions.Versions):
+ def dispatch(self, request, *args):
+ """Respond to a request for all OpenStack API versions."""
+ builder = views_versions.get_view_builder(request)
+ if request.path == '/':
+ # List Versions
+ return builder.build_versions(VERSIONS)
+ else:
+ # Versions Multiple Choice
+ return builder.build_choices(VERSIONS, request)
+
+
+class VolumeVersionV1(object):
+ @wsgi.serializers(xml=versions.VersionTemplate,
+ atom=versions.VersionAtomSerializer)
+ def show(self, req):
+ builder = views_versions.get_view_builder(req)
+ return builder.build_version(VERSIONS['v2.0'])
+
+
+def create_resource():
+ return wsgi.Resource(VolumeVersionV1())
diff --git a/nova/api/openstack/volume/views/__init__.py b/nova/api/openstack/volume/views/__init__.py
new file mode 100644
index 000000000..d65c689a8
--- /dev/null
+++ b/nova/api/openstack/volume/views/__init__.py
@@ -0,0 +1,16 @@
+# 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.
diff --git a/nova/api/openstack/volume/views/versions.py b/nova/api/openstack/volume/views/versions.py
new file mode 100644
index 000000000..e446a4b64
--- /dev/null
+++ b/nova/api/openstack/volume/views/versions.py
@@ -0,0 +1,37 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010-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.
+
+import copy
+import os
+
+from nova.api.openstack.compute.views import versions as compute_views
+
+
+def get_view_builder(req):
+ base_url = req.application_url
+ return ViewBuilder(base_url)
+
+
+class ViewBuilder(compute_views.ViewBuilder):
+ def generate_href(self, path=None):
+ """Create an url that refers to a specific version_number."""
+ version_number = 'v1'
+ if path:
+ path = path.strip('/')
+ return os.path.join(self.base_url, version_number, path)
+ else:
+ return os.path.join(self.base_url, version_number) + '/'
diff --git a/nova/api/openstack/volume/volumes.py b/nova/api/openstack/volume/volumes.py
new file mode 100644
index 000000000..5e16f4fde
--- /dev/null
+++ b/nova/api/openstack/volume/volumes.py
@@ -0,0 +1,254 @@
+# Copyright 2011 Justin Santa Barbara
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""The volumes api."""
+
+from webob import exc
+import webob
+
+from nova.api.openstack import common
+from nova.api.openstack.compute import servers
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import volume
+from nova.volume import volume_types
+
+
+LOG = logging.getLogger("nova.api.openstack.volume.volumes")
+
+
+FLAGS = flags.FLAGS
+
+
+def _translate_volume_detail_view(context, vol):
+ """Maps keys for volumes details view."""
+
+ d = _translate_volume_summary_view(context, vol)
+
+ # No additional data / lookups at the moment
+
+ return d
+
+
+def _translate_volume_summary_view(context, vol):
+ """Maps keys for volumes summary view."""
+ d = {}
+
+ d['id'] = vol['id']
+ d['status'] = vol['status']
+ d['size'] = vol['size']
+ d['availabilityZone'] = vol['availability_zone']
+ d['createdAt'] = vol['created_at']
+
+ if vol['attach_status'] == 'attached':
+ d['attachments'] = [_translate_attachment_detail_view(context, vol)]
+ else:
+ d['attachments'] = [{}]
+
+ d['displayName'] = vol['display_name']
+ d['displayDescription'] = vol['display_description']
+
+ if vol['volume_type_id'] and vol.get('volume_type'):
+ d['volumeType'] = vol['volume_type']['name']
+ else:
+ d['volumeType'] = vol['volume_type_id']
+
+ d['snapshotId'] = vol['snapshot_id']
+ LOG.audit(_("vol=%s"), vol, context=context)
+
+ if vol.get('volume_metadata'):
+ meta_dict = {}
+ for i in vol['volume_metadata']:
+ meta_dict[i['key']] = i['value']
+ d['metadata'] = meta_dict
+ else:
+ d['metadata'] = {}
+
+ return d
+
+
+class VolumeController(object):
+ """The Volumes API controller for the OpenStack API."""
+
+ def __init__(self):
+ self.volume_api = volume.API()
+ super(VolumeController, self).__init__()
+
+ def show(self, req, id):
+ """Return data about the given volume."""
+ context = req.environ['nova.context']
+
+ try:
+ vol = self.volume_api.get(context, id)
+ except exception.NotFound:
+ raise exc.HTTPNotFound()
+
+ return {'volume': _translate_volume_detail_view(context, vol)}
+
+ def delete(self, req, id):
+ """Delete a volume."""
+ context = req.environ['nova.context']
+
+ LOG.audit(_("Delete volume with id: %s"), id, context=context)
+
+ try:
+ self.volume_api.delete(context, volume_id=id)
+ except exception.NotFound:
+ raise exc.HTTPNotFound()
+ return webob.Response(status_int=202)
+
+ def index(self, req):
+ """Returns a summary list of volumes."""
+ return self._items(req, entity_maker=_translate_volume_summary_view)
+
+ def detail(self, req):
+ """Returns a detailed list of volumes."""
+ return self._items(req, entity_maker=_translate_volume_detail_view)
+
+ def _items(self, req, entity_maker):
+ """Returns a list of volumes, transformed through entity_maker."""
+ context = req.environ['nova.context']
+
+ volumes = self.volume_api.get_all(context)
+ limited_list = common.limited(volumes, req)
+ res = [entity_maker(context, vol) for vol in limited_list]
+ return {'volumes': res}
+
+ def create(self, req, body):
+ """Creates a new volume."""
+ context = req.environ['nova.context']
+
+ if not body:
+ raise exc.HTTPUnprocessableEntity()
+
+ vol = body['volume']
+ size = vol['size']
+ LOG.audit(_("Create volume of %s GB"), size, context=context)
+
+ vol_type = vol.get('volume_type', None)
+ if vol_type:
+ try:
+ vol_type = volume_types.get_volume_type_by_name(context,
+ vol_type)
+ except exception.NotFound:
+ raise exc.HTTPNotFound()
+
+ metadata = vol.get('metadata', None)
+
+ new_volume = self.volume_api.create(context, size,
+ vol.get('snapshot_id'),
+ vol.get('display_name'),
+ vol.get('display_description'),
+ volume_type=vol_type,
+ metadata=metadata)
+
+ # Work around problem that instance is lazy-loaded...
+ new_volume = self.volume_api.get(context, new_volume['id'])
+
+ retval = _translate_volume_detail_view(context, new_volume)
+
+ return {'volume': retval}
+
+
+class VolumeAttachmentTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumeAttachment',
+ selector='volumeAttachment')
+ make_attachment(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeAttachmentsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumeAttachments')
+ elem = xmlutil.SubTemplateElement(root, 'volumeAttachment',
+ selector='volumeAttachments')
+ make_attachment(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeAttachmentSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VolumeAttachmentTemplate()
+
+ def index(self):
+ return VolumeAttachmentsTemplate()
+
+
+def make_attachment(elem):
+ elem.set('id')
+ elem.set('serverId')
+ elem.set('volumeId')
+ elem.set('device')
+
+
+def make_volume(elem):
+ elem.set('id')
+ elem.set('status')
+ elem.set('size')
+ elem.set('availabilityZone')
+ elem.set('createdAt')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('volumeType')
+ elem.set('snapshotId')
+
+ attachments = xmlutil.SubTemplateElement(elem, 'attachments')
+ attachment = xmlutil.SubTemplateElement(attachments, 'attachment',
+ selector='attachments')
+ make_attachment(attachment)
+
+ metadata = xmlutil.make_flat_dict('metadata')
+ elem.append(metadata)
+
+
+class VolumeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume', selector='volume')
+ make_volume(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumes')
+ elem = xmlutil.SubTemplateElement(root, 'volume', selector='volumes')
+ make_volume(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VolumeTemplate()
+
+ def index(self):
+ return VolumesTemplate()
+
+ def detail(self):
+ return VolumesTemplate()
+
+
+def create_resource():
+ body_serializers = {
+ 'application/xml': VolumeSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
+ deserializer = wsgi.RequestDeserializer()
+
+ return wsgi.Resource(VolumeController(), serializer=serializer)
diff --git a/nova/api/openstack/xmlutil.py b/nova/api/openstack/xmlutil.py
index 90861ad4f..4b64d4a8f 100644
--- a/nova/api/openstack/xmlutil.py
+++ b/nova/api/openstack/xmlutil.py
@@ -31,9 +31,9 @@ XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
def validate_schema(xml, schema_name):
if isinstance(xml, str):
xml = etree.fromstring(xml)
- base_path = 'nova/api/openstack/v2/schemas/v1.1/'
+ base_path = 'nova/api/openstack/compute/schemas/v1.1/'
if schema_name in ('atom', 'atom-link'):
- base_path = 'nova/api/openstack/v2/schemas/'
+ base_path = 'nova/api/openstack/compute/schemas/'
schema_path = os.path.join(utils.novadir(),
'%s%s.rng' % (base_path, schema_name))
schema_doc = etree.parse(schema_path)
diff --git a/nova/auth/manager.py b/nova/auth/manager.py
index 3d984f1bf..f6c88e082 100644
--- a/nova/auth/manager.py
+++ b/nova/auth/manager.py
@@ -827,7 +827,7 @@ class AuthManager(object):
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
'os': '%s://%s:%s%s' % (FLAGS.osapi_scheme,
ec2_host,
- FLAGS.osapi_port,
+ FLAGS.osapi_compute_listen_port,
FLAGS.osapi_path),
'user': user.name,
'nova': FLAGS.ca_file,
diff --git a/nova/common/cfg.py b/nova/common/cfg.py
index 58d17d99f..bfb7b8a19 100644
--- a/nova/common/cfg.py
+++ b/nova/common/cfg.py
@@ -32,14 +32,14 @@ Options can be strings, integers, floats, booleans, lists or 'multi strings':
enabled_apis_opt = \
cfg.ListOpt('enabled_apis',
- default=['ec2', 'osapi'],
+ default=['ec2', 'osapi_compute'],
help='List of APIs to enable by default')
DEFAULT_EXTENSIONS = [
'nova.api.openstack.contrib.standard_extensions'
]
- osapi_extension_opt = \
- cfg.MultiStrOpt('osapi_extension',
+ osapi_compute_extension_opt = \
+ cfg.MultiStrOpt('osapi_compute_extension',
default=DEFAULT_EXTENSIONS)
Option schemas are registered with with the config manager at runtime, but
@@ -55,7 +55,7 @@ before the option is referenced:
...
def _load_extensions(self):
- for ext_factory in self.conf.osapi_extension:
+ for ext_factory in self.conf.osapi_compute_extension:
....
A common usage pattern is for each option schema to be defined in the module or
diff --git a/nova/flags.py b/nova/flags.py
index a51508c97..b566f303a 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -309,19 +309,21 @@ DEFINE_integer('rabbit_max_retries', 0,
'maximum rabbit connection attempts (0=try forever)')
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
DEFINE_boolean('rabbit_durable_queues', False, 'use durable queues')
-DEFINE_list('enabled_apis', ['ec2', 'osapi', 'metadata'],
+DEFINE_list('enabled_apis',
+ ['ec2', 'osapi_compute', 'osapi_volume', 'metadata'],
'list of APIs to enable by default')
DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
DEFINE_string('ec2_dmz_host', '$my_ip', 'internal ip of api server')
DEFINE_integer('ec2_port', 8773, 'cloud controller port')
DEFINE_string('ec2_scheme', 'http', 'prefix for ec2')
DEFINE_string('ec2_path', '/services/Cloud', 'suffix for ec2')
-DEFINE_multistring('osapi_extension',
- ['nova.api.openstack.v2.contrib.standard_extensions'],
- 'osapi extension to load')
-DEFINE_string('osapi_host', '$my_ip', 'ip of api server')
+DEFINE_multistring('osapi_compute_extension',
+ ['nova.api.openstack.compute.contrib.standard_extensions'],
+ 'osapi compute extension to load')
+DEFINE_multistring('osapi_volume_extension',
+ ['nova.api.openstack.volume.contrib.standard_extensions'],
+ 'osapi volume extension to load')
DEFINE_string('osapi_scheme', 'http', 'prefix for openstack')
-DEFINE_integer('osapi_port', 8774, 'OpenStack API port')
DEFINE_string('osapi_path', '/v1.1/', 'suffix for openstack')
DEFINE_integer('osapi_max_limit', 1000,
'max number of items returned in a collection response')
diff --git a/nova/service.py b/nova/service.py
index 95399f650..bfe6d1d54 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -48,9 +48,10 @@ flags.DEFINE_integer('periodic_interval', 60,
flags.DEFINE_string('ec2_listen', "0.0.0.0",
'IP address for EC2 API to listen')
flags.DEFINE_integer('ec2_listen_port', 8773, 'port for ec2 api to listen')
-flags.DEFINE_string('osapi_listen', "0.0.0.0",
+flags.DEFINE_string('osapi_compute_listen', "0.0.0.0",
'IP address for OpenStack API to listen')
-flags.DEFINE_integer('osapi_listen_port', 8774, 'port for os api to listen')
+flags.DEFINE_integer('osapi_compute_listen_port', 8774,
+ 'list port for osapi compute')
flags.DEFINE_string('metadata_manager', 'nova.api.manager.MetadataManager',
'OpenStack metadata service manager')
flags.DEFINE_string('metadata_listen', "0.0.0.0",
@@ -59,6 +60,10 @@ flags.DEFINE_integer('metadata_listen_port', 8775,
'port for metadata api to listen')
flags.DEFINE_string('api_paste_config', "api-paste.ini",
'File name for the paste.deploy config for nova-api')
+flags.DEFINE_string('osapi_volume_listen', "0.0.0.0",
+ 'IP address for OpenStack Volume API to listen')
+flags.DEFINE_integer('osapi_volume_listen_port', 8776,
+ 'port for os volume api to listen')
class Launcher(object):
diff --git a/nova/tests/api/openstack/v2/__init__.py b/nova/tests/api/openstack/compute/__init__.py
index 00fcfbb00..00fcfbb00 100644
--- a/nova/tests/api/openstack/v2/__init__.py
+++ b/nova/tests/api/openstack/compute/__init__.py
diff --git a/nova/tests/api/openstack/v2/contrib/__init__.py b/nova/tests/api/openstack/compute/contrib/__init__.py
index 848908a95..848908a95 100644
--- a/nova/tests/api/openstack/v2/contrib/__init__.py
+++ b/nova/tests/api/openstack/compute/contrib/__init__.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_accounts.py b/nova/tests/api/openstack/compute/contrib/test_accounts.py
index f799853dc..dbf0e2600 100644
--- a/nova/tests/api/openstack/v2/contrib/test_accounts.py
+++ b/nova/tests/api/openstack/compute/contrib/test_accounts.py
@@ -20,7 +20,7 @@ from lxml import etree
import webob
from nova import test
-from nova.api.openstack.v2.contrib import accounts
+from nova.api.openstack.compute.contrib import accounts
from nova.auth.manager import User
from nova.tests.api.openstack import fakes
diff --git a/nova/tests/api/openstack/v2/contrib/test_admin_actions.py b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py
index e3c5e6b08..f8a5d1103 100644
--- a/nova/tests/api/openstack/v2/contrib/test_admin_actions.py
+++ b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py
@@ -17,8 +17,8 @@ import json
import webob
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import compute as compute_api
+from nova.api.openstack.compute import extensions
from nova.api.openstack import wsgi
from nova import compute
from nova import exception
@@ -123,7 +123,7 @@ class CreateBackupTests(test.TestCase):
self.backup_stubs = fakes.stub_out_compute_api_backup(self.stubs)
self.flags(allow_admin_api=True)
- router = v2.APIRouter()
+ router = compute_api.APIRouter()
ext_middleware = extensions.ExtensionMiddleware(router)
self.app = wsgi.LazySerializationMiddleware(ext_middleware)
diff --git a/nova/tests/api/openstack/v2/contrib/test_cloudpipe.py b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
index b2a5d308a..7c8a8b09f 100644
--- a/nova/tests/api/openstack/v2/contrib/test_cloudpipe.py
+++ b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py
@@ -20,9 +20,9 @@ import webob
from lxml import etree
from nova.api import auth
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import wsgi
-from nova.api.openstack.v2.contrib import cloudpipe
+from nova.api.openstack import compute
+from nova.api.openstack.compute import wsgi
+from nova.api.openstack.compute.contrib import cloudpipe
from nova.auth import manager
from nova.cloudpipe import pipelib
from nova import context
@@ -112,7 +112,7 @@ class CloudpipeTest(test.TestCase):
super(CloudpipeTest, self).setUp()
self.flags(allow_admin_api=True)
self.app = fakes.wsgi_app()
- inner_app = v2.APIRouter()
+ inner_app = compute.APIRouter()
self.context = context.RequestContext('fake', 'fake', is_admin=True)
self.app = auth.InjectContext(self.context, inner_app)
route = inner_app.map.match('/1234/os-cloudpipe')
diff --git a/nova/tests/api/openstack/v2/contrib/test_console_output.py b/nova/tests/api/openstack/compute/contrib/test_console_output.py
index ad22ff4cf..ad22ff4cf 100644
--- a/nova/tests/api/openstack/v2/contrib/test_console_output.py
+++ b/nova/tests/api/openstack/compute/contrib/test_console_output.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_createserverext.py b/nova/tests/api/openstack/compute/contrib/test_createserverext.py
index 2393780a2..2393780a2 100644
--- a/nova/tests/api/openstack/v2/contrib/test_createserverext.py
+++ b/nova/tests/api/openstack/compute/contrib/test_createserverext.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_deferred_delete.py b/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py
index 222e62577..4addcf5c8 100644
--- a/nova/tests/api/openstack/v2/contrib/test_deferred_delete.py
+++ b/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py
@@ -18,7 +18,7 @@
import mox
import webob
-from nova.api.openstack.v2.contrib import deferred_delete
+from nova.api.openstack.compute.contrib import deferred_delete
from nova import compute
from nova import exception
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_disk_config.py b/nova/tests/api/openstack/compute/contrib/test_disk_config.py
index 95cfd3747..bd995fd3d 100644
--- a/nova/tests/api/openstack/v2/contrib/test_disk_config.py
+++ b/nova/tests/api/openstack/compute/contrib/test_disk_config.py
@@ -17,8 +17,8 @@
import datetime
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import compute
+from nova.api.openstack.compute import extensions
from nova.api.openstack import wsgi
import nova.db.api
from nova import flags
@@ -117,7 +117,7 @@ class DiskConfigTestCase(test.TestCase):
self.stubs.Set(nova.db, 'instance_create', fake_instance_create)
- app = v2.APIRouter()
+ app = compute.APIRouter()
app = extensions.ExtensionMiddleware(app)
app = wsgi.LazySerializationMiddleware(app)
self.app = app
diff --git a/nova/tests/api/openstack/v2/contrib/test_extendedstatus.py b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py
index dc7f0cefa..dc7f0cefa 100644
--- a/nova/tests/api/openstack/v2/contrib/test_extendedstatus.py
+++ b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_flavors_extra_specs.py b/nova/tests/api/openstack/compute/contrib/test_flavors_extra_specs.py
index add8c627d..94aac9621 100644
--- a/nova/tests/api/openstack/v2/contrib/test_flavors_extra_specs.py
+++ b/nova/tests/api/openstack/compute/contrib/test_flavors_extra_specs.py
@@ -18,7 +18,7 @@
import webob
from nova.api.openstack import wsgi
-from nova.api.openstack.v2.contrib import flavorextraspecs
+from nova.api.openstack.compute.contrib import flavorextraspecs
from nova import test
from nova.tests.api.openstack import fakes
import nova.wsgi
diff --git a/nova/tests/api/openstack/v2/contrib/test_floating_ip_dns.py b/nova/tests/api/openstack/compute/contrib/test_floating_ip_dns.py
index 58fdb4788..3107e50c4 100644
--- a/nova/tests/api/openstack/v2/contrib/test_floating_ip_dns.py
+++ b/nova/tests/api/openstack/compute/contrib/test_floating_ip_dns.py
@@ -19,8 +19,8 @@ from lxml import etree
import webob
import urllib
-from nova.api.openstack.v2.contrib import floating_ips
-from nova.api.openstack.v2.contrib import floating_ip_dns
+from nova.api.openstack.compute.contrib import floating_ips
+from nova.api.openstack.compute.contrib import floating_ip_dns
from nova import context
from nova import db
from nova import network
diff --git a/nova/tests/api/openstack/v2/contrib/test_floating_ip_pools.py b/nova/tests/api/openstack/compute/contrib/test_floating_ip_pools.py
index d061f9af3..ffe84a1ba 100644
--- a/nova/tests/api/openstack/v2/contrib/test_floating_ip_pools.py
+++ b/nova/tests/api/openstack/compute/contrib/test_floating_ip_pools.py
@@ -15,7 +15,7 @@
from lxml import etree
-from nova.api.openstack.v2.contrib import floating_ip_pools
+from nova.api.openstack.compute.contrib import floating_ip_pools
from nova import context
from nova import network
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_floating_ips.py b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py
index dae58aa14..fe5444419 100644
--- a/nova/tests/api/openstack/v2/contrib/test_floating_ips.py
+++ b/nova/tests/api/openstack/compute/contrib/test_floating_ips.py
@@ -17,7 +17,7 @@
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import floating_ips
+from nova.api.openstack.compute.contrib import floating_ips
from nova import context
from nova import db
from nova import network
diff --git a/nova/tests/api/openstack/v2/contrib/test_hosts.py b/nova/tests/api/openstack/compute/contrib/test_hosts.py
index a954890ba..e6a91477e 100644
--- a/nova/tests/api/openstack/v2/contrib/test_hosts.py
+++ b/nova/tests/api/openstack/compute/contrib/test_hosts.py
@@ -21,7 +21,7 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova import test
-from nova.api.openstack.v2.contrib import hosts as os_hosts
+from nova.api.openstack.compute.contrib import hosts as os_hosts
from nova.scheduler import api as scheduler_api
diff --git a/nova/tests/api/openstack/v2/contrib/test_keypairs.py b/nova/tests/api/openstack/compute/contrib/test_keypairs.py
index 6ecd3a86c..4c252e176 100644
--- a/nova/tests/api/openstack/v2/contrib/test_keypairs.py
+++ b/nova/tests/api/openstack/compute/contrib/test_keypairs.py
@@ -19,7 +19,7 @@ import webob
from lxml import etree
from nova.api.openstack import wsgi
-from nova.api.openstack.v2.contrib import keypairs
+from nova.api.openstack.compute.contrib import keypairs
from nova import context
from nova import db
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_multinic_xs.py b/nova/tests/api/openstack/compute/contrib/test_multinic_xs.py
index 0d9b6e3ce..0d9b6e3ce 100644
--- a/nova/tests/api/openstack/v2/contrib/test_multinic_xs.py
+++ b/nova/tests/api/openstack/compute/contrib/test_multinic_xs.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py
index 04bd82e2c..0eefca652 100644
--- a/nova/tests/api/openstack/v2/contrib/test_networks.py
+++ b/nova/tests/api/openstack/compute/contrib/test_networks.py
@@ -18,7 +18,7 @@ import copy
import webob
-from nova.api.openstack.v2.contrib import networks
+from nova.api.openstack.compute.contrib import networks
from nova import context
from nova import exception
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_quotas.py b/nova/tests/api/openstack/compute/contrib/test_quotas.py
index 9bcfc7ded..29b01e117 100644
--- a/nova/tests/api/openstack/v2/contrib/test_quotas.py
+++ b/nova/tests/api/openstack/compute/contrib/test_quotas.py
@@ -19,7 +19,7 @@ import webob
from lxml import etree
from nova.api.openstack import wsgi
-from nova.api.openstack.v2.contrib import quotas
+from nova.api.openstack.compute.contrib import quotas
from nova import context
from nova import test
from nova.tests.api.openstack import fakes
diff --git a/nova/tests/api/openstack/v2/contrib/test_rescue.py b/nova/tests/api/openstack/compute/contrib/test_rescue.py
index 9a3706173..9a3706173 100644
--- a/nova/tests/api/openstack/v2/contrib/test_rescue.py
+++ b/nova/tests/api/openstack/compute/contrib/test_rescue.py
diff --git a/nova/tests/api/openstack/v2/contrib/test_security_groups.py b/nova/tests/api/openstack/compute/contrib/test_security_groups.py
index 7848ef9bb..e4ea99f40 100644
--- a/nova/tests/api/openstack/v2/contrib/test_security_groups.py
+++ b/nova/tests/api/openstack/compute/contrib/test_security_groups.py
@@ -20,7 +20,7 @@ from lxml import etree
import mox
import webob
-from nova.api.openstack.v2.contrib import security_groups
+from nova.api.openstack.compute.contrib import security_groups
from nova.api.openstack import wsgi
import nova.db
from nova import exception
diff --git a/nova/tests/api/openstack/v2/contrib/test_server_action_list.py b/nova/tests/api/openstack/compute/contrib/test_server_action_list.py
index d943376b3..aa5a7275c 100644
--- a/nova/tests/api/openstack/v2/contrib/test_server_action_list.py
+++ b/nova/tests/api/openstack/compute/contrib/test_server_action_list.py
@@ -19,9 +19,9 @@ import unittest
from lxml import etree
-from nova.api.openstack import v2
-from nova.api.openstack.v2.contrib import server_action_list
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import compute
+from nova.api.openstack.compute import extensions
+from nova.api.openstack.compute.contrib import server_action_list
from nova.api.openstack import wsgi
import nova.compute
from nova import test
@@ -53,7 +53,7 @@ class ServerActionsTest(test.TestCase):
self.stubs.Set(nova.compute.API, 'get', fake_instance_get)
self.compute_api = nova.compute.API()
- self.router = v2.APIRouter()
+ self.router = compute.APIRouter()
ext_middleware = extensions.ExtensionMiddleware(self.router)
self.app = wsgi.LazySerializationMiddleware(ext_middleware)
diff --git a/nova/tests/api/openstack/v2/contrib/test_server_diagnostics.py b/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py
index 2e2850f32..69aabdc26 100644
--- a/nova/tests/api/openstack/v2/contrib/test_server_diagnostics.py
+++ b/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py
@@ -18,9 +18,9 @@ import unittest
from lxml import etree
-from nova.api.openstack import v2
-from nova.api.openstack.v2.contrib import server_diagnostics
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import compute
+from nova.api.openstack.compute import extensions
+from nova.api.openstack.compute.contrib import server_diagnostics
from nova.api.openstack import wsgi
import nova.compute
from nova import test
@@ -47,7 +47,7 @@ class ServerDiagnosticsTest(test.TestCase):
self.stubs.Set(nova.compute.API, 'get', fake_instance_get)
self.compute_api = nova.compute.API()
- self.router = v2.APIRouter()
+ self.router = compute.APIRouter()
ext_middleware = extensions.ExtensionMiddleware(self.router)
self.app = wsgi.LazySerializationMiddleware(ext_middleware)
diff --git a/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py
index 7a1f2b35c..3ff12bf3a 100644
--- a/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py
+++ b/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py
@@ -21,7 +21,7 @@ import json
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import simple_tenant_usage
+from nova.api.openstack.compute.contrib import simple_tenant_usage
from nova.compute import api
from nova import context
from nova import flags
diff --git a/nova/tests/api/openstack/v2/contrib/test_snapshots.py b/nova/tests/api/openstack/compute/contrib/test_snapshots.py
index 5b585db82..69784e516 100644
--- a/nova/tests/api/openstack/v2/contrib/test_snapshots.py
+++ b/nova/tests/api/openstack/compute/contrib/test_snapshots.py
@@ -20,7 +20,7 @@ import stubout
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import volumes
+from nova.api.openstack.compute.contrib import volumes
from nova import context
from nova import exception
from nova import flags
diff --git a/nova/tests/api/openstack/v2/contrib/test_users.py b/nova/tests/api/openstack/compute/contrib/test_users.py
index ace243f58..5895f4f66 100644
--- a/nova/tests/api/openstack/v2/contrib/test_users.py
+++ b/nova/tests/api/openstack/compute/contrib/test_users.py
@@ -15,7 +15,7 @@
from lxml import etree
-from nova.api.openstack.v2.contrib import users
+from nova.api.openstack.compute.contrib import users
from nova.auth.manager import User, Project
from nova import test
from nova.tests.api.openstack import fakes
diff --git a/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py b/nova/tests/api/openstack/compute/contrib/test_virtual_interfaces.py
index 3530e68fd..d9f41f07b 100644
--- a/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py
+++ b/nova/tests/api/openstack/compute/contrib/test_virtual_interfaces.py
@@ -18,7 +18,7 @@ import json
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import virtual_interfaces
+from nova.api.openstack.compute.contrib import virtual_interfaces
from nova.api.openstack import wsgi
from nova import network
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_volume_types.py b/nova/tests/api/openstack/compute/contrib/test_volume_types.py
index de3cf86e1..fdd2214e3 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volume_types.py
+++ b/nova/tests/api/openstack/compute/contrib/test_volume_types.py
@@ -16,7 +16,7 @@
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import volumetypes
+from nova.api.openstack.compute.contrib import volumetypes
from nova import exception
from nova import test
from nova import log as logging
@@ -24,7 +24,7 @@ from nova.volume import volume_types
from nova.tests.api.openstack import fakes
-LOG = logging.getLogger('nova.tests.api.openstack.v2.contrib.'
+LOG = logging.getLogger('nova.tests.api.openstack.compute.contrib.'
'test_volume_types')
last_param = {}
diff --git a/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py b/nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py
index 81e57cee9..e9c4034f0 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py
+++ b/nova/tests/api/openstack/compute/contrib/test_volume_types_extra_specs.py
@@ -20,7 +20,7 @@
from lxml import etree
import webob
-from nova.api.openstack.v2.contrib import volumetypes
+from nova.api.openstack.compute.contrib import volumetypes
from nova import test
from nova.tests.api.openstack import fakes
import nova.wsgi
diff --git a/nova/tests/api/openstack/v2/contrib/test_volumes.py b/nova/tests/api/openstack/compute/contrib/test_volumes.py
index a5585bd64..f32f4d867 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volumes.py
+++ b/nova/tests/api/openstack/compute/contrib/test_volumes.py
@@ -20,7 +20,7 @@ from lxml import etree
import webob
import nova
-from nova.api.openstack.v2.contrib import volumes
+from nova.api.openstack.compute.contrib import volumes
from nova.compute import instance_types
from nova import flags
from nova import test
diff --git a/nova/tests/api/openstack/v2/contrib/test_vsa.py b/nova/tests/api/openstack/compute/contrib/test_vsa.py
index fa5127db6..e19aeedba 100644
--- a/nova/tests/api/openstack/v2/contrib/test_vsa.py
+++ b/nova/tests/api/openstack/compute/contrib/test_vsa.py
@@ -20,7 +20,8 @@ from lxml import etree
import stubout
import webob
-from nova.api.openstack.v2.contrib import virtual_storage_arrays as vsa_ext
+from nova.api.openstack.compute.contrib\
+ import virtual_storage_arrays as vsa_ext
from nova import context
import nova.db
from nova import exception
@@ -34,7 +35,7 @@ from nova import vsa
FLAGS = flags.FLAGS
-LOG = logging.getLogger('nova.tests.api.openstack.v2.contrib.test_vsa')
+LOG = logging.getLogger('nova.tests.api.openstack.compute.contrib.test_vsa')
last_param = {}
diff --git a/nova/tests/api/openstack/v2/contrib/test_zones.py b/nova/tests/api/openstack/compute/contrib/test_zones.py
index a44a7c82e..e23ea85e6 100644
--- a/nova/tests/api/openstack/v2/contrib/test_zones.py
+++ b/nova/tests/api/openstack/compute/contrib/test_zones.py
@@ -18,7 +18,7 @@ import json
from lxml import etree
-from nova.api.openstack.v2.contrib import zones
+from nova.api.openstack.compute.contrib import zones
from nova.api.openstack import xmlutil
from nova import crypto
import nova.db
diff --git a/nova/tests/api/openstack/v2/extensions/__init__.py b/nova/tests/api/openstack/compute/extensions/__init__.py
index 848908a95..848908a95 100644
--- a/nova/tests/api/openstack/v2/extensions/__init__.py
+++ b/nova/tests/api/openstack/compute/extensions/__init__.py
diff --git a/nova/tests/api/openstack/v2/extensions/foxinsocks.py b/nova/tests/api/openstack/compute/extensions/foxinsocks.py
index ba1508668..302fe7ddf 100644
--- a/nova/tests/api/openstack/v2/extensions/foxinsocks.py
+++ b/nova/tests/api/openstack/compute/extensions/foxinsocks.py
@@ -17,7 +17,7 @@
import webob.exc
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import extensions
class FoxInSocksController(object):
diff --git a/nova/tests/api/openstack/v2/test_api.py b/nova/tests/api/openstack/compute/test_api.py
index d09bb0cfa..15768ff33 100644
--- a/nova/tests/api/openstack/v2/test_api.py
+++ b/nova/tests/api/openstack/compute/test_api.py
@@ -23,8 +23,9 @@ import webob.dec
from webob import Request
from nova import test
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import wsgi
+from nova.api import openstack as openstack_api
+from nova.api.openstack import compute
+from nova.api.openstack.compute import wsgi
from nova.tests.api.openstack import fakes
@@ -32,7 +33,7 @@ class APITest(test.TestCase):
def _wsgi_app(self, inner_app):
# simpler version of the app than fakes.wsgi_app
- return v2.FaultWrapper(inner_app)
+ return openstack_api.FaultWrapper(inner_app)
def test_malformed_json(self):
req = webob.Request.blank('/')
diff --git a/nova/tests/api/openstack/v2/test_auth.py b/nova/tests/api/openstack/compute/test_auth.py
index d1dbc3319..bc83a8b96 100644
--- a/nova/tests/api/openstack/v2/test_auth.py
+++ b/nova/tests/api/openstack/compute/test_auth.py
@@ -20,9 +20,9 @@ import datetime
import webob
import webob.dec
-import nova.api.openstack.v2
-import nova.api.openstack.v2.auth
+import nova.api.openstack.compute
import nova.auth.manager
+from nova.api.openstack import auth
from nova import context
from nova import db
from nova import test
@@ -33,7 +33,7 @@ class Test(test.TestCase):
def setUp(self):
super(Test, self).setUp()
- self.stubs.Set(nova.api.openstack.v2.auth.AuthMiddleware,
+ self.stubs.Set(auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
fakes.FakeAuthManager.clear_fakes()
@@ -80,7 +80,8 @@ class Test(test.TestCase):
self.assertEqual(result.headers['X-Storage-Url'], "")
token = result.headers['X-Auth-Token']
- self.stubs.Set(nova.api.openstack.v2, 'APIRouter', fakes.FakeRouter)
+ self.stubs.Set(nova.api.openstack.compute, 'APIRouter',
+ fakes.FakeRouter)
req = webob.Request.blank('/v2/user1_project')
req.headers['X-Auth-Token'] = token
result = req.get_response(fakes.wsgi_app(fake_auth=False))
@@ -124,7 +125,8 @@ class Test(test.TestCase):
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
- self.stubs.Set(nova.api.openstack.v2, 'APIRouter', fakes.FakeRouter)
+ self.stubs.Set(nova.api.openstack.compute, 'APIRouter',
+ fakes.FakeRouter)
req = webob.Request.blank('/v2/user2_project')
req.headers['X-Auth-Token'] = token
result = req.get_response(fakes.wsgi_app(fake_auth=False))
@@ -177,7 +179,8 @@ class Test(test.TestCase):
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
- self.stubs.Set(nova.api.openstack.v2, 'APIRouter', fakes.FakeRouter)
+ self.stubs.Set(nova.api.openstack.compute, 'APIRouter',
+ fakes.FakeRouter)
req = webob.Request.blank('/v2/user2_project')
req.headers['X-Auth-Token'] = token
result = req.get_response(fakes.wsgi_app(fake_auth=False))
@@ -200,7 +203,8 @@ class Test(test.TestCase):
self.assertEqual(result.status, '204 No Content')
token = result.headers['X-Auth-Token']
- self.stubs.Set(nova.api.openstack.v2, 'APIRouter', fakes.FakeRouter)
+ self.stubs.Set(nova.api.openstack.compute, 'APIRouter',
+ fakes.FakeRouter)
req = webob.Request.blank('/v2/user2_project')
req.headers['X-Auth-Token'] = token
result = req.get_response(fakes.wsgi_app(fake_auth=False))
@@ -237,7 +241,7 @@ class TestFunctional(test.TestCase):
class TestLimiter(test.TestCase):
def setUp(self):
super(TestLimiter, self).setUp()
- self.stubs.Set(nova.api.openstack.v2.auth.AuthMiddleware,
+ self.stubs.Set(auth.AuthMiddleware,
'__init__', fakes.fake_auth_init)
self.stubs.Set(context, 'RequestContext', fakes.FakeRequestContext)
fakes.FakeAuthManager.clear_fakes()
@@ -261,7 +265,8 @@ class TestLimiter(test.TestCase):
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
token = result.headers['X-Auth-Token']
- self.stubs.Set(nova.api.openstack.v2, 'APIRouter', fakes.FakeRouter)
+ self.stubs.Set(nova.api.openstack.compute, 'APIRouter',
+ fakes.FakeRouter)
req = webob.Request.blank('/v2/test')
req.method = 'POST'
req.headers['X-Auth-Token'] = token
diff --git a/nova/tests/api/openstack/v2/test_consoles.py b/nova/tests/api/openstack/compute/test_consoles.py
index 5953737a8..f58e76a3f 100644
--- a/nova/tests/api/openstack/v2/test_consoles.py
+++ b/nova/tests/api/openstack/compute/test_consoles.py
@@ -22,7 +22,7 @@ import json
from lxml import etree
import webob
-from nova.api.openstack.v2 import consoles
+from nova.api.openstack.compute import consoles
from nova import console
from nova import db
from nova.compute import vm_states
diff --git a/nova/tests/api/openstack/v2/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index f2a49c3ed..a4585781b 100644
--- a/nova/tests/api/openstack/v2/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -21,8 +21,9 @@ import json
import webob
from lxml import etree
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack import compute
+from nova.api.openstack import extensions as base_extensions
+from nova.api.openstack.compute import extensions as compute_extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import flags
@@ -86,11 +87,13 @@ class StubExtensionManager(object):
class ExtensionTestCase(test.TestCase):
def setUp(self):
super(ExtensionTestCase, self).setUp()
- ext_list = FLAGS.osapi_extension[:]
- ext_list.append('nova.tests.api.openstack.v2.extensions.'
- 'foxinsocks.Foxinsocks')
- self.flags(osapi_extension=ext_list)
- extensions.ExtensionManager.reset()
+ ext_list = FLAGS.osapi_compute_extension[:]
+ fox = ('nova.tests.api.openstack.compute.extensions.'
+ 'foxinsocks.Foxinsocks')
+ if fox not in ext_list:
+ ext_list.append(fox)
+ self.flags(osapi_compute_extension=ext_list)
+ compute_extensions.ExtensionManager.reset()
class ExtensionControllerTest(ExtensionTestCase):
@@ -133,8 +136,8 @@ class ExtensionControllerTest(ExtensionTestCase):
self.ext_list.sort()
def test_list_extensions_json(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/extensions")
response = request.get_response(ser_midware)
@@ -142,8 +145,10 @@ class ExtensionControllerTest(ExtensionTestCase):
# Make sure we have all the extensions.
data = json.loads(response.body)
- names = [x['name'] for x in data['extensions']]
+ names = [str(x['name']) for x in data['extensions']]
names.sort()
+ print names
+ print self.ext_list
self.assertEqual(names, self.ext_list)
# Make sure that at least Fox in Sox is correct.
@@ -160,8 +165,8 @@ class ExtensionControllerTest(ExtensionTestCase):
)
def test_get_extension_json(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/extensions/FOXNSOX")
response = request.get_response(ser_midware)
@@ -177,15 +182,15 @@ class ExtensionControllerTest(ExtensionTestCase):
"links": []})
def test_get_non_existing_extension_json(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
request = webob.Request.blank("/fake/extensions/4")
response = request.get_response(ext_midware)
self.assertEqual(404, response.status_int)
def test_list_extensions_xml(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/extensions")
request.accept = "application/xml"
@@ -212,8 +217,8 @@ class ExtensionControllerTest(ExtensionTestCase):
xmlutil.validate_schema(root, 'extensions')
def test_get_extension_xml(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/extensions/FOXNSOX")
request.accept = "application/xml"
@@ -239,19 +244,19 @@ class ResourceExtensionTest(ExtensionTestCase):
def test_no_extension_present(self):
manager = StubExtensionManager(None)
- app = v2.APIRouter(manager)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ app = compute.APIRouter(manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/blah")
response = request.get_response(ser_midware)
self.assertEqual(404, response.status_int)
def test_get_resources(self):
- res_ext = extensions.ResourceExtension('tweedles',
- StubController(response_body))
+ res_ext = base_extensions.ResourceExtension('tweedles',
+ StubController(response_body))
manager = StubExtensionManager(res_ext)
- app = v2.APIRouter(manager)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ app = compute.APIRouter(manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/tweedles")
response = request.get_response(ser_midware)
@@ -259,11 +264,11 @@ class ResourceExtensionTest(ExtensionTestCase):
self.assertEqual(response_body, response.body)
def test_get_resources_with_controller(self):
- res_ext = extensions.ResourceExtension('tweedles',
+ res_ext = base_extensions.ResourceExtension('tweedles',
StubController(response_body))
manager = StubExtensionManager(res_ext)
- app = v2.APIRouter(manager)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ app = compute.APIRouter(manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/tweedles")
response = request.get_response(ser_midware)
@@ -271,11 +276,11 @@ class ResourceExtensionTest(ExtensionTestCase):
self.assertEqual(response_body, response.body)
def test_bad_request(self):
- res_ext = extensions.ResourceExtension('tweedles',
- StubController(response_body))
+ res_ext = base_extensions.ResourceExtension('tweedles',
+ StubController(response_body))
manager = StubExtensionManager(res_ext)
- app = v2.APIRouter(manager)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ app = compute.APIRouter(manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/tweedles")
request.method = "POST"
@@ -292,11 +297,11 @@ class ResourceExtensionTest(ExtensionTestCase):
self.assertDictMatch(expected, body)
def test_non_exist_resource(self):
- res_ext = extensions.ResourceExtension('tweedles',
+ res_ext = base_extensions.ResourceExtension('tweedles',
StubController(response_body))
manager = StubExtensionManager(res_ext)
- app = v2.APIRouter(manager)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ app = compute.APIRouter(manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/tweedles/1")
response = request.get_response(ser_midware)
@@ -317,7 +322,7 @@ class InvalidExtension(object):
alias = "THIRD"
-class AdminExtension(extensions.ExtensionDescriptor):
+class AdminExtension(base_extensions.ExtensionDescriptor):
"""Admin-only extension"""
name = "Admin Ext"
@@ -335,8 +340,8 @@ class ExtensionManagerTest(ExtensionTestCase):
response_body = "Try to say this Mr. Knox, sir..."
def test_get_resources(self):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/fake/foxnsocks")
response = request.get_response(ser_midware)
@@ -346,8 +351,8 @@ class ExtensionManagerTest(ExtensionTestCase):
def test_invalid_extensions(self):
# Don't need the serialization middleware here because we're
# not testing any serialization
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ext_mgr = ext_midware.ext_mgr
ext_mgr.register(InvalidExtension())
self.assertTrue('FOXNSOX' in ext_mgr.extensions)
@@ -355,8 +360,8 @@ class ExtensionManagerTest(ExtensionTestCase):
def test_admin_extensions(self):
self.flags(allow_admin_api=True)
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ext_mgr = ext_midware.ext_mgr
ext_mgr.register(AdminExtension())
self.assertTrue('FOXNSOX' in ext_mgr.extensions)
@@ -364,8 +369,8 @@ class ExtensionManagerTest(ExtensionTestCase):
def test_admin_extensions_no_admin_api(self):
self.flags(allow_admin_api=False)
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ext_mgr = ext_midware.ext_mgr
ext_mgr.register(AdminExtension())
self.assertTrue('FOXNSOX' in ext_mgr.extensions)
@@ -375,8 +380,8 @@ class ExtensionManagerTest(ExtensionTestCase):
class ActionExtensionTest(ExtensionTestCase):
def _send_server_action_request(self, url, body):
- app = v2.APIRouter()
- ext_midware = extensions.ExtensionMiddleware(app)
+ app = compute.APIRouter()
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank(url)
request.method = 'POST'
@@ -443,13 +448,13 @@ class RequestExtensionTest(ExtensionTestCase):
body['flavor']['googoose'] = req.GET.get('chewing')
return res
- req_ext = extensions.RequestExtension('GET',
- '/v2/fake/flavors/:(id)',
- _req_handler)
+ req_ext = base_extensions.RequestExtension('GET',
+ '/v2/fake/flavors/:(id)',
+ _req_handler)
manager = StubExtensionManager(None, None, req_ext)
app = fakes.wsgi_app(serialization=base_wsgi.Middleware)
- ext_midware = extensions.ExtensionMiddleware(app, manager)
+ ext_midware = compute_extensions.ExtensionMiddleware(app, manager)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/v2/fake/flavors/1?chewing=bluegoo")
request.environ['api.version'] = '2'
@@ -461,7 +466,7 @@ class RequestExtensionTest(ExtensionTestCase):
def test_get_resources_with_mgr(self):
app = fakes.wsgi_app(serialization=base_wsgi.Middleware)
- ext_midware = extensions.ExtensionMiddleware(app)
+ ext_midware = compute_extensions.ExtensionMiddleware(app)
ser_midware = wsgi.LazySerializationMiddleware(ext_midware)
request = webob.Request.blank("/v2/fake/flavors/1?chewing=newblue")
request.environ['api.version'] = '2'
@@ -476,7 +481,7 @@ class RequestExtensionTest(ExtensionTestCase):
class ExtensionsXMLSerializerTest(test.TestCase):
def test_serialize_extension(self):
- serializer = extensions.ExtensionsXMLSerializer()
+ serializer = base_extensions.ExtensionsXMLSerializer()
data = {'extension': {
'name': 'ext1',
'namespace': 'http://docs.rack.com/servers/api/ext/pie/v1.0',
@@ -509,7 +514,7 @@ class ExtensionsXMLSerializerTest(test.TestCase):
xmlutil.validate_schema(root, 'extension')
def test_serialize_extensions(self):
- serializer = extensions.ExtensionsXMLSerializer()
+ serializer = base_extensions.ExtensionsXMLSerializer()
data = {"extensions": [{
"name": "Public Image Extension",
"namespace": "http://foo.com/api/ext/pie/v1.0",
diff --git a/nova/tests/api/openstack/v2/test_flavors.py b/nova/tests/api/openstack/compute/test_flavors.py
index d70d581df..37b67fc32 100644
--- a/nova/tests/api/openstack/v2/test_flavors.py
+++ b/nova/tests/api/openstack/compute/test_flavors.py
@@ -18,7 +18,7 @@
from lxml import etree
import webob
-from nova.api.openstack.v2 import flavors
+from nova.api.openstack.compute import flavors
from nova.api.openstack import xmlutil
import nova.compute.instance_types
from nova import exception
diff --git a/nova/tests/api/openstack/v2/test_image_metadata.py b/nova/tests/api/openstack/compute/test_image_metadata.py
index e3e774ba3..62f047a2a 100644
--- a/nova/tests/api/openstack/v2/test_image_metadata.py
+++ b/nova/tests/api/openstack/compute/test_image_metadata.py
@@ -18,7 +18,7 @@
import json
import webob
-from nova.api.openstack.v2 import image_metadata
+from nova.api.openstack.compute import image_metadata
from nova import flags
from nova import test
from nova.tests.api.openstack import fakes
diff --git a/nova/tests/api/openstack/v2/test_images.py b/nova/tests/api/openstack/compute/test_images.py
index 70c6db679..7bb1d44d9 100644
--- a/nova/tests/api/openstack/v2/test_images.py
+++ b/nova/tests/api/openstack/compute/test_images.py
@@ -26,8 +26,8 @@ from lxml import etree
import stubout
import webob
-from nova.api.openstack.v2 import images
-from nova.api.openstack.v2.views import images as images_view
+from nova.api.openstack.compute import images
+from nova.api.openstack.compute.views import images as images_view
from nova.api.openstack import xmlutil
from nova import test
from nova import utils
diff --git a/nova/tests/api/openstack/v2/test_limits.py b/nova/tests/api/openstack/compute/test_limits.py
index 1c299d751..20ec0d1a0 100644
--- a/nova/tests/api/openstack/v2/test_limits.py
+++ b/nova/tests/api/openstack/compute/test_limits.py
@@ -27,8 +27,8 @@ from lxml import etree
import stubout
import webob
-from nova.api.openstack.v2 import limits
-from nova.api.openstack.v2 import views
+from nova.api.openstack.compute import limits
+from nova.api.openstack.compute import views
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.context
diff --git a/nova/tests/api/openstack/v2/test_server_actions.py b/nova/tests/api/openstack/compute/test_server_actions.py
index d2958e3b2..2f3976375 100644
--- a/nova/tests/api/openstack/v2/test_server_actions.py
+++ b/nova/tests/api/openstack/compute/test_server_actions.py
@@ -20,7 +20,7 @@ import mox
import stubout
import webob
-from nova.api.openstack.v2 import servers
+from nova.api.openstack.compute import servers
from nova.compute import vm_states
from nova.compute import instance_types
from nova import context
diff --git a/nova/tests/api/openstack/v2/test_server_metadata.py b/nova/tests/api/openstack/compute/test_server_metadata.py
index 49ff1bcd8..61bf4fc47 100644
--- a/nova/tests/api/openstack/v2/test_server_metadata.py
+++ b/nova/tests/api/openstack/compute/test_server_metadata.py
@@ -18,7 +18,7 @@
import json
import webob
-from nova.api.openstack.v2 import server_metadata
+from nova.api.openstack.compute import server_metadata
import nova.db
from nova import exception
from nova import flags
diff --git a/nova/tests/api/openstack/v2/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 7216699b4..83b0e345c 100644
--- a/nova/tests/api/openstack/v2/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -23,9 +23,10 @@ import urlparse
from lxml import etree
import webob
-import nova.api.openstack.v2
-from nova.api.openstack.v2 import ips
-from nova.api.openstack.v2 import servers
+import nova.api.openstack.compute
+from nova.api.openstack.compute import ips
+from nova.api.openstack.compute import servers
+from nova.api.openstack.compute import views
from nova.api.openstack import xmlutil
import nova.compute.api
from nova.compute import instance_types
@@ -2290,8 +2291,8 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase):
class TestAddressesXMLSerialization(test.TestCase):
- index_serializer = nova.api.openstack.v2.ips.AddressesTemplate()
- show_serializer = nova.api.openstack.v2.ips.NetworkTemplate()
+ index_serializer = nova.api.openstack.compute.ips.AddressesTemplate()
+ show_serializer = nova.api.openstack.compute.ips.NetworkTemplate()
def test_xml_declaration(self):
fixture = {
@@ -2369,7 +2370,7 @@ class ServersViewBuilderTest(test.TestCase):
include_fake_metadata=False)
self.uuid = self.instance['uuid']
- self.view_builder = nova.api.openstack.v2.views.servers.ViewBuilder()
+ self.view_builder = views.servers.ViewBuilder()
self.request = fakes.HTTPRequest.blank("/v2")
def test_build_server(self):
diff --git a/nova/tests/api/openstack/v2/test_urlmap.py b/nova/tests/api/openstack/compute/test_urlmap.py
index 82a870a50..ae269d01f 100644
--- a/nova/tests/api/openstack/v2/test_urlmap.py
+++ b/nova/tests/api/openstack/compute/test_urlmap.py
@@ -20,7 +20,7 @@ from nova import log as logging
from nova import test
from nova.tests.api.openstack import fakes
-LOG = logging.getLogger('nova.tests.api.openstack.v2.test_urlmap')
+LOG = logging.getLogger('nova.tests.api.openstack.compute.test_urlmap')
class UrlmapTest(test.TestCase):
diff --git a/nova/tests/api/openstack/v2/test_versions.py b/nova/tests/api/openstack/compute/test_versions.py
index 7e250471a..b1383be60 100644
--- a/nova/tests/api/openstack/v2/test_versions.py
+++ b/nova/tests/api/openstack/compute/test_versions.py
@@ -22,8 +22,8 @@ from lxml import etree
import stubout
import webob
-from nova.api.openstack.v2 import versions
-from nova.api.openstack.v2 import views
+from nova.api.openstack.compute import versions
+from nova.api.openstack.compute import views
from nova.api.openstack import xmlutil
from nova import context
from nova import test
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index f9f8dd0a0..9fa1749ef 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -24,14 +24,14 @@ import webob.request
from glance import client as glance_client
-import nova.api.openstack.v2.auth
from nova.api import auth as api_auth
-from nova.api.openstack import v2
-from nova.api.openstack.v2 import auth
-from nova.api.openstack.v2 import extensions
-from nova.api.openstack.v2 import limits
-from nova.api.openstack.v2 import urlmap
-from nova.api.openstack.v2 import versions
+from nova.api import openstack as openstack_api
+from nova.api.openstack import compute
+from nova.api.openstack import auth
+from nova.api.openstack.compute import extensions
+from nova.api.openstack.compute import limits
+from nova.api.openstack import urlmap
+from nova.api.openstack.compute import versions
from nova.api.openstack import wsgi as os_wsgi
from nova.auth.manager import User, Project
from nova.compute import instance_types
@@ -77,24 +77,24 @@ def wsgi_app(inner_app_v2=None, fake_auth=True, fake_auth_context=None,
serialization=os_wsgi.LazySerializationMiddleware,
use_no_auth=False):
if not inner_app_v2:
- inner_app_v2 = v2.APIRouter()
+ inner_app_v2 = compute.APIRouter()
if fake_auth:
if fake_auth_context is not None:
ctxt = fake_auth_context
else:
ctxt = context.RequestContext('fake', 'fake', auth_token=True)
- api_v2 = v2.FaultWrapper(api_auth.InjectContext(ctxt,
+ api_v2 = openstack_api.FaultWrapper(api_auth.InjectContext(ctxt,
limits.RateLimitingMiddleware(
serialization(
extensions.ExtensionMiddleware(inner_app_v2)))))
elif use_no_auth:
- api_v2 = v2.FaultWrapper(auth.NoAuthMiddleware(
+ api_v2 = openstack_api.FaultWrapper(auth.NoAuthMiddleware(
limits.RateLimitingMiddleware(
serialization(
extensions.ExtensionMiddleware(inner_app_v2)))))
else:
- api_v2 = v2.FaultWrapper(auth.AuthMiddleware(
+ api_v2 = openstack_api.FaultWrapper(auth.AuthMiddleware(
limits.RateLimitingMiddleware(
serialization(
extensions.ExtensionMiddleware(inner_app_v2)))))
@@ -102,7 +102,7 @@ def wsgi_app(inner_app_v2=None, fake_auth=True, fake_auth_context=None,
mapper = urlmap.URLMap()
mapper['/v2'] = api_v2
mapper['/v1.1'] = api_v2
- mapper['/'] = v2.FaultWrapper(versions.Versions())
+ mapper['/'] = openstack_api.FaultWrapper(versions.Versions())
return mapper
@@ -138,9 +138,9 @@ def stub_out_auth(stubs):
def fake_auth_init(self, app):
self.application = app
- stubs.Set(nova.api.openstack.v2.auth.AuthMiddleware,
+ stubs.Set(auth.AuthMiddleware,
'__init__', fake_auth_init)
- stubs.Set(nova.api.openstack.v2.auth.AuthMiddleware,
+ stubs.Set(auth.AuthMiddleware,
'__call__', fake_wsgi)
@@ -149,10 +149,10 @@ def stub_out_rate_limiting(stubs):
super(limits.RateLimitingMiddleware, self).__init__(app)
self.application = app
- stubs.Set(nova.api.openstack.v2.limits.RateLimitingMiddleware,
+ stubs.Set(nova.api.openstack.compute.limits.RateLimitingMiddleware,
'__init__', fake_rate_init)
- stubs.Set(nova.api.openstack.v2.limits.RateLimitingMiddleware,
+ stubs.Set(nova.api.openstack.compute.limits.RateLimitingMiddleware,
'__call__', fake_wsgi)
diff --git a/nova/tests/api/openstack/volume/__init__.py b/nova/tests/api/openstack/volume/__init__.py
new file mode 100644
index 000000000..00fcfbb00
--- /dev/null
+++ b/nova/tests/api/openstack/volume/__init__.py
@@ -0,0 +1,16 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
diff --git a/nova/tests/api/openstack/volume/test_snapshots.py b/nova/tests/api/openstack/volume/test_snapshots.py
new file mode 100644
index 000000000..06543ae5f
--- /dev/null
+++ b/nova/tests/api/openstack/volume/test_snapshots.py
@@ -0,0 +1,299 @@
+# Copyright 2011 Denali Systems, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import datetime
+import json
+import stubout
+
+from lxml import etree
+import webob
+
+from nova.api.openstack.volume import snapshots
+from nova import context
+from nova import exception
+from nova import flags
+from nova import log as logging
+from nova import test
+from nova import volume
+from nova.tests.api.openstack import fakes
+
+FLAGS = flags.FLAGS
+
+LOG = logging.getLogger('nova.tests.api.openstack.snapshot')
+
+_last_param = {}
+
+
+def _get_default_snapshot_param():
+ return {
+ 'id': 123,
+ 'volume_id': 12,
+ 'status': 'available',
+ 'volume_size': 100,
+ 'created_at': None,
+ 'display_name': 'Default name',
+ 'display_description': 'Default description',
+ }
+
+
+def stub_snapshot_create(self, context, volume_id, name, description):
+ global _last_param
+ snapshot = _get_default_snapshot_param()
+ snapshot['volume_id'] = volume_id
+ snapshot['display_name'] = name
+ snapshot['display_description'] = description
+
+ LOG.debug(_("_create: %s"), snapshot)
+ _last_param = snapshot
+ return snapshot
+
+
+def stub_snapshot_delete(self, context, snapshot_id):
+ global _last_param
+ _last_param = dict(snapshot_id=snapshot_id)
+
+ LOG.debug(_("_delete: %s"), locals())
+ if snapshot_id != '123':
+ raise exception.NotFound
+
+
+def stub_snapshot_get(self, context, snapshot_id):
+ global _last_param
+ _last_param = dict(snapshot_id=snapshot_id)
+
+ LOG.debug(_("_get: %s"), locals())
+ if snapshot_id != '123':
+ raise exception.NotFound
+
+ param = _get_default_snapshot_param()
+ param['id'] = snapshot_id
+ return param
+
+
+def stub_snapshot_get_all(self, context):
+ LOG.debug(_("_get_all: %s"), locals())
+ param = _get_default_snapshot_param()
+ param['id'] = 123
+ return [param]
+
+
+class SnapshotApiTest(test.TestCase):
+ def setUp(self):
+ super(SnapshotApiTest, self).setUp()
+ self.stubs = stubout.StubOutForTesting()
+ fakes.FakeAuthManager.reset_fake_data()
+ fakes.FakeAuthDatabase.data = {}
+ fakes.stub_out_networking(self.stubs)
+ fakes.stub_out_rate_limiting(self.stubs)
+ fakes.stub_out_auth(self.stubs)
+ self.stubs.Set(volume.api.API, "create_snapshot", stub_snapshot_create)
+ self.stubs.Set(volume.api.API, "create_snapshot_force",
+ stub_snapshot_create)
+ self.stubs.Set(volume.api.API, "delete_snapshot", stub_snapshot_delete)
+ self.stubs.Set(volume.api.API, "get_snapshot", stub_snapshot_get)
+ self.stubs.Set(volume.api.API, "get_all_snapshots",
+ stub_snapshot_get_all)
+
+ self.context = context.get_admin_context()
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(SnapshotApiTest, self).tearDown()
+
+ def test_snapshot_create(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot = {"volume_id": 12,
+ "force": False,
+ "display_name": "Snapshot Test Name",
+ "display_description": "Snapshot Test Desc"}
+ body = dict(snapshot=snapshot)
+ req = webob.Request.blank('/v1.1/fake/os-snapshots')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ LOG.debug(_("test_snapshot_create: param=%s"), _last_param)
+ self.assertEqual(resp.status_int, 200)
+
+ # Compare if parameters were correctly passed to stub
+ self.assertEqual(_last_param['display_name'], "Snapshot Test Name")
+ self.assertEqual(_last_param['display_description'],
+ "Snapshot Test Desc")
+
+ resp_dict = json.loads(resp.body)
+ LOG.debug(_("test_snapshot_create: resp_dict=%s"), resp_dict)
+ self.assertTrue('snapshot' in resp_dict)
+ self.assertEqual(resp_dict['snapshot']['displayName'],
+ snapshot['display_name'])
+ self.assertEqual(resp_dict['snapshot']['displayDescription'],
+ snapshot['display_description'])
+
+ def test_snapshot_create_force(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot = {"volume_id": 12,
+ "force": True,
+ "display_name": "Snapshot Test Name",
+ "display_description": "Snapshot Test Desc"}
+ body = dict(snapshot=snapshot)
+ req = webob.Request.blank('/v1.1/fake/os-snapshots')
+ req.method = 'POST'
+ req.body = json.dumps(body)
+ req.headers['content-type'] = 'application/json'
+
+ resp = req.get_response(fakes.wsgi_app())
+ LOG.debug(_("test_snapshot_create_force: param=%s"), _last_param)
+ self.assertEqual(resp.status_int, 200)
+
+ # Compare if parameters were correctly passed to stub
+ self.assertEqual(_last_param['display_name'], "Snapshot Test Name")
+ self.assertEqual(_last_param['display_description'],
+ "Snapshot Test Desc")
+
+ resp_dict = json.loads(resp.body)
+ LOG.debug(_("test_snapshot_create_force: resp_dict=%s"), resp_dict)
+ self.assertTrue('snapshot' in resp_dict)
+ self.assertEqual(resp_dict['snapshot']['displayName'],
+ snapshot['display_name'])
+ self.assertEqual(resp_dict['snapshot']['displayDescription'],
+ snapshot['display_description'])
+
+ def test_snapshot_delete(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot_id = 123
+ req = webob.Request.blank('/v1.1/fake/os-snapshots/%d' % snapshot_id)
+ req.method = 'DELETE'
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 202)
+ self.assertEqual(str(_last_param['snapshot_id']), str(snapshot_id))
+
+ def test_snapshot_delete_invalid_id(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot_id = 234
+ req = webob.Request.blank('/v1.1/fake/os-snapshots/%d' % snapshot_id)
+ req.method = 'DELETE'
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 404)
+ self.assertEqual(str(_last_param['snapshot_id']), str(snapshot_id))
+
+ def test_snapshot_show(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot_id = 123
+ req = webob.Request.blank('/v1.1/fake/os-snapshots/%d' % snapshot_id)
+ req.method = 'GET'
+ resp = req.get_response(fakes.wsgi_app())
+
+ LOG.debug(_("test_snapshot_show: resp=%s"), resp)
+ self.assertEqual(resp.status_int, 200)
+ self.assertEqual(str(_last_param['snapshot_id']), str(snapshot_id))
+
+ resp_dict = json.loads(resp.body)
+ self.assertTrue('snapshot' in resp_dict)
+ self.assertEqual(resp_dict['snapshot']['id'], str(snapshot_id))
+
+ def test_snapshot_show_invalid_id(self):
+ global _last_param
+ _last_param = {}
+
+ snapshot_id = 234
+ req = webob.Request.blank('/v1.1/fake/os-snapshots/%d' % snapshot_id)
+ req.method = 'GET'
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 404)
+ self.assertEqual(str(_last_param['snapshot_id']), str(snapshot_id))
+
+ def test_snapshot_detail(self):
+ req = webob.Request.blank('/v1.1/fake/os-snapshots/detail')
+ req.method = 'GET'
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 200)
+
+ resp_dict = json.loads(resp.body)
+ LOG.debug(_("test_snapshot_detail: resp_dict=%s"), resp_dict)
+ self.assertTrue('snapshots' in resp_dict)
+ resp_snapshots = resp_dict['snapshots']
+ self.assertEqual(len(resp_snapshots), 1)
+
+ resp_snapshot = resp_snapshots.pop()
+ self.assertEqual(resp_snapshot['id'], 123)
+
+
+class SnapshotSerializerTest(test.TestCase):
+ def _verify_snapshot(self, snap, tree):
+ self.assertEqual(tree.tag, 'snapshot')
+
+ for attr in ('id', 'status', 'size', 'createdAt',
+ 'displayName', 'displayDescription', 'volumeId'):
+ self.assertEqual(str(snap[attr]), tree.get(attr))
+
+ def test_snapshot_show_create_serializer(self):
+ serializer = snapshots.SnapshotSerializer()
+ raw_snapshot = dict(
+ id='snap_id',
+ status='snap_status',
+ size=1024,
+ createdAt=datetime.datetime.now(),
+ displayName='snap_name',
+ displayDescription='snap_desc',
+ volumeId='vol_id',
+ )
+ text = serializer.serialize(dict(snapshot=raw_snapshot), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_snapshot(raw_snapshot, tree)
+
+ def test_snapshot_index_detail_serializer(self):
+ serializer = snapshots.SnapshotSerializer()
+ raw_snapshots = [dict(
+ id='snap1_id',
+ status='snap1_status',
+ size=1024,
+ createdAt=datetime.datetime.now(),
+ displayName='snap1_name',
+ displayDescription='snap1_desc',
+ volumeId='vol1_id',
+ ),
+ dict(
+ id='snap2_id',
+ status='snap2_status',
+ size=1024,
+ createdAt=datetime.datetime.now(),
+ displayName='snap2_name',
+ displayDescription='snap2_desc',
+ volumeId='vol2_id',
+ )]
+ text = serializer.serialize(dict(snapshots=raw_snapshots), 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('snapshots', tree.tag)
+ self.assertEqual(len(raw_snapshots), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_snapshot(raw_snapshots[idx], child)
diff --git a/nova/tests/api/openstack/volume/test_types.py b/nova/tests/api/openstack/volume/test_types.py
new file mode 100644
index 000000000..34d861bed
--- /dev/null
+++ b/nova/tests/api/openstack/volume/test_types.py
@@ -0,0 +1,166 @@
+# 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.
+
+from lxml import etree
+import webob
+
+from nova.api.openstack.volume import types
+from nova import exception
+from nova import test
+from nova import log as logging
+from nova.volume import volume_types
+from nova.tests.api.openstack import fakes
+
+
+LOG = logging.getLogger('nova.tests.api.openstack.volume.'
+ 'test_volume_types')
+
+last_param = {}
+
+
+def stub_volume_type(id):
+ specs = {
+ "key1": "value1",
+ "key2": "value2",
+ "key3": "value3",
+ "key4": "value4",
+ "key5": "value5"}
+ return dict(id=id, name='vol_type_%s' % str(id), extra_specs=specs)
+
+
+def return_volume_types_get_all_types(context):
+ return dict(vol_type_1=stub_volume_type(1),
+ vol_type_2=stub_volume_type(2),
+ vol_type_3=stub_volume_type(3))
+
+
+def return_empty_volume_types_get_all_types(context):
+ return {}
+
+
+def return_volume_types_get_volume_type(context, id):
+ if id == "777":
+ raise exception.VolumeTypeNotFound(volume_type_id=id)
+ return stub_volume_type(int(id))
+
+
+def return_volume_types_destroy(context, name):
+ if name == "777":
+ raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
+ pass
+
+
+def return_volume_types_create(context, name, specs):
+ pass
+
+
+def return_volume_types_get_by_name(context, name):
+ if name == "777":
+ raise exception.VolumeTypeNotFoundByName(volume_type_name=name)
+ return stub_volume_type(int(name.split("_")[2]))
+
+
+class VolumeTypesApiTest(test.TestCase):
+ def setUp(self):
+ super(VolumeTypesApiTest, self).setUp()
+ fakes.stub_out_key_pair_funcs(self.stubs)
+ self.controller = types.VolumeTypesController()
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+ super(VolumeTypesApiTest, self).tearDown()
+
+ def test_volume_types_index(self):
+ self.stubs.Set(volume_types, 'get_all_types',
+ return_volume_types_get_all_types)
+
+ req = fakes.HTTPRequest.blank('/v2/123/os-volume-types')
+ res_dict = self.controller.index(req)
+
+ self.assertEqual(3, len(res_dict))
+ for name in ['vol_type_1', 'vol_type_2', 'vol_type_3']:
+ self.assertEqual(name, res_dict[name]['name'])
+ self.assertEqual('value1', res_dict[name]['extra_specs']['key1'])
+
+ def test_volume_types_index_no_data(self):
+ self.stubs.Set(volume_types, 'get_all_types',
+ return_empty_volume_types_get_all_types)
+
+ req = fakes.HTTPRequest.blank('/v2/123/os-volume-types')
+ res_dict = self.controller.index(req)
+
+ self.assertEqual(0, len(res_dict))
+
+ def test_volume_types_show(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+
+ req = fakes.HTTPRequest.blank('/v2/123/os-volume-types/1')
+ res_dict = self.controller.show(req, 1)
+
+ self.assertEqual(1, len(res_dict))
+ self.assertEqual('vol_type_1', res_dict['volume_type']['name'])
+
+ def test_volume_types_show_not_found(self):
+ self.stubs.Set(volume_types, 'get_volume_type',
+ return_volume_types_get_volume_type)
+
+ req = fakes.HTTPRequest.blank('/v2/123/os-volume-types/777')
+ self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
+ req, '777')
+
+
+class VolumeTypesSerializerTest(test.TestCase):
+ def setUp(self):
+ super(VolumeTypesSerializerTest, self).setUp()
+ self.serializer = types.VolumeTypesSerializer()
+
+ def _verify_volume_type(self, vtype, tree):
+ self.assertEqual('volume_type', tree.tag)
+ self.assertEqual(vtype['name'], tree.get('name'))
+ self.assertEqual(str(vtype['id']), tree.get('id'))
+ self.assertEqual(1, len(tree))
+ extra_specs = tree[0]
+ self.assertEqual('extra_specs', extra_specs.tag)
+ seen = set(vtype['extra_specs'].keys())
+ for child in extra_specs:
+ self.assertTrue(child.tag in seen)
+ self.assertEqual(vtype['extra_specs'][child.tag], child.text)
+ seen.remove(child.tag)
+ self.assertEqual(len(seen), 0)
+
+ def test_index_serializer(self):
+ # Just getting some input data
+ vtypes = return_volume_types_get_all_types(None)
+ text = self.serializer.serialize(vtypes, 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volume_types', tree.tag)
+ self.assertEqual(len(vtypes), len(tree))
+ for child in tree:
+ name = child.get('name')
+ self.assertTrue(name in vtypes)
+ self._verify_volume_type(vtypes[name], child)
+
+ def test_voltype_serializer(self):
+ vtype = stub_volume_type(1)
+ text = self.serializer.serialize(dict(volume_type=vtype))
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_volume_type(vtype, tree)
diff --git a/nova/tests/api/openstack/volume/test_volumes.py b/nova/tests/api/openstack/volume/test_volumes.py
new file mode 100644
index 000000000..2f17c4b22
--- /dev/null
+++ b/nova/tests/api/openstack/volume/test_volumes.py
@@ -0,0 +1,179 @@
+# Copyright 2013 Josh Durgin
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import datetime
+import json
+
+from lxml import etree
+import webob
+
+import nova
+from nova.api.openstack.volume import volumes
+from nova.compute import instance_types
+from nova import flags
+from nova import test
+from nova.tests.api.openstack import fakes
+
+
+FLAGS = flags.FLAGS
+
+
+class VolumeSerializerTest(test.TestCase):
+ def _verify_volume_attachment(self, attach, tree):
+ for attr in ('id', 'volumeId', 'serverId', 'device'):
+ self.assertEqual(str(attach[attr]), tree.get(attr))
+
+ def _verify_volume(self, vol, tree):
+ self.assertEqual(tree.tag, 'volume')
+
+ for attr in ('id', 'status', 'size', 'availabilityZone', 'createdAt',
+ 'displayName', 'displayDescription', 'volumeType',
+ 'snapshotId'):
+ self.assertEqual(str(vol[attr]), tree.get(attr))
+
+ for child in tree:
+ self.assertTrue(child.tag in ('attachments', 'metadata'))
+ if child.tag == 'attachments':
+ self.assertEqual(1, len(child))
+ self.assertEqual('attachment', child[0].tag)
+ self._verify_volume_attachment(vol['attachments'][0], child[0])
+ elif child.tag == 'metadata':
+ not_seen = set(vol['metadata'].keys())
+ for gr_child in child:
+ self.assertTrue(gr_child.tag in not_seen)
+ self.assertEqual(str(vol['metadata'][gr_child.tag]),
+ gr_child.text)
+ not_seen.remove(gr_child.tag)
+ self.assertEqual(0, len(not_seen))
+
+ def test_attach_show_create_serializer(self):
+ serializer = volumes.VolumeAttachmentSerializer()
+ raw_attach = dict(
+ id='vol_id',
+ volumeId='vol_id',
+ serverId='instance_uuid',
+ device='/foo')
+ text = serializer.serialize(dict(volumeAttachment=raw_attach), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumeAttachment', tree.tag)
+ self._verify_volume_attachment(raw_attach, tree)
+
+ def test_attach_index_serializer(self):
+ serializer = volumes.VolumeAttachmentSerializer()
+ raw_attaches = [dict(
+ id='vol_id1',
+ volumeId='vol_id1',
+ serverId='instance1_uuid',
+ device='/foo1'),
+ dict(
+ id='vol_id2',
+ volumeId='vol_id2',
+ serverId='instance2_uuid',
+ device='/foo2')]
+ text = serializer.serialize(dict(volumeAttachments=raw_attaches),
+ 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumeAttachments', tree.tag)
+ self.assertEqual(len(raw_attaches), len(tree))
+ for idx, child in enumerate(tree):
+ self.assertEqual('volumeAttachment', child.tag)
+ self._verify_volume_attachment(raw_attaches[idx], child)
+
+ def test_volume_show_create_serializer(self):
+ serializer = volumes.VolumeSerializer()
+ raw_volume = dict(
+ id='vol_id',
+ status='vol_status',
+ size=1024,
+ availabilityZone='vol_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol_id',
+ volumeId='vol_id',
+ serverId='instance_uuid',
+ device='/foo')],
+ displayName='vol_name',
+ displayDescription='vol_desc',
+ volumeType='vol_type',
+ snapshotId='snap_id',
+ metadata=dict(
+ foo='bar',
+ baz='quux',
+ ),
+ )
+ text = serializer.serialize(dict(volume=raw_volume), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_volume(raw_volume, tree)
+
+ def test_volume_index_detail_serializer(self):
+ serializer = volumes.VolumeSerializer()
+ raw_volumes = [dict(
+ id='vol1_id',
+ status='vol1_status',
+ size=1024,
+ availabilityZone='vol1_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol1_id',
+ volumeId='vol1_id',
+ serverId='instance_uuid',
+ device='/foo1')],
+ displayName='vol1_name',
+ displayDescription='vol1_desc',
+ volumeType='vol1_type',
+ snapshotId='snap1_id',
+ metadata=dict(
+ foo='vol1_foo',
+ bar='vol1_bar',
+ ),
+ ),
+ dict(
+ id='vol2_id',
+ status='vol2_status',
+ size=1024,
+ availabilityZone='vol2_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol2_id',
+ volumeId='vol2_id',
+ serverId='instance_uuid',
+ device='/foo2')],
+ displayName='vol2_name',
+ displayDescription='vol2_desc',
+ volumeType='vol2_type',
+ snapshotId='snap2_id',
+ metadata=dict(
+ foo='vol2_foo',
+ bar='vol2_bar',
+ ),
+ )]
+ text = serializer.serialize(dict(volumes=raw_volumes), 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumes', tree.tag)
+ self.assertEqual(len(raw_volumes), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_volume(raw_volumes[idx], child)
diff --git a/nova/tests/integrated/api/client.py b/nova/tests/integrated/api/client.py
index c942b0108..ccf83c1da 100644
--- a/nova/tests/integrated/api/client.py
+++ b/nova/tests/integrated/api/client.py
@@ -261,17 +261,17 @@ class TestOpenStackClient(object):
return self.api_delete('/flavors/%s' % flavor_id)
def get_volume(self, volume_id):
- return self.api_get('/os-volumes/%s' % volume_id)['volume']
+ return self.api_get('/volumes/%s' % volume_id)['volume']
def get_volumes(self, detail=True):
- rel_url = '/os-volumes/detail' if detail else '/os-volumes'
+ rel_url = '/volumes/detail' if detail else '/volumes'
return self.api_get(rel_url)['volumes']
def post_volume(self, volume):
- return self.api_post('/os-volumes', volume)['volume']
+ return self.api_post('/volumes', volume)['volume']
def delete_volume(self, volume_id):
- return self.api_delete('/os-volumes/%s' % volume_id)
+ return self.api_delete('/volumes/%s' % volume_id)
def get_server_volume(self, server_id, attachment_id):
return self.api_get('/servers/%s/os-volume_attachments/%s' %
diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py
index b18d24bd4..a98c94f65 100644
--- a/nova/tests/integrated/integrated_helpers.py
+++ b/nova/tests/integrated/integrated_helpers.py
@@ -80,10 +80,14 @@ class _IntegratedTestBase(test.TestCase):
self.api = client.TestOpenStackClient('fake', 'fake', self.auth_url)
+ def tearDown(self):
+ self.osapi.stop()
+ super(_IntegratedTestBase, self).tearDown()
+
def _start_api_service(self):
- osapi = service.WSGIService("osapi")
- osapi.start()
- self.auth_url = 'http://%s:%s/v2' % (osapi.host, osapi.port)
+ self.osapi = service.WSGIService("osapi_compute")
+ self.osapi.start()
+ self.auth_url = 'http://%s:%s/v2' % (self.osapi.host, self.osapi.port)
LOG.warn(self.auth_url)
def _get_flags(self):
diff --git a/nova/tests/integrated/test_extensions.py b/nova/tests/integrated/test_extensions.py
index b10da166a..70c998ef0 100644
--- a/nova/tests/integrated/test_extensions.py
+++ b/nova/tests/integrated/test_extensions.py
@@ -17,7 +17,7 @@
import os
-from nova.api.openstack.v2 import extensions
+from nova.api.openstack.compute import extensions
from nova import flags
from nova.log import logging
from nova.tests.integrated import integrated_helpers
@@ -32,9 +32,10 @@ class ExtensionsTest(integrated_helpers._IntegratedTestBase):
extensions.ExtensionManager.reset()
f = super(ExtensionsTest, self)._get_flags()
- f['osapi_extension'] = FLAGS.osapi_extension[:]
- f['osapi_extension'].append('nova.tests.api.openstack.v2.extensions.'
- 'foxinsocks.Foxinsocks')
+ f['osapi_compute_extension'] = FLAGS.osapi_compute_extension[:]
+ f['osapi_compute_extension'].append(
+ 'nova.tests.api.openstack.compute.extensions.'
+ 'foxinsocks.Foxinsocks')
return f
def test_get_foxnsocks(self):
diff --git a/nova/tests/integrated/test_volumes.py b/nova/tests/integrated/test_volumes.py
index 9e19f2cff..d07865181 100644
--- a/nova/tests/integrated/test_volumes.py
+++ b/nova/tests/integrated/test_volumes.py
@@ -18,6 +18,7 @@
import unittest
import time
+from nova import service
from nova.log import logging
from nova.tests.integrated import integrated_helpers
from nova.tests.integrated.api import client
@@ -32,6 +33,12 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
super(VolumesTest, self).setUp()
driver.LoggingVolumeDriver.clear_logs()
+ def _start_api_service(self):
+ self.osapi = service.WSGIService("osapi_volume")
+ self.osapi.start()
+ self.auth_url = 'http://%s:%s/v1' % (self.osapi.host, self.osapi.port)
+ LOG.warn(self.auth_url)
+
def _get_flags(self):
f = super(VolumesTest, self)._get_flags()
f['use_local_volumes'] = False # Avoids calling local_path
@@ -135,157 +142,6 @@ class VolumesTest(integrated_helpers._IntegratedTestBase):
delete_action = export_actions[0]
self.assertEquals(delete_action['id'], created_volume_id)
- def test_attach_and_detach_volume(self):
- """Creates, attaches, detaches and deletes a volume."""
- self.flags(stub_network=True)
-
- # Create server
- server_req = {'server': self._build_minimal_create_server_request()}
- # NOTE(justinsb): Create an extra server so that server_id != volume_id
- self.api.post_server(server_req)
- created_server = self.api.post_server(server_req)
- LOG.debug("created_server: %s" % created_server)
- server_id = created_server['id']
-
- # Create volume
- created_volume = self.api.post_volume({'volume': {'size': 1}})
- LOG.debug("created_volume: %s" % created_volume)
- volume_id = created_volume['id']
- self._poll_while(volume_id, ['creating'])
-
- # Check we've got different IDs
- self.assertNotEqual(server_id, volume_id)
-
- # List current server attachments - should be none
- attachments = self.api.get_server_volumes(server_id)
- self.assertEquals([], attachments)
-
- # Template attach request
- device = '/dev/sdc'
- attach_req = {'device': device}
- post_req = {'volumeAttachment': attach_req}
-
- # Try to attach to a non-existent volume; should fail
- attach_req['volumeId'] = 3405691582
- self.assertRaises(client.OpenStackApiNotFoundException,
- self.api.post_server_volume, server_id, post_req)
-
- # Try to attach to a non-existent server; should fail
- attach_req['volumeId'] = volume_id
- self.assertRaises(client.OpenStackApiNotFoundException,
- self.api.post_server_volume, 3405691582, post_req)
-
- # Should still be no attachments...
- attachments = self.api.get_server_volumes(server_id)
- self.assertEquals([], attachments)
-
- # Do a real attach
- attach_req['volumeId'] = volume_id
- attach_result = self.api.post_server_volume(server_id, post_req)
- LOG.debug(_("Attachment = %s") % attach_result)
-
- attachment_id = attach_result['id']
- self.assertEquals(volume_id, attach_result['volumeId'])
-
- # These fields aren't set because it's async
- #self.assertEquals(server_id, attach_result['serverId'])
- #self.assertEquals(device, attach_result['device'])
-
- # This is just an implementation detail, but let's check it...
- self.assertEquals(volume_id, attachment_id)
-
- # NOTE(justinsb): There's an issue with the attach code, in that
- # it's currently asynchronous and not recorded until the attach
- # completes. So the caller must be 'smart', like this...
- attach_done = None
- retries = 0
- while True:
- try:
- attach_done = self.api.get_server_volume(server_id,
- attachment_id)
- break
- except client.OpenStackApiNotFoundException:
- LOG.debug("Got 404, waiting")
-
- time.sleep(1)
- retries = retries + 1
- if retries > 10:
- break
-
- expect_attach = {}
- expect_attach['id'] = volume_id
- expect_attach['volumeId'] = volume_id
- expect_attach['serverId'] = server_id
- expect_attach['device'] = device
-
- self.assertEqual(expect_attach, attach_done)
-
- # Should be one attachemnt
- attachments = self.api.get_server_volumes(server_id)
- self.assertEquals([expect_attach], attachments)
-
- # Should be able to get details
- attachment_info = self.api.get_server_volume(server_id, attachment_id)
- self.assertEquals(expect_attach, attachment_info)
-
- # Getting details on a different id should fail
- self.assertRaises(client.OpenStackApiNotFoundException,
- self.api.get_server_volume, server_id, 3405691582)
- self.assertRaises(client.OpenStackApiNotFoundException,
- self.api.get_server_volume,
- 3405691582, attachment_id)
-
- # Trying to detach a different id should fail
- self.assertRaises(client.OpenStackApiNotFoundException,
- self.api.delete_server_volume, server_id, 3405691582)
-
- # Detach should work
- self.api.delete_server_volume(server_id, attachment_id)
-
- # Again, it's async, so wait...
- retries = 0
- while True:
- try:
- attachment = self.api.get_server_volume(server_id,
- attachment_id)
- LOG.debug("Attachment still there: %s" % attachment)
- except client.OpenStackApiNotFoundException:
- LOG.debug("Got 404, delete done")
- break
-
- time.sleep(1)
- retries = retries + 1
- self.assertTrue(retries < 10)
-
- # Should be no attachments again
- attachments = self.api.get_server_volumes(server_id)
- self.assertEquals([], attachments)
-
- LOG.debug("Logs: %s" % driver.LoggingVolumeDriver.all_logs())
-
- # prepare_attach and prepare_detach are called from compute
- # on attach/detach
-
- disco_moves = driver.LoggingVolumeDriver.logs_like(
- 'initialize_connection',
- id=volume_id)
- LOG.debug("initialize_connection actions: %s" % disco_moves)
-
- self.assertEquals(1, len(disco_moves))
- disco_move = disco_moves[0]
- self.assertEquals(disco_move['id'], volume_id)
-
- last_days_of_disco_moves = driver.LoggingVolumeDriver.logs_like(
- 'terminate_connection',
- id=volume_id)
- LOG.debug("terminate_connection actions: %s" %
- last_days_of_disco_moves)
-
- self.assertEquals(1, len(last_days_of_disco_moves))
- undisco_move = last_days_of_disco_moves[0]
- self.assertEquals(undisco_move['id'], volume_id)
- self.assertEquals(undisco_move['mountpoint'], device)
-
def test_create_volume_with_metadata(self):
"""Creates and deletes a volume."""
diff --git a/setup.py b/setup.py
index cf6499782..9eb9ef92b 100644
--- a/setup.py
+++ b/setup.py
@@ -87,7 +87,8 @@ setup(name='nova',
'bin/nova-api',
'bin/nova-api-ec2',
'bin/nova-api-metadata',
- 'bin/nova-api-os',
+ 'bin/nova-api-os-compute',
+ 'bin/nova-api-os-volume',
'bin/nova-compute',
'bin/nova-console',
'bin/nova-dhcpbridge',