Implements blueprint separate-nova-volumeapi
* Moves openstack/v2 directory to compute and fixes tests accordingly * Moves some code from api/openstack/compute to shared location, for use by volume api * Implements basic volume functionality for types, volumes, and snapshots * Changes service name from osapi to osapi_compute (and adds osapi_volume) * Renames nova-api-os to nova-api-os-compute, adds nove-api-os-volume * Separate extension mechanism for compute and volume ** Removes flag osapi_extension and replaces with osapi_compute_extension and osapi_volume_extension * Updates the paste config * Fixes setup.py to include nova-os-api-compute and nova-os-api-volume * Fix bug in volume version code that occurred as result of trunk merge * Update integrated/test_volumes.py to use new endpoint Change-Id: I4c2e57c3cafd4e1a9e2ff3ce201c8cf28326afcd
This commit is contained in:
parent
26de3426d4
commit
60ff2e3b72
47
bin/nova-api-os-compute
Executable file
47
bin/nova-api-os-compute
Executable file
@ -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()
|
@ -42,6 +42,6 @@ if __name__ == '__main__':
|
|||||||
flags.FLAGS(sys.argv)
|
flags.FLAGS(sys.argv)
|
||||||
logging.setup()
|
logging.setup()
|
||||||
utils.monkey_patch()
|
utils.monkey_patch()
|
||||||
server = service.WSGIService('osapi')
|
server = service.WSGIService('osapi_volume')
|
||||||
service.serve(server)
|
service.serve(server)
|
||||||
service.wait()
|
service.wait()
|
@ -78,40 +78,60 @@ paste.app_factory = nova.api.ec2:Executor.factory
|
|||||||
# Openstack #
|
# Openstack #
|
||||||
#############
|
#############
|
||||||
|
|
||||||
[composite:osapi]
|
[composite:osapi_compute]
|
||||||
use = call:nova.api.openstack.v2.urlmap:urlmap_factory
|
use = call:nova.api.openstack.urlmap:urlmap_factory
|
||||||
/: osversions
|
/: oscomputeversions
|
||||||
/v1.1: openstack_api_v2
|
/v1.1: openstack_compute_api_v2
|
||||||
/v2: openstack_api_v2
|
/v2: openstack_compute_api_v2
|
||||||
|
|
||||||
[pipeline:openstack_api_v2]
|
[composite:osapi_volume]
|
||||||
pipeline = faultwrap noauth ratelimit serialize extensions osapi_app_v2
|
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
|
# 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]
|
[filter:faultwrap]
|
||||||
paste.filter_factory = nova.api.openstack.v2:FaultWrapper.factory
|
paste.filter_factory = nova.api.openstack:FaultWrapper.factory
|
||||||
|
|
||||||
[filter:auth]
|
[filter:auth]
|
||||||
paste.filter_factory = nova.api.openstack.v2.auth:AuthMiddleware.factory
|
paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory
|
||||||
|
|
||||||
[filter:noauth]
|
[filter:noauth]
|
||||||
paste.filter_factory = nova.api.openstack.v2.auth:NoAuthMiddleware.factory
|
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory
|
||||||
|
|
||||||
[filter:ratelimit]
|
[filter:ratelimit]
|
||||||
paste.filter_factory = nova.api.openstack.v2.limits:RateLimitingMiddleware.factory
|
paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory
|
||||||
|
|
||||||
[filter:serialize]
|
[filter:serialize]
|
||||||
paste.filter_factory = nova.api.openstack.wsgi:LazySerializationMiddleware.factory
|
paste.filter_factory = nova.api.openstack.wsgi:LazySerializationMiddleware.factory
|
||||||
|
|
||||||
[filter:extensions]
|
[filter:compute_extensions]
|
||||||
paste.filter_factory = nova.api.openstack.v2.extensions:ExtensionMiddleware.factory
|
paste.filter_factory = nova.api.openstack.compute.extensions:ExtensionMiddleware.factory
|
||||||
|
|
||||||
[app:osapi_app_v2]
|
[filter:volume_extensions]
|
||||||
paste.app_factory = nova.api.openstack.v2:APIRouter.factory
|
paste.filter_factory = nova.api.openstack.volume.extensions:ExtensionMiddleware.factory
|
||||||
|
|
||||||
[pipeline:osversions]
|
[app:osapi_compute_app_v2]
|
||||||
pipeline = faultwrap osversionapp
|
paste.app_factory = nova.api.openstack.compute:APIRouter.factory
|
||||||
|
|
||||||
[app:osversionapp]
|
[pipeline:oscomputeversions]
|
||||||
paste.app_factory = nova.api.openstack.v2.versions:Versions.factory
|
pipeline = faultwrap oscomputeversionapp
|
||||||
|
|
||||||
|
[app:osapi_volume_app_v1]
|
||||||
|
paste.app_factory = nova.api.openstack.volume:APIRouter.factory
|
||||||
|
|
||||||
|
[app:oscomputeversionapp]
|
||||||
|
paste.app_factory = nova.api.openstack.compute.versions:Versions.factory
|
||||||
|
|
||||||
|
[pipeline:osvolumeversions]
|
||||||
|
pipeline = faultwrap osvolumeversionapp
|
||||||
|
|
||||||
|
[app:osvolumeversionapp]
|
||||||
|
paste.app_factory = nova.api.openstack.volume.versions:Versions.factory
|
||||||
|
76
nova/api/mapper.py
Normal file
76
nova/api/mapper.py
Normal file
@ -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)
|
@ -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)
|
@ -32,7 +32,7 @@ from nova import log as logging
|
|||||||
from nova import utils
|
from nova import utils
|
||||||
from nova import wsgi as base_wsgi
|
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 = flags.FLAGS
|
||||||
flags.DECLARE('use_forwarded_for', 'nova.api.auth')
|
flags.DECLARE('use_forwarded_for', 'nova.api.auth')
|
||||||
|
|
@ -24,23 +24,24 @@ import routes
|
|||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from nova.api.openstack.v2 import consoles
|
import nova.api.openstack
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack.compute import consoles
|
||||||
from nova.api.openstack.v2 import flavors
|
from nova.api.openstack.compute import extensions
|
||||||
from nova.api.openstack.v2 import images
|
from nova.api.openstack.compute import flavors
|
||||||
from nova.api.openstack.v2 import image_metadata
|
from nova.api.openstack.compute import images
|
||||||
from nova.api.openstack.v2 import ips
|
from nova.api.openstack.compute import image_metadata
|
||||||
from nova.api.openstack.v2 import limits
|
from nova.api.openstack.compute import ips
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import limits
|
||||||
from nova.api.openstack.v2 import server_metadata
|
from nova.api.openstack.compute import servers
|
||||||
from nova.api.openstack.v2 import versions
|
from nova.api.openstack.compute import server_metadata
|
||||||
|
from nova.api.openstack.compute import versions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import wsgi as base_wsgi
|
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 = flags.FLAGS
|
||||||
flags.DEFINE_bool('allow_admin_api',
|
flags.DEFINE_bool('allow_admin_api',
|
||||||
False,
|
False,
|
||||||
@ -50,43 +51,6 @@ flags.DEFINE_bool('allow_instance_snapshots',
|
|||||||
'When True, this API service will permit instance snapshot operations.')
|
'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):
|
class APIRouter(base_wsgi.Router):
|
||||||
"""
|
"""
|
||||||
Routes requests on the OpenStack API to the appropriate controller
|
Routes requests on the OpenStack API to the appropriate controller
|
||||||
@ -102,7 +66,7 @@ class APIRouter(base_wsgi.Router):
|
|||||||
if ext_mgr is None:
|
if ext_mgr is None:
|
||||||
ext_mgr = extensions.ExtensionManager()
|
ext_mgr = extensions.ExtensionManager()
|
||||||
|
|
||||||
mapper = ProjectMapper()
|
mapper = nova.api.openstack.ProjectMapper()
|
||||||
self._setup_routes(mapper)
|
self._setup_routes(mapper)
|
||||||
self._setup_ext_routes(mapper, ext_mgr)
|
self._setup_ext_routes(mapper, ext_mgr)
|
||||||
super(APIRouter, self).__init__(mapper)
|
super(APIRouter, self).__init__(mapper)
|
32
nova/api/openstack/compute/contrib/__init__.py
Normal file
32
nova/api/openstack/compute/contrib/__init__.py
Normal file
@ -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__)
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import webob.exc
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
@ -25,7 +25,7 @@ from nova import log as logging
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class AccountTemplate(xmlutil.TemplateBuilder):
|
@ -19,7 +19,7 @@ import webob
|
|||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack import common
|
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 compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@ -28,7 +28,7 @@ from nova.scheduler import api as scheduler_api
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class Admin_actions(extensions.ExtensionDescriptor):
|
@ -18,7 +18,7 @@ import os
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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.auth import manager
|
||||||
from nova.cloudpipe import pipelib
|
from nova.cloudpipe import pipelib
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -31,7 +31,7 @@ from nova import utils
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class CloudpipeTemplate(xmlutil.TemplateBuilder):
|
@ -21,10 +21,10 @@ import webob
|
|||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import log as logging
|
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):
|
class Console_output(extensions.ExtensionDescriptor):
|
@ -14,9 +14,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License
|
# under the License
|
||||||
|
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import servers
|
||||||
from nova.api.openstack.v2 import views
|
from nova.api.openstack.compute import views
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
|
|
||||||
|
|
@ -18,14 +18,14 @@
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import servers
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import log as logging
|
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):
|
class Deferred_delete(extensions.ExtensionDescriptor):
|
@ -20,7 +20,7 @@ from xml.dom import minidom
|
|||||||
|
|
||||||
from webob import exc
|
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.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import db
|
from nova import db
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
from webob import exc
|
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.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
@ -25,7 +25,7 @@ from nova import log as logging
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class Extended_status(extensions.ExtensionDescriptor):
|
@ -24,7 +24,7 @@ attributes. This extension adds to that list:
|
|||||||
swap
|
swap
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
|
|
||||||
|
|
||||||
class Flavorextradata(extensions.ExtensionDescriptor):
|
class Flavorextradata(extensions.ExtensionDescriptor):
|
@ -21,7 +21,7 @@ from webob import exc
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
|
|
@ -20,13 +20,13 @@ import webob
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 exception
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import network
|
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):
|
def make_dns_entry(elem):
|
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 log as logging
|
||||||
from nova import network
|
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):
|
def _translate_floating_ip_view(pool):
|
@ -21,7 +21,7 @@ import webob
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
@ -29,7 +29,7 @@ from nova import network
|
|||||||
from nova import rpc
|
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):
|
def make_float_ip(elem):
|
@ -21,7 +21,7 @@ from xml.parsers import expat
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@ -29,7 +29,7 @@ from nova import log as logging
|
|||||||
from nova.scheduler import api as scheduler_api
|
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
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ from webob import exc
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 crypto
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova import exception
|
from nova import exception
|
@ -18,13 +18,13 @@
|
|||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import log as logging
|
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
|
# Note: The class name is as it has to be for this to be loaded as an
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
@ -27,7 +27,7 @@ import nova.network.api
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
def network_dict(network):
|
@ -19,7 +19,7 @@ import webob
|
|||||||
|
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
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 db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import quota
|
from nova import quota
|
@ -17,7 +17,7 @@
|
|||||||
import webob
|
import webob
|
||||||
from webob import exc
|
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 compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@ -26,7 +26,7 @@ from nova import utils
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class Rescue(exts.ExtensionDescriptor):
|
@ -22,7 +22,7 @@ from webob import exc
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import common
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -33,7 +33,7 @@ from nova import log as logging
|
|||||||
from nova import utils
|
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
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import webob.exc
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import webob.exc
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
@ -20,7 +20,7 @@ import urlparse
|
|||||||
|
|
||||||
import webob
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova.compute import api
|
from nova.compute import api
|
@ -16,7 +16,7 @@
|
|||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack import common
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
@ -16,14 +16,15 @@
|
|||||||
"""The virtual interfaces extension."""
|
"""The virtual interfaces extension."""
|
||||||
|
|
||||||
from nova.api.openstack import common
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import network
|
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}
|
vif_nsmap = {None: wsgi.XMLNS_V11}
|
@ -22,9 +22,9 @@ import webob
|
|||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2.contrib import volumes
|
from nova.api.openstack.compute.contrib import volumes
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import servers
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -40,7 +40,7 @@ from nova import volume
|
|||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
def _vsa_view(context, vsa, details=False, instances=None):
|
@ -19,8 +19,8 @@ from webob import exc
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import servers
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -31,7 +31,7 @@ from nova import volume
|
|||||||
from nova.volume import volume_types
|
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
|
FLAGS = flags.FLAGS
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
from webob import exc
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import db
|
from nova import db
|
@ -20,8 +20,8 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2 import servers
|
from nova.api.openstack.compute import servers
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack import extensions
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.compute import api as compute
|
from nova.compute import api as compute
|
||||||
@ -32,7 +32,7 @@ from nova import log as logging
|
|||||||
import nova.scheduler.api
|
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
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
45
nova/api/openstack/compute/extensions.py
Normal file
45
nova/api/openstack/compute/extensions.py
Normal file
@ -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)
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import webob
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova.compute import instance_types
|
from nova.compute import instance_types
|
@ -16,7 +16,7 @@
|
|||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from nova.api.openstack import common
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -26,7 +26,7 @@ import nova.image
|
|||||||
from nova import log
|
from nova import log
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger('nova.api.openstack.v2.images')
|
LOG = log.getLogger('nova.api.openstack.compute.images')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
SUPPORTED_FILTERS = {
|
SUPPORTED_FILTERS = {
|
@ -19,14 +19,14 @@ from webob import exc
|
|||||||
|
|
||||||
import nova
|
import nova
|
||||||
from nova.api.openstack import common
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import flags
|
from nova import flags
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.api.openstack.v2.ips')
|
LOG = logging.getLogger('nova.api.openstack.compute.ips')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ import time
|
|||||||
from webob.dec import wsgify
|
from webob.dec import wsgify
|
||||||
import webob.exc
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import quota
|
from nova import quota
|
@ -22,8 +22,8 @@ from webob import exc
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2 import ips
|
from nova.api.openstack.compute import ips
|
||||||
from nova.api.openstack.v2.views import servers as views_servers
|
from nova.api.openstack.compute.views import servers as views_servers
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import compute
|
from nova import compute
|
||||||
@ -36,7 +36,7 @@ from nova.scheduler import api as scheduler_api
|
|||||||
from nova import utils
|
from nova import utils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.api.openstack.v2.servers')
|
LOG = logging.getLogger('nova.api.openstack.compute.servers')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from lxml import etree
|
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 wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
|
|
@ -23,7 +23,7 @@ from nova import log as logging
|
|||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
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):
|
class ViewBuilder(common.ViewBuilder):
|
@ -19,14 +19,14 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from nova.api.openstack import common
|
from nova.api.openstack import common
|
||||||
from nova.api.openstack.v2.views import addresses as views_addresses
|
from nova.api.openstack.compute.views import addresses as views_addresses
|
||||||
from nova.api.openstack.v2.views import flavors as views_flavors
|
from nova.api.openstack.compute.views import flavors as views_flavors
|
||||||
from nova.api.openstack.v2.views import images as views_images
|
from nova.api.openstack.compute.views import images as views_images
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import utils
|
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):
|
class ViewBuilder(common.ViewBuilder):
|
@ -16,11 +16,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
import routes
|
import routes
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
import nova.api.openstack.v2
|
import nova.api.openstack
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova.api.openstack import xmlutil
|
from nova.api.openstack import xmlutil
|
||||||
from nova import exception
|
from nova import exception
|
||||||
@ -30,7 +31,7 @@ from nova import utils
|
|||||||
from nova import wsgi as base_wsgi
|
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
|
FLAGS = flags.FLAGS
|
||||||
@ -326,7 +327,7 @@ class ExtensionMiddleware(base_wsgi.Middleware):
|
|||||||
ext_mgr = ExtensionManager()
|
ext_mgr = ExtensionManager()
|
||||||
self.ext_mgr = ext_mgr
|
self.ext_mgr = ext_mgr
|
||||||
|
|
||||||
mapper = nova.api.openstack.v2.ProjectMapper()
|
mapper = nova.api.openstack.ProjectMapper()
|
||||||
|
|
||||||
# extended actions
|
# extended actions
|
||||||
action_resources = self._action_ext_resources(application, ext_mgr,
|
action_resources = self._action_ext_resources(application, ext_mgr,
|
||||||
@ -388,17 +389,6 @@ class ExtensionManager(object):
|
|||||||
def reset(cls):
|
def reset(cls):
|
||||||
cls._ext_mgr = None
|
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):
|
def register(self, ext):
|
||||||
# Do nothing if the extension doesn't check out
|
# Do nothing if the extension doesn't check out
|
||||||
if not self._check_extension(ext):
|
if not self._check_extension(ext):
|
||||||
@ -483,7 +473,6 @@ class ExtensionManager(object):
|
|||||||
LOG.debug(_("Loading extension %s"), ext_factory)
|
LOG.debug(_("Loading extension %s"), ext_factory)
|
||||||
|
|
||||||
# Load the factory
|
# Load the factory
|
||||||
|
|
||||||
factory = utils.import_class(ext_factory)
|
factory = utils.import_class(ext_factory)
|
||||||
|
|
||||||
# Call it
|
# Call it
|
||||||
@ -493,7 +482,7 @@ class ExtensionManager(object):
|
|||||||
def _load_extensions(self):
|
def _load_extensions(self):
|
||||||
"""Load extensions specified on the command line."""
|
"""Load extensions specified on the command line."""
|
||||||
|
|
||||||
extensions = list(FLAGS.osapi_extension)
|
extensions = list(self.cls_list)
|
||||||
|
|
||||||
for ext_factory in extensions:
|
for ext_factory in extensions:
|
||||||
try:
|
try:
|
||||||
@ -573,3 +562,62 @@ def wrap_errors(fn):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
raise webob.exc.HTTPInternalServerError()
|
raise webob.exc.HTTPInternalServerError()
|
||||||
return wrapped
|
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
|
@ -28,7 +28,7 @@ _option_header_piece_re = re.compile(r';\s*([^\s;=]+|%s)\s*'
|
|||||||
r'(?:=\s*([^;]+|%s))?\s*' %
|
r'(?:=\s*([^;]+|%s))?\s*' %
|
||||||
(_quoted_string_re, _quoted_string_re))
|
(_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):
|
def unquote_header_value(value):
|
@ -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
|
|
99
nova/api/openstack/volume/__init__.py
Normal file
99
nova/api/openstack/volume/__init__.py
Normal file
@ -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())
|
32
nova/api/openstack/volume/contrib/__init__.py
Normal file
32
nova/api/openstack/volume/contrib/__init__.py
Normal file
@ -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__)
|
44
nova/api/openstack/volume/extensions.py
Normal file
44
nova/api/openstack/volume/extensions.py
Normal file
@ -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)
|
183
nova/api/openstack/volume/snapshots.py
Normal file
183
nova/api/openstack/volume/snapshots.py
Normal file
@ -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)
|
89
nova/api/openstack/volume/types.py
Normal file
89
nova/api/openstack/volume/types.py
Normal file
@ -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)
|
83
nova/api/openstack/volume/versions.py
Normal file
83
nova/api/openstack/volume/versions.py
Normal file
@ -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())
|
16
nova/api/openstack/volume/views/__init__.py
Normal file
16
nova/api/openstack/volume/views/__init__.py
Normal file
@ -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.
|
37
nova/api/openstack/volume/views/versions.py
Normal file
37
nova/api/openstack/volume/views/versions.py
Normal file
@ -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) + '/'
|
254
nova/api/openstack/volume/volumes.py
Normal file
254
nova/api/openstack/volume/volumes.py
Normal file
@ -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)
|
@ -31,9 +31,9 @@ XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
|
|||||||
def validate_schema(xml, schema_name):
|
def validate_schema(xml, schema_name):
|
||||||
if isinstance(xml, str):
|
if isinstance(xml, str):
|
||||||
xml = etree.fromstring(xml)
|
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'):
|
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(),
|
schema_path = os.path.join(utils.novadir(),
|
||||||
'%s%s.rng' % (base_path, schema_name))
|
'%s%s.rng' % (base_path, schema_name))
|
||||||
schema_doc = etree.parse(schema_path)
|
schema_doc = etree.parse(schema_path)
|
||||||
|
@ -827,7 +827,7 @@ class AuthManager(object):
|
|||||||
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
's3': 'http://%s:%s' % (s3_host, FLAGS.s3_port),
|
||||||
'os': '%s://%s:%s%s' % (FLAGS.osapi_scheme,
|
'os': '%s://%s:%s%s' % (FLAGS.osapi_scheme,
|
||||||
ec2_host,
|
ec2_host,
|
||||||
FLAGS.osapi_port,
|
FLAGS.osapi_compute_listen_port,
|
||||||
FLAGS.osapi_path),
|
FLAGS.osapi_path),
|
||||||
'user': user.name,
|
'user': user.name,
|
||||||
'nova': FLAGS.ca_file,
|
'nova': FLAGS.ca_file,
|
||||||
|
@ -32,14 +32,14 @@ Options can be strings, integers, floats, booleans, lists or 'multi strings':
|
|||||||
|
|
||||||
enabled_apis_opt = \
|
enabled_apis_opt = \
|
||||||
cfg.ListOpt('enabled_apis',
|
cfg.ListOpt('enabled_apis',
|
||||||
default=['ec2', 'osapi'],
|
default=['ec2', 'osapi_compute'],
|
||||||
help='List of APIs to enable by default')
|
help='List of APIs to enable by default')
|
||||||
|
|
||||||
DEFAULT_EXTENSIONS = [
|
DEFAULT_EXTENSIONS = [
|
||||||
'nova.api.openstack.contrib.standard_extensions'
|
'nova.api.openstack.contrib.standard_extensions'
|
||||||
]
|
]
|
||||||
osapi_extension_opt = \
|
osapi_compute_extension_opt = \
|
||||||
cfg.MultiStrOpt('osapi_extension',
|
cfg.MultiStrOpt('osapi_compute_extension',
|
||||||
default=DEFAULT_EXTENSIONS)
|
default=DEFAULT_EXTENSIONS)
|
||||||
|
|
||||||
Option schemas are registered with with the config manager at runtime, but
|
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):
|
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
|
A common usage pattern is for each option schema to be defined in the module or
|
||||||
|
@ -309,19 +309,21 @@ DEFINE_integer('rabbit_max_retries', 0,
|
|||||||
'maximum rabbit connection attempts (0=try forever)')
|
'maximum rabbit connection attempts (0=try forever)')
|
||||||
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
DEFINE_string('control_exchange', 'nova', 'the main exchange to connect to')
|
||||||
DEFINE_boolean('rabbit_durable_queues', False, 'use durable queues')
|
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')
|
'list of APIs to enable by default')
|
||||||
DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
|
DEFINE_string('ec2_host', '$my_ip', 'ip of api server')
|
||||||
DEFINE_string('ec2_dmz_host', '$my_ip', 'internal 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_integer('ec2_port', 8773, 'cloud controller port')
|
||||||
DEFINE_string('ec2_scheme', 'http', 'prefix for ec2')
|
DEFINE_string('ec2_scheme', 'http', 'prefix for ec2')
|
||||||
DEFINE_string('ec2_path', '/services/Cloud', 'suffix for ec2')
|
DEFINE_string('ec2_path', '/services/Cloud', 'suffix for ec2')
|
||||||
DEFINE_multistring('osapi_extension',
|
DEFINE_multistring('osapi_compute_extension',
|
||||||
['nova.api.openstack.v2.contrib.standard_extensions'],
|
['nova.api.openstack.compute.contrib.standard_extensions'],
|
||||||
'osapi extension to load')
|
'osapi compute extension to load')
|
||||||
DEFINE_string('osapi_host', '$my_ip', 'ip of api server')
|
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_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_string('osapi_path', '/v1.1/', 'suffix for openstack')
|
||||||
DEFINE_integer('osapi_max_limit', 1000,
|
DEFINE_integer('osapi_max_limit', 1000,
|
||||||
'max number of items returned in a collection response')
|
'max number of items returned in a collection response')
|
||||||
|
@ -48,9 +48,10 @@ flags.DEFINE_integer('periodic_interval', 60,
|
|||||||
flags.DEFINE_string('ec2_listen', "0.0.0.0",
|
flags.DEFINE_string('ec2_listen', "0.0.0.0",
|
||||||
'IP address for EC2 API to listen')
|
'IP address for EC2 API to listen')
|
||||||
flags.DEFINE_integer('ec2_listen_port', 8773, 'port 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')
|
'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',
|
flags.DEFINE_string('metadata_manager', 'nova.api.manager.MetadataManager',
|
||||||
'OpenStack metadata service manager')
|
'OpenStack metadata service manager')
|
||||||
flags.DEFINE_string('metadata_listen', "0.0.0.0",
|
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')
|
'port for metadata api to listen')
|
||||||
flags.DEFINE_string('api_paste_config', "api-paste.ini",
|
flags.DEFINE_string('api_paste_config', "api-paste.ini",
|
||||||
'File name for the paste.deploy config for nova-api')
|
'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):
|
class Launcher(object):
|
||||||
|
@ -20,7 +20,7 @@ from lxml import etree
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova import test
|
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.auth.manager import User
|
||||||
from nova.tests.api.openstack import fakes
|
from nova.tests.api.openstack import fakes
|
||||||
|
|
@ -17,8 +17,8 @@ import json
|
|||||||
|
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from nova.api.openstack import v2
|
from nova.api.openstack import compute as compute_api
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack.compute import extensions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
from nova import compute
|
from nova import compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
@ -123,7 +123,7 @@ class CreateBackupTests(test.TestCase):
|
|||||||
self.backup_stubs = fakes.stub_out_compute_api_backup(self.stubs)
|
self.backup_stubs = fakes.stub_out_compute_api_backup(self.stubs)
|
||||||
|
|
||||||
self.flags(allow_admin_api=True)
|
self.flags(allow_admin_api=True)
|
||||||
router = v2.APIRouter()
|
router = compute_api.APIRouter()
|
||||||
ext_middleware = extensions.ExtensionMiddleware(router)
|
ext_middleware = extensions.ExtensionMiddleware(router)
|
||||||
self.app = wsgi.LazySerializationMiddleware(ext_middleware)
|
self.app = wsgi.LazySerializationMiddleware(ext_middleware)
|
||||||
|
|
@ -20,9 +20,9 @@ import webob
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from nova.api import auth
|
from nova.api import auth
|
||||||
from nova.api.openstack import v2
|
from nova.api.openstack import compute
|
||||||
from nova.api.openstack.v2 import wsgi
|
from nova.api.openstack.compute import wsgi
|
||||||
from nova.api.openstack.v2.contrib import cloudpipe
|
from nova.api.openstack.compute.contrib import cloudpipe
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
from nova.cloudpipe import pipelib
|
from nova.cloudpipe import pipelib
|
||||||
from nova import context
|
from nova import context
|
||||||
@ -112,7 +112,7 @@ class CloudpipeTest(test.TestCase):
|
|||||||
super(CloudpipeTest, self).setUp()
|
super(CloudpipeTest, self).setUp()
|
||||||
self.flags(allow_admin_api=True)
|
self.flags(allow_admin_api=True)
|
||||||
self.app = fakes.wsgi_app()
|
self.app = fakes.wsgi_app()
|
||||||
inner_app = v2.APIRouter()
|
inner_app = compute.APIRouter()
|
||||||
self.context = context.RequestContext('fake', 'fake', is_admin=True)
|
self.context = context.RequestContext('fake', 'fake', is_admin=True)
|
||||||
self.app = auth.InjectContext(self.context, inner_app)
|
self.app = auth.InjectContext(self.context, inner_app)
|
||||||
route = inner_app.map.match('/1234/os-cloudpipe')
|
route = inner_app.map.match('/1234/os-cloudpipe')
|
@ -18,7 +18,7 @@
|
|||||||
import mox
|
import mox
|
||||||
import webob
|
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 compute
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import test
|
from nova import test
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from nova.api.openstack import v2
|
from nova.api.openstack import compute
|
||||||
from nova.api.openstack.v2 import extensions
|
from nova.api.openstack.compute import extensions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
import nova.db.api
|
import nova.db.api
|
||||||
from nova import flags
|
from nova import flags
|
||||||
@ -117,7 +117,7 @@ class DiskConfigTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.stubs.Set(nova.db, 'instance_create', fake_instance_create)
|
self.stubs.Set(nova.db, 'instance_create', fake_instance_create)
|
||||||
|
|
||||||
app = v2.APIRouter()
|
app = compute.APIRouter()
|
||||||
app = extensions.ExtensionMiddleware(app)
|
app = extensions.ExtensionMiddleware(app)
|
||||||
app = wsgi.LazySerializationMiddleware(app)
|
app = wsgi.LazySerializationMiddleware(app)
|
||||||
self.app = app
|
self.app = app
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user