From 9c548de6f0e967d860d4280413dbeaf1d33ab8e5 Mon Sep 17 00:00:00 2001 From: Edward Hope-Morley Date: Mon, 22 May 2023 20:05:29 +0100 Subject: [PATCH] Ensure mgmt network mtu This will ensure that mtu is set whenever setup_hm_port() is called regardless of if the port has just been created or not. Also checks mtu in update-status hook. Change-Id: I80b5cea812becd1724fcfe2a8a232253eac76735 Closes-Bug: #2018998 (cherry picked from commit f326ef267aa3e671b608b823bfcaf938868cba45) (cherry picked from commit 3ebb523f89cda314b52805443fb4782a16888c66) (cherry picked from commit 1fa839826f5009d1cbf8bcc97234afa1fbd5dfb0) (cherry picked from commit 5747bcad9386e30a63e7f2bbb56f81b55979785a) (cherry picked from commit 31cb8fe1eb6df48c1b2a8aa2486a699bc544a96f) (cherry picked from commit 52f34c5ca6f43cb5e0da1f93a1e13e5de6e43b53) (cherry picked from commit 45dad04e0b05e67b4b79515cc8243249b46b359e) --- src/lib/charm/openstack/api_crud.py | 33 +++++++++++++++++++ src/reactive/octavia_handlers.py | 11 +++++++ .../test_lib_charm_openstack_api_crud.py | 27 ++++++++++++--- unit_tests/test_octavia_handlers.py | 2 ++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/lib/charm/openstack/api_crud.py b/src/lib/charm/openstack/api_crud.py index 46caa78d..d313d539 100644 --- a/src/lib/charm/openstack/api_crud.py +++ b/src/lib/charm/openstack/api_crud.py @@ -455,6 +455,35 @@ def wait_for_hm_port_bound(identity_service, local_unit_name): return False +def ensure_hm_port_mtu(identity_service): + """ + Ensure the Octavia health manager port has the same mtu as the network it + is attached to. This is to ensure that of the mtu changes in Neutron it is + reflected here as well. + """ + session = session_from_identity_service(identity_service) + nc = init_neutron_client(session) + resp = nc.list_networks(tags='charm-octavia') + if len(resp['networks']) > 0: + network = resp['networks'][0] + ch_core.hookenv.log('ensuring mgmt network {} mtu={}'. + format(network['id'], network['mtu']), + level=ch_core.hookenv.DEBUG) + try: + subprocess.check_call( + ['ovs-vsctl', 'set', 'Interface', octavia.OCTAVIA_MGMT_INTF, + 'mtu={}'.format(network['mtu'])]) + subprocess.check_call( + ['ip', 'link', 'set', octavia.OCTAVIA_MGMT_INTF, 'mtu', + str(network['mtu'])]) + except subprocess.CalledProcessError as exc: + ch_core.hookenv.log("failed to apply mtu to interface '{}': {}". + format(octavia.OCTAVIA_MGMT_INTF, exc), + level=ch_core.hookenv.DEBUG) + else: + ch_core.hookenv.log('mgmt network not found - cannot set mtu') + + def setup_hm_port(identity_service, octavia_charm, host_id=None): """Create a per unit Neutron and OVS port for Octavia Health Manager. @@ -523,6 +552,10 @@ def setup_hm_port(identity_service, octavia_charm, host_id=None): else: # unknown error, raise raise e + + # NOTE: apply this always to ensure consistency + ensure_hm_port_mtu(identity_service) + if (not hm_port['admin_state_up'] or not is_hm_port_bound(identity_service, octavia_charm.local_unit_name) or diff --git a/src/reactive/octavia_handlers.py b/src/reactive/octavia_handlers.py index 5ce9abce..34f48ade 100644 --- a/src/reactive/octavia_handlers.py +++ b/src/reactive/octavia_handlers.py @@ -124,6 +124,17 @@ def setup_neutron_lbaas_proxy(): neutron.publish_load_balancer_info('octavia', octavia_url) +@reactive.when('is-update-status-hook', 'octavia.hm-port.available') +def ensure_hm_port_mtu(): + try: + identity_service = reactive.endpoint_from_flag( + 'identity-service.available') + api_crud.ensure_hm_port_mtu(identity_service) + except Exception: + ch_core.hookenv.log('failed to ensure health manager port mtu', + level=ch_core.hookenv.DEBUG) + + @reactive.when('config.default.enable-amphora', 'charm.octavia.action_setup_hm_port') def action_setup_hm_port(): diff --git a/unit_tests/test_lib_charm_openstack_api_crud.py b/unit_tests/test_lib_charm_openstack_api_crud.py index 7912f956..96bd3655 100644 --- a/unit_tests/test_lib_charm_openstack_api_crud.py +++ b/unit_tests/test_lib_charm_openstack_api_crud.py @@ -282,6 +282,14 @@ class TestAPICrud(test_utils.PatchHelper): 'ids', 'fake-unit-name')) def test_setup_hm_port(self): + self.patch_object(api_crud, 'session_from_identity_service') + self.patch_object(api_crud, 'init_neutron_client') + nc = mock.MagicMock() + self.init_neutron_client.return_value = nc + network_uuid = 'fake-network-uuid' + nc.list_networks.return_value = {'networks': [{'id': network_uuid, + 'mtu': 9000}]} + self.patch('subprocess.check_output', 'check_output') self.patch('subprocess.check_call', 'check_call') self.patch_object(api_crud, 'get_hm_port') @@ -328,10 +336,21 @@ class TestAPICrud(test_utils.PatchHelper): mock.call(['ip', 'link', 'set', 'o-hm0', 'up', 'address', 'fake-mac-address']), ]) - self.check_call.assert_called_with( - ['ip', 'link', 'set', api_crud.octavia.OCTAVIA_MGMT_INTF, - 'up', 'address', port_mac_address]) - self.toggle_hm_port.assert_called + self.check_call.assert_has_calls([ + mock.call(['ovs-vsctl', '--', 'add-port', 'br-int', 'o-hm0', '--', + 'set', 'Interface', 'o-hm0', 'type=internal', '--', + 'set', 'Interface', 'o-hm0', + 'external-ids:iface-status=active', + '--', 'set', 'Interface', 'o-hm0', + 'external-ids:attached-mac=fake-mac-address', '--', + 'set', 'Interface', 'o-hm0', + 'external-ids:iface-id=fake-port-uuid', + '--', 'set', 'Interface', 'o-hm0', + 'external-ids:skip_cleanup=true']), + mock.call(['ip', 'link', 'set', 'o-hm0', 'up', 'address', + 'fake-mac-address']), + mock.call(['ovs-vsctl', 'set', 'Interface', 'o-hm0', 'mtu=9000']), + mock.call(['ip', 'link', 'set', 'o-hm0', 'mtu', '9000'])]) def test_get_port_ips(self): self.patch_object(api_crud, 'session_from_identity_service') diff --git a/unit_tests/test_octavia_handlers.py b/unit_tests/test_octavia_handlers.py index 4f0f78bd..f5677d7d 100644 --- a/unit_tests/test_octavia_handlers.py +++ b/unit_tests/test_octavia_handlers.py @@ -36,6 +36,8 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks): ] hook_set = { 'when': { + 'ensure_hm_port_mtu': ('is-update-status-hook', + 'octavia.hm-port.available'), 'render': ('shared-db.available', 'identity-service.available', 'amqp.available',