Allow any Keystone domain for cinder store
add two new config options for cinder store - cinder_store_user_domain_name - cinder_store_project_domain_name that allow to set the internal user and project to Keystone domains other that the 'Default' one. Closes-Bug: #1930299 Change-Id: I1d6c07b6c0e7e6a4da9adabaa026f024b64bb029
This commit is contained in:
parent
04e5ead7c0
commit
4ea3313951
@ -25,6 +25,9 @@ import time
|
||||
|
||||
from keystoneauth1.access import service_catalog as keystone_sc
|
||||
from keystoneauth1 import exceptions as keystone_exc
|
||||
from keystoneauth1 import identity as ksa_identity
|
||||
from keystoneauth1 import session as ksa_session
|
||||
from keystoneauth1 import token_endpoint as ksa_token_endpoint
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
@ -79,6 +82,8 @@ Related options:
|
||||
* cinder_store_user_name
|
||||
* cinder_store_project_name
|
||||
* cinder_store_password
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_domain_name
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_endpoint_template',
|
||||
@ -104,6 +109,8 @@ Related options:
|
||||
* cinder_store_user_name
|
||||
* cinder_store_project_name
|
||||
* cinder_store_password
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_domain_name
|
||||
* cinder_catalog_info
|
||||
|
||||
"""),
|
||||
@ -215,6 +222,8 @@ Related options:
|
||||
* cinder_store_user_name
|
||||
* cinder_store_password
|
||||
* cinder_store_project_name
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_domain_name
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_store_user_name',
|
||||
@ -222,8 +231,9 @@ Related options:
|
||||
help="""
|
||||
User name to authenticate against cinder.
|
||||
|
||||
This must be used with all the following related options. If any of these are
|
||||
not specified, the user of the current context is used.
|
||||
This must be used with all the following non-domain-related options.
|
||||
If any of these are not specified (except domain-related options),
|
||||
the user of the current context is used.
|
||||
|
||||
Possible values:
|
||||
* A valid user name
|
||||
@ -232,14 +242,33 @@ Related options:
|
||||
* cinder_store_auth_address
|
||||
* cinder_store_password
|
||||
* cinder_store_project_name
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_domain_name
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_store_user_domain_name',
|
||||
default='Default',
|
||||
help="""
|
||||
Domain of the user to authenticate against cinder.
|
||||
|
||||
Possible values:
|
||||
* A valid domain name for the user specified by ``cinder_store_user_name``
|
||||
|
||||
Related options:
|
||||
* cinder_store_auth_address
|
||||
* cinder_store_password
|
||||
* cinder_store_project_name
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_name
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_store_password', secret=True,
|
||||
help="""
|
||||
Password for the user authenticating against cinder.
|
||||
|
||||
This must be used with all the following related options. If any of these are
|
||||
not specified, the user of the current context is used.
|
||||
This must be used with all the following related options.
|
||||
If any of these are not specified (except domain-related options),
|
||||
the user of the current context is used.
|
||||
|
||||
Possible values:
|
||||
* A valid password for the user specified by ``cinder_store_user_name``
|
||||
@ -248,6 +277,8 @@ Related options:
|
||||
* cinder_store_auth_address
|
||||
* cinder_store_user_name
|
||||
* cinder_store_project_name
|
||||
* cinder_store_project_domain_name
|
||||
* cinder_store_user_domain_name
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_store_project_name',
|
||||
@ -258,8 +289,9 @@ Project name where the image volume is stored in cinder.
|
||||
If this configuration option is not set, the project in current context is
|
||||
used.
|
||||
|
||||
This must be used with all the following related options. If any of these are
|
||||
not specified, the project of the current context is used.
|
||||
This must be used with all the following related options.
|
||||
If any of these are not specified (except domain-related options),
|
||||
the user of the current context is used.
|
||||
|
||||
Possible values:
|
||||
* A valid project name
|
||||
@ -268,6 +300,25 @@ Related options:
|
||||
* ``cinder_store_auth_address``
|
||||
* ``cinder_store_user_name``
|
||||
* ``cinder_store_password``
|
||||
* ``cinder_store_project_domain_name``
|
||||
* ``cinder_store_user_domain_name``
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('cinder_store_project_domain_name',
|
||||
default='Default',
|
||||
help="""
|
||||
Domain of the project where the image volume is stored in cinder.
|
||||
|
||||
Possible values:
|
||||
* A valid domain name of the project specified by
|
||||
``cinder_store_project_name``
|
||||
|
||||
Related options:
|
||||
* ``cinder_store_auth_address``
|
||||
* ``cinder_store_user_name``
|
||||
* ``cinder_store_password``
|
||||
* ``cinder_store_project_domain_name``
|
||||
* ``cinder_store_user_domain_name``
|
||||
|
||||
"""),
|
||||
cfg.StrOpt('rootwrap_config',
|
||||
@ -350,6 +401,34 @@ Possible values:
|
||||
"""),
|
||||
]
|
||||
|
||||
CINDER_SESSION = None
|
||||
|
||||
|
||||
def _reset_cinder_session():
|
||||
global CINDER_SESSION
|
||||
CINDER_SESSION = None
|
||||
|
||||
|
||||
def get_cinder_session(conf):
|
||||
global CINDER_SESSION
|
||||
if not CINDER_SESSION:
|
||||
auth = ksa_identity.V3Password(
|
||||
password=conf.cinder_store_password,
|
||||
username=conf.cinder_store_user_name,
|
||||
user_domain_name=conf.cinder_store_user_domain_name,
|
||||
project_name=conf.cinder_store_project_name,
|
||||
project_domain_name=conf.cinder_store_project_domain_name,
|
||||
auth_url=conf.cinder_store_auth_address
|
||||
)
|
||||
if conf.cinder_api_insecure:
|
||||
verify = False
|
||||
elif conf.cinder_ca_certificates_file:
|
||||
verify = conf.cinder_ca_certificates_file
|
||||
else:
|
||||
verify = True
|
||||
CINDER_SESSION = ksa_session.Session(auth=auth, verify=verify)
|
||||
return CINDER_SESSION
|
||||
|
||||
|
||||
class StoreLocation(glance_store.location.StoreLocation):
|
||||
|
||||
@ -476,15 +555,18 @@ class Store(glance_store.driver.Store):
|
||||
else:
|
||||
user_overriden = self.is_user_overriden()
|
||||
|
||||
session = get_cinder_session(self.store_conf)
|
||||
|
||||
if user_overriden:
|
||||
username = self.store_conf.cinder_store_user_name
|
||||
password = self.store_conf.cinder_store_password
|
||||
project = self.store_conf.cinder_store_project_name
|
||||
url = self.store_conf.cinder_store_auth_address
|
||||
# use auth that is already in the session
|
||||
auth = None
|
||||
else:
|
||||
username = context.user_id
|
||||
password = context.auth_token
|
||||
project = context.project_id
|
||||
# noauth extracts user_id:project_id from auth_token
|
||||
token = context.auth_token or '%s:%s' % (username, project)
|
||||
|
||||
if self.store_conf.cinder_endpoint_template:
|
||||
template = self.store_conf.cinder_endpoint_template
|
||||
@ -504,23 +586,17 @@ class Store(glance_store.driver.Store):
|
||||
reason = _("Failed to find Cinder from a service catalog.")
|
||||
raise exceptions.BadStoreConfiguration(store_name="cinder",
|
||||
reason=reason)
|
||||
auth = ksa_token_endpoint.Token(endpoint=url, token=token)
|
||||
|
||||
c = cinderclient.Client(
|
||||
username, password, project, auth_url=url,
|
||||
session=session, auth=auth,
|
||||
region_name=self.store_conf.cinder_os_region_name,
|
||||
insecure=self.store_conf.cinder_api_insecure,
|
||||
retries=self.store_conf.cinder_http_retries,
|
||||
cacert=self.store_conf.cinder_ca_certificates_file)
|
||||
retries=self.store_conf.cinder_http_retries)
|
||||
|
||||
LOG.debug(
|
||||
'Cinderclient connection created for user %(user)s using URL: '
|
||||
'%(url)s.', {'user': username, 'url': url})
|
||||
|
||||
# noauth extracts user_id:project_id from auth_token
|
||||
if not user_overriden:
|
||||
c.client.auth_token = context.auth_token or '%s:%s' % (username,
|
||||
project)
|
||||
c.client.management_url = url
|
||||
return c
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
@ -26,7 +26,6 @@ import tempfile
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from cinderclient.v3 import client as cinderclient
|
||||
from os_brick.initiator import connector
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_utils.secretutils import md5
|
||||
@ -67,31 +66,30 @@ class TestCinderStore(base.StoreBaseTest,
|
||||
auth_token='fake_token',
|
||||
project_id='fake_project')
|
||||
self.hash_algo = 'sha256'
|
||||
cinder._reset_cinder_session()
|
||||
|
||||
def test_get_cinderclient(self):
|
||||
cc = self.store.get_cinderclient(self.context)
|
||||
self.assertEqual('fake_token', cc.client.auth_token)
|
||||
self.assertEqual('http://foo/public_url', cc.client.management_url)
|
||||
self.assertEqual('fake_token', cc.client.auth.token)
|
||||
self.assertEqual('http://foo/public_url', cc.client.auth.endpoint)
|
||||
|
||||
def test_get_cinderclient_with_user_overriden(self):
|
||||
def _test_get_cinderclient_with_user_overriden(self):
|
||||
self.config(cinder_store_user_name='test_user')
|
||||
self.config(cinder_store_password='test_password')
|
||||
self.config(cinder_store_project_name='test_project')
|
||||
self.config(cinder_store_auth_address='test_address')
|
||||
cc = self.store.get_cinderclient(self.context)
|
||||
self.assertIsNone(cc.client.auth_token)
|
||||
self.assertEqual('test_address', cc.client.management_url)
|
||||
self.assertEqual('test_project', cc.client.session.auth.project_name)
|
||||
self.assertEqual('Default', cc.client.session.auth.project_domain_name)
|
||||
return cc
|
||||
|
||||
def test_get_cinderclient_with_user_overriden(self):
|
||||
self._test_get_cinderclient_with_user_overriden()
|
||||
|
||||
def test_get_cinderclient_with_user_overriden_and_region(self):
|
||||
self.config(cinder_os_region_name='test_region')
|
||||
fake_client = FakeObject(client=FakeObject(auth_token=None))
|
||||
with mock.patch.object(cinderclient, 'Client',
|
||||
return_value=fake_client) as mock_client:
|
||||
self.test_get_cinderclient_with_user_overriden()
|
||||
mock_client.assert_called_once_with(
|
||||
'test_user', 'test_password', 'test_project',
|
||||
auth_url='test_address', cacert=None, insecure=False,
|
||||
region_name='test_region', retries=3)
|
||||
cc = self._test_get_cinderclient_with_user_overriden()
|
||||
self.assertEqual('test_region', cc.client.region_name)
|
||||
|
||||
def test_temporary_chown(self):
|
||||
class fake_stat(object):
|
||||
|
@ -98,14 +98,15 @@ class TestMultiCinderStore(base.MultiStoreBaseTest,
|
||||
user_id='admin_user',
|
||||
auth_token='admin_token',
|
||||
project_id='admin_project')
|
||||
cinder._reset_cinder_session()
|
||||
|
||||
def test_location_url_prefix_is_set(self):
|
||||
self.assertEqual("cinder://cinder1", self.store.url_prefix)
|
||||
|
||||
def test_get_cinderclient(self):
|
||||
cc = self.store.get_cinderclient(self.context)
|
||||
self.assertEqual('fake_token', cc.client.auth_token)
|
||||
self.assertEqual('http://foo/public_url', cc.client.management_url)
|
||||
self.assertEqual('fake_token', cc.client.auth.token)
|
||||
self.assertEqual('http://foo/public_url', cc.client.auth.endpoint)
|
||||
|
||||
def test_get_cinderclient_with_user_overriden(self):
|
||||
self.config(cinder_store_user_name='test_user', group="cinder1")
|
||||
@ -113,16 +114,14 @@ class TestMultiCinderStore(base.MultiStoreBaseTest,
|
||||
self.config(cinder_store_project_name='test_project', group="cinder1")
|
||||
self.config(cinder_store_auth_address='test_address', group="cinder1")
|
||||
cc = self.store.get_cinderclient(self.context)
|
||||
self.assertIsNone(cc.client.auth_token)
|
||||
self.assertEqual('test_address', cc.client.management_url)
|
||||
self.assertEqual('Default', cc.client.session.auth.project_domain_name)
|
||||
self.assertEqual('test_project', cc.client.session.auth.project_name)
|
||||
|
||||
def test_get_cinderclient_legacy_update(self):
|
||||
cc = self.store.get_cinderclient(self.fake_admin_context,
|
||||
legacy_update=True)
|
||||
self.assertEqual('admin_token', cc.client.auth_token)
|
||||
self.assertEqual('admin_user', cc.client.user)
|
||||
self.assertEqual('admin_project', cc.client.projectid)
|
||||
self.assertEqual('http://foo/public_url', cc.client.management_url)
|
||||
self.assertEqual('admin_token', cc.client.auth.token)
|
||||
self.assertEqual('http://foo/public_url', cc.client.auth.endpoint)
|
||||
|
||||
def test_temporary_chown(self):
|
||||
class fake_stat(object):
|
||||
|
@ -77,8 +77,10 @@ class OptsTestCase(base.StoreBaseTest):
|
||||
'cinder_state_transition_timeout',
|
||||
'cinder_store_auth_address',
|
||||
'cinder_store_user_name',
|
||||
'cinder_store_user_domain_name',
|
||||
'cinder_store_password',
|
||||
'cinder_store_project_name',
|
||||
'cinder_store_project_domain_name',
|
||||
'cinder_volume_type',
|
||||
'cinder_use_multipath',
|
||||
'cinder_enforce_multipath',
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
For the Cinder store, if using an internal user to store images,
|
||||
it is now possible to have the internal user and the internal project
|
||||
in Keystone domains other than the ``Default`` one.
|
||||
Two new config options ``cinder_store_user_domain_name`` and
|
||||
``cinder_store_project_domain_name`` are added
|
||||
(both default to ``Default``) and now are possible to use in the
|
||||
configuration of the Cinder store.
|
Loading…
Reference in New Issue
Block a user