diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index d64331720fcb85cccc829f58d6d3d8b437e55b77..8b67404d87f4c8efe00c60f9a97a43897894100e 100644 --- a/gso/workflows/iptrunk/modify_trunk_interface.py +++ b/gso/workflows/iptrunk/modify_trunk_interface.py @@ -34,6 +34,8 @@ from gso.utils.helpers import ( validate_tt_number, ) from gso.utils.shared_enums import IPv4AddressType, IPv6AddressType, Vendor +from gso.workflows.iptrunk.migrate_iptrunk import check_ip_trunk_optical_levels_pre +from gso.workflows.iptrunk.validate_iptrunk import check_ip_trunk_isis T = TypeVar("T", bound=LAGMember) @@ -175,6 +177,69 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ) +@step("Determine whether we should be running interface checks") +def determine_change_in_capacity( + subscription: Iptrunk, iptrunk_speed: str, side_a_ae_members: list[LAGMember], side_b_ae_members: list[LAGMember] +) -> State: + """Determine whether we should run pre- and post-checks on the IP trunk. + + This can be caused by the following conditions: + * The total capacity of the trunk changes + * The amount of interfaces changes + * One or more interface names have changed on side A + * One or more interface names have changed on side B + """ + capacity_has_changed = ( + iptrunk_speed != subscription.iptrunk.iptrunk_speed + or len(side_a_ae_members) != len(subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members) + or any( + old_interface.interface_name != new_interface.interface_name + for old_interface, new_interface in zip( + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members, side_a_ae_members, strict=False + ) + ) + or any( + old_interface.interface_name != new_interface.interface_name + for old_interface, new_interface in zip( + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members, side_b_ae_members, strict=False + ) + ) + ) + + return {"capacity_has_changed": capacity_has_changed} + + +@step("Check IP connectivity of the trunk") +def check_ip_trunk_connectivity(subscription: Iptrunk, callback_route: str) -> State: + """Check successful connectivity across a trunk.""" + extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "ping"} + + execute_playbook( + playbook_name="iptrunks_checks.yaml", + callback_route=callback_route, + inventory=subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn, + extra_vars=extra_vars, + ) + + return {"subscription": subscription} + + +@step("Check LLDP on the trunk endpoints") +def check_ip_trunk_lldp(subscription: Iptrunk, callback_route: str) -> State: + """Check LLDP on trunk endpoints.""" + extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "lldp"} + + execute_playbook( + playbook_name="iptrunks_checks.yaml", + callback_route=callback_route, + inventory=f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}\n" + f"{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}\n", + extra_vars=extra_vars, + ) + + return {"subscription": subscription} + + @step("Update subscription") def modify_iptrunk_subscription( subscription: Iptrunk, @@ -422,10 +487,17 @@ def modify_trunk_interface() -> StepList: ) == Vendor.NOKIA ) + capacity_has_changed = conditional(lambda state: state["capacity_has_changed"]) + return ( begin >> store_process_subscription(Target.MODIFY) >> unsync + >> determine_change_in_capacity + >> capacity_has_changed(lso_interaction(check_ip_trunk_optical_levels_pre)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_connectivity)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_lldp)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_isis)) >> modify_iptrunk_subscription >> side_a_is_nokia(netbox_update_interfaces_side_a) >> side_b_is_nokia(netbox_update_interfaces_side_b) @@ -433,6 +505,10 @@ def modify_trunk_interface() -> StepList: >> lso_interaction(provision_ip_trunk_iface_real) >> side_a_is_nokia(allocate_interfaces_in_netbox_side_a) >> side_b_is_nokia(allocate_interfaces_in_netbox_side_b) + >> capacity_has_changed(lso_interaction(check_ip_trunk_optical_levels_pre)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_connectivity)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_lldp)) + >> capacity_has_changed(lso_interaction(check_ip_trunk_isis)) >> resync >> done ) diff --git a/test/workflows/iptrunk/test_modify_trunk_interface.py b/test/workflows/iptrunk/test_modify_trunk_interface.py index 2a95cc90fc6428dd19c7e9a2b0a0f77a58ef3a2b..1383ea2edc1380613900ae62b0024b4622ac6d57 100644 --- a/test/workflows/iptrunk/test_modify_trunk_interface.py +++ b/test/workflows/iptrunk/test_modify_trunk_interface.py @@ -90,7 +90,7 @@ def input_form_iptrunk_data( indirect=True, ) @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.modify_trunk_interface.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces") @patch("gso.services.netbox_client.NetboxClient.attach_interface_to_lag") @patch("gso.services.netbox_client.NetboxClient.reserve_interface") @@ -120,8 +120,10 @@ def test_iptrunk_modify_trunk_interface_success( # Run workflow result, process_stat, step_log = run_workflow("modify_trunk_interface", input_form_iptrunk_data) + state = extract_state(result) + lso_interaction_count = 10 if state["capacity_has_changed"] else 2 - for _ in range(2): + for _ in range(lso_interaction_count): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) assert_complete(result) @@ -131,7 +133,7 @@ def test_iptrunk_modify_trunk_interface_success( subscription = Iptrunk.from_subscription(subscription_id) assert subscription.status == "active" - assert mock_provision_ip_trunk.call_count == 2 + assert mock_provision_ip_trunk.call_count == lso_interaction_count # Assert all Netbox calls have been made new_sid = input_form_iptrunk_data[1]["geant_s_sid"] new_side_a_sid = input_form_iptrunk_data[3]["side_a_ae_geant_a_sid"]