Change keystone_authtoken configs

Blazar uses os_auth_host, os_auth_port and os_auth_version to the auth
uri for now. However, current approach can not be applied to uri with some
prefixes such like "http://127.0.0.1/identity".

In this patch, authentification is executed by using "keystone_authtoken"
configs. This patch enables us to use any forms of auth uri.

Closes-Bug: #1681419
Change-Id: I7c8728593ecf503b23d742a5f464af8a2a6e5253
This commit is contained in:
Hiroki Ito 2017-04-27 07:13:58 +00:00
parent ebf507933f
commit 2d0cabb17d
10 changed files with 129 additions and 59 deletions

View File

@ -30,13 +30,6 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('os_auth_host', 'blazar.config')
CONF.import_opt('os_auth_port', 'blazar.config')
CONF.import_opt('os_auth_protocol', 'blazar.config')
CONF.import_opt('os_admin_username', 'blazar.config')
CONF.import_opt('os_admin_password', 'blazar.config')
CONF.import_opt('os_admin_project_name', 'blazar.config')
CONF.import_opt('os_auth_version', 'blazar.config')
CONF.import_opt('log_exchange', 'blazar.config')
@ -96,15 +89,6 @@ def make_app():
if cfg.CONF.log_exchange:
app.wsgi_app = debug.Debug.factory(app.config)(app.wsgi_app)
app.wsgi_app = auth_token.filter_factory(
app.config,
auth_host=cfg.CONF.os_auth_host,
auth_port=cfg.CONF.os_auth_port,
auth_protocol=cfg.CONF.os_auth_protocol,
admin_user=cfg.CONF.os_admin_username,
admin_password=cfg.CONF.os_admin_password,
admin_tenant_name=cfg.CONF.os_admin_project_name,
auth_version=cfg.CONF.os_auth_version,
)(app.wsgi_app)
app.wsgi_app = auth_token.filter_factory(app.config)(app.wsgi_app)
return app

View File

@ -33,28 +33,31 @@ cli_opts = [
os_opts = [
cfg.StrOpt('os_auth_protocol',
default='http',
help='Protocol used to access OpenStack Identity service'),
help='Protocol used to access OpenStack Identity service.'),
cfg.StrOpt('os_auth_host',
default='127.0.0.1',
help='IP or hostname of machine on which OpenStack Identity '
'service is located'),
'service is located.'),
cfg.StrOpt('os_auth_port',
default='35357',
help='Port of OpenStack Identity service'),
help='Port of OpenStack Identity service.'),
cfg.StrOpt('os_auth_prefix',
default='',
help='Prefix of URL to access OpenStack Identity service.'),
cfg.StrOpt('os_admin_username',
default='admin',
help='This OpenStack user is used to verify provided tokens. '
help='This OpenStack user is used to treat trusts. '
'The user must have admin role in <os_admin_project_name> '
'project'),
'project.'),
cfg.StrOpt('os_admin_password',
default='blazar',
help='Password of the admin user'),
help='Password of the admin user to treat trusts.'),
cfg.StrOpt('os_admin_project_name',
default='admin',
help='Name of project where the user is admin'),
help='Name of project where the user is admin.'),
cfg.StrOpt('os_auth_version',
default='v2.0',
help='We use API v3 to allow trusts using.'),
help='Blazar uses API v3 to allow trusts using.'),
]
CONF = cfg.CONF

View File

@ -94,3 +94,8 @@ class Timeout(BlazarException):
class InvalidInput(BlazarException):
code = 400
msg_fmt = _("Expected a %(cls)s type but received %(value)s.")
class UnsupportedAPIVersion(BlazarException):
msg_fmt = _('API version %(version)s is not supported. Blazar only '
'supports Keystone v3 API.')

View File

@ -70,14 +70,7 @@ class AppTestCase(tests.TestCase):
def test_make_app(self):
fake_app = self.patch(self.flask, 'Flask')
self.app.make_app()
self.fake_ff.assert_called_once_with(fake_app().config,
admin_user='admin',
admin_tenant_name='admin',
auth_port='35357',
auth_protocol='http',
auth_version='v2.0',
admin_password='blazar',
auth_host='127.0.0.1')
self.fake_ff.assert_called_once_with(fake_app().config)
class AppTestCaseForHostsPlugin(tests.TestCase):

View File

@ -16,6 +16,7 @@
from keystoneclient import client as keystone_client
from blazar import context
from blazar import exceptions
from blazar import tests
from blazar.utils.openstack import base
from blazar.utils.openstack import keystone
@ -35,7 +36,7 @@ class TestCKClient(tests.TestCase):
self.client = self.patch(self.k_client, 'Client')
self.patch(self.base, 'url_for').return_value = 'http://fake.com/'
self.version = '1'
self.version = '3'
self.username = 'fake_user'
self.token = 'fake_token'
self.password = 'fake_pass'
@ -87,6 +88,37 @@ class TestCKClient(tests.TestCase):
auth_url='http://fake.com/',
endpoint='http://fake.com/')
def test_complement_auth_url_supported_api_version(self):
bkc = self.keystone.BlazarKeystoneClient()
expected_url = self.auth_url + '/v3'
returned_url = bkc.complement_auth_url(auth_url=self.auth_url,
version='v3')
self.assertEqual(expected_url, returned_url)
def test_complement_auth_url_unsupported_api_version(self):
bkc = self.keystone.BlazarKeystoneClient()
kwargs = {'auth_url': self.auth_url,
'version': 2.0}
self.assertRaises(exceptions.UnsupportedAPIVersion,
bkc.complement_auth_url,
**kwargs)
def test_complement_auth_url_valid_url(self):
bkc = self.keystone.BlazarKeystoneClient()
auth_url = self.auth_url + '/v3'
returned_url = bkc.complement_auth_url(auth_url=auth_url,
version='v3')
self.assertEqual(auth_url, returned_url)
def test_complement_auth_url_invalid_url(self):
bkc = self.keystone.BlazarKeystoneClient()
auth_url = self.auth_url + '/v2.0'
kwargs = {'auth_url': auth_url,
'version': 'v3'}
self.assertRaises(exceptions.UnsupportedAPIVersion,
bkc.complement_auth_url,
**kwargs)
def test_getattr(self):
# TODO(n.s.): Will be done as soon as pypi package will be updated
pass

View File

@ -13,18 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import re
from keystoneclient import client as keystone_client
from keystoneclient import exceptions as keystone_exception
from oslo_config import cfg
from blazar import context
from blazar import exceptions
from blazar.manager import exceptions as manager_exceptions
from blazar.utils.openstack import base
opts = [
cfg.StrOpt('identity_service',
default='identityv3',
default='identity',
help='Identity service to use.')
]
@ -113,12 +116,46 @@ class BlazarKeystoneClient(object):
# https://review.openstack.org/#/c/66494/ will be merged
self.keystone = keystone_client.Client(**kwargs)
self.keystone.session.auth = self.keystone
self.keystone.authenticate(auth_url=kwargs.get('auth_url', None))
auth_url = self.complement_auth_url(kwargs.get('auth_url', None),
kwargs.get('version', None))
self.keystone.authenticate(auth_url=auth_url)
except AttributeError:
raise manager_exceptions.WrongClientVersion()
self.exceptions = keystone_exception
def complement_auth_url(self, auth_url, version):
"""Return auth_url with api version.
This method checks whether auth_url contains api version info.
If api version info is not contained in auth_url, this method
complements version info to auth_url. This method only support
complementing auth_url to v3 api url since we use keystone v3
api to treat trusts.
"""
# Create api version from major number of keystoneclient version.
# keystoneclient version can take forms of "3", "v3" or "3.0" and
# so this method convert them to form of "v3" for keystone api
# version.
api_version = version
if isinstance(api_version, str):
api_version = api_version.lstrip('v')
api_version = int(float(api_version))
if api_version != 3:
raise exceptions.UnsupportedAPIVersion(version=api_version)
if re.search(r'/v2.0/{,1}$', auth_url) is not None:
raise exceptions.UnsupportedAPIVersion(version='v2.0')
elif re.search(r'/v3/{,1}$', auth_url) is None:
complemented_url = auth_url.rstrip('/') + '/v' + str(api_version)
else:
return auth_url
return complemented_url
def __getattr__(self, name):
func = getattr(self.keystone, name)
return func

View File

@ -54,9 +54,10 @@ def create_ctx_from_trust(trust_id):
user_name=CONF.os_admin_username,
project_name=CONF.os_admin_project_name,
)
auth_url = "%s://%s:%s/v3" % (CONF.os_auth_protocol,
auth_url = "%s://%s:%s/%s" % (CONF.os_auth_protocol,
CONF.os_auth_host,
CONF.os_auth_port)
CONF.os_auth_port,
CONF.os_auth_prefix)
client = keystone.BlazarKeystoneClient(
password=CONF.os_admin_password,
trust_id=trust_id,

View File

@ -44,18 +44,15 @@ function configure_blazar {
touch $BLAZAR_CONF_FILE
iniset $BLAZAR_CONF_FILE DEFAULT os_auth_version v3
iniset $BLAZAR_CONF_FILE DEFAULT os_auth_port $KEYSTONE_SERVICE_PORT
iniset $BLAZAR_CONF_FILE DEFAULT os_auth_port 80
iniset $BLAZAR_CONF_FILE DEFAULT os_auth_prefix identity
iniset $BLAZAR_CONF_FILE DEFAULT os_admin_password $SERVICE_PASSWORD
iniset $BLAZAR_CONF_FILE DEFAULT os_admin_username blazar
iniset $BLAZAR_CONF_FILE DEFAULT os_admin_project_name $SERVICE_TENANT_NAME
iniset $BLAZAR_CONF_FILE DEFAULT identity_service $BLAZAR_IDENTITY_SERVICE_NAME
# keystone authtoken
iniset $BLAZAR_CONF_FILE keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
iniset $BLAZAR_CONF_FILE keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
iniset $BLAZAR_CONF_FILE keystone_authtoken admin_user blazar
iniset $BLAZAR_CONF_FILE keystone_authtoken admin_password $SERVICE_PASSWORD
iniset $BLAZAR_CONF_FILE keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
_blazar_setup_keystone $BLAZAR_CONF_FILE keystone_authtoken
iniset $BLAZAR_CONF_FILE physical:host blazar_username $BLAZAR_USER_NAME
iniset $BLAZAR_CONF_FILE physical:host blazar_password $SERVICE_PASSWORD
@ -97,6 +94,29 @@ function configure_blazar {
$BLAZAR_BIN_DIR/blazar-db-manage --config-file $BLAZAR_CONF_FILE upgrade head
}
# Configures keystone integration for blazar service
function _blazar_setup_keystone {
local conf_file=$1
local section=$2
local use_auth_url=$3
if [[ -z $skip_auth_cache ]]; then
iniset $conf_file $section signing_dir $BLAZAR_AUTH_CACHE_DIR
# Create cache dir
create_blazar_cache_dir
fi
configure_auth_token_middleware $conf_file $BLAZAR_USER_NAME $BLAZAR_AUTH_CACHE_DIR $section
}
# create_blazar_cache_dir() - Part of the _blazar_setup_keystone process
function create_blazar_cache_dir {
# Create cache dir
sudo mkdir -m 700 -p $BLAZAR_AUTH_CACHE_DIR
sudo chown $STACK_USER $BLAZAR_AUTH_CACHE_DIR
rm -f $BLAZAR_AUTH_CACHE_DIR/*
}
# create_blazar_aggregate_freepool() - Create a Nova aggregate to use as freepool (for host reservation)
function create_blazar_aggregate_freepool {
openstack aggregate create $BLAZAR_FREEPOOL_NAME

View File

@ -24,6 +24,7 @@ BLAZAR_DIR=$DEST/blazar
BLAZAR_CONF_DIR=${BLAZAR_CONF_DIR:-/etc/blazar}
BLAZAR_CONF_FILE=$BLAZAR_CONF_DIR/blazar.conf
BLAZARCLIENT_DIR=$DEST/python-blazarclient
BLAZAR_AUTH_CACHE_DIR=${BLAZAR_AUTH_CACHE_DIR:-/var/cache/blazar}
BLAZARNOVA_DIR=$DEST/blazar-nova
BLAZAR_SERVICE_HOST=${BLAZAR_SERVICE_HOST:-$SERVICE_HOST}
@ -31,7 +32,7 @@ BLAZAR_SERVICE_PORT=${BLAZAR_SERVICE_PORT:-1234}
BLAZAR_SERVICE_PROTOCOL=${BLAZAR_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
# Blazar specific configurations
BLAZAR_IDENTITY_SERVICE_NAME=${BLAZAR_IDENTITY_SERVICE_NAME:-"identityv3"}
BLAZAR_IDENTITY_SERVICE_NAME=${BLAZAR_IDENTITY_SERVICE_NAME:-"identity"}
BLAZAR_FREEPOOL_NAME=${BLAZAR_FREEPOOL_NAME:-freepool}
# Tell Tempest this project is present

View File

@ -117,13 +117,19 @@ Then edit */etc/blazar/blazar.conf* using the following example:
os_admin_username=<username>
os_admin_password=<password>
os_admin_project_name=<project_name>
identity_service=identityv3
identity_service=<identity_service_name>
[manager]
plugins=physical.host.plugin
[keystone_authtoken]
auth_uri=<auth_uri>
auth_type=<password, for example>
project_domain_name=<project_domain_name>
project_name=<project_name>
user_domain_name=<user_domain_name>
username=<username>
password=<password>
auth_url=<identity_service_url>
[physical:host]
aggregate_freepool_name=freepool
@ -169,18 +175,6 @@ reservation:
..
Blazar uses Keystone trusts to commit actions on behalf of user-created leases.
That's why we need to create identityv3 service with appropriate endpoints:
.. sourcecode:: console
openstack service create --name keystonev3 --description "Keystone Identity Service v3" identityv3
openstack endpoint create --region <region> keystonev3 public "<auth_protocol>://<auth_host>:<auth_port>/v3"
openstack endpoint create --region <region> keystonev3 admin "<auth_protocol>://<auth_host>:<auth_port>/v3"
openstack endpoint create --region <region> keystonev3 internal "<auth_protocol>://<auth_host>:<auth_port>/v3"
..
And we need to create the reservation service in Keystone with its endpoints:
.. sourcecode:: console