diff --git a/os_cloud_config/cmd/init_keystone_heat_domain.py b/os_cloud_config/cmd/init_keystone_heat_domain.py new file mode 100644 index 0000000..4ff7d8b --- /dev/null +++ b/os_cloud_config/cmd/init_keystone_heat_domain.py @@ -0,0 +1,53 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import logging +import textwrap + +import os_cloud_config.cmd.utils._clients as clients +from os_cloud_config.cmd.utils import environment +from os_cloud_config.keystone import initialize_for_heat + + +def parse_args(): + description = textwrap.dedent(""" + Create a domain for Heat to use, as well as a user to administer it. + + This will create a heat domain in Keystone, as well as an admin user that + has rights to administer the domain. + """) + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=description) + parser.add_argument('-d', '--domain-admin-password', + dest='domain_admin_password', + help="domain admin user's password to be set", + required=True) + environment._add_logging_arguments(parser) + return parser.parse_args() + + +def main(): + args = parse_args() + environment._configure_logging(args) + try: + environment._ensure() + keystone_client = clients.get_keystone_v3_client() + initialize_for_heat(keystone_client, args.domain_admin_password) + except Exception: + logging.exception("Unexpected error during command execution") + return 1 + return 0 diff --git a/os_cloud_config/cmd/tests/test_init_keystone_heat_domain.py b/os_cloud_config/cmd/tests/test_init_keystone_heat_domain.py new file mode 100644 index 0000000..cabaf2b --- /dev/null +++ b/os_cloud_config/cmd/tests/test_init_keystone_heat_domain.py @@ -0,0 +1,35 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys + +import mock + +from os_cloud_config.cmd import init_keystone_heat_domain +from os_cloud_config.tests import base + + +class InitKeystoneHeatDomainTest(base.TestCase): + + @mock.patch('os_cloud_config.cmd.init_keystone_heat_domain.environment') + @mock.patch('os_cloud_config.cmd.init_keystone_heat_domain' + '.initialize_for_heat') + @mock.patch('os_cloud_config.cmd.utils._clients.get_keystone_v3_client', + return_value='keystone_v3_client_mock') + @mock.patch.object(sys, 'argv', ['init-keystone', '-d', 'password']) + def test_script(self, environment_mock, initialize_mock, client_mock): + init_keystone_heat_domain.main() + initialize_mock.assert_called_once_with('keystone_v3_client_mock', + 'password') diff --git a/os_cloud_config/keystone.py b/os_cloud_config/keystone.py index d8b10b7..9b9ffe2 100644 --- a/os_cloud_config/keystone.py +++ b/os_cloud_config/keystone.py @@ -161,35 +161,34 @@ def initialize_for_swift(host, admin_token, ssl=None, public=None): keystone.roles.create('ResellerAdmin') -def initialize_for_heat(host, admin_token, domain_admin_password, - ssl=None, public=None): +def initialize_for_heat(keystone, domain_admin_password): """Create Heat domain and an admin user for it. - :param host: ip/hostname of node where Keystone is running - :param admin_token: admin token to use with Keystone's admin endpoint + :param keystone: A keystone v3 client :param domain_admin_password: heat domain admin's password to be set - :param ssl: ip/hostname to use as the ssl endpoint, if required - :param public: ip/hostname to use as the public endpoint, if the default - is not suitable """ - LOG.warn('This function is deprecated.') - - keystone = _create_admin_client_v2(host, admin_token, ssl, public) - admin_role = keystone.roles.find(name='admin') - - LOG.debug('Creating heat domain.') - heat_domain = keystone.domains.create( - 'heat', - description='Owns users and tenants created by heat' - ) - LOG.debug('Creating heat_domain_admin user.') - heat_admin = keystone.users.create( - 'heat_domain_admin', - description='Manages users and tenants created by heat', - domain=heat_domain, - password=domain_admin_password, - ) + try: + heat_domain = keystone.domains.find(name='heat') + LOG.debug('Domain heat already exists.') + except exceptions.NotFound: + LOG.debug('Creating heat domain.') + heat_domain = keystone.domains.create( + 'heat', + description='Owns users and tenants created by heat' + ) + try: + heat_admin = keystone.users.find(name='heat_domain_admin') + LOG.debug('Heat domain admin already exists.') + except exceptions.NotFound: + LOG.debug('Creating heat_domain_admin user.') + heat_admin = keystone.users.create( + 'heat_domain_admin', + description='Manages users and tenants created by heat', + domain=heat_domain, + password=domain_admin_password, + ) LOG.debug('Granting admin role to heat_domain_admin user on heat domain.') + admin_role = keystone.roles.find(name='admin') keystone.roles.grant(admin_role, user=heat_admin, domain=heat_domain) diff --git a/os_cloud_config/tests/test_keystone.py b/os_cloud_config/tests/test_keystone.py index 1ff5d70..cb84970 100644 --- a/os_cloud_config/tests/test_keystone.py +++ b/os_cloud_config/tests/test_keystone.py @@ -77,22 +77,24 @@ class KeystoneTest(base.TestCase): [mock.call('swiftoperator'), mock.call('ResellerAdmin')]) def test_initialize_for_heat(self): - self._patch_client() + client = mock.MagicMock() + client.domains.find.side_effect = exceptions.NotFound + client.users.find.side_effect = exceptions.NotFound - keystone.initialize_for_heat('192.0.0.3', 'mytoken', 'heatadminpasswd') + keystone.initialize_for_heat(client, 'heatadminpasswd') - self.client.domains.create.assert_called_once_with( + client.domains.create.assert_called_once_with( 'heat', description='Owns users and tenants created by heat') - self.client.users.create.assert_called_once_with( + client.users.create.assert_called_once_with( 'heat_domain_admin', description='Manages users and tenants created by heat', - domain=self.client.domains.create.return_value, + domain=client.domains.create.return_value, password='heatadminpasswd') - self.client.roles.find.assert_called_once_with(name='admin') - self.client.roles.grant.assert_called_once_with( - self.client.roles.find.return_value, - user=self.client.users.create.return_value, - domain=self.client.domains.create.return_value) + client.roles.find.assert_called_once_with(name='admin') + client.roles.grant.assert_called_once_with( + client.roles.find.return_value, + user=client.users.create.return_value, + domain=client.domains.create.return_value) @mock.patch('subprocess.check_call') def test_idempotent_initialize(self, check_call_mock): diff --git a/setup.cfg b/setup.cfg index f17515b..41b3e2f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,7 @@ packages = console_scripts = generate-keystone-pki = os_cloud_config.cmd.generate_keystone_pki:main init-keystone = os_cloud_config.cmd.init_keystone:main + init-keystone-heat-domain = os_cloud_config.cmd.init_keystone_heat_domain:main register-nodes = os_cloud_config.cmd.register_nodes:main setup-endpoints = os_cloud_config.cmd.setup_endpoints:main setup-flavors = os_cloud_config.cmd.setup_flavors:main