Drop minion
This is no longer valid with the switch to ephemeral heat for
deployments.
Depends-On: https://review.rdoproject.org/r/c/openstack/tripleoclient-distgit/+/35977
Change-Id: Id3e21879c0fb831583ec41804e99da8cffcb9d86
(cherry picked from commit 4dbb45315b
)
This commit is contained in:
parent
d0a9648d81
commit
c22f23a075
@ -100,8 +100,6 @@ openstack.tripleoclient.v2 =
|
||||
tripleo_container_image_prepare_default = tripleoclient.v1.container_image:TripleOImagePrepareDefault
|
||||
undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud
|
||||
undercloud_upgrade = tripleoclient.v1.undercloud:UpgradeUndercloud
|
||||
undercloud_minion_install = tripleoclient.v1.undercloud_minion:InstallUndercloudMinion
|
||||
undercloud_minion_upgrade = tripleoclient.v1.undercloud_minion:UpgradeUndercloudMinion
|
||||
undercloud_backup = tripleoclient.v1.undercloud_backup:BackupUndercloud
|
||||
tripleo_validator_group_info = tripleoclient.v1.tripleo_validator:TripleOValidatorGroupInfo
|
||||
tripleo_validator_list = tripleoclient.v1.tripleo_validator:TripleOValidatorList
|
||||
@ -114,7 +112,6 @@ openstack.tripleoclient.v2 =
|
||||
oslo.config.opts =
|
||||
undercloud_config = tripleoclient.config.undercloud:list_opts
|
||||
standalone_config = tripleoclient.config.standalone:list_opts
|
||||
minion_config = tripleoclient.config.minion:list_opts
|
||||
|
||||
[flake8]
|
||||
show-source = True
|
||||
|
1
tox.ini
1
tox.ini
@ -85,7 +85,6 @@ setenv =
|
||||
commands =
|
||||
oslo-config-generator --config-file config-generator/undercloud.conf
|
||||
oslo-config-generator --config-file config-generator/standalone.conf
|
||||
oslo-config-generator --config-file config-generator/minion.conf
|
||||
|
||||
[testenv:releasenotes]
|
||||
deps =
|
||||
|
@ -1,158 +0,0 @@
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
#
|
||||
# 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 copy
|
||||
|
||||
from osc_lib.i18n import _
|
||||
from oslo_config import cfg
|
||||
|
||||
from tripleoclient import constants
|
||||
|
||||
from tripleoclient.config.standalone import StandaloneConfig
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class MinionConfig(StandaloneConfig):
|
||||
def get_minion_service_opts(self, heat_engine=True,
|
||||
ironic_conductor=False):
|
||||
_opts = [
|
||||
cfg.BoolOpt('enable_heat_engine',
|
||||
default=heat_engine,
|
||||
help=_(
|
||||
'Whether to install the Heat Engine service.')),
|
||||
cfg.BoolOpt('enable_ironic_conductor',
|
||||
default=ironic_conductor,
|
||||
help=_(
|
||||
'Whether to install the Ironic Conductor service. '
|
||||
'This is currently disabled by default.')),
|
||||
]
|
||||
return self.sort_opts(_opts)
|
||||
|
||||
def get_base_opts(self):
|
||||
_base_opts = super(MinionConfig, self).get_base_opts()
|
||||
_opts = [
|
||||
cfg.StrOpt('minion_log_file',
|
||||
default=constants.MINION_LOG_FILE,
|
||||
help=_(
|
||||
'The path to a log file to store the '
|
||||
'install/upgrade logs.'),
|
||||
),
|
||||
cfg.StrOpt('minion_hostname',
|
||||
help=_(
|
||||
'Fully qualified hostname (including domain) to '
|
||||
'set on the Undercloud Minion. If left unset, the '
|
||||
'current hostname will be used, but the user is '
|
||||
'responsible for configuring all system hostname '
|
||||
'settings appropriately. If set, the Undercloud '
|
||||
'Minion install will configure all system hostname '
|
||||
'settings.'),
|
||||
),
|
||||
cfg.StrOpt('minion_local_ip',
|
||||
default='192.168.24.50/24',
|
||||
help=_(
|
||||
'IP information for the interface on the '
|
||||
'Undercloud Minion. The IP portion '
|
||||
'of the value will be assigned to the network '
|
||||
'interface defined by local_interface, with the '
|
||||
'netmask defined by the prefix portion of the '
|
||||
'value.')
|
||||
),
|
||||
cfg.ListOpt('minion_nameservers',
|
||||
default=[],
|
||||
help=_(
|
||||
'DNS nameserver(s) to configure on the Undercloud '
|
||||
'Minion.')
|
||||
),
|
||||
cfg.ListOpt('minion_ntp_servers',
|
||||
default=['0.pool.ntp.org', '1.pool.ntp.org',
|
||||
'2.pool.ntp.org', '3.pool.ntp.org'],
|
||||
help=_('List of ntp servers to use.')),
|
||||
cfg.StrOpt('minion_timezone', default=None,
|
||||
help=_('Host timezone to be used. If no timezone is '
|
||||
'specified, the existing timezone configuration '
|
||||
'is used.')),
|
||||
cfg.StrOpt('minion_service_certificate',
|
||||
default='',
|
||||
help=_(
|
||||
'TODO: '
|
||||
'Certificate file to use for OpenStack service SSL '
|
||||
'connections. Setting this enables SSL for the '
|
||||
'OpenStack API endpoints, leaving it unset '
|
||||
'disables SSL.')
|
||||
),
|
||||
cfg.StrOpt('minion_password_file',
|
||||
default='tripleo-undercloud-passwords.yaml',
|
||||
help=_(
|
||||
'The name of the file to look for the passwords '
|
||||
'used to connect to the Undercloud. We assume '
|
||||
'this file is in output_dir if a fully qualified '
|
||||
'path is not provided.')
|
||||
),
|
||||
cfg.StrOpt('minion_undercloud_output_file',
|
||||
default='tripleo-undercloud-outputs.yaml',
|
||||
help=_(
|
||||
'The name of the file to look for the Undercloud '
|
||||
'output file that contains configuration '
|
||||
'information. We assume this file is in the folder '
|
||||
'where the command is executed if a fully '
|
||||
'qualified path is not provided.')
|
||||
),
|
||||
|
||||
cfg.StrOpt('minion_local_interface',
|
||||
default='eth1',
|
||||
help=_('Network interface on the Undercloud Minion '
|
||||
'that will be used for the services.')
|
||||
),
|
||||
cfg.IntOpt('minion_local_mtu',
|
||||
default=1500,
|
||||
help=_('MTU to use for the local_interface.')
|
||||
),
|
||||
cfg.BoolOpt('minion_debug',
|
||||
default=True,
|
||||
help=_(
|
||||
'Whether to enable the debug log level for '
|
||||
'OpenStack services and Container Image Prepare '
|
||||
'step.')
|
||||
),
|
||||
cfg.BoolOpt('minion_enable_selinux',
|
||||
default=True,
|
||||
help=_('Enable or disable SELinux during the '
|
||||
'deployment.')),
|
||||
cfg.BoolOpt('minion_enable_validations',
|
||||
default=True,
|
||||
help=_(
|
||||
'Run pre-flight checks when installing or '
|
||||
'upgrading.')
|
||||
),
|
||||
|
||||
]
|
||||
return self.sort_opts(_base_opts + _opts)
|
||||
|
||||
def get_opts(self):
|
||||
_base_opts = self.get_base_opts()
|
||||
_service_opts = self.get_minion_service_opts()
|
||||
return self.sort_opts(_base_opts + _service_opts)
|
||||
|
||||
|
||||
def list_opts():
|
||||
"""List config opts for oslo config generator"""
|
||||
return [(None, copy.deepcopy(MinionConfig().get_opts()))]
|
||||
|
||||
|
||||
def load_global_config():
|
||||
"""Register MinionConfig options into global config"""
|
||||
_opts = MinionConfig().get_opts()
|
||||
CONF.register_opts(_opts)
|
@ -1,103 +0,0 @@
|
||||
# Copyright 2018 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
from tripleoclient.config.minion import MinionConfig
|
||||
from tripleoclient.tests import base
|
||||
|
||||
|
||||
class TestMinionConfig(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestMinionConfig, self).setUp()
|
||||
# Get the class object to test
|
||||
self.config = MinionConfig()
|
||||
|
||||
def test_get_base_opts(self):
|
||||
ret = self.config.get_base_opts()
|
||||
expected = ['cleanup',
|
||||
'container_cli',
|
||||
'container_healthcheck_disabled',
|
||||
'container_images_file',
|
||||
'container_insecure_registries',
|
||||
'container_registry_mirror',
|
||||
'custom_env_files',
|
||||
'deployment_user',
|
||||
'heat_container_image',
|
||||
'heat_native',
|
||||
'hieradata_override',
|
||||
'minion_debug',
|
||||
'minion_enable_selinux',
|
||||
'minion_enable_validations',
|
||||
'minion_hostname',
|
||||
'minion_local_interface',
|
||||
'minion_local_ip',
|
||||
'minion_local_mtu',
|
||||
'minion_log_file',
|
||||
'minion_nameservers',
|
||||
'minion_ntp_servers',
|
||||
'minion_password_file',
|
||||
'minion_service_certificate',
|
||||
'minion_timezone',
|
||||
'minion_undercloud_output_file',
|
||||
'net_config_override',
|
||||
'networks_file',
|
||||
'output_dir',
|
||||
'roles_file',
|
||||
'templates']
|
||||
self.assertEqual(expected, [x.name for x in ret])
|
||||
|
||||
def test_get_opts(self):
|
||||
ret = self.config.get_opts()
|
||||
expected = ['cleanup',
|
||||
'container_cli',
|
||||
'container_healthcheck_disabled',
|
||||
'container_images_file',
|
||||
'container_insecure_registries',
|
||||
'container_registry_mirror',
|
||||
'custom_env_files',
|
||||
'deployment_user',
|
||||
'enable_heat_engine',
|
||||
'enable_ironic_conductor',
|
||||
'heat_container_image',
|
||||
'heat_native',
|
||||
'hieradata_override',
|
||||
'minion_debug',
|
||||
'minion_enable_selinux',
|
||||
'minion_enable_validations',
|
||||
'minion_hostname',
|
||||
'minion_local_interface',
|
||||
'minion_local_ip',
|
||||
'minion_local_mtu',
|
||||
'minion_log_file',
|
||||
'minion_nameservers',
|
||||
'minion_ntp_servers',
|
||||
'minion_password_file',
|
||||
'minion_service_certificate',
|
||||
'minion_timezone',
|
||||
'minion_undercloud_output_file',
|
||||
'net_config_override',
|
||||
'networks_file',
|
||||
'output_dir',
|
||||
'roles_file',
|
||||
'templates']
|
||||
self.assertEqual(expected, [x.name for x in ret])
|
||||
|
||||
def test_get_minion_service_opts(self):
|
||||
ret = self.config.get_minion_service_opts()
|
||||
expected = {'enable_heat_engine': True,
|
||||
'enable_ironic_conductor': False}
|
||||
self.assertEqual(sorted(expected.keys()), [x.name for x in ret])
|
||||
for x in ret:
|
||||
self.assertEqual(expected[x.name], x.default, "%s config not %s" %
|
||||
(x.name, expected[x.name]))
|
@ -1,248 +0,0 @@
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
#
|
||||
# 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 mock
|
||||
import sys
|
||||
import tempfile
|
||||
import yaml
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as oslo_fixture
|
||||
|
||||
from tripleo_common.image import kolla_builder
|
||||
|
||||
from tripleoclient.tests import base
|
||||
from tripleoclient.v1 import minion_config
|
||||
|
||||
|
||||
class TestMinionDeploy(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestMinionDeploy, self).setUp()
|
||||
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
self.conf.set_default('output_dir', '/home/stack')
|
||||
# set timezone so we don't have to mock it everywhere
|
||||
self.conf.set_default('minion_timezone', 'UTC')
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config._process_undercloud_passwords')
|
||||
@mock.patch('tripleoclient.v1.undercloud_preflight.minion_check')
|
||||
@mock.patch('os.makedirs', return_value=None)
|
||||
@mock.patch('tripleoclient.v1.minion_config._process_undercloud_output',
|
||||
return_value='output.yaml')
|
||||
@mock.patch('tripleoclient.v1.minion_config._container_images_config')
|
||||
@mock.patch('tripleoclient.utils.write_env_file')
|
||||
@mock.patch('tripleoclient.utils.get_deployment_user')
|
||||
@mock.patch('tripleoclient.utils.load_config')
|
||||
def test_basic_deploy(self, mock_load_config, mock_get_user,
|
||||
mock_write_env, mock_undercloud_output,
|
||||
mock_images_config, mock_isdir,
|
||||
mock_check, mock_pass):
|
||||
mock_get_user.return_value = 'foo'
|
||||
cmd = minion_config.prepare_minion_deploy()
|
||||
expected_cmd = ['sudo', '--preserve-env',
|
||||
'openstack', 'tripleo', 'deploy',
|
||||
'--standalone', '--standalone-role',
|
||||
'UndercloudMinion', '--stack', 'minion',
|
||||
'-r',
|
||||
'/usr/share/openstack-tripleo-heat-templates/roles/'
|
||||
'UndercloudMinion.yaml',
|
||||
'--local-ip=192.168.24.50/24',
|
||||
'--templates='
|
||||
'/usr/share/openstack-tripleo-heat-templates/',
|
||||
'--networks-file='
|
||||
'/usr/share/openstack-tripleo-heat-templates/'
|
||||
'network_data_undercloud.yaml',
|
||||
'-e', 'output.yaml',
|
||||
'--heat-native',
|
||||
'-e', '/usr/share/openstack-tripleo-heat-templates/'
|
||||
'environments/undercloud/undercloud-minion.yaml',
|
||||
'-e', '/usr/share/openstack-tripleo-heat-templates/'
|
||||
'environments/use-dns-for-vips.yaml',
|
||||
'-e', '/usr/share/openstack-tripleo-heat-templates/'
|
||||
'environments/services/heat-engine.yaml',
|
||||
'--deployment-user', 'foo',
|
||||
'--output-dir=/home/stack',
|
||||
'-e', '/home/stack/tripleo-config-generated-env-files/'
|
||||
'minion_parameters.yaml',
|
||||
'--log-file=install-minion.log',
|
||||
'-e', '/usr/share/openstack-tripleo-heat-templates/'
|
||||
'minion-stack-vstate-dropin.yaml']
|
||||
self.assertEqual(expected_cmd, cmd)
|
||||
env_data = {
|
||||
'PythonInterpreter': sys.executable,
|
||||
'ContainerImagePrepareDebug': True,
|
||||
'Debug': True,
|
||||
'UndercloudMinionLocalMtu': 1500,
|
||||
'ContainerHealthcheckDisabled': False,
|
||||
'NeutronPublicInterface': 'eth1',
|
||||
'SELinuxMode': 'enforcing',
|
||||
'NtpServer': ['0.pool.ntp.org',
|
||||
'1.pool.ntp.org',
|
||||
'2.pool.ntp.org',
|
||||
'3.pool.ntp.org'],
|
||||
'TimeZone': 'UTC',
|
||||
'DockerInsecureRegistryAddress': ['192.168.24.50:8787'],
|
||||
'ContainerCli': 'podman',
|
||||
'LocalContainerRegistry': '192.168.24.50',
|
||||
'DeploymentUser': 'foo'}
|
||||
mock_write_env.assert_called_once_with(
|
||||
env_data, '/home/stack/tripleo-config-generated-env-files/'
|
||||
'minion_parameters.yaml', {})
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config._process_undercloud_passwords')
|
||||
@mock.patch('tripleoclient.v1.undercloud_preflight.minion_check')
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('os.makedirs', return_value=None)
|
||||
@mock.patch('tripleoclient.v1.minion_config._process_undercloud_output',
|
||||
return_value='output.yaml')
|
||||
@mock.patch('tripleoclient.v1.minion_config._container_images_config')
|
||||
@mock.patch('tripleoclient.utils.write_env_file')
|
||||
@mock.patch('tripleoclient.utils.load_config')
|
||||
def test_configured_deploy(self, mock_load_config,
|
||||
mock_write_env, mock_undercloud_output,
|
||||
mock_images_config, mock_isdir, mock_exists,
|
||||
mock_check, mock_pass):
|
||||
self.conf.set_default('deployment_user', 'bar')
|
||||
self.conf.set_default('enable_heat_engine', False)
|
||||
self.conf.set_default('enable_ironic_conductor', True)
|
||||
self.conf.set_default('hieradata_override', '/data.yaml')
|
||||
self.conf.set_default('minion_debug', False)
|
||||
self.conf.set_default('minion_enable_selinux', False)
|
||||
self.conf.set_default('minion_local_interface', 'enp0s4')
|
||||
self.conf.set_default('minion_local_ip', '1.1.1.1/24')
|
||||
self.conf.set_default('minion_local_mtu', '1350')
|
||||
self.conf.set_default('minion_ntp_servers', ['pool.ntp.org'])
|
||||
self.conf.set_default('networks_file', 'network.yaml')
|
||||
self.conf.set_default('output_dir', '/bar')
|
||||
self.conf.set_default('templates', '/foo')
|
||||
cmd = minion_config.prepare_minion_deploy()
|
||||
expected_cmd = ['sudo', '--preserve-env',
|
||||
'openstack', 'tripleo', 'deploy',
|
||||
'--standalone', '--standalone-role',
|
||||
'UndercloudMinion', '--stack', 'minion',
|
||||
'-r', '/foo/roles/UndercloudMinion.yaml',
|
||||
'--local-ip=1.1.1.1/24',
|
||||
'--templates=/foo',
|
||||
'--networks-file=network.yaml',
|
||||
'-e', 'output.yaml',
|
||||
'--heat-native',
|
||||
'-e', '/foo/environments/undercloud/'
|
||||
'undercloud-minion.yaml',
|
||||
'-e', '/foo/environments/use-dns-for-vips.yaml',
|
||||
'-e', '/foo/environments/services/'
|
||||
'ironic-conductor.yaml',
|
||||
'--deployment-user', 'bar',
|
||||
'--output-dir=/bar',
|
||||
'-e', '/bar/tripleo-config-generated-env-files/'
|
||||
'minion_parameters.yaml',
|
||||
'--hieradata-override=/data.yaml',
|
||||
'--log-file=install-minion.log',
|
||||
'-e', '/foo/minion-stack-vstate-dropin.yaml']
|
||||
self.assertEqual(expected_cmd, cmd)
|
||||
env_data = {
|
||||
'PythonInterpreter': sys.executable,
|
||||
'ContainerImagePrepareDebug': False,
|
||||
'Debug': False,
|
||||
'UndercloudMinionLocalMtu': 1350,
|
||||
'ContainerHealthcheckDisabled': False,
|
||||
'NeutronPublicInterface': 'enp0s4',
|
||||
'SELinuxMode': 'permissive',
|
||||
'NtpServer': ['pool.ntp.org'],
|
||||
'TimeZone': 'UTC',
|
||||
'DockerInsecureRegistryAddress': ['1.1.1.1:8787'],
|
||||
'ContainerCli': 'podman',
|
||||
'LocalContainerRegistry': '1.1.1.1',
|
||||
'DeploymentUser': 'bar'}
|
||||
mock_write_env.assert_called_once_with(
|
||||
env_data, '/bar/tripleo-config-generated-env-files/'
|
||||
'minion_parameters.yaml', {})
|
||||
|
||||
|
||||
class TestMinionContainerImageConfig(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestMinionContainerImageConfig, self).setUp()
|
||||
conf_keys = (
|
||||
'container_images_file',
|
||||
)
|
||||
self.conf = mock.Mock(**{key: getattr(minion_config.CONF, key)
|
||||
for key in conf_keys})
|
||||
|
||||
@mock.patch('shutil.copy')
|
||||
def test_defaults(self, mock_copy):
|
||||
env = {}
|
||||
deploy_args = []
|
||||
cip_default = getattr(kolla_builder,
|
||||
'CONTAINER_IMAGE_PREPARE_PARAM', None)
|
||||
self.addCleanup(setattr, kolla_builder,
|
||||
'CONTAINER_IMAGE_PREPARE_PARAM', cip_default)
|
||||
|
||||
setattr(kolla_builder, 'CONTAINER_IMAGE_PREPARE_PARAM', [{
|
||||
'set': {
|
||||
'namespace': 'one',
|
||||
'name_prefix': 'two',
|
||||
'name_suffix': 'three',
|
||||
'tag': 'four',
|
||||
},
|
||||
'tag_from_label': 'five',
|
||||
}])
|
||||
|
||||
minion_config._container_images_config(self.conf, deploy_args,
|
||||
env, None)
|
||||
self.assertEqual([], deploy_args)
|
||||
cip = env['ContainerImagePrepare'][0]
|
||||
set = cip['set']
|
||||
|
||||
self.assertEqual(
|
||||
'one', set['namespace'])
|
||||
self.assertEqual(
|
||||
'two', set['name_prefix'])
|
||||
self.assertEqual(
|
||||
'three', set['name_suffix'])
|
||||
self.assertEqual(
|
||||
'four', set['tag'])
|
||||
self.assertEqual(
|
||||
'five', cip['tag_from_label'])
|
||||
|
||||
@mock.patch('shutil.copy')
|
||||
def test_container_images_file(self, mock_copy):
|
||||
env = {}
|
||||
deploy_args = []
|
||||
self.conf.container_images_file = '/tmp/container_images_file.yaml'
|
||||
minion_config._container_images_config(self.conf, deploy_args,
|
||||
env, None)
|
||||
self.assertEqual(['-e', '/tmp/container_images_file.yaml'],
|
||||
deploy_args)
|
||||
self.assertEqual({}, env)
|
||||
|
||||
@mock.patch('shutil.copy')
|
||||
def test_custom(self, mock_copy):
|
||||
env = {}
|
||||
deploy_args = []
|
||||
with tempfile.NamedTemporaryFile(mode='w') as f:
|
||||
yaml.dump({
|
||||
'parameter_defaults': {'ContainerImagePrepare': [{
|
||||
'set': {
|
||||
'namespace': 'one',
|
||||
'name_prefix': 'two',
|
||||
'name_suffix': 'three',
|
||||
'tag': 'four',
|
||||
},
|
||||
'tag_from_label': 'five',
|
||||
}]}
|
||||
}, f)
|
||||
self.conf.container_images_file = f.name
|
||||
cif_name = f.name
|
||||
|
||||
minion_config._container_images_config(
|
||||
self.conf, deploy_args, env, None)
|
||||
self.assertEqual(['-e', cif_name], deploy_args)
|
@ -1,130 +0,0 @@
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 fixtures
|
||||
import mock
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as oslo_fixture
|
||||
|
||||
from tripleoclient.tests.v1.test_plugin import TestPluginV1
|
||||
|
||||
# Load the plugin init module for the plugin list and show commands
|
||||
from tripleoclient.v1 import undercloud_minion
|
||||
|
||||
|
||||
class FakePluginV1Client(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.auth_token = kwargs['token']
|
||||
self.management_url = kwargs['endpoint']
|
||||
|
||||
|
||||
class TestMinionInstall(TestPluginV1):
|
||||
|
||||
def setUp(self):
|
||||
super(TestMinionInstall, self).setUp()
|
||||
|
||||
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
# don't actually load config from ~/minion.conf
|
||||
self.mock_config_load = self.useFixture(
|
||||
fixtures.MockPatch('tripleoclient.utils.load_config'))
|
||||
# Get the command object to test
|
||||
app_args = mock.Mock()
|
||||
app_args.verbose_level = 1
|
||||
self.cmd = undercloud_minion.InstallUndercloudMinion(self.app,
|
||||
app_args)
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config.prepare_minion_deploy')
|
||||
@mock.patch('tripleoclient.utils.ensure_run_as_normal_user')
|
||||
@mock.patch('tripleoclient.utils.configure_logging')
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_take_action(self, mock_subprocess, mock_logging, mock_usercheck,
|
||||
mock_prepare_deploy):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_prepare_deploy.return_value = ['foo']
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_prepare_deploy.assert_called_once_with(
|
||||
dry_run=False, force_stack_update=False, no_validations=False,
|
||||
verbose_level=1)
|
||||
mock_usercheck.assert_called_once()
|
||||
mock_subprocess.assert_called_with(['foo'])
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config.prepare_minion_deploy')
|
||||
@mock.patch('tripleoclient.utils.ensure_run_as_normal_user')
|
||||
@mock.patch('tripleoclient.utils.configure_logging')
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_take_action_dry_run(self, mock_subprocess, mock_logging,
|
||||
mock_usercheck, mock_prepare_deploy):
|
||||
arglist = ['--dry-run']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_prepare_deploy.assert_called_once_with(
|
||||
dry_run=True, force_stack_update=False, no_validations=True,
|
||||
verbose_level=1)
|
||||
mock_usercheck.assert_called_once()
|
||||
self.assertCountEqual(mock_subprocess.call_args_list, [])
|
||||
|
||||
|
||||
class TestMinionUpgrade(TestPluginV1):
|
||||
|
||||
def setUp(self):
|
||||
super(TestMinionUpgrade, self).setUp()
|
||||
|
||||
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||
# don't actually load config from ~/minion.conf
|
||||
self.mock_config_load = self.useFixture(
|
||||
fixtures.MockPatch('tripleoclient.utils.load_config'))
|
||||
# Get the command object to test
|
||||
app_args = mock.Mock()
|
||||
app_args.verbose_level = 1
|
||||
self.cmd = undercloud_minion.UpgradeUndercloudMinion(self.app,
|
||||
app_args)
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config.prepare_minion_deploy')
|
||||
@mock.patch('tripleoclient.utils.ensure_run_as_normal_user')
|
||||
@mock.patch('tripleoclient.utils.configure_logging')
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_take_action(self, mock_subprocess, mock_logging, mock_usercheck,
|
||||
mock_prepare_deploy):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_prepare_deploy.return_value = ['foo']
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_prepare_deploy.assert_called_once_with(
|
||||
force_stack_update=False, no_validations=False, upgrade=True,
|
||||
verbose_level=1, yes=False)
|
||||
mock_usercheck.assert_called_once()
|
||||
mock_subprocess.assert_called_with(['foo'])
|
||||
|
||||
@mock.patch('tripleoclient.v1.minion_config.prepare_minion_deploy')
|
||||
@mock.patch('tripleoclient.utils.ensure_run_as_normal_user')
|
||||
@mock.patch('tripleoclient.utils.configure_logging')
|
||||
@mock.patch('subprocess.check_call', autospec=True)
|
||||
def test_take_action_yes(self, mock_subprocess, mock_logging,
|
||||
mock_usercheck, mock_prepare_deploy):
|
||||
arglist = ['--yes']
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
mock_prepare_deploy.return_value = ['foo']
|
||||
self.cmd.take_action(parsed_args)
|
||||
mock_prepare_deploy.assert_called_once_with(
|
||||
force_stack_update=False, no_validations=False, upgrade=True,
|
||||
verbose_level=1, yes=True)
|
||||
mock_usercheck.assert_called_once()
|
||||
mock_subprocess.assert_called_with(['foo'])
|
@ -1,421 +0,0 @@
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""Plugin action implementation"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from cryptography import x509
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
from jinja2 import Environment
|
||||
from jinja2 import FileSystemLoader
|
||||
|
||||
from osc_lib.i18n import _
|
||||
from oslo_config import cfg
|
||||
from tripleo_common.image import kolla_builder
|
||||
|
||||
from tripleoclient.config.minion import load_global_config
|
||||
from tripleoclient.config.minion import MinionConfig
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import utils
|
||||
from tripleoclient.v1 import undercloud_preflight
|
||||
|
||||
|
||||
# Provides mappings for some of the instack_env tags to minion heat
|
||||
# params or minion.conf opts known here (as a fallback), needed to maintain
|
||||
# feature parity with instack net config override templates.
|
||||
# TODO(bogdando): all of the needed mappings should be wired-in, eventually
|
||||
# NOTE(aschultz): this is used by the custom netconfig still, even though
|
||||
# the minion config is new.
|
||||
INSTACK_NETCONF_MAPPING = {
|
||||
'LOCAL_INTERFACE': 'minion_local_interface',
|
||||
'LOCAL_IP': 'minion_local_ip',
|
||||
'LOCAL_MTU': 'UndercloudMinionLocalMtu',
|
||||
'PUBLIC_INTERFACE_IP': 'minion_local_ip', # can't be 'CloudName'
|
||||
'UNDERCLOUD_NAMESERVERS': 'minion_nameservers',
|
||||
'SUBNETS_STATIC_ROUTES': 'ControlPlaneStaticRoutes',
|
||||
}
|
||||
|
||||
|
||||
PARAMETER_MAPPING = {
|
||||
'minion_debug': 'Debug',
|
||||
'minion_local_mtu': 'UndercloudMinionLocalMtu',
|
||||
'container_healthcheck_disabled': 'ContainerHealthcheckDisabled',
|
||||
'minion_local_interface': 'NeutronPublicInterface',
|
||||
}
|
||||
|
||||
SUBNET_PARAMETER_MAPPING = {
|
||||
'cidr': 'NetworkCidr',
|
||||
'gateway': 'NetworkGateway',
|
||||
'host_routes': 'HostRoutes'
|
||||
}
|
||||
|
||||
THT_HOME = os.environ.get('THT_HOME',
|
||||
"/usr/share/openstack-tripleo-heat-templates/")
|
||||
|
||||
USER_HOME = os.environ.get('HOME', '')
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
# When adding new options to the lists below, make sure to regenerate the
|
||||
# sample config by running "tox -e genconfig" in the project root.
|
||||
ci_defaults = kolla_builder.container_images_prepare_defaults()
|
||||
|
||||
config = MinionConfig()
|
||||
|
||||
# Routed subnets
|
||||
_opts = config.get_opts()
|
||||
load_global_config()
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__ + ".minion_config")
|
||||
|
||||
|
||||
def _get_jinja_env_source(f):
|
||||
path, filename = os.path.split(f)
|
||||
env = Environment(loader=FileSystemLoader(path))
|
||||
src = env.loader.get_source(env, filename)[0]
|
||||
return (env, src)
|
||||
|
||||
|
||||
def _process_undercloud_output(templates_dir, output_file_path):
|
||||
"""copy the undercloud output file to our work dir"""
|
||||
output_file = os.path.join(constants.MINION_OUTPUT_DIR, output_file_path)
|
||||
env_file = os.path.join(templates_dir, 'tripleo-undercloud-base.yaml')
|
||||
if os.path.exists(output_file):
|
||||
src_file = output_file
|
||||
elif os.path.exists(output_file_path):
|
||||
src_file = output_file_path
|
||||
else:
|
||||
raise exceptions.DeploymentError('Cannot locate undercloud output '
|
||||
'file {}'.format(output_file_path))
|
||||
|
||||
try:
|
||||
shutil.copy(os.path.abspath(src_file), env_file)
|
||||
except Exception:
|
||||
msg = _('Cannot copy undercloud output file %s into a '
|
||||
'tempdir!') % src_file
|
||||
LOG.error(msg)
|
||||
raise exceptions.DeploymentError(msg)
|
||||
return env_file
|
||||
|
||||
|
||||
def _process_undercloud_passwords(src_file, dest_file):
|
||||
try:
|
||||
shutil.copy(os.path.abspath(src_file), dest_file)
|
||||
except Exception:
|
||||
msg = _('Cannot copy undercloud password file %(src)s to '
|
||||
'%(dest)s') % {'src': src_file, 'dest': dest_file}
|
||||
LOG.error(msg)
|
||||
raise exceptions.DeploymentError(msg)
|
||||
|
||||
|
||||
def prepare_minion_deploy(upgrade=False, no_validations=False,
|
||||
verbose_level=1, yes=False,
|
||||
force_stack_update=False, dry_run=False):
|
||||
"""Prepare Minion deploy command based on minion.conf"""
|
||||
|
||||
env_data = {}
|
||||
registry_overwrites = {}
|
||||
deploy_args = []
|
||||
# Fetch configuration and use its log file param to add logging to a file
|
||||
utils.load_config(CONF, constants.MINION_CONF_PATH)
|
||||
utils.configure_logging(LOG, verbose_level, CONF['minion_log_file'])
|
||||
|
||||
# NOTE(bogdando): the generated env files are stored another path then
|
||||
# picked up later.
|
||||
# NOTE(aschultz): We copy this into the tht root that we save because
|
||||
# we move any user provided environment files into this root later.
|
||||
if not CONF.get('output_dir'):
|
||||
output_dir = os.path.join(constants.MINION_OUTPUT_DIR,
|
||||
'tripleo-deploy',
|
||||
'minion')
|
||||
else:
|
||||
output_dir = CONF['output_dir']
|
||||
tempdir = os.path.join(os.path.abspath(output_dir),
|
||||
'tripleo-config-generated-env-files')
|
||||
utils.makedirs(tempdir)
|
||||
|
||||
env_data['PythonInterpreter'] = sys.executable
|
||||
|
||||
env_data['ContainerImagePrepareDebug'] = CONF['minion_debug']
|
||||
|
||||
for param_key, param_value in PARAMETER_MAPPING.items():
|
||||
if param_key in CONF.keys():
|
||||
env_data[param_value] = CONF[param_key]
|
||||
|
||||
# Parse the minion.conf options to include necessary args and
|
||||
# yaml files for minion deploy command
|
||||
|
||||
if CONF.get('minion_enable_selinux'):
|
||||
env_data['SELinuxMode'] = 'enforcing'
|
||||
else:
|
||||
env_data['SELinuxMode'] = 'permissive'
|
||||
|
||||
if CONF.get('minion_ntp_servers', None):
|
||||
env_data['NtpServer'] = CONF['minion_ntp_servers']
|
||||
|
||||
if CONF.get('minion_timezone', None):
|
||||
env_data['TimeZone'] = CONF['minion_timezone']
|
||||
else:
|
||||
env_data['TimeZone'] = utils.get_local_timezone()
|
||||
|
||||
# TODO(aschultz): fix this logic, look it up out of undercloud-outputs.yaml
|
||||
env_data['DockerInsecureRegistryAddress'] = [
|
||||
'%s:8787' % CONF['minion_local_ip'].split('/')[0]]
|
||||
env_data['DockerInsecureRegistryAddress'].extend(
|
||||
CONF['container_insecure_registries'])
|
||||
|
||||
env_data['ContainerCli'] = CONF['container_cli']
|
||||
|
||||
if CONF.get('container_registry_mirror', None):
|
||||
env_data['DockerRegistryMirror'] = CONF['container_registry_mirror']
|
||||
|
||||
# This parameter the IP address used to bind the local container registry
|
||||
env_data['LocalContainerRegistry'] = CONF['minion_local_ip'].split('/')[0]
|
||||
|
||||
if CONF.get('minion_local_ip', None):
|
||||
deploy_args.append('--local-ip=%s' % CONF['minion_local_ip'])
|
||||
|
||||
if CONF.get('templates', None):
|
||||
tht_templates = CONF['templates']
|
||||
deploy_args.append('--templates=%s' % tht_templates)
|
||||
else:
|
||||
tht_templates = THT_HOME
|
||||
deploy_args.append('--templates=%s' % THT_HOME)
|
||||
|
||||
if CONF.get('roles_file', constants.MINION_ROLES_FILE):
|
||||
deploy_args.append('--roles-file=%s' % CONF['roles_file'])
|
||||
|
||||
if CONF.get('networks_file'):
|
||||
deploy_args.append('--networks-file=%s' % CONF['networks_file'])
|
||||
else:
|
||||
deploy_args.append('--networks-file=%s' %
|
||||
os.path.join(tht_templates,
|
||||
constants.UNDERCLOUD_NETWORKS_FILE))
|
||||
|
||||
if yes:
|
||||
deploy_args += ['-y']
|
||||
|
||||
# copy the undercloud output file into our working dir and include it
|
||||
output_file = _process_undercloud_output(
|
||||
tempdir, CONF['minion_undercloud_output_file'])
|
||||
deploy_args += ['-e', output_file]
|
||||
|
||||
# copy undercloud password file (the configuration is minion_password_file
|
||||
# to the place that triple deploy looks for it
|
||||
# tripleo-<stack name>-passwords.yaml)
|
||||
_process_undercloud_passwords(
|
||||
CONF['minion_password_file'],
|
||||
os.path.join(output_dir, 'tripleo-minion-passwords.yaml'))
|
||||
|
||||
if upgrade:
|
||||
# TODO(aschultz): validate minion upgrade, should be the same as the
|
||||
# undercloud one.
|
||||
deploy_args += [
|
||||
'--upgrade',
|
||||
'-e', os.path.join(
|
||||
tht_templates,
|
||||
"environments/lifecycle/undercloud-upgrade-prepare.yaml")]
|
||||
|
||||
if not CONF.get('heat_native', False):
|
||||
deploy_args.append('--heat-native=False')
|
||||
else:
|
||||
deploy_args.append('--heat-native')
|
||||
|
||||
if CONF.get('heat_container_image'):
|
||||
deploy_args.append('--heat-container-image=%s'
|
||||
% CONF['heat_container_image'])
|
||||
|
||||
# These should be loaded first so we can override all the bits later
|
||||
deploy_args += [
|
||||
"-e", os.path.join(tht_templates,
|
||||
'environments/undercloud/undercloud-minion.yaml'),
|
||||
'-e', os.path.join(tht_templates, 'environments/use-dns-for-vips.yaml')
|
||||
]
|
||||
|
||||
# If a container images file is used, copy it into the tempdir to make it
|
||||
# later into other deployment artifacts and user-provided files.
|
||||
_container_images_config(CONF, deploy_args, env_data, tempdir)
|
||||
|
||||
if CONF.get('enable_heat_engine'):
|
||||
deploy_args += ['-e', os.path.join(
|
||||
tht_templates, "environments/services/heat-engine.yaml")]
|
||||
if CONF.get('enable_ironic_conductor'):
|
||||
deploy_args += ['-e', os.path.join(
|
||||
tht_templates, "environments/services/ironic-conductor.yaml")]
|
||||
|
||||
if CONF.get('minion_service_certificate'):
|
||||
# We assume that the certificate is trusted
|
||||
env_data['InternalTLSCAFile'] = ''
|
||||
env_data.update(
|
||||
_get_public_tls_parameters(
|
||||
CONF.get('minion_service_certificate')))
|
||||
|
||||
u = CONF.get('deployment_user') or utils.get_deployment_user()
|
||||
env_data['DeploymentUser'] = u
|
||||
# TODO(cjeanner) drop that once using oslo.privsep
|
||||
deploy_args += ['--deployment-user', u]
|
||||
|
||||
deploy_args += ['--output-dir=%s' % output_dir]
|
||||
utils.makedirs(output_dir)
|
||||
|
||||
# TODO(aschultz): move this to a central class
|
||||
if CONF.get('net_config_override', None):
|
||||
data_file = CONF['net_config_override']
|
||||
if os.path.abspath(data_file) != data_file:
|
||||
data_file = os.path.join(USER_HOME, data_file)
|
||||
|
||||
if not os.path.exists(data_file):
|
||||
msg = _("Could not find net_config_override file '%s'") % data_file
|
||||
LOG.error(msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
# NOTE(bogdando): Process templated net config override data:
|
||||
# * get a list of used instack_env j2 tags (j2 vars, like {{foo}}),
|
||||
# * fetch values for the tags from the known mappins,
|
||||
# * raise, if there is unmatched tags left
|
||||
# * render the template into a JSON dict
|
||||
net_config_env, template_source = _get_jinja_env_source(data_file)
|
||||
|
||||
# Create rendering context from the known to be present mappings for
|
||||
# identified instack_env tags to generated in env_data minion heat
|
||||
# params. Fall back to config opts, when env_data misses a param.
|
||||
context = {}
|
||||
for tag in INSTACK_NETCONF_MAPPING.keys():
|
||||
mapped_value = INSTACK_NETCONF_MAPPING[tag]
|
||||
if mapped_value in env_data.keys() or mapped_value in CONF.keys():
|
||||
try:
|
||||
context[tag] = CONF[mapped_value]
|
||||
except cfg.NoSuchOptError:
|
||||
context[tag] = env_data.get(mapped_value, None)
|
||||
|
||||
# this returns a unicode string, convert it in into json
|
||||
net_config_str = net_config_env.get_template(
|
||||
os.path.split(data_file)[-1]).render(context).replace(
|
||||
"'", '"').replace('"', '"')
|
||||
try:
|
||||
net_config_json = json.loads(net_config_str)
|
||||
except ValueError:
|
||||
net_config_json = json.loads("{%s}" % net_config_str)
|
||||
|
||||
if 'network_config' not in net_config_json:
|
||||
msg = ('Unsupported data format in net_config_override '
|
||||
'file %s: %s' % (data_file, net_config_str))
|
||||
LOG.error(msg)
|
||||
raise exceptions.DeploymentError(msg)
|
||||
|
||||
env_data['UndercloudNetConfigOverride'] = net_config_json
|
||||
|
||||
params_file = os.path.join(tempdir, 'minion_parameters.yaml')
|
||||
utils.write_env_file(env_data, params_file, registry_overwrites)
|
||||
deploy_args += ['-e', params_file]
|
||||
|
||||
if CONF.get('hieradata_override', None):
|
||||
data_file = CONF['hieradata_override']
|
||||
if os.path.abspath(data_file) != data_file:
|
||||
data_file = os.path.join(USER_HOME, data_file)
|
||||
|
||||
if not os.path.exists(data_file):
|
||||
msg = _("Could not find hieradata_override file '%s'") % data_file
|
||||
LOG.error(msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
deploy_args += ['--hieradata-override=%s' % data_file]
|
||||
|
||||
if CONF.get('minion_hostname'):
|
||||
utils.set_hostname(CONF.get('minion_hostname'))
|
||||
|
||||
if CONF.get('minion_enable_validations') and not no_validations:
|
||||
undercloud_preflight.minion_check(verbose_level, upgrade)
|
||||
|
||||
if CONF.get('custom_env_files'):
|
||||
for custom_file in CONF['custom_env_files']:
|
||||
deploy_args += ['-e', custom_file]
|
||||
|
||||
if verbose_level > 1:
|
||||
deploy_args.append('--debug')
|
||||
|
||||
deploy_args.append('--log-file=%s' % CONF['minion_log_file'])
|
||||
|
||||
# Always add a drop-in for the ephemeral minion heat stack
|
||||
# virtual state tracking (the actual file will be created later)
|
||||
stack_vstate_dropin = os.path.join(
|
||||
tht_templates, 'minion-stack-vstate-dropin.yaml')
|
||||
deploy_args += ["-e", stack_vstate_dropin]
|
||||
if force_stack_update:
|
||||
deploy_args += ["--force-stack-update"]
|
||||
|
||||
roles_file = os.path.join(tht_templates, constants.MINION_ROLES_FILE)
|
||||
cmd = ["sudo", "--preserve-env", "openstack", "tripleo", "deploy",
|
||||
"--standalone", "--standalone-role", "UndercloudMinion", "--stack",
|
||||
"minion", "-r", roles_file]
|
||||
cmd += deploy_args[:]
|
||||
|
||||
# In dry-run, also report the expected heat stack virtual state/action
|
||||
if dry_run:
|
||||
stack_update_mark = os.path.join(
|
||||
constants.STANDALONE_EPHEMERAL_STACK_VSTATE,
|
||||
'update_mark_minion')
|
||||
if os.path.isfile(stack_update_mark) or force_stack_update:
|
||||
LOG.warning(_('The heat stack minion virtual state/action '
|
||||
' would be UPDATE'))
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def _get_public_tls_parameters(service_certificate_path):
|
||||
with open(service_certificate_path, "rb") as pem_file:
|
||||
pem_data = pem_file.read()
|
||||
cert = x509.load_pem_x509_certificate(pem_data, default_backend())
|
||||
private_key = serialization.load_pem_private_key(
|
||||
pem_data,
|
||||
password=None,
|
||||
backend=default_backend())
|
||||
|
||||
key_pem = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||
encryption_algorithm=serialization.NoEncryption())
|
||||
cert_pem = cert.public_bytes(serialization.Encoding.PEM)
|
||||
return {
|
||||
'SSLCertificate': cert_pem,
|
||||
'SSLKey': key_pem
|
||||
}
|
||||
|
||||
|
||||
def _container_images_config(conf, deploy_args, env_data, tempdir):
|
||||
if conf.container_images_file:
|
||||
deploy_args += ['-e', conf.container_images_file]
|
||||
try:
|
||||
shutil.copy(os.path.abspath(conf.container_images_file), tempdir)
|
||||
except Exception:
|
||||
msg = _('Cannot copy a container images'
|
||||
'file %s into a tempdir!') % conf.container_images_file
|
||||
LOG.error(msg)
|
||||
raise exceptions.DeploymentError(msg)
|
||||
else:
|
||||
# no images file was provided. Set a default ContainerImagePrepare
|
||||
# parameter to trigger the preparation of the required container list
|
||||
cip = kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM
|
||||
env_data['ContainerImagePrepare'] = cip
|
@ -1,162 +0,0 @@
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""Plugin action implementation"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from openstackclient.i18n import _
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from tripleoclient import command
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import utils
|
||||
from tripleoclient.v1 import minion_config
|
||||
|
||||
MINION_FAILURE_MESSAGE = """
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
An error has occured while deploying the Undercloud Minion
|
||||
|
||||
See the previous output for details about what went wrong.
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
"""
|
||||
|
||||
MINION_COMPLETION_MESSAGE = """
|
||||
##########################################################
|
||||
|
||||
The Undercloud Minion has been successfully installed.
|
||||
|
||||
##########################################################
|
||||
"""
|
||||
MINION_UPGRADE_COMPLETION_MESSAGE = """
|
||||
##########################################################
|
||||
|
||||
The Undercloud Minion has been successfully upgraded.
|
||||
|
||||
##########################################################
|
||||
"""
|
||||
|
||||
|
||||
class InstallUndercloudMinion(command.Command):
|
||||
"""Install and setup the undercloud minion"""
|
||||
|
||||
auth_required = False
|
||||
log = logging.getLogger(__name__ + ".InstallUndercloudMinion")
|
||||
osloconfig = cfg.CONF
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = argparse.ArgumentParser(
|
||||
description=self.get_description(),
|
||||
prog=prog_name,
|
||||
add_help=False
|
||||
)
|
||||
parser.add_argument('--force-stack-update',
|
||||
dest='force_stack_update',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Do a virtual update of the ephemeral "
|
||||
"heat stack. New or failed deployments "
|
||||
"always have the stack_action=CREATE. This "
|
||||
"option enforces stack_action=UPDATE."),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--no-validations',
|
||||
dest='no_validations',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Do not perform minion configuration validations"),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--dry-run',
|
||||
dest='dry_run',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Print the install command instead of running it"),
|
||||
)
|
||||
parser.add_argument('-y', '--yes', default=False,
|
||||
action='store_true',
|
||||
help=_("Skip yes/no prompt (assume yes)."))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.warning("[DEPRECATED] This command has been deprecated. "
|
||||
"The minion functionality is no longer as necessary "
|
||||
"with the move to nova-less provisioning.")
|
||||
# Fetch configuration used to add logging to a file
|
||||
utils.load_config(self.osloconfig, constants.MINION_CONF_PATH)
|
||||
utils.configure_logging(self.log, self.app_args.verbose_level,
|
||||
self.osloconfig['minion_log_file'])
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
|
||||
utils.ensure_run_as_normal_user()
|
||||
no_validations = parsed_args.dry_run or parsed_args.no_validations
|
||||
cmd = minion_config.prepare_minion_deploy(
|
||||
no_validations=no_validations,
|
||||
verbose_level=self.app_args.verbose_level,
|
||||
force_stack_update=parsed_args.force_stack_update,
|
||||
dry_run=parsed_args.dry_run)
|
||||
|
||||
self.log.warning("Running: %s" % ' '.join(cmd))
|
||||
if not parsed_args.dry_run:
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
self.log.warning(MINION_COMPLETION_MESSAGE)
|
||||
except Exception as e:
|
||||
self.log.error(MINION_FAILURE_MESSAGE)
|
||||
self.log.error(e)
|
||||
raise exceptions.DeploymentError(e)
|
||||
|
||||
|
||||
class UpgradeUndercloudMinion(InstallUndercloudMinion):
|
||||
"""Upgrade undercloud minion"""
|
||||
|
||||
auth_required = False
|
||||
log = logging.getLogger(__name__ + ".UpgradeUndercloudMinion")
|
||||
osloconfig = cfg.CONF
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.warning("[DEPRECATED] This command has been deprecated. "
|
||||
"The minion functionality is no longer as necessary "
|
||||
"with the move to nova-less provisioning.")
|
||||
# Fetch configuration used to add logging to a file
|
||||
utils.load_config(self.osloconfig, constants.MINION_CONF_PATH)
|
||||
utils.configure_logging(self.log, self.app_args.verbose_level,
|
||||
self.osloconfig['minion_log_file'])
|
||||
self.log.debug("take action(%s)" % parsed_args)
|
||||
|
||||
utils.ensure_run_as_normal_user()
|
||||
cmd = minion_config.\
|
||||
prepare_minion_deploy(
|
||||
upgrade=True,
|
||||
yes=parsed_args.yes,
|
||||
no_validations=parsed_args.
|
||||
no_validations,
|
||||
verbose_level=self.app_args.verbose_level,
|
||||
force_stack_update=parsed_args.force_stack_update)
|
||||
self.log.warning("Running: %s" % ' '.join(cmd))
|
||||
if not parsed_args.dry_run:
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
self.log.warning(MINION_UPGRADE_COMPLETION_MESSAGE)
|
||||
except Exception as e:
|
||||
self.log.error(MINION_FAILURE_MESSAGE)
|
||||
self.log.error(e)
|
||||
raise exceptions.DeploymentError(e)
|
@ -18,16 +18,3 @@
|
||||
- openstack-tox-pep8
|
||||
- openstack-tox-py36
|
||||
- openstack-tox-py37
|
||||
- tripleo-ci-centos-8-containers-undercloud-minion:
|
||||
vars:
|
||||
consumer_job: true
|
||||
build_container_images: false
|
||||
remove_tags:
|
||||
- build
|
||||
dependencies:
|
||||
- tripleo-ci-centos-8-content-provider
|
||||
files:
|
||||
- ^config-generator/.*minion.*$
|
||||
- ^tripleoclient/config/.*minion.*$
|
||||
- ^tripleoclient/v1/.*minion.*$
|
||||
- ^tripleoclient/v1/tripleo_deploy.py$
|
||||
|
Loading…
Reference in New Issue
Block a user