Allow Cinder to call Nova client
This code allows Cinder to call Nova client functions. This will be used for online migration and guest-assisted snapshots, which are both in progress. Change-Id: I9c94917bddcf250b880ca730df463a8402fe6b1d
This commit is contained in:
parent
08b6480ca8
commit
dee13e6a36
|
@ -28,6 +28,7 @@ import webob.exc
|
|||
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder import context
|
||||
from cinder.openstack.common import jsonutils
|
||||
from cinder.openstack.common import log as logging
|
||||
from cinder import wsgi as base_wsgi
|
||||
|
||||
|
@ -98,6 +99,16 @@ class CinderKeystoneContext(base_wsgi.Middleware):
|
|||
|
||||
# Build a context, including the auth_token...
|
||||
remote_address = req.remote_addr
|
||||
|
||||
service_catalog = None
|
||||
if req.headers.get('X_SERVICE_CATALOG') is not None:
|
||||
try:
|
||||
catalog_header = req.headers.get('X_SERVICE_CATALOG')
|
||||
service_catalog = jsonutils.loads(catalog_header)
|
||||
except ValueError:
|
||||
raise webob.exc.HTTPInternalServerError(
|
||||
_('Invalid service catalog json.'))
|
||||
|
||||
if CONF.use_forwarded_for:
|
||||
remote_address = req.headers.get('X-Forwarded-For', remote_address)
|
||||
ctx = context.RequestContext(user_id,
|
||||
|
@ -105,7 +116,8 @@ class CinderKeystoneContext(base_wsgi.Middleware):
|
|||
project_name=project_name,
|
||||
roles=roles,
|
||||
auth_token=auth_token,
|
||||
remote_address=remote_address)
|
||||
remote_address=remote_address,
|
||||
service_catalog=service_catalog)
|
||||
|
||||
req.environ['cinder.context'] = ctx
|
||||
return self.application
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2013 OpenStack Foundation.
|
||||
# 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 oslo.config.cfg
|
||||
|
||||
import cinder.openstack.common.importutils
|
||||
|
||||
_compute_opts = [
|
||||
oslo.config.cfg.StrOpt('compute_api_class',
|
||||
default='cinder.compute.nova.API',
|
||||
help='The full class name of the '
|
||||
'compute API class to use'),
|
||||
]
|
||||
|
||||
oslo.config.cfg.CONF.register_opts(_compute_opts)
|
||||
|
||||
|
||||
def API():
|
||||
importutils = cinder.openstack.common.importutils
|
||||
compute_api_class = oslo.config.cfg.CONF.compute_api_class
|
||||
cls = importutils.import_class(compute_api_class)
|
||||
return cls()
|
|
@ -0,0 +1,99 @@
|
|||
# Copyright 2013 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Handles all requests to Nova.
|
||||
"""
|
||||
|
||||
|
||||
from novaclient import service_catalog
|
||||
from novaclient.v1_1 import client as nova_client
|
||||
from oslo.config import cfg
|
||||
|
||||
from cinder.db import base
|
||||
from cinder.openstack.common import log as logging
|
||||
|
||||
nova_opts = [
|
||||
cfg.StrOpt('nova_catalog_info',
|
||||
default='compute:nova:publicURL',
|
||||
help='Info to match when looking for nova in the service '
|
||||
'catalog. Format is : separated values of the form: '
|
||||
'<service_type>:<service_name>:<endpoint_type>'),
|
||||
cfg.StrOpt('nova_endpoint_template',
|
||||
default=None,
|
||||
help='Override service catalog lookup with template for nova '
|
||||
'endpoint e.g. http://localhost:8774/v2/%(tenant_id)s'),
|
||||
cfg.StrOpt('os_region_name',
|
||||
default=None,
|
||||
help='region name of this node'),
|
||||
cfg.StrOpt('nova_ca_certificates_file',
|
||||
default=None,
|
||||
help='Location of ca certicates file to use for nova client '
|
||||
'requests.'),
|
||||
cfg.BoolOpt('nova_api_insecure',
|
||||
default=False,
|
||||
help='Allow to perform insecure SSL requests to nova'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(nova_opts)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def novaclient(context):
|
||||
|
||||
# FIXME: the novaclient ServiceCatalog object is mis-named.
|
||||
# It actually contains the entire access blob.
|
||||
# Only needed parts of the service catalog are passed in, see
|
||||
# nova/context.py.
|
||||
compat_catalog = {
|
||||
'access': {'serviceCatalog': context.service_catalog or []}
|
||||
}
|
||||
sc = service_catalog.ServiceCatalog(compat_catalog)
|
||||
if CONF.nova_endpoint_template:
|
||||
url = CONF.nova_endpoint_template % context.to_dict()
|
||||
else:
|
||||
info = CONF.nova_catalog_info
|
||||
service_type, service_name, endpoint_type = info.split(':')
|
||||
# extract the region if set in configuration
|
||||
if CONF.os_region_name:
|
||||
attr = 'region'
|
||||
filter_value = CONF.os_region_name
|
||||
else:
|
||||
attr = None
|
||||
filter_value = None
|
||||
url = sc.url_for(attr=attr,
|
||||
filter_value=filter_value,
|
||||
service_type=service_type,
|
||||
service_name=service_name,
|
||||
endpoint_type=endpoint_type)
|
||||
|
||||
LOG.debug(_('Novaclient connection created using URL: %s') % url)
|
||||
|
||||
c = nova_client.Client(context.user_id,
|
||||
context.auth_token,
|
||||
context.project_id,
|
||||
auth_url=url,
|
||||
insecure=CONF.nova_api_insecure,
|
||||
cacert=CONF.nova_ca_certificates_file)
|
||||
# noauth extracts user_id:project_id from auth_token
|
||||
c.client.auth_token = context.auth_token or '%s:%s' % (context.user_id,
|
||||
context.project_id)
|
||||
c.client.management_url = url
|
||||
return c
|
||||
|
||||
|
||||
class API(base.Base):
|
||||
"""API for interacting with novaclient."""
|
|
@ -45,7 +45,8 @@ class RequestContext(object):
|
|||
def __init__(self, user_id, project_id, is_admin=None, read_deleted="no",
|
||||
roles=None, project_name=None, remote_address=None,
|
||||
timestamp=None, request_id=None, auth_token=None,
|
||||
overwrite=True, quota_class=None, **kwargs):
|
||||
overwrite=True, quota_class=None, service_catalog=None,
|
||||
**kwargs):
|
||||
"""
|
||||
:param read_deleted: 'no' indicates deleted records are hidden, 'yes'
|
||||
indicates deleted records are visible, 'only' indicates that
|
||||
|
@ -85,6 +86,14 @@ class RequestContext(object):
|
|||
if overwrite or not hasattr(local.store, 'context'):
|
||||
self.update_store()
|
||||
|
||||
if service_catalog:
|
||||
# Only include required parts of service_catalog
|
||||
self.service_catalog = [s for s in service_catalog
|
||||
if s.get('type') in ('compute')]
|
||||
else:
|
||||
# if list is empty or none
|
||||
self.service_catalog = []
|
||||
|
||||
def _get_read_deleted(self):
|
||||
return self._read_deleted
|
||||
|
||||
|
@ -115,6 +124,7 @@ class RequestContext(object):
|
|||
'request_id': self.request_id,
|
||||
'auth_token': self.auth_token,
|
||||
'quota_class': self.quota_class,
|
||||
'service_catalog': self.service_catalog,
|
||||
'tenant': self.tenant,
|
||||
'user': self.user}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2013 IBM Corp.
|
||||
#
|
||||
# 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 cinderclient import exceptions as cinder_exception
|
||||
|
||||
from cinder.compute import nova
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
|
||||
|
||||
class FakeNovaClient(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
class NovaApiTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(NovaApiTestCase, self).setUp()
|
||||
|
||||
self.api = nova.API()
|
||||
self.novaclient = FakeNovaClient()
|
||||
self.ctx = context.get_admin_context()
|
||||
self.mox.StubOutWithMock(nova, 'novaclient')
|
Loading…
Reference in New Issue