From 52f34c5ca6f43cb5e0da1f93a1e13e5de6e43b53 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) --- 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',