From 7e7ccea3dcd988820f5ee3e8c89d2057cdd93a05 Mon Sep 17 00:00:00 2001 From: Ben Nemec Date: Fri, 3 Mar 2017 10:26:54 -0600 Subject: [PATCH] Support keystone v3 Make all the various bits of OVB that interact with the host cloud able to use keystone v3 authentication. Note that my experience has been that a newer novaclient is needed on the bmc in order for this to work. The pre-built BMC image in the docs has been updated with a new enough novaclient. --- bin/install_openstackbmc.sh | 15 ++- .../build_nodes_json.py | 52 ++++++++--- openstack_virtual_baremetal/deploy.py | 70 +++++++++++--- openstack_virtual_baremetal/openstackbmc.py | 42 +++++++-- .../tests/test_build_nodes_json.py | 61 +++++++++++- .../tests/test_deploy.py | 92 ++++++++++++++++++- .../tests/test_openstackbmc.py | 60 ++++++++++-- templates/quintupleo.yaml | 24 +++++ templates/virtual-baremetal.yaml | 24 +++++ 9 files changed, 391 insertions(+), 49 deletions(-) diff --git a/bin/install_openstackbmc.sh b/bin/install_openstackbmc.sh index 8064cfe..d8edc53 100644 --- a/bin/install_openstackbmc.sh +++ b/bin/install_openstackbmc.sh @@ -36,7 +36,13 @@ export OS_USERNAME=$os_user export OS_TENANT_NAME=$os_tenant export OS_PASSWORD=$os_password export OS_AUTH_URL=$os_auth_url -private_subnet=$(neutron net-show -f value -c subnets $private_net) +export OS_PROJECT_NAME=$os_project +export OS_USER_DOMAIN_ID=$os_user_domain +export OS_PROJECT_DOMAIN_ID=$os_project_domain +# At some point neutronclient started returning a python list repr from this +# command instead of just the value. This sed will strip off the bits we +# don't care about without messing up the output from older clients. +private_subnet=$(neutron net-show -f value -c subnets $private_net | sed "s/\[u'\(.*\)'\]/\1/") default_gw=$(neutron subnet-show $private_subnet -f value -c gateway_ip) prefix_len=$(neutron subnet-show -f value -c cidr $private_subnet | awk -F / '{print $2}') @@ -76,6 +82,11 @@ do bm_instance=$(neutron port-show $bm_port -c device_id -f value) bmc_port="$bmc_prefix_$(($i-1))" bmc_ip=$(neutron port-show $bmc_port -c fixed_ips -f value | jq -r .ip_address) + # Newer neutronclient requires explicit json output and a slightly + # different jq query + if [ -z "$bmc_ip" ]; then + bmc_ip=$(neutron port-show $bmc_port -c fixed_ips -f json | jq -r .fixed_ips[0].ip_address) + fi unit="openstack-bmc-$bm_port.service" cat </usr/lib/systemd/system/$unit @@ -85,7 +96,7 @@ Requires=config-bmc-ips.service After=config-bmc-ips.service [Service] -ExecStart=/usr/local/bin/openstackbmc --os-user $os_user --os-password $os_password --os-tenant $os_tenant --os-auth-url $os_auth_url --instance $bm_instance --address $bmc_ip +ExecStart=/usr/local/bin/openstackbmc --os-user $os_user --os-password $os_password --os-tenant "$os_tenant" --os-auth-url $os_auth_url --os-project "$os_project" --os-user-domain "$os_user_domain" --os-project-domain "$os_project_domain" --instance $bm_instance --address $bmc_ip Restart=always User=root diff --git a/openstack_virtual_baremetal/build_nodes_json.py b/openstack_virtual_baremetal/build_nodes_json.py index 20486ae..e8f6b0f 100755 --- a/openstack_virtual_baremetal/build_nodes_json.py +++ b/openstack_virtual_baremetal/build_nodes_json.py @@ -94,24 +94,48 @@ def _get_clients(): username = os.environ.get('OS_USERNAME') password = os.environ.get('OS_PASSWORD') tenant = os.environ.get('OS_TENANT_NAME') - auth_url = os.environ.get('OS_AUTH_URL') - if not username or not password or not tenant or not auth_url: - print('Source an appropriate rc file first') - sys.exit(1) + auth_url = os.environ.get('OS_AUTH_URL', '') + project = os.environ.get('OS_PROJECT_NAME') + user_domain = os.environ.get('OS_USER_DOMAIN_ID') + project_domain = os.environ.get('OS_PROJECT_DOMAIN_ID') - # novaclient 7+ is backwards-incompatible :-( - if int(nc.__version__[0]) <= 6: - nova = novaclient.Client(2, username, password, tenant, auth_url) + if '/v3' not in auth_url: + if not username or not password or not tenant or not auth_url: + print('Source an appropriate rc file first') + sys.exit(1) + # novaclient 7+ is backwards-incompatible :-( + if int(nc.__version__[0]) <= 6: + nova = novaclient.Client(2, username, password, tenant, auth_url) + else: + nova = novaclient.Client(2, username, password, + auth_url=auth_url, + project_name=tenant) + neutron = neutronclient.Client( + username=username, + password=password, + tenant_name=tenant, + auth_url=auth_url + ) else: + if (not username or not password or not auth_url or not project or + not user_domain or not project_domain): + print('Source an appropriate rc file first') + sys.exit(1) nova = novaclient.Client(2, username, password, auth_url=auth_url, - project_name=tenant) - neutron = neutronclient.Client( - username=username, - password=password, - tenant_name=tenant, - auth_url=auth_url - ) + project_name=project, + user_domain_name=user_domain, + project_domain_name=project_domain) + from keystoneauth1.identity import v3 + from keystoneauth1 import session + auth = v3.Password(auth_url=auth_url, + username=username, + password=password, + project_name=project, + user_domain_name=user_domain, + project_domain_name=project_domain) + sess = session.Session(auth=auth) + neutron = neutronclient.Client(session=sess) return nova, neutron diff --git a/openstack_virtual_baremetal/deploy.py b/openstack_virtual_baremetal/deploy.py index 45c70f9..15bcba7 100755 --- a/openstack_virtual_baremetal/deploy.py +++ b/openstack_virtual_baremetal/deploy.py @@ -23,6 +23,7 @@ import yaml from heatclient import client as heat_client from heatclient.common import template_utils from keystoneclient.v2_0 import client as keystone_client +from keystoneclient.v3 import client as keystone_v3_client def _parse_args(): parser = argparse.ArgumentParser(description='Deploy an OVB environment') @@ -143,24 +144,59 @@ def _get_heat_client(): password = os.environ.get('OS_PASSWORD') tenant = os.environ.get('OS_TENANT_NAME') auth_url = os.environ.get('OS_AUTH_URL') - if not username or not password or not tenant or not auth_url: - print('Source an appropriate rc file first') - sys.exit(1) + project = os.environ.get('OS_PROJECT_NAME') + user_domain = os.environ.get('OS_USER_DOMAIN_ID') + project_domain = os.environ.get('OS_PROJECT_DOMAIN_ID') # Get token for Heat to use - kclient = keystone_client.Client(username=username, password=password, - tenant_name=tenant, auth_url=auth_url) - token_data = kclient.get_raw_token_from_identity_service( - username=username, - password=password, - tenant_name=tenant, - auth_url=auth_url) - token_id = token_data['token']['id'] + if '/v3' not in auth_url: + if not username or not password or not tenant or not auth_url: + print('Source an appropriate rc file first') + sys.exit(1) + kclient = keystone_client.Client(username=username, password=password, + tenant_name=tenant, auth_url=auth_url) + token_data = kclient.get_raw_token_from_identity_service( + username=username, + password=password, + tenant_name=tenant, + auth_url=auth_url) + token_id = token_data['token']['id'] + catalog_key = 'serviceCatalog' + else: + if (not username or not password or not auth_url or not project or + not user_domain or not project_domain): + print('Source an appropriate rc file first') + sys.exit(1) + from keystoneauth1.identity import v3 + from keystoneauth1 import session + auth = v3.Password(auth_url=auth_url, + username=username, + password=password, + project_name=project, + user_domain_name=user_domain, + project_domain_name=project_domain) + sess = session.Session(auth=auth) + kclient = keystone_v3_client.Client(session=sess) + token_data = kclient.get_raw_token_from_identity_service( + username=username, + password=password, + project_name=project, + auth_url=auth_url, + user_domain_name=user_domain, + project_domain_name=project_domain) + token_id = token_data['auth_token'] + catalog_key = 'catalog' + # Get Heat endpoint - for endpoint in token_data['serviceCatalog']: + for endpoint in token_data[catalog_key]: if endpoint['name'] == 'heat': - # TODO: What if there's more than one endpoint? - heat_endpoint = endpoint['endpoints'][0]['publicURL'] + try: + # TODO: What if there's more than one endpoint? + heat_endpoint = endpoint['endpoints'][0]['publicURL'] + except KeyError: + # Keystone v3 endpoint data looks different + heat_endpoint = [e for e in endpoint['endpoints'] + if e['interface'] == 'public'][0]['url'] return heat_client.Client('1', endpoint=heat_endpoint, token=token_id) @@ -179,10 +215,16 @@ def _create_auth_parameters(): password = os.environ.get('OS_PASSWORD') tenant = os.environ.get('OS_TENANT_NAME') auth_url = os.environ.get('OS_AUTH_URL') + project = os.environ.get('OS_PROJECT_NAME') + user_domain = os.environ.get('OS_USER_DOMAIN_ID') + project_domain = os.environ.get('OS_PROJECT_DOMAIN_ID') return {'os_user': username, 'os_password': password, 'os_tenant': tenant, 'os_auth_url': auth_url, + 'os_project': project, + 'os_user_domain': user_domain, + 'os_project_domain': project_domain, } def _deploy(stack_name, stack_template, env_path, poll): diff --git a/openstack_virtual_baremetal/openstackbmc.py b/openstack_virtual_baremetal/openstackbmc.py index 9ef7a59..d4871d6 100755 --- a/openstack_virtual_baremetal/openstackbmc.py +++ b/openstack_virtual_baremetal/openstackbmc.py @@ -35,16 +35,23 @@ import pyghmi.ipmi.bmc as bmc class OpenStackBmc(bmc.Bmc): def __init__(self, authdata, port, address, instance, user, password, tenant, - auth_url): + auth_url, project, user_domain, project_domain): super(OpenStackBmc, self).__init__(authdata, port=port, address=address) - # novaclient 7+ is backwards-incompatible :-( - if int(nc.__version__[0]) <= 6: - self.novaclient = novaclient.Client(2, user, password, - tenant, auth_url) + if not '/v3' in auth_url: + # novaclient 7+ is backwards-incompatible :-( + if int(nc.__version__[0]) <= 6: + self.novaclient = novaclient.Client(2, user, password, + tenant, auth_url) + else: + self.novaclient = novaclient.Client(2, user, password, + auth_url=auth_url, + project_name=tenant) else: self.novaclient = novaclient.Client(2, user, password, auth_url=auth_url, - project_name=tenant) + project_name=project, + user_domain_name=user_domain, + project_domain_name=project_domain) self.instance = None self.cached_status = None self.target_status = None @@ -191,12 +198,28 @@ def main(): help='The password for connecting to OpenStack') parser.add_argument('--os-tenant', dest='tenant', - required=True, + required=False, + default='', help='The tenant for connecting to OpenStack') parser.add_argument('--os-auth-url', dest='auth_url', required=True, help='The OpenStack Keystone auth url') + parser.add_argument('--os-project', + dest='project', + required=False, + default='', + help='The project for connecting to OpenStack') + parser.add_argument('--os-user-domain', + dest='user_domain', + required=False, + default='', + help='The user domain for connecting to OpenStack') + parser.add_argument('--os-project-domain', + dest='project_domain', + required=False, + default='', + help='The project domain for connecting to OpenStack') args = parser.parse_args() # Default to ipv6 format, but if we get an ipv4 address passed in use the # appropriate format for pyghmi to listen on it. @@ -209,7 +232,10 @@ def main(): user=args.user, password=args.password, tenant=args.tenant, - auth_url=args.auth_url) + auth_url=args.auth_url, + project=args.project, + user_domain=args.user_domain, + project_domain=args.project_domain) mybmc.listen() diff --git a/openstack_virtual_baremetal/tests/test_build_nodes_json.py b/openstack_virtual_baremetal/tests/test_build_nodes_json.py index 5cc9e68..e9c7540 100644 --- a/openstack_virtual_baremetal/tests/test_build_nodes_json.py +++ b/openstack_virtual_baremetal/tests/test_build_nodes_json.py @@ -164,9 +164,7 @@ class TestBuildNodesJson(testtools.TestCase): mock.call('network', cloud='foo')] self.assertEqual(calls, mock_make_client.mock_calls) - @mock.patch('neutronclient.v2_0.client.Client') - @mock.patch('novaclient.client.Client') - def test_get_clients_env(self, mock_nova, mock_neutron): + def _test_get_clients_env(self, mock_nova, mock_neutron): self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin')) self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw')) self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME', @@ -180,11 +178,68 @@ class TestBuildNodesJson(testtools.TestCase): self.assertEqual(mock_nova_client, nova) self.assertEqual(mock_neutron_client, neutron) + @mock.patch('openstack_virtual_baremetal.build_nodes_json.nc.__version__', + ('6', '0', '0')) + @mock.patch('neutronclient.v2_0.client.Client') + @mock.patch('novaclient.client.Client') + def test_get_clients_env_6(self, mock_nova, mock_neutron): + self._test_get_clients_env(mock_nova, mock_neutron) + + @mock.patch('openstack_virtual_baremetal.build_nodes_json.nc.__version__', + ('7', '0', '0')) + @mock.patch('neutronclient.v2_0.client.Client') + @mock.patch('novaclient.client.Client') + def test_get_clients_env_7(self, mock_nova, mock_neutron): + self._test_get_clients_env(mock_nova, mock_neutron) + + @mock.patch('keystoneauth1.session.Session') + @mock.patch('keystoneauth1.identity.v3.Password') + @mock.patch('neutronclient.v2_0.client.Client') + @mock.patch('novaclient.client.Client') + def test_get_clients_env_v3(self, mock_nova, mock_neutron, mock_password, + mock_session): + self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw')) + self.useFixture(fixtures.EnvironmentVariable('OS_PROJECT_NAME', + 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_AUTH_URL', 'auth/v3')) + self.useFixture(fixtures.EnvironmentVariable('OS_USER_DOMAIN_ID', + 'default')) + self.useFixture(fixtures.EnvironmentVariable('OS_PROJECT_DOMAIN_ID', + 'default')) + mock_nova_client = mock.Mock() + mock_nova.return_value = mock_nova_client + mock_neutron_client = mock.Mock() + mock_neutron.return_value = mock_neutron_client + mock_auth = mock.Mock() + mock_password.return_value = mock_auth + mock_session_inst = mock.Mock() + mock_session.return_value = mock_session_inst + nova, neutron = build_nodes_json._get_clients() + mock_password.assert_called_once_with(auth_url='auth/v3', + username='admin', + password='pw', + project_name='admin', + user_domain_name='default', + project_domain_name='default' + ) + mock_session.assert_called_once_with(auth=mock_auth) + mock_neutron.assert_called_once_with(session=mock_session_inst) + self.assertEqual(mock_nova_client, nova) + self.assertEqual(mock_neutron_client, neutron) + @mock.patch('sys.exit') def test_get_clients_missing(self, mock_exit): build_nodes_json._get_clients() mock_exit.assert_called_once_with(1) + @mock.patch('sys.exit') + def test_get_clients_missing_v3(self, mock_exit): + self.useFixture(fixtures.EnvironmentVariable('OS_AUTH_URL', + 'http://host/v3')) + build_nodes_json._get_clients() + mock_exit.assert_called_once_with(1) + def test_get_ports(self): neutron = mock.Mock() fake_ports = {'ports': diff --git a/openstack_virtual_baremetal/tests/test_deploy.py b/openstack_virtual_baremetal/tests/test_deploy.py index f4df313..1619dd5 100755 --- a/openstack_virtual_baremetal/tests/test_deploy.py +++ b/openstack_virtual_baremetal/tests/test_deploy.py @@ -17,7 +17,9 @@ import io import unittest import yaml +import fixtures import mock +import testtools import deploy @@ -58,7 +60,7 @@ class TestProcessArgs(unittest.TestCase): self.assertEqual('foo', name) self.assertEqual('templates/quintupleo.yaml', template) - def test_id_quintuple(self): + def test_id_quintupleo(self): mock_args = mock.Mock() mock_args.id = 'foo' mock_args.quintupleo = False @@ -368,5 +370,93 @@ class TestDeploy(unittest.TestCase): deploy._validate_env(args, 'foo.yaml') +V2_TOKEN_DATA = {'token': {'id': 'fake_token'}, + 'serviceCatalog': [{'name': 'nova'}, + {'name': 'heat', + 'endpoints': [ + {'publicURL': 'heat_endpoint'} + ] + } + ]} +V3_TOKEN_DATA = {'auth_token': 'fake_v3_token', + 'catalog': [{'name': 'nova'}, + {'name': 'heat', + 'endpoints': [ + {'interface': 'private'}, + {'interface': 'public', + 'url': 'heat_endpoint'} + ] + } + ]} +class TestGetHeatClient(testtools.TestCase): + @mock.patch('os_client_config.make_client') + def test_os_cloud(self, mock_make_client): + self.useFixture(fixtures.EnvironmentVariable('OS_CLOUD', 'foo')) + deploy._get_heat_client() + mock_make_client.assert_called_once_with('orchestration', cloud='foo') + + @mock.patch('heatclient.client.Client') + @mock.patch('keystoneclient.v2_0.client.Client') + def test_keystone_v2(self, mock_ksc, mock_hc): + self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw')) + self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME', + 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_AUTH_URL', 'auth')) + mock_ks_client = mock.Mock() + mock_ksc.return_value = mock_ks_client + mock_ks_client.get_raw_token_from_identity_service.return_value = ( + V2_TOKEN_DATA) + mock_token_value = 'fake_token' + deploy._get_heat_client() + mock_ksc.assert_called_once_with(username='admin', password='pw', + tenant_name='admin', auth_url='auth') + get_token = mock_ks_client.get_raw_token_from_identity_service + get_token.assert_called_once_with(username='admin', password='pw', + tenant_name='admin', auth_url='auth') + mock_hc.assert_called_once_with('1', endpoint='heat_endpoint', + token=mock_token_value) + + @mock.patch('keystoneauth1.session.Session') + @mock.patch('keystoneauth1.identity.v3.Password') + @mock.patch('heatclient.client.Client') + @mock.patch('keystoneclient.v3.client.Client') + def test_keystone_v3(self, mock_ksc, mock_hc, mock_password, mock_session): + self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw')) + self.useFixture(fixtures.EnvironmentVariable('OS_AUTH_URL', 'auth/v3')) + self.useFixture(fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'admin')) + self.useFixture(fixtures.EnvironmentVariable('OS_USER_DOMAIN_ID', + 'default')) + self.useFixture(fixtures.EnvironmentVariable('OS_PROJECT_DOMAIN_ID', + 'default')) + mock_auth = mock.Mock() + mock_password.return_value = mock_auth + mock_session_inst = mock.Mock() + mock_session.return_value = mock_session_inst + mock_ks_client = mock.Mock() + mock_ksc.return_value = mock_ks_client + mock_ks_client.get_raw_token_from_identity_service.return_value = ( + V3_TOKEN_DATA) + mock_token_value = 'fake_v3_token' + deploy._get_heat_client() + mock_password.assert_called_once_with(auth_url='auth/v3', + username='admin', + password='pw', + project_name='admin', + user_domain_name='default', + project_domain_name='default' + ) + mock_session.assert_called_once_with(auth=mock_auth) + get_token = mock_ks_client.get_raw_token_from_identity_service + get_token.assert_called_once_with(username='admin', password='pw', + project_name='admin', + auth_url='auth/v3', + user_domain_name='default', + project_domain_name='default') + mock_hc.assert_called_once_with('1', endpoint='heat_endpoint', + token=mock_token_value) + + if __name__ == '__main__': unittest.main() diff --git a/openstack_virtual_baremetal/tests/test_openstackbmc.py b/openstack_virtual_baremetal/tests/test_openstackbmc.py index 59900b9..29f5484 100755 --- a/openstack_virtual_baremetal/tests/test_openstackbmc.py +++ b/openstack_virtual_baremetal/tests/test_openstackbmc.py @@ -42,7 +42,10 @@ class TestOpenStackBmcInit(unittest.TestCase): user='admin', password='password', tenant='admin', - auth_url='http://keystone:5000' + auth_url='http://keystone:5000', + project='', + user_domain='', + project_domain='' ) if old_nova: mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin', @@ -60,16 +63,47 @@ class TestOpenStackBmcInit(unittest.TestCase): @mock.patch('openstack_virtual_baremetal.openstackbmc.nc.__version__', ('6', '0', '0')) def test_init_6(self, mock_find_instance, mock_nova, mock_bmc_init, - mock_log): + mock_log): self._test_init(mock_find_instance, mock_nova, mock_bmc_init, mock_log) @mock.patch('openstack_virtual_baremetal.openstackbmc.nc.__version__', ('7', '0', '0')) def test_init_7(self, mock_find_instance, mock_nova, mock_bmc_init, - mock_log): + mock_log): self._test_init(mock_find_instance, mock_nova, mock_bmc_init, mock_log, old_nova=False) + def test_init_v3(self, mock_find_instance, mock_nova, mock_bmc_init, + mock_log, old_nova=True): + mock_client = mock.Mock() + mock_server = mock.Mock() + mock_server.name = 'foo-instance' + mock_client.servers.get.return_value = mock_server + mock_nova.return_value = mock_client + mock_find_instance.return_value = 'abc-123' + bmc = openstackbmc.OpenStackBmc(authdata={'admin': 'password'}, + port=623, + address='::ffff:127.0.0.1', + instance='foo', + user='admin', + password='password', + tenant='', + auth_url='http://keystone:5000/v3', + project='admin', + user_domain='default', + project_domain='default' + ) + mock_nova.assert_called_once_with(2, 'admin', 'password', + auth_url='http://keystone:5000/v3', + project_name='admin', + user_domain_name='default', + project_domain_name='default') + mock_find_instance.assert_called_once_with('foo') + self.assertEqual('abc-123', bmc.instance) + mock_client.servers.get.assert_called_once_with('abc-123') + mock_log.assert_called_once_with('Managing instance: %s UUID: %s' % + ('foo-instance', 'abc-123')) + @mock.patch('openstack_virtual_baremetal.openstackbmc.nc.__version__', ('6', '0', '0')) @mock.patch('time.sleep') @@ -88,7 +122,10 @@ class TestOpenStackBmcInit(unittest.TestCase): user='admin', password='password', tenant='admin', - auth_url='http://keystone:5000' + auth_url='http://keystone:5000', + project='', + user_domain='', + project_domain='' ) mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin', 'http://keystone:5000') @@ -119,7 +156,10 @@ class TestOpenStackBmc(unittest.TestCase): user='admin', password='password', tenant='admin', - auth_url='http://keystone:5000' + auth_url='http://keystone:5000', + project='', + user_domain='', + project_domain='' ) self.bmc.novaclient = self.mock_client self.bmc.instance = 'abc-123' @@ -321,7 +361,10 @@ class TestMain(unittest.TestCase): user='admin', password='password', tenant='admin', - auth_url='http://host:5000/v2.0' + auth_url='http://host:5000/v2.0', + project='', + user_domain='', + project_domain='' ) mock_instance.listen.assert_called_once_with() @@ -342,6 +385,9 @@ class TestMain(unittest.TestCase): user='admin', password='password', tenant='admin', - auth_url='http://host:5000/v2.0' + auth_url='http://host:5000/v2.0', + project='', + user_domain='', + project_domain='' ) mock_instance.listen.assert_called_once_with() diff --git a/templates/quintupleo.yaml b/templates/quintupleo.yaml index b2ac7d8..aa70eeb 100644 --- a/templates/quintupleo.yaml +++ b/templates/quintupleo.yaml @@ -137,6 +137,27 @@ parameters: default: http://127.0.0.1:5000/v2.0 description: The Keystone auth_url of the host cloud + os_project: + type: string + default: '' + description: | + The project for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + + os_user_domain: + type: string + default: '' + description: | + The user domain for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + + os_project_domain: + type: string + default: '' + description: | + The project domain for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + resources: provision_network: type: OS::Neutron::Net @@ -209,6 +230,9 @@ resources: os_password: {get_param: os_password} os_tenant: {get_param: os_tenant} os_auth_url: {get_param: os_auth_url} + os_project: {get_param: os_project} + os_user_domain: {get_param: os_user_domain} + os_project_domain: {get_param: os_project_domain} outputs: undercloud_host_floating_ip: diff --git a/templates/virtual-baremetal.yaml b/templates/virtual-baremetal.yaml index a0beca6..6f25ede 100644 --- a/templates/virtual-baremetal.yaml +++ b/templates/virtual-baremetal.yaml @@ -87,6 +87,27 @@ parameters: default: http://127.0.0.1:5000/v2.0 description: The Keystone auth_url of the host cloud + os_project: + type: string + default: '' + description: | + The project for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + + os_user_domain: + type: string + default: '' + description: | + The user domain for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + + os_project_domain: + type: string + default: '' + description: | + The project domain for os_user. Required for Keystone v3, should be left + blank for Keystone v2. + default_sg: type: string default: all_sg @@ -154,6 +175,9 @@ resources: $os_password: {get_param: os_password} $os_tenant: {get_param: os_tenant} $os_auth_url: {get_param: os_auth_url} + $os_project: {get_param: os_project} + $os_user_domain: {get_param: os_user_domain} + $os_project_domain: {get_param: os_project_domain} $bm_node_count: {get_param: node_count} $bmc_prefix: {get_param: bmc_prefix} $bmc_utility: {get_attr: [bmc_port, fixed_ips, 0, ip_address]}