overcloud deploy - provision virtual ips

When the --vip-file argument provides the vip_data.yaml
provision Virtual IPs and include the deployed network
environment file in user environments.

Depends-On: https://review.opendev.org/795080
Change-Id: I1e4f8dde9f56311bed8dcbe1b08ade09225fd595
This commit is contained in:
Harald Jensås 2021-05-27 12:41:40 +02:00
parent 15f2539428
commit ef077696a0
5 changed files with 133 additions and 20 deletions

View File

@ -30,6 +30,7 @@ UNDERCLOUD_ROLES_FILE = "roles_data_undercloud.yaml"
STANDALONE_EPHEMERAL_STACK_VSTATE = '/var/lib/tripleo-heat-installer' STANDALONE_EPHEMERAL_STACK_VSTATE = '/var/lib/tripleo-heat-installer'
UNDERCLOUD_LOG_FILE = "install-undercloud.log" UNDERCLOUD_LOG_FILE = "install-undercloud.log"
OVERCLOUD_NETWORKS_FILE = "network_data.yaml" OVERCLOUD_NETWORKS_FILE = "network_data.yaml"
OVERCLOUD_VIP_FILE = "vip_data_default.yaml"
STANDALONE_NETWORKS_FILE = "/dev/null" STANDALONE_NETWORKS_FILE = "/dev/null"
UNDERCLOUD_NETWORKS_FILE = "network_data_undercloud.yaml" UNDERCLOUD_NETWORKS_FILE = "network_data_undercloud.yaml"
ANSIBLE_HOSTS_FILENAME = "hosts.yaml" ANSIBLE_HOSTS_FILENAME = "hosts.yaml"

View File

@ -110,6 +110,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
os.unlink(self.parameter_defaults_env_file) os.unlink(self.parameter_defaults_env_file)
shutil.rmtree = self.real_shutil shutil.rmtree = self.real_shutil
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_virtual_ips', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_networks', autospec=True) '_provision_networks', autospec=True)
@mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service') @mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service')
@ -156,7 +158,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_container_prepare, mock_generate_password, mock_container_prepare, mock_generate_password,
mock_rc_params, mock_default_image_params, mock_rc_params, mock_default_image_params,
mock_stack_data, mock_check_service_vip_migr, mock_stack_data, mock_check_service_vip_migr,
mock_provision_networks): mock_provision_networks, mock_provision_virtual_ips):
fixture = deployment.DeploymentWorkflowFixture() fixture = deployment.DeploymentWorkflowFixture()
self.useFixture(fixture) self.useFixture(fixture)
clients = self.app.client_manager clients = self.app.client_manager
@ -340,6 +342,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_validate_args.assert_called_once_with(parsed_args) mock_validate_args.assert_called_once_with(parsed_args)
self.assertFalse(mock_invoke_plan_env_wf.called) self.assertFalse(mock_invoke_plan_env_wf.called)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_virtual_ips', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_networks', autospec=True) '_provision_networks', autospec=True)
@mock.patch('tripleoclient.utils.build_stack_data', autospec=True) @mock.patch('tripleoclient.utils.build_stack_data', autospec=True)
@ -382,7 +386,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_process_env, mock_roles_data, mock_process_env, mock_roles_data,
mock_image_prepare, mock_generate_password, mock_image_prepare, mock_generate_password,
mock_rc_params, mock_stack_data, mock_rc_params, mock_stack_data,
mock_provision_networks): mock_provision_networks, mock_provision_virtual_ips):
fixture = deployment.DeploymentWorkflowFixture() fixture = deployment.DeploymentWorkflowFixture()
self.useFixture(fixture) self.useFixture(fixture)
utils_fixture = deployment.UtilsFixture() utils_fixture = deployment.UtilsFixture()
@ -431,6 +435,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
mock_copy.assert_called_once() mock_copy.assert_called_once()
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_virtual_ips', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_networks', autospec=True) '_provision_networks', autospec=True)
@mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service') @mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service')
@ -476,7 +482,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_rc_params, mock_rc_params,
mock_stack_data, mock_stack_data,
mock_check_service_vip_migr, mock_check_service_vip_migr,
mock_provision_networks): mock_provision_networks,
mock_provision_virtual_ips):
fixture = deployment.DeploymentWorkflowFixture() fixture = deployment.DeploymentWorkflowFixture()
self.useFixture(fixture) self.useFixture(fixture)
utils_fixture = deployment.UtilsFixture() utils_fixture = deployment.UtilsFixture()
@ -758,6 +765,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertFalse(utils_fixture.mock_deploy_tht.called) self.assertFalse(utils_fixture.mock_deploy_tht.called)
self.assertFalse(mock_deploy.called) self.assertFalse(mock_deploy.called)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_virtual_ips', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_networks', autospec=True) '_provision_networks', autospec=True)
@mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service') @mock.patch('tripleoclient.utils.check_service_vips_migrated_to_service')
@ -788,7 +797,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_roles_data, mock_image_prepare, mock_roles_data, mock_image_prepare,
mock_generate_password, mock_rc_params, mock_generate_password, mock_rc_params,
mock_check_service_vip_migr, mock_check_service_vip_migr,
mock_provision_networks): mock_provision_networks, mock_provision_virtual_ips):
fixture = deployment.DeploymentWorkflowFixture() fixture = deployment.DeploymentWorkflowFixture()
self.useFixture(fixture) self.useFixture(fixture)
clients = self.app.client_manager clients = self.app.client_manager
@ -865,6 +874,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
output_dir=self.cmd.working_dir) output_dir=self.cmd.working_dir)
mock_copy.assert_called_once() mock_copy.assert_called_once()
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_virtual_ips', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_provision_networks', autospec=True) '_provision_networks', autospec=True)
@mock.patch('tripleoclient.utils.build_stack_data', autospec=True) @mock.patch('tripleoclient.utils.build_stack_data', autospec=True)
@ -917,7 +928,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_rc_params, mock_rc_params,
mock_default_image_params, mock_default_image_params,
mock_stack_data, mock_stack_data,
mock_provision_networks): mock_provision_networks,
mock_provision_virtual_ips):
fixture = deployment.DeploymentWorkflowFixture() fixture = deployment.DeploymentWorkflowFixture()
self.useFixture(fixture) self.useFixture(fixture)
utils_fixture = deployment.UtilsFixture() utils_fixture = deployment.UtilsFixture()
@ -1553,6 +1565,47 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
verbosity=3, verbosity=3,
workdir=mock.ANY) workdir=mock.ANY)
def test__provision_virtual_ips(self):
networks_file_path = self.tmp_dir.join('networks.yaml')
network_data = [
{'name': 'Network', 'name_lower': 'network', 'subnets': {}}
]
with open(networks_file_path, 'w') as temp_file:
yaml.safe_dump(network_data, temp_file)
vips_file_path = self.tmp_dir.join('virtual_ips.yaml')
vip_data = [
{'network': 'internal_api', 'subnet': 'internal_api_subnet'}
]
with open(vips_file_path, 'w') as temp_file:
yaml.safe_dump(vip_data, temp_file)
stack_name = 'overcloud'
arglist = ['--stack', stack_name,
'--vip-file', vips_file_path,
'--networks-file', networks_file_path]
verifylist = [('stack', stack_name),
('vip_file', vips_file_path),
('networks_file', networks_file_path)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
tht_root = self.tmp_dir.join('tht')
env_dir = os.path.join(tht_root, 'user-environments')
env_path = os.path.join(env_dir, 'virtual-ips-deployed.yaml')
os.makedirs(env_dir)
result = self.cmd._provision_virtual_ips(parsed_args, tht_root)
self.assertEqual([env_path], result)
self.mock_playbook.assert_called_once_with(
extra_vars={'stack_name': stack_name,
'vip_data_path': vips_file_path,
'vip_deployed_path': env_path,
'overwrite': True},
inventory='localhost,',
playbook='cli-overcloud-network-vip-provision.yaml',
playbook_dir='/usr/share/ansible/tripleo-playbooks',
verbosity=3,
workdir=mock.ANY)
def test_check_limit_warning(self): def test_check_limit_warning(self):
mock_warning = mock.MagicMock() mock_warning = mock.MagicMock()
mock_log = mock.MagicMock() mock_log = mock.MagicMock()

View File

@ -1704,6 +1704,12 @@ def get_networks_file_path(networks_file, tht_root):
return os.path.abspath(networks_file) return os.path.abspath(networks_file)
def get_vip_file_path(vip_file, tht_root):
vip_file = vip_file or os.path.join(
tht_root, constants.OVERCLOUD_VIP_FILE)
return os.path.abspath(vip_file)
def build_stack_data(clients, stack_name, template, def build_stack_data(clients, stack_name, template,
files, env_files): files, env_files):
orchestration_client = clients.orchestration orchestration_client = clients.orchestration
@ -2789,3 +2795,21 @@ def copy_env_files(files_dict, tht_root):
relocate_path = os.path.join(tht_root, "user-environments", relocate_path = os.path.join(tht_root, "user-environments",
os.path.basename(path)) os.path.basename(path))
safe_write(relocate_path, files_dict[full_path]) safe_write(relocate_path, files_dict[full_path])
def is_network_data_v2(networks_file_path):
"""Parse the network data, if any network have 'ip_subnet' or
'ipv6_subnet' keys this is not a network-v2 format file.
:param networks_file_path:
:return: boolean
"""
with open(networks_file_path, 'r') as f:
network_data = yaml.safe_load(f.read())
if isinstance(network_data, list):
for network in network_data:
if 'ip_subnet' in network or 'ipv6_subnet' in network:
return False
return True

View File

@ -89,8 +89,8 @@ def _validate_args(parsed_args):
not_found = [x for x in [parsed_args.networks_file, not_found = [x for x in [parsed_args.networks_file,
parsed_args.plan_environment_file, parsed_args.plan_environment_file,
parsed_args.plan_environment_file, parsed_args.answers_file,
parsed_args.answers_file] parsed_args.vip_file]
if x and not os.path.isfile(x)] if x and not os.path.isfile(x)]
jinja2_envs = [] jinja2_envs = []
@ -118,6 +118,16 @@ def _validate_args(parsed_args):
"mean {}?".format(' -e '.join(jinja2_envs), "mean {}?".format(' -e '.join(jinja2_envs),
' -e '.join(rewritten_paths))) ' -e '.join(rewritten_paths)))
if parsed_args.vip_file:
# Check vip_file only used with network data v2
networks_file_path = utils.get_networks_file_path(
parsed_args.networks_file, parsed_args.templates)
if not utils.is_network_data_v2(networks_file_path):
raise exceptions.CommandError(
'The --vip-file option can only be used in combination with a '
'network data v2 format networks file. The provided file {} '
'is network data v1 format'.format(networks_file_path))
class DeployOvercloud(command.Command): class DeployOvercloud(command.Command):
"""Deploy Overcloud""" """Deploy Overcloud"""
@ -274,6 +284,8 @@ class DeployOvercloud(command.Command):
created_env_files.extend( created_env_files.extend(
self._provision_networks(parsed_args, new_tht_root)) self._provision_networks(parsed_args, new_tht_root))
created_env_files.extend(
self._provision_virtual_ips(parsed_args, new_tht_root))
created_env_files.extend( created_env_files.extend(
self._provision_baremetal(parsed_args, new_tht_root)) self._provision_baremetal(parsed_args, new_tht_root))
@ -472,24 +484,13 @@ class DeployOvercloud(command.Command):
} }
) )
@staticmethod
def _is_network_data_v2(networks_file_path):
with open(networks_file_path, 'r') as f:
network_data = yaml.safe_load(f.read())
for network in network_data:
if 'ip_subnet' in network or 'ipv6_subnet' in network:
return False
return True
def _provision_networks(self, parsed_args, tht_root): def _provision_networks(self, parsed_args, tht_root):
# Parse the network data, if any network have 'ip_subnet' or # Parse the network data, if any network have 'ip_subnet' or
# 'ipv6_subnet' keys this is not a network-v2 format file. In this # 'ipv6_subnet' keys this is not a network-v2 format file. In this
# case do nothing. # case do nothing.
networks_file_path = utils.get_networks_file_path( networks_file_path = utils.get_networks_file_path(
parsed_args.networks_file, parsed_args.templates) parsed_args.networks_file, parsed_args.templates)
if not utils.is_network_data_v2(networks_file_path):
if not self._is_network_data_v2(networks_file_path):
return [] return []
output_path = utils.build_user_env_path( output_path = utils.build_user_env_path(
@ -513,6 +514,37 @@ class DeployOvercloud(command.Command):
return [output_path] return [output_path]
def _provision_virtual_ips(self, parsed_args, tht_root):
networks_file_path = utils.get_networks_file_path(
parsed_args.networks_file, parsed_args.templates)
if not utils.is_network_data_v2(networks_file_path):
return []
vip_file_path = utils.get_vip_file_path(parsed_args.vip_file,
parsed_args.templates)
output_path = utils.build_user_env_path(
'virtual-ips-deployed.yaml',
tht_root)
extra_vars = {
"stack_name": parsed_args.stack,
"vip_data_path": vip_file_path,
"vip_deployed_path": output_path,
"overwrite": True,
}
with utils.TempDirs() as tmp:
utils.run_ansible_playbook(
playbook='cli-overcloud-network-vip-provision.yaml',
inventory='localhost,',
workdir=tmp,
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
verbosity=utils.playbook_verbosity(self=self),
extra_vars=extra_vars,
)
return [output_path]
def setup_ephemeral_heat(self, parsed_args): def setup_ephemeral_heat(self, parsed_args):
self.log.info("Using ephemeral heat for stack operation") self.log.info("Using ephemeral heat for stack operation")
restore_db = (parsed_args.setup_only or restore_db = (parsed_args.setup_only or
@ -613,6 +645,9 @@ class DeployOvercloud(command.Command):
help=_('Networks file, overrides the default %s in the ' help=_('Networks file, overrides the default %s in the '
'--templates directory') % constants.OVERCLOUD_NETWORKS_FILE '--templates directory') % constants.OVERCLOUD_NETWORKS_FILE
) )
parser.add_argument(
'--vip-file', dest='vip_file',
help=_('Configuration file describing the network Virtual IPs.'))
parser.add_argument( parser.add_argument(
'--plan-environment-file', '-p', '--plan-environment-file', '-p',
help=_('Plan Environment file for derived parameters.') help=_('Plan Environment file for derived parameters.')

View File

@ -201,7 +201,7 @@ class OvercloudVirtualIPsProvision(command.Command):
parser.add_argument('vip_file', parser.add_argument('vip_file',
metavar='<vip_data.yaml>', metavar='<vip_data.yaml>',
help=_('Configuration file describing the network ' help=_('Configuration file describing the network '
'deployment.')) 'Virtual IPs.'))
parser.add_argument('--stack', dest='stack', required=True, parser.add_argument('--stack', dest='stack', required=True,
help=_('Name of heat stack ' help=_('Name of heat stack '
'(default=Env: OVERCLOUD_STACK_NAME)'), '(default=Env: OVERCLOUD_STACK_NAME)'),