help='The full class name of the volume replication API class'),
cfg.StrOpt('consistencygroup_api_class',
default='cinder.consistencygroup.api.API',
- help='The full class name of the consistencygroup API class'), ]
+ help='The full class name of the consistencygroup API class'),
+ cfg.StrOpt('os_privileged_user_name',
+ default=None,
+ help='OpenStack privileged account username. Used for requests '
+ 'to other services (such as Nova) that require an account '
+ 'with special rights.'),
+ cfg.StrOpt('os_privileged_user_password',
+ default=None,
+ help='Password associated with the OpenStack privileged '
+ 'account.'),
+ cfg.StrOpt('os_privileged_user_tenant',
+ default=None,
+ help='Tenant name associated with the OpenStack privileged '
+ 'account.'),
+]
CONF.register_opts(global_opts)
from novaclient.v1_1.contrib import assisted_volume_snapshots
from oslo.config import cfg
+from cinder import context as ctx
from cinder.db import base
from cinder.openstack.common import log as logging
LOG = logging.getLogger(__name__)
-def novaclient(context, admin=False):
+def novaclient(context, admin_endpoint=False, privileged_user=False):
+ """Returns a Nova client
+
+ @param admin_endpoint: If True, use the admin endpoint template from
+ configuration ('nova_endpoint_admin_template' and 'nova_catalog_info')
+ @param privileged_user: If True, use the account from configuration
+ (requires 'os_privileged_user_name', 'os_privileged_user_password' and
+ 'os_privileged_user_tenant' to be set)
+ """
# 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_endpoint_template = CONF.nova_endpoint_template
nova_catalog_info = CONF.nova_catalog_info
- if admin:
+ if admin_endpoint:
nova_endpoint_template = CONF.nova_endpoint_admin_template
nova_catalog_info = CONF.nova_catalog_admin_info
- if nova_endpoint_template:
- url = nova_endpoint_template % context.to_dict()
+ if privileged_user and CONF.os_privileged_user_name:
+ context = ctx.RequestContext(
+ CONF.os_privileged_user_name, None,
+ auth_token=CONF.os_privileged_user_password,
+ project_name=CONF.os_privileged_user_tenant,
+ service_catalog=context.service_catalog)
+
+ # The admin user needs to authenticate before querying Nova
+ url = sc.url_for(service_type='identity')
+
+ LOG.debug('Creating a Nova client using "%s" user' %
+ CONF.os_privileged_user_name)
else:
- info = 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
+ if nova_endpoint_template:
+ url = nova_endpoint_template % context.to_dict()
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)
+ info = 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('Nova client connection created using URL: %s' % url)
extensions = [assisted_volume_snapshots]
c = nova_client.Client(context.user_id,
context.auth_token,
- context.project_id,
+ context.project_name,
auth_url=url,
insecure=CONF.nova_api_insecure,
cacert=CONF.nova_ca_certificates_file,
extensions=extensions)
- # 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
+
+ if not privileged_user:
+ # 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
new_volume_id)
def create_volume_snapshot(self, context, volume_id, create_info):
- nova = novaclient(context, admin=True)
+ nova = novaclient(context, admin_endpoint=True)
nova.assisted_volume_snapshots.create(
volume_id,
create_info=create_info)
def delete_volume_snapshot(self, context, snapshot_id, delete_info):
- nova = novaclient(context, admin=True)
+ nova = novaclient(context, admin_endpoint=True)
nova.assisted_volume_snapshots.delete(
snapshot_id,
import contextlib
import mock
+from novaclient.v1_1.contrib import assisted_volume_snapshots
from cinder.compute import nova
from cinder import context
from cinder import test
+class NovaClientTestCase(test.TestCase):
+ def setUp(self):
+ super(NovaClientTestCase, self).setUp()
+
+ self.ctx = context.RequestContext('regularuser', 'e3f0833dc08b4cea',
+ auth_token='token', is_admin=False)
+ self.ctx.service_catalog = \
+ [{'type': 'compute', 'name': 'nova', 'endpoints':
+ [{'publicURL': 'http://novahost:8774/v2/e3f0833dc08b4cea'}]},
+ {'type': 'identity', 'name': 'keystone', 'endpoints':
+ [{'publicURL': 'http://keystonehost:5000/v2.0'}]}]
+
+ self.override_config('nova_endpoint_template',
+ 'http://novahost:8774/v2/%(project_id)s')
+ self.override_config('nova_endpoint_admin_template',
+ 'http://novaadmhost:4778/v2/%(project_id)s')
+ self.override_config('os_privileged_user_name', 'adminuser')
+ self.override_config('os_privileged_user_password', 'strongpassword')
+
+ @mock.patch('novaclient.v1_1.client.Client')
+ def test_nova_client_regular(self, p_client):
+ nova.novaclient(self.ctx)
+ p_client.assert_called_once_with(
+ 'regularuser', 'token', None,
+ auth_url='http://novahost:8774/v2/e3f0833dc08b4cea',
+ insecure=False, cacert=None,
+ extensions=[assisted_volume_snapshots])
+
+ @mock.patch('novaclient.v1_1.client.Client')
+ def test_nova_client_admin_endpoint(self, p_client):
+ nova.novaclient(self.ctx, admin_endpoint=True)
+ p_client.assert_called_once_with(
+ 'regularuser', 'token', None,
+ auth_url='http://novaadmhost:4778/v2/e3f0833dc08b4cea',
+ insecure=False, cacert=None,
+ extensions=[assisted_volume_snapshots])
+
+ @mock.patch('novaclient.v1_1.client.Client')
+ def test_nova_client_privileged_user(self, p_client):
+ nova.novaclient(self.ctx, privileged_user=True)
+ p_client.assert_called_once_with(
+ 'adminuser', 'strongpassword', None,
+ auth_url='http://keystonehost:5000/v2.0',
+ insecure=False, cacert=None,
+ extensions=[assisted_volume_snapshots])
+
+
class FakeNovaClient(object):
class Volumes(object):
def __getattr__(self, item):