From 812383a42918c612b829c54941caa27118a224a0 Mon Sep 17 00:00:00 2001 From: ramishra Date: Thu, 22 Apr 2021 14:40:08 +0530 Subject: [PATCH] Delete service_vips before deleting stack We create some ports for service vips as part of deploy steps. Heat network/subnet resources can't be deleted without deleting those. Change-Id: I101ae36816e03846245277901084fabb39425a93 --- .ansible-lint | 1 + .../modules/tripleo_service_vip.py | 59 +++++++++++++++---- .../playbooks/cli-overcloud-delete.yaml | 4 ++ .../tests/modules/test_tripleo_service_vip.py | 28 +++++++++ 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/.ansible-lint b/.ansible-lint index ef2964ddb..bec4bd7ac 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -60,6 +60,7 @@ mock_modules: - tripleo_passwords_rotate - tripleo_plan_deploy - tripleo_plan_parameters_update + - tripleo_service_vip - tripleo_swift_tempurl - tripleo_templates_upload - tripleo_unmanaged_populate_environment diff --git a/tripleo_ansible/ansible_plugins/modules/tripleo_service_vip.py b/tripleo_ansible/ansible_plugins/modules/tripleo_service_vip.py index 96c9991c2..a14ab2641 100644 --- a/tripleo_ansible/ansible_plugins/modules/tripleo_service_vip.py +++ b/tripleo_ansible/ansible_plugins/modules/tripleo_service_vip.py @@ -61,6 +61,14 @@ options: description: - Name of the service the Virtual IP is intended for type: str + state: + description: + - The desired provision state, "present" to provision, "absent" to + unprovision + default: present + choices: + - present + - absent network: description: - Neutron network where the Virtual IP port will be created @@ -93,7 +101,7 @@ RETURN = ''' EXAMPLES = ''' - name: Create redis Virtual IP - tripleo_service_vip_port: + tripleo_service_vip: stack_name: overcloud service_name: redis network: internal_api @@ -101,7 +109,7 @@ EXAMPLES = ''' - subnet: internal_api_subnet register: redis_vip - name: Create foo Virtual IP (Not creating a neutron port) - tripleo_service_vip_port: + tripleo_service_vip: stack_name: overcloud service_name: foo network: foo @@ -150,7 +158,7 @@ def create_or_update_port(conn, net, stack=None, service=None, '{}. Service {} is mapped to a subnet that ' 'does not exist. Verify that the VipSubnetMap ' 'parameter has the correct values.'.format( - subnet_name, net.name, service)) + subnet_name, net.name, service)) ip_def['subnet_id'] = subnet.id fixed_ips_def.append(ip_def) @@ -248,6 +256,30 @@ def _openstack_cloud_from_module(module): return _, conn +def delete_service_vip(module, stack, service='all'): + try: + _, conn = _openstack_cloud_from_module(module) + _use_neutron = conn.identity.find_service('neutron') is not None + except kauth1_exc.MissingRequiredOptions: + return + if not _use_neutron: + return + if service == 'all': + tags = {'tripleo_stack_name={}'.format(stack)} + ports = conn.network.ports(tags=list(tags)) + matching = [p for p in ports + if any("tripleo_service_vip" in tag for tag in p.tags)] + else: + tags = {'tripleo_stack_name={}'.format(stack), + 'tripleo_service_vip={}'.format(service)} + matching = conn.network.ports(tags=list(tags)) + for p in matching: + try: + conn.network.delete_port(p.id) + except Exception: + pass + + def create_service_vip(module, stack, service, network, fixed_ips, playbook_dir): _use_neutron = True @@ -289,22 +321,27 @@ def run_module(): ) stack = module.params.get('stack_name', 'overcloud') - service = module.params['service_name'] - network = module.params['network'] - fixed_ips = module.params.get('fixed_ips', []) - playbook_dir = module.params['playbook_dir'] + service = module.params.get('service_name', 'all') + state = module.params.get('state', 'present') try: - create_service_vip(module, stack, service, network, fixed_ips, - playbook_dir) + if state == 'present' and service == 'all': + raise Exception("Provide service_name for service_vip creation.") + if state == 'absent': + delete_service_vip(module, stack, service) + else: + network = module.params['network'] + fixed_ips = module.params.get('fixed_ips', []) + playbook_dir = module.params['playbook_dir'] + create_service_vip(module, stack, service, network, fixed_ips, + playbook_dir) result['changed'] = True result['success'] = True module.exit_json(**result) - except Exception as err: result['error'] = str(err) - result['msg'] = ('ERROR: Failed creating service virtual IP!' + result['msg'] = ('ERROR: Failed creating/deleting service virtual IP!' ' {}'.format(err)) module.fail_json(**result) diff --git a/tripleo_ansible/playbooks/cli-overcloud-delete.yaml b/tripleo_ansible/playbooks/cli-overcloud-delete.yaml index ec4cfa276..a8a02afe6 100644 --- a/tripleo_ansible/playbooks/cli-overcloud-delete.yaml +++ b/tripleo_ansible/playbooks/cli-overcloud-delete.yaml @@ -30,6 +30,10 @@ loop: - stack_name tasks: + - name: Delete service vips used + tripleo_service_vip: + stack_name: "{{ stack_name }}" + state: absent - name: Delete heat stack os_stack: name: "{{ stack_name }}" diff --git a/tripleo_ansible/tests/modules/test_tripleo_service_vip.py b/tripleo_ansible/tests/modules/test_tripleo_service_vip.py index 10e3703af..ced92b557 100644 --- a/tripleo_ansible/tests/modules/test_tripleo_service_vip.py +++ b/tripleo_ansible/tests/modules/test_tripleo_service_vip.py @@ -156,6 +156,34 @@ class TestTripleoServiceVip(tests_base.TestCase): 'network', fixed_ips) mock_write_file.assert_called_with(mock_port, 'service', '/tmp/dir') + @mock.patch.object(openstack.connection, 'Connection', autospec=True) + @mock.patch.object(plugin, '_openstack_cloud_from_module', autospec=True) + def test_delete_service_vip(self, mock_ocfm, mock_conn): + module = mock.Mock() + mock_ocfm.return_value = None, mock_conn + mock_conn.identity.find_service.return_value = True + mock_port1 = mock.Mock(id=123, + tags=['tripleo_stack_name=overcloud', + 'tripleo_service_vip=ovn_dbs']) + mock_port2 = mock.Mock(id=456, tags=[]) + mock_conn.network.ports.return_value = [mock_port1, mock_port2] + plugin.delete_service_vip(module, 'overcloud') + mock_conn.network.delete_port.assert_called_with(123) + self.assertEqual(1, mock_conn.network.delete_port.call_count) + + @mock.patch.object(openstack.connection, 'Connection', autospec=True) + @mock.patch.object(plugin, '_openstack_cloud_from_module', autospec=True) + def test_delete_service_vip_with_service(self, mock_ocfm, mock_conn): + module = mock.Mock() + mock_ocfm.return_value = None, mock_conn + mock_conn.identity.find_service.return_value = True + mock_port = mock.Mock(id=123, + tags=['tripleo_stack_name=overcloud', + 'tripleo_service_vip=redis']) + mock_conn.network.ports.return_value = [mock_port] + plugin.delete_service_vip(module, 'overcloud', 'redis') + mock_conn.network.delete_port.assert_called_with(123) + @mock.patch.object(plugin, 'write_vars_file', autospec=True) @mock.patch.object(plugin, 'use_fake', autospec=True) @mock.patch.object(openstack.connection, 'Connection', autospec=True)