Use more os-client-config to handle bmc auth

It turns out to be a giant PITA to do keystone v3 auth by hand, as
the bmc install script was trying to.  Different clouds require a
different combination of auth values set, and os-client-config
already exists to handle these variations.

To do this, the os-client-config data is passed directly into the
bmc install script as json, which is then written to clouds.yaml
so it can be used by the clients.  In theory this should mean that
the bmc can handle any cloud where we were able to deploy the heat
stack because it's using the exact same auth data.

In addition, this change makes os-client-config mandatory on the bmc
image.  This is not a meaningful change though because it was already
pulled in by the clients, so it should already exist on any bmc
images in the wild.

It also deprecates the old method of providing auth data to the bmc.
For the moment it should continue to work, but the os-client-config
method should be used going forward.  Note that by default the bmc
will now read auth parameters from the environment, which is
actually an improvement over how it worked before when running
interactively.
This commit is contained in:
Ben Nemec 2017-07-20 15:39:44 -05:00
parent 9cd9267c42
commit ae02e88b98
9 changed files with 193 additions and 93 deletions

View File

@ -5,9 +5,7 @@ set -x
# install python2-crypto from EPEL # install python2-crypto from EPEL
# python-[nova|neutron]client are in a similar situation. They were renamed # python-[nova|neutron]client are in a similar situation. They were renamed
# in RDO to python2-* # in RDO to python2-*
# os-client-config is not a hard requirement, but it will be installed if required_packages="python-pip os-net-config git jq python2-os-client-config"
# we're installing packages anyway.
required_packages="python-pip os-net-config git jq"
function have_packages() { function have_packages() {
for i in $required_packages; do for i in $required_packages; do
@ -33,7 +31,7 @@ function have_packages() {
if ! have_packages; then if ! have_packages; then
yum -y update centos-release # required for rdo-release install to work yum -y update centos-release # required for rdo-release install to work
yum install -y https://rdo.fedorapeople.org/rdo-release.rpm yum install -y https://rdo.fedorapeople.org/rdo-release.rpm
yum install -y $required_packages python-crypto python2-novaclient python2-neutronclient python2-os-client-config yum install -y $required_packages python-crypto python2-novaclient python2-neutronclient
pip install pyghmi pip install pyghmi
fi fi
@ -42,22 +40,23 @@ $openstackbmc_script
EOF EOF
chmod +x /usr/local/bin/openstackbmc chmod +x /usr/local/bin/openstackbmc
export OS_USERNAME="$os_user" # Configure clouds.yaml so we can authenticate to the host cloud
export OS_TENANT_NAME="$os_tenant" mkdir -p ~/.config/openstack
set +x # Passing this as an argument is problematic because it has quotes inline that
echo "exporting OS_PASSWORD" # cause syntax errors. Reading from a file should be easier.
export OS_PASSWORD="$os_password" cat <<EOF >/tmp/bmc-cloud-data
set -x $cloud_data
export OS_AUTH_URL="$os_auth_url" EOF
export OS_PROJECT_NAME="$os_project" python -c 'import json
# NOTE(bnemec): The double _ in these names is intentional. It prevents import sys
# collisions with the $os_user and $os_project values above. import yaml
export OS_USER_DOMAIN="$os__user_domain" with open("/tmp/bmc-cloud-data") as f:
export OS_PROJECT_DOMAIN="$os__project_domain" data=json.loads(f.read())
# v3 env vars mess up v2 auth clouds={"clouds": {"host_cloud": data}}
[ -z $OS_PROJECT_NAME ] && unset OS_PROJECT_NAME print(yaml.safe_dump(clouds, default_flow_style=False))' > ~/.config/openstack/clouds.yaml
[ -z $OS_USER_DOMAIN ] && unset OS_USER_DOMAIN rm -f /tmp/bmc-cloud-data
[ -z $OS_PROJECT_DOMAIN ] && unset OS_PROJECT_DOMAIN export OS_CLOUD=host_cloud
# At some point neutronclient started returning a python list repr from this # 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 # 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. # don't care about without messing up the output from older clients.
@ -119,7 +118,7 @@ Requires=config-bmc-ips.service
After=config-bmc-ips.service After=config-bmc-ips.service
[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 --os-project "$os_project" --os-user-domain "$os__user_domain" --os-project-domain "$os__project_domain" --instance $bm_instance --address $bmc_ip $cache_status ExecStart=/usr/local/bin/openstackbmc --os-cloud host_cloud --instance $bm_instance --address $bmc_ip $cache_status
Restart=always Restart=always
User=root User=root

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import json
import os import os
import sys import sys
@ -59,3 +60,11 @@ def _create_auth_parameters():
'os_user_domain': user_domain, 'os_user_domain': user_domain,
'os_project_domain': project_domain, 'os_project_domain': project_domain,
} }
def _cloud_json():
"""Return the current cloud's data in JSON
Retrieves the cloud from os-client-config and serializes it to JSON.
"""
config = os_client_config.OpenStackConfig().get_one_cloud(OS_CLOUD)
return json.dumps(config.config)

View File

@ -153,7 +153,7 @@ def _deploy(stack_name, stack_template, env_path, poll):
all_files = {} all_files = {}
all_files.update(template_files) all_files.update(template_files)
all_files.update(env_files) all_files.update(env_files)
parameters = auth._create_auth_parameters() parameters = {'cloud_data': auth._cloud_json()}
hclient.stacks.create(stack_name=stack_name, hclient.stacks.create(stack_name=stack_name,
template=template, template=template,

View File

@ -24,6 +24,7 @@
# ipmitool -I lanplus -U admin -P password -H 127.0.0.1 mc reset cold # ipmitool -I lanplus -U admin -P password -H 127.0.0.1 mc reset cold
import argparse import argparse
import os
import sys import sys
import time import time
@ -44,17 +45,24 @@ NO_OCC_DEPRECATION = ('WARNING: Creating novaclient without os-client-config '
class OpenStackBmc(bmc.Bmc): class OpenStackBmc(bmc.Bmc):
def __init__(self, authdata, port, address, instance, user, password, tenant, def __init__(self, authdata, port, address, instance, user, password, tenant,
auth_url, project, user_domain, project_domain, cache_status): auth_url, project, user_domain, project_domain, cache_status,
os_cloud):
super(OpenStackBmc, self).__init__(authdata, port=port, address=address) super(OpenStackBmc, self).__init__(authdata, port=port, address=address)
if os_client_config: if os_client_config:
kwargs = dict(os_username=user, if user:
os_password=password, # NOTE(bnemec): This is deprecated. clouds.yaml is a much
os_project_name=tenant, # more robust way to specify auth details.
os_auth_url=auth_url, kwargs = dict(os_username=user,
os_user_domain=user_domain, os_password=password,
os_project_domain=project_domain) os_project_name=tenant,
self.novaclient = os_client_config.make_client('compute', os_auth_url=auth_url,
**kwargs) os_user_domain=user_domain,
os_project_domain=project_domain)
self.novaclient = os_client_config.make_client('compute',
**kwargs)
else:
self.novaclient = os_client_config.make_client('compute',
cloud=os_cloud)
else: else:
# NOTE(bnemec): This path was deprecated 2017-7-17 # NOTE(bnemec): This path was deprecated 2017-7-17
self.log(NO_OCC_DEPRECATION) self.log(NO_OCC_DEPRECATION)
@ -216,36 +224,53 @@ def main():
help='The uuid or name of the OpenStack instance to manage') help='The uuid or name of the OpenStack instance to manage')
parser.add_argument('--os-user', parser.add_argument('--os-user',
dest='user', dest='user',
required=True, required=False,
help='The user for connecting to OpenStack') default='',
help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The user for connecting to OpenStack')
parser.add_argument('--os-password', parser.add_argument('--os-password',
dest='password', dest='password',
required=True, required=False,
help='The password for connecting to OpenStack') default='',
help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The password for connecting to OpenStack')
parser.add_argument('--os-tenant', parser.add_argument('--os-tenant',
dest='tenant', dest='tenant',
required=False, required=False,
default='', default='',
help='The tenant for connecting to OpenStack') help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The tenant for connecting to OpenStack')
parser.add_argument('--os-auth-url', parser.add_argument('--os-auth-url',
dest='auth_url', dest='auth_url',
required=True, required=False,
help='The OpenStack Keystone auth url') default='',
help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The OpenStack Keystone auth url')
parser.add_argument('--os-project', parser.add_argument('--os-project',
dest='project', dest='project',
required=False, required=False,
default='', default='',
help='The project for connecting to OpenStack') help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The project for connecting to OpenStack')
parser.add_argument('--os-user-domain', parser.add_argument('--os-user-domain',
dest='user_domain', dest='user_domain',
required=False, required=False,
default='', default='',
help='The user domain for connecting to OpenStack') help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The user domain for connecting to OpenStack')
parser.add_argument('--os-project-domain', parser.add_argument('--os-project-domain',
dest='project_domain', dest='project_domain',
required=False, required=False,
default='', default='',
help='The project domain for connecting to OpenStack') help='DEPRECATED: Use --os-cloud to specify auth '
'details. '
'The project domain for connecting to OpenStack')
parser.add_argument('--cache-status', parser.add_argument('--cache-status',
dest='cache_status', dest='cache_status',
default=False, default=False,
@ -254,6 +279,12 @@ def main():
'can reduce load on the host cloud, but if the ' 'can reduce load on the host cloud, but if the '
'instance status is changed outside the BMC then ' 'instance status is changed outside the BMC then '
'it may become out of sync.') 'it may become out of sync.')
parser.add_argument('--os-cloud',
dest='os_cloud',
required=False,
default=os.environ.get('OS_CLOUD'),
help='Use the specified cloud from clouds.yaml. '
'Defaults to the OS_CLOUD environment variable.')
args = parser.parse_args() args = parser.parse_args()
# Default to ipv6 format, but if we get an ipv4 address passed in use the # Default to ipv6 format, but if we get an ipv4 address passed in use the
# appropriate format for pyghmi to listen on it. # appropriate format for pyghmi to listen on it.
@ -270,7 +301,8 @@ def main():
project=args.project, project=args.project,
user_domain=args.user_domain, user_domain=args.user_domain,
project_domain=args.project_domain, project_domain=args.project_domain,
cache_status=args.cache_status) cache_status=args.cache_status,
os_cloud=args.os_cloud)
mybmc.listen() mybmc.listen()

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
import fixtures import fixtures
import json
import mock import mock
import testtools import testtools
@ -138,3 +139,22 @@ class TestCreateAuthParameters(testtools.TestCase):
'os_project_domain': 'default', 'os_project_domain': 'default',
} }
self.assertEqual(expected, result) self.assertEqual(expected, result)
class TestCloudJSON(testtools.TestCase):
@mock.patch('openstack_virtual_baremetal.auth.OS_CLOUD', 'foo')
@mock.patch('os_client_config.OpenStackConfig')
def test_cloud_json(self, mock_osc):
mock_data = mock.Mock()
mock_data.config = {'auth': {'username': 'admin',
'password': 'password',
'project_name': 'admin',
'auth_url': 'http://host:5000',
'user_domain_name': 'default',
'project_domain_name': 'default',
}}
mock_instance = mock.Mock()
mock_instance.get_one_cloud.return_value = mock_data
mock_osc.return_value = mock_instance
result = auth._cloud_json()
expected = json.dumps(mock_data.config)
self.assertEqual(expected, result)

View File

@ -215,7 +215,7 @@ role_original_data = {
# end _process_role test data # end _process_role test data
class TestDeploy(testtools.TestCase): class TestDeploy(testtools.TestCase):
def _test_deploy(self, mock_ghc, mock_tu, mock_poll, mock_cap, poll=False): def _test_deploy(self, mock_ghc, mock_tu, mock_poll, mock_cj, poll=False):
mock_client = mock.Mock() mock_client = mock.Mock()
mock_ghc.return_value = mock_client mock_ghc.return_value = mock_client
template_files = {'template.yaml': {'foo': 'bar'}} template_files = {'template.yaml': {'foo': 'bar'}}
@ -232,40 +232,43 @@ class TestDeploy(testtools.TestCase):
all_files = {} all_files = {}
all_files.update(template_files) all_files.update(template_files)
all_files.update(env_files) all_files.update(env_files)
params = {'os_user': 'admin', auth = {'os_user': 'admin',
'os_password': 'password', 'os_password': 'password',
'os_tenant': 'admin', 'os_tenant': 'admin',
'os_auth_url': 'http://1.1.1.1:5000/v2.0', 'os_auth_url': 'http://1.1.1.1:5000/v2.0',
} }
mock_cap.return_value = params params = {'auth': auth}
expected_params = {'cloud_data': params}
mock_cj.return_value = params
deploy._deploy('test', 'template.yaml', 'env.yaml', poll) deploy._deploy('test', 'template.yaml', 'env.yaml', poll)
mock_tu.get_template_contents.assert_called_once_with('template.yaml') mock_tu.get_template_contents.assert_called_once_with('template.yaml')
process = mock_tu.process_multiple_environments_and_files process = mock_tu.process_multiple_environments_and_files
process.assert_called_once_with(['templates/resource-registry.yaml', process.assert_called_once_with(['templates/resource-registry.yaml',
'env.yaml']) 'env.yaml'])
mock_client.stacks.create.assert_called_once_with(stack_name='test', mock_client.stacks.create.assert_called_once_with(
template=template, stack_name='test',
environment=env, template=template,
files=all_files, environment=env,
parameters=params) files=all_files,
parameters=expected_params)
if not poll: if not poll:
mock_poll.assert_not_called() mock_poll.assert_not_called()
else: else:
mock_poll.assert_called_once_with('test', mock_client) mock_poll.assert_called_once_with('test', mock_client)
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters') @mock.patch('openstack_virtual_baremetal.auth._cloud_json')
@mock.patch('openstack_virtual_baremetal.deploy._poll_stack') @mock.patch('openstack_virtual_baremetal.deploy._poll_stack')
@mock.patch('openstack_virtual_baremetal.deploy.template_utils') @mock.patch('openstack_virtual_baremetal.deploy.template_utils')
@mock.patch('openstack_virtual_baremetal.deploy._get_heat_client') @mock.patch('openstack_virtual_baremetal.deploy._get_heat_client')
def test_deploy(self, mock_ghc, mock_tu, mock_poll, mock_cap): def test_deploy(self, mock_ghc, mock_tu, mock_poll, mock_cj):
self._test_deploy(mock_ghc, mock_tu, mock_poll, mock_cap) self._test_deploy(mock_ghc, mock_tu, mock_poll, mock_cj)
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters') @mock.patch('openstack_virtual_baremetal.auth._cloud_json')
@mock.patch('openstack_virtual_baremetal.deploy._poll_stack') @mock.patch('openstack_virtual_baremetal.deploy._poll_stack')
@mock.patch('openstack_virtual_baremetal.deploy.template_utils') @mock.patch('openstack_virtual_baremetal.deploy.template_utils')
@mock.patch('openstack_virtual_baremetal.deploy._get_heat_client') @mock.patch('openstack_virtual_baremetal.deploy._get_heat_client')
def test_deploy_poll(self, mock_ghc, mock_tu, mock_poll, mock_cap): def test_deploy_poll(self, mock_ghc, mock_tu, mock_poll, mock_cj):
self._test_deploy(mock_ghc, mock_tu, mock_poll, mock_cap, True) self._test_deploy(mock_ghc, mock_tu, mock_poll, mock_cj, True)
@mock.patch('time.sleep') @mock.patch('time.sleep')
def test_poll(self, mock_sleep): def test_poll(self, mock_sleep):

View File

@ -48,7 +48,8 @@ class TestOpenStackBmcInitDeprecated(unittest.TestCase):
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud=None
) )
if old_nova: if old_nova:
mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin', mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin',
@ -103,7 +104,8 @@ class TestOpenStackBmcInitDeprecated(unittest.TestCase):
project='admin', project='admin',
user_domain='default', user_domain='default',
project_domain='default', project_domain='default',
cache_status=False cache_status=False,
os_cloud=None
) )
mock_nova.assert_called_once_with(2, 'admin', 'password', mock_nova.assert_called_once_with(2, 'admin', 'password',
auth_url='http://keystone:5000/v3', auth_url='http://keystone:5000/v3',
@ -127,7 +129,6 @@ class TestOpenStackBmcInitDeprecated(unittest.TestCase):
class TestOpenStackBmcInit(testtools.TestCase): class TestOpenStackBmcInit(testtools.TestCase):
def test_init_os_client_config(self, mock_make_client, mock_find_instance, def test_init_os_client_config(self, mock_make_client, mock_find_instance,
mock_bmc_init, mock_log): mock_bmc_init, mock_log):
self.useFixture(fixtures.EnvironmentVariable('OS_CLOUD', None))
mock_client = mock.Mock() mock_client = mock.Mock()
mock_server = mock.Mock() mock_server = mock.Mock()
mock_server.name = 'foo-instance' mock_server.name = 'foo-instance'
@ -145,7 +146,8 @@ class TestOpenStackBmcInit(testtools.TestCase):
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud=None
) )
mock_make_client.assert_called_once_with('compute', mock_make_client.assert_called_once_with('compute',
@ -161,6 +163,36 @@ class TestOpenStackBmcInit(testtools.TestCase):
mock_log.assert_called_once_with('Managing instance: %s UUID: %s' % mock_log.assert_called_once_with('Managing instance: %s UUID: %s' %
('foo-instance', 'abc-123')) ('foo-instance', 'abc-123'))
def test_init_os_cloud(self, mock_make_client, mock_find_instance,
mock_bmc_init, mock_log):
mock_client = mock.Mock()
mock_server = mock.Mock()
mock_server.name = 'foo-instance'
mock_client.servers.get.return_value = mock_server
mock_make_client.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='',
password='',
tenant='',
auth_url='',
project='',
user_domain='',
project_domain='',
cache_status=False,
os_cloud='bar'
)
mock_make_client.assert_called_once_with('compute', cloud='bar')
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('time.sleep') @mock.patch('time.sleep')
def test_init_retry(self, _, mock_make_client, mock_find_instance, def test_init_retry(self, _, mock_make_client, mock_find_instance,
mock_bmc_init, mock_log): mock_bmc_init, mock_log):
@ -175,22 +207,17 @@ class TestOpenStackBmcInit(testtools.TestCase):
port=623, port=623,
address='::ffff:127.0.0.1', address='::ffff:127.0.0.1',
instance='foo', instance='foo',
user='admin', user='',
password='password', password='',
tenant='admin', tenant='',
auth_url='http://keystone:5000', auth_url='',
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud='foo'
) )
mock_make_client.assert_called_once_with('compute', mock_make_client.assert_called_once_with('compute', cloud='foo')
os_auth_url='http://keystone:5000',
os_password='password',
os_project_domain='',
os_project_name='admin',
os_user_domain='',
os_username='admin')
find_calls = [mock.call('foo'), mock.call('foo')] find_calls = [mock.call('foo'), mock.call('foo')]
self.assertEqual(find_calls, mock_find_instance.mock_calls) self.assertEqual(find_calls, mock_find_instance.mock_calls)
self.assertEqual('abc-123', bmc.instance) self.assertEqual('abc-123', bmc.instance)
@ -222,7 +249,8 @@ class TestOpenStackBmc(unittest.TestCase):
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud=None
) )
self.bmc.novaclient = self.mock_client self.bmc.novaclient = self.mock_client
self.bmc.instance = 'abc-123' self.bmc.instance = 'abc-123'
@ -424,23 +452,22 @@ class TestMain(unittest.TestCase):
mock_instance = mock.Mock() mock_instance = mock.Mock()
mock_bmc.return_value = mock_instance mock_bmc.return_value = mock_instance
mock_argv = ['openstackbmc', '--port', '111', '--address', '1.2.3.4', mock_argv = ['openstackbmc', '--port', '111', '--address', '1.2.3.4',
'--instance', 'foobar', '--os-user', 'admin', '--instance', 'foobar', '--os-cloud', 'foo']
'--os-password', 'password', '--os-tenant', 'admin',
'--os-auth-url', 'http://host:5000/v2.0']
with mock.patch.object(sys, 'argv', mock_argv): with mock.patch.object(sys, 'argv', mock_argv):
openstackbmc.main() openstackbmc.main()
mock_bmc.assert_called_once_with({'admin': 'password'}, mock_bmc.assert_called_once_with({'admin': 'password'},
port=111, port=111,
address='::ffff:1.2.3.4', address='::ffff:1.2.3.4',
instance='foobar', instance='foobar',
user='admin', user='',
password='password', password='',
tenant='admin', tenant='',
auth_url='http://host:5000/v2.0', auth_url='',
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud='foo'
) )
mock_instance.listen.assert_called_once_with() mock_instance.listen.assert_called_once_with()
@ -449,22 +476,21 @@ class TestMain(unittest.TestCase):
mock_instance = mock.Mock() mock_instance = mock.Mock()
mock_bmc.return_value = mock_instance mock_bmc.return_value = mock_instance
mock_argv = ['openstackbmc', '--port', '111', mock_argv = ['openstackbmc', '--port', '111',
'--instance', 'foobar', '--os-user', 'admin', '--instance', 'foobar']
'--os-password', 'password', '--os-tenant', 'admin',
'--os-auth-url', 'http://host:5000/v2.0']
with mock.patch.object(sys, 'argv', mock_argv): with mock.patch.object(sys, 'argv', mock_argv):
openstackbmc.main() openstackbmc.main()
mock_bmc.assert_called_once_with({'admin': 'password'}, mock_bmc.assert_called_once_with({'admin': 'password'},
port=111, port=111,
address='::', address='::',
instance='foobar', instance='foobar',
user='admin', user='',
password='password', password='',
tenant='admin', tenant='',
auth_url='http://host:5000/v2.0', auth_url='',
project='', project='',
user_domain='', user_domain='',
project_domain='', project_domain='',
cache_status=False cache_status=False,
os_cloud=None
) )
mock_instance.listen.assert_called_once_with() mock_instance.listen.assert_called_once_with()

View File

@ -158,6 +158,11 @@ parameters:
The project domain for os_user. Required for Keystone v3, should be left The project domain for os_user. Required for Keystone v3, should be left
blank for Keystone v2. blank for Keystone v2.
cloud_data:
type: string
default: '{}'
resources: resources:
provision_network: provision_network:
type: OS::Neutron::Net type: OS::Neutron::Net
@ -233,6 +238,7 @@ resources:
os_project: {get_param: os_project} os_project: {get_param: os_project}
os_user_domain: {get_param: os_user_domain} os_user_domain: {get_param: os_user_domain}
os_project_domain: {get_param: os_project_domain} os_project_domain: {get_param: os_project_domain}
cloud_data: {get_param: cloud_data}
outputs: outputs:
undercloud_host_floating_ip: undercloud_host_floating_ip:

View File

@ -116,6 +116,10 @@ parameters:
The project domain for os_user. Required for Keystone v3, should be left The project domain for os_user. Required for Keystone v3, should be left
blank for Keystone v2. blank for Keystone v2.
cloud_data:
type: string
default: '{}'
# Ignored parameters for compatibility with QuintupleO env files # Ignored parameters for compatibility with QuintupleO env files
undercloud_image: undercloud_image:
type: string type: string
@ -184,6 +188,7 @@ resources:
$bm_prefix: {get_param: baremetal_prefix} $bm_prefix: {get_param: baremetal_prefix}
$private_net: {get_param: private_net} $private_net: {get_param: private_net}
$openstackbmc_script: {get_file: ../bin/openstackbmc} $openstackbmc_script: {get_file: ../bin/openstackbmc}
$cloud_data: {get_param: cloud_data}
template: {get_file: ../bin/install_openstackbmc.sh} template: {get_file: ../bin/install_openstackbmc.sh}
baremetal_networks: baremetal_networks: