diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e54ad156d4279d0bba424c9ee36aeff2548dc19..0ed900004f54ad77ce3c2cf9a1a327e498f54e83 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,7 @@ run-tox-pipeline: sonarqube: stage: sonarqube - image: sonarsource/sonar-scanner-cli + image: sonarsource/sonar-scanner-cli:10.0 script: - sonar-scanner -Dsonar.login=$SONAR_TOKEN -Dproject.settings=./sonar.properties tags: diff --git a/Changelog.md b/Changelog.md index cead4f9864c1a03b5ad75134e9d577931ebd4bc6..2df8db9ae19a869f38b9012ab4ad6d9b343f7bd6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,19 @@ # Changelog + +## [2.18] - 2024-10-01 +- Use solo pool for Celery workers + +## [2.17] - 2024-09-30 +- NOTHING IS HERE (JENKINS ISSUE) + +## [2.16] - 2024-09-30 +- NOTHING IS HERE (JENKINS ISSUE) + +## [2.15] - 2024-09-30 +- Show current license usage when updating Kentik license of a router +- Fix the bug of clearing all the AE members and creating new objects instead of updating it. +- make orchestrator-core==2.7.5 + ## [2.14] - 2024-09-19 - Fixes to Infoblox client. diff --git a/gso/utils/workflow_steps.py b/gso/utils/workflow_steps.py index a67558c4fc3f73d2096c51e394b8f111fb1fa282..a595bbc00b0176fcdbec51d29749d54d412f2f1d 100644 --- a/gso/utils/workflow_steps.py +++ b/gso/utils/workflow_steps.py @@ -1,6 +1,7 @@ """Workflow steps that are shared across multiple workflows.""" import json +from operator import inv from typing import Any from orchestrator import inputstep, step @@ -14,7 +15,7 @@ from pydantic_forms.validators import Label from gso.products.product_blocks.router import RouterRole from gso.products.product_types.iptrunk import Iptrunk -from gso.services import lso_client +from gso.services.lso_client import LSOState from gso.settings import load_oss_params from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.shared_enums import Vendor @@ -23,13 +24,10 @@ from gso.utils.shared_enums import Vendor def _deploy_base_config( subscription: dict[str, Any], tt_number: str, - callback_route: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: - inventory = subscription["router"]["router_fqdn"] - +) -> LSOState: extra_vars = { "wfo_router_json": subscription, "dry_run": dry_run, @@ -37,27 +35,23 @@ def _deploy_base_config( "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy base config", } - lso_client.execute_playbook( - playbook_name="base_config.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "base_config.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } def _update_sdp_mesh( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: +) -> LSOState: inventory = generate_inventory_for_active_routers( router_role=RouterRole.PE, router_vendor=Vendor.NOKIA, exclude_routers=[subscription["router"]["router_fqdn"]] ) - if len(inventory["all"]["hosts"].keys()) == 0: - return # Skip this Ansible interaction if the inventory is empty. extra_vars = { "dry_run": dry_run, @@ -73,23 +67,20 @@ def _update_sdp_mesh( }, } - lso_client.execute_playbook( - playbook_name="update_pe_sdp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_pe_sdp_mesh.yaml", + "inventory": inventory, + "extra_vars": extra_vars, + } def _update_sdp_single_pe( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: - inventory = subscription["router"]["router_fqdn"] +) -> LSOState: extra_vars = { "dry_run": dry_run, "subscription": subscription, @@ -103,23 +94,20 @@ def _update_sdp_single_pe( )["all"]["hosts"], } - lso_client.execute_playbook( - playbook_name="update_pe_sdp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_pe_sdp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } def _add_pe_mesh_to_pe( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: - inventory = subscription["router"]["router_fqdn"] +) -> LSOState: extra_vars = { "dry_run": dry_run, "subscription": subscription, @@ -131,22 +119,20 @@ def _add_pe_mesh_to_pe( )["all"]["hosts"], } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } def _add_pe_to_pe_mesh( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: +) -> LSOState: inventory = generate_inventory_for_active_routers( router_role=RouterRole.PE, exclude_routers=[subscription["router"]["router_fqdn"]] ) @@ -158,23 +144,20 @@ def _add_pe_to_pe_mesh( "verb": "add_pe_to_pe_mesh", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": inventory, + "extra_vars": extra_vars, + } def _add_all_p_to_pe( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: - inventory = subscription["router"]["router_fqdn"] +) -> LSOState: extra_vars = { "dry_run": dry_run, "subscription": subscription, @@ -185,22 +168,20 @@ def _add_all_p_to_pe( )["all"]["hosts"], } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } def _add_pe_to_all_p( subscription: dict[str, Any], - callback_route: str, tt_number: str, process_id: UUIDstr, *, dry_run: bool, -) -> None: +) -> LSOState: inventory = generate_inventory_for_active_routers( router_role=RouterRole.P, exclude_routers=[subscription["router"]["router_fqdn"]] ) @@ -212,258 +193,99 @@ def _add_pe_to_all_p( "verb": "add_pe_to_all_p", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=inventory, - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": inventory, + "extra_vars": extra_vars, + } + + +@step("[DRY RUN] Deploy base config") +def deploy_base_config_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: + """Perform a dry run of provisioning base config on a router.""" + return _deploy_base_config(subscription, tt_number, process_id, dry_run=True) + + +@step("[FOR REAL] Deploy base config") +def deploy_base_config_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: + """Deploy base config on a router using the provisioning proxy.""" + return _deploy_base_config(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Add the PE to all P routers") -def add_pe_to_all_p_dry( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_pe_to_all_p_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of adding the PE router to all P routers.""" - _add_pe_to_all_p( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _add_pe_to_all_p(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Add the PE to all P routers") -def add_pe_to_all_p_real( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_pe_to_all_p_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a real run of adding the PE router to all P routers.""" - _add_pe_to_all_p( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} + return _add_pe_to_all_p(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Add all P routers to the PE") -def add_all_p_to_pe_dry( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_all_p_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of adding all P routers to the PE router.""" - _add_all_p_to_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _add_all_p_to_pe(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Add all P routers to the PE") -def add_all_p_to_pe_real( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_all_p_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a real run of adding all P routers to the PE router.""" - _add_all_p_to_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} + return _add_all_p_to_pe(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Add the PE to PE mesh") -def add_pe_to_pe_mesh_dry( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of adding the PE router to all PE routers in iGEANT/iGEANT6.""" - _add_pe_to_pe_mesh( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _add_pe_to_pe_mesh(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Add the PE to PE mesh") -def add_pe_to_pe_mesh_real( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: - """Perform a dry run of adding the PE router to all PE routers in iGEANT/iGEANT6.""" - _add_pe_to_pe_mesh( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} +def add_pe_to_pe_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: + """Perform a real run of adding the PE router to all PE routers in iGEANT/iGEANT6.""" + return _add_pe_to_pe_mesh(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Add PE mesh to the PE") -def add_pe_mesh_to_pe_dry( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of adding list of PE routers into iGEANT/iGEANT6 of the router.""" - _add_pe_mesh_to_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _add_pe_mesh_to_pe(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Add PE mesh to the PE") -def add_pe_mesh_to_pe_real( - subscription: dict[str, Any], - callback_route: str, - tt_number: str, - process_id: UUIDstr, -) -> State: +def add_pe_mesh_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a real run of adding list of PE routers into iGEANT/iGEANT6 of the router.""" - _add_pe_mesh_to_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} - - -@step("[DRY RUN] Deploy base config") -def deploy_base_config_dry( - subscription: dict[str, Any], - tt_number: str, - callback_route: str, - process_id: UUIDstr, -) -> State: - """Perform a dry run of provisioning base config on a router.""" - _deploy_base_config(subscription, tt_number, callback_route, process_id, dry_run=True) - - return {"subscription": subscription} - - -@step("[FOR REAL] Deploy base config") -def deploy_base_config_real( - subscription: dict[str, Any], - tt_number: str, - callback_route: str, - process_id: UUIDstr, -) -> State: - """Deploy base config on a router using the provisioning proxy.""" - _deploy_base_config(subscription, tt_number, callback_route, process_id, dry_run=False) - - return {"subscription": subscription} + return _add_pe_mesh_to_pe(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Include the PE into SDP mesh on other Nokia PEs") -def update_sdp_mesh_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> State: +def update_sdp_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of including new PE router in SDP mesh on other NOKIA PE routers.""" - _update_sdp_mesh( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _update_sdp_mesh(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Include the PE into SDP mesh on other Nokia PEs") -def update_sdp_mesh_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> State: - """Include new PE router in SDP mesh on other NOKIA PE routers.""" - _update_sdp_mesh( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} +def update_sdp_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: + """Perform a real run of including new PE router in SDP mesh on other NOKIA PE routers.""" + return _update_sdp_mesh(subscription, tt_number, process_id, dry_run=False) @step("[DRY RUN] Configure SDP on the PE to all other Nokia PEs") -def update_sdp_single_pe_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> State: +def update_sdp_single_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Perform a dry run of configuring SDP on a new PE router to all other NOKIA PE routers.""" - _update_sdp_single_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=True, - ) - - return {"subscription": subscription} + return _update_sdp_single_pe(subscription, tt_number, process_id, dry_run=True) @step("[FOR REAL] Configure SDP on the PE to all other Nokia PEs") -def update_sdp_single_pe_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> State: +def update_sdp_single_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: """Configure SDP on a new PE router to all other NOKIA PE routers.""" - _update_sdp_single_pe( - subscription=subscription, - tt_number=tt_number, - callback_route=callback_route, - process_id=process_id, - dry_run=False, - ) - - return {"subscription": subscription} + return _update_sdp_single_pe(subscription, tt_number, process_id, dry_run=False) @step("[FOR REAL] Set ISIS metric to very high value") -def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, callback_route: str, tt_number: str) -> State: +def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Workflow step for setting the :term:`ISIS` metric to an arbitrarily high value to drain a link.""" old_isis_metric = subscription.iptrunk.iptrunk_isis_metric params = load_oss_params() @@ -477,33 +299,34 @@ def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, callback_route: f"{subscription.iptrunk.geant_s_sid}", } - lso_client.execute_playbook( - playbook_name="iptrunks.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, + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, "old_isis_metric": old_isis_metric, } @step("Run show commands after base config install") -def run_checks_after_base_config(subscription: dict[str, Any], callback_route: str) -> None: +def run_checks_after_base_config(subscription: dict[str, Any]) -> LSOState: """Workflow step for running show commands after installing base config.""" - lso_client.execute_playbook( - playbook_name="base_config_checks.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars={"wfo_router_json": subscription}, - ) + return { + "playbook_name": "base_config_checks.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]}}}, + "extra_vars": {"wfo_router_json": subscription}, + } -@step("Check PE iBGP sessions") -def check_pe_ibgp(subscription: dict[str, Any], callback_route: str) -> None: +@step("Check iBGP session") +def check_pe_ibgp(subscription: dict[str, Any]) -> LSOState: """Check the iBGP session.""" extra_vars = { "dry_run": False, @@ -511,16 +334,15 @@ def check_pe_ibgp(subscription: dict[str, Any], callback_route: str) -> None: "verb": "check_pe_ibgp", } - lso_client.execute_playbook( - playbook_name="check_ibgp.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "check_ibgp.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } -@step("Check L3 VPRN services") -def check_l3_services(subscription: dict[str, Any], callback_route: str) -> None: +@step("Check L3 services") +def check_l3_services(subscription: dict[str, Any]) -> LSOState: """Check L3 services.""" extra_vars = { "dry_run": False, @@ -528,12 +350,11 @@ def check_l3_services(subscription: dict[str, Any], callback_route: str) -> None "verb": "check_base_ris", } - lso_client.execute_playbook( - playbook_name="check_l3_services.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "check_l3_services.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @inputstep("Prompt for new SharePoint checklist", assignee=Assignee.SYSTEM) diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index 56907a6c22e52c5f7d82642563e78d0a62b09853..ae3c6a74a54054b6a4fe07cd2cef9e9ee75ff3fa 100644 --- a/gso/workflows/iptrunk/create_iptrunk.py +++ b/gso/workflows/iptrunk/create_iptrunk.py @@ -28,7 +28,7 @@ from gso.products.product_blocks.iptrunk import ( from gso.products.product_types.iptrunk import Iptrunk, IptrunkInactive, IptrunkProvisioning from gso.products.product_types.router import Router from gso.services import infoblox, subscriptions -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.services.partners import get_partner_by_name from gso.services.sharepoint import SharePointClient @@ -325,12 +325,7 @@ def initialize_subscription( @step("[DRY RUN] Provision IP trunk interface") -def provision_ip_trunk_iface_dry( - subscription: IptrunkInactive, - callback_route: str, - process_id: UUIDstr, - tt_number: str, -) -> State: +def provision_ip_trunk_iface_dry(subscription: IptrunkInactive, process_id: UUIDstr, tt_number: str) -> LSOState: """Perform a dry run of deploying configuration on both sides of the trunk.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -341,24 +336,22 @@ def provision_ip_trunk_iface_dry( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Provision IP trunk interface") -def provision_ip_trunk_iface_real( - subscription: IptrunkInactive, - callback_route: str, - process_id: UUIDstr, - tt_number: str, -) -> State: +def provision_ip_trunk_iface_real(subscription: IptrunkInactive, process_id: UUIDstr, tt_number: str) -> LSOState: """Deploy IP trunk configuration on both sides.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -369,42 +362,34 @@ def provision_ip_trunk_iface_real( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity( - subscription: IptrunkInactive, - callback_route: str, -) -> State: +def check_ip_trunk_connectivity(subscription: IptrunkInactive) -> LSOState: """Check successful connectivity across the new 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, # type: ignore[arg-type] - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": {"all": {"hosts": {subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None}}}, + "extra_vars": extra_vars, + } @step("[DRY RUN] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_dry( - subscription: IptrunkInactive, - callback_route: str, - process_id: UUIDstr, - tt_number: str, -) -> State: +def provision_ip_trunk_isis_iface_dry(subscription: IptrunkInactive, process_id: UUIDstr, tt_number: str) -> LSOState: """Perform a dry run of deploying :term:`ISIS` configuration.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -415,24 +400,22 @@ def provision_ip_trunk_isis_iface_dry( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_real( - subscription: IptrunkInactive, - callback_route: str, - process_id: UUIDstr, - tt_number: str, -) -> State: +def provision_ip_trunk_isis_iface_real(subscription: IptrunkInactive, process_id: UUIDstr, tt_number: str) -> LSOState: """Deploy :term:`ISIS` configuration on both sides.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -443,33 +426,30 @@ def provision_ip_trunk_isis_iface_real( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check ISIS adjacency") -def check_ip_trunk_isis( - subscription: IptrunkInactive, - callback_route: str, -) -> State: +def check_ip_trunk_isis(subscription: IptrunkInactive) -> LSOState: """Run an Ansible playbook to confirm :term:`ISIS` adjacency.""" extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "isis"} - execute_playbook( - playbook_name="iptrunks_checks.yaml", - callback_route=callback_route, - inventory=subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn, # type: ignore[arg-type] - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": {"all": {"hosts": {subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None}}}, + "extra_vars": extra_vars, + } @step("Register DNS records for both sides of the trunk") diff --git a/gso/workflows/iptrunk/deploy_twamp.py b/gso/workflows/iptrunk/deploy_twamp.py index 11dce53ba260fd8c8dae08611ae66e4069619d49..b43de54c60885b130c9ad57d8bc5a3adf435c084 100644 --- a/gso/workflows/iptrunk/deploy_twamp.py +++ b/gso/workflows/iptrunk/deploy_twamp.py @@ -5,14 +5,14 @@ import json from orchestrator.forms import FormPage from orchestrator.forms.validators import Label from orchestrator.targets import Target -from orchestrator.types import FormGenerator, State, UUIDstr +from orchestrator.types import FormGenerator, UUIDstr from orchestrator.utils.json import json_dumps from orchestrator.workflow import StepList, begin, done, step, workflow from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_types.iptrunk import Iptrunk -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.utils.types.tt_number import TTNumber @@ -33,7 +33,7 @@ def _initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: @step("[DRY RUN] Deploy TWAMP on both sides") -def deploy_twamp_dry(subscription: Iptrunk, process_id: UUIDstr, callback_route: str, tt_number: str) -> State: +def deploy_twamp_dry(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Perform a dry run of deploying the :term:`TWAMP` session.""" extra_vars = { "subscription": json.loads(json_dumps(subscription)), @@ -43,18 +43,22 @@ def deploy_twamp_dry(subscription: Iptrunk, process_id: UUIDstr, callback_route: "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy TWAMP", } - inventory = ( - f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}" - f"\n{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}" - ) - - execute_playbook("deploy_twamp.yaml", callback_route, inventory, extra_vars) - - return {"subscription": subscription} + return { + "playbook_name": "deploy_twamp.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deploy TWAMP on both sides") -def deploy_twamp_real(subscription: Iptrunk, process_id: UUIDstr, callback_route: str, tt_number: str) -> State: +def deploy_twamp_real(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Deploy the :term:`TWAMP` session.""" extra_vars = { "subscription": json.loads(json_dumps(subscription)), @@ -64,32 +68,40 @@ def deploy_twamp_real(subscription: Iptrunk, process_id: UUIDstr, callback_route "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy TWAMP", } - inventory = ( - f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}" - f"\n{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}" - ) - - execute_playbook("deploy_twamp.yaml", callback_route, inventory, extra_vars) - - return {"subscription": subscription} + return { + "playbook_name": "deploy_twamp.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check TWAMP status on both sides") -def check_twamp_status(subscription: Iptrunk, callback_route: str) -> State: +def check_twamp_status(subscription: Iptrunk) -> LSOState: """Check TWAMP session.""" extra_vars = { "subscription": json.loads(json_dumps(subscription)), "verb": "check_twamp", } - inventory = ( - f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}" - f"\n{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}" - ) - - execute_playbook("deploy_twamp.yaml", callback_route, inventory, extra_vars) - - return {"subscription": subscription} + return { + "playbook_name": "deploy_twamp.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @workflow( diff --git a/gso/workflows/iptrunk/migrate_iptrunk.py b/gso/workflows/iptrunk/migrate_iptrunk.py index c7021875a1d7f2e2fde5424b5493de028b209d58..3c04fb8e03213eb218f6fc0f230b1b5b504343e5 100644 --- a/gso/workflows/iptrunk/migrate_iptrunk.py +++ b/gso/workflows/iptrunk/migrate_iptrunk.py @@ -28,7 +28,7 @@ from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkTy from gso.products.product_types.iptrunk import Iptrunk from gso.products.product_types.router import Router from gso.services import infoblox -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.services.sharepoint import SharePointClient from gso.services.subscriptions import get_active_router_subscriptions @@ -203,29 +203,28 @@ def calculate_old_side_data(subscription: Iptrunk, replace_index: int) -> State: @step("Check Optical PRE levels on the trunk endpoint") -def check_ip_trunk_optical_levels_pre(subscription: Iptrunk, callback_route: str) -> State: +def check_ip_trunk_optical_levels_pre(subscription: Iptrunk) -> LSOState: """Check Optical PRE levels on the trunk.""" extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "optical_pre"} - 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} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check Optical POST levels on the trunk endpoint") def check_ip_trunk_optical_levels_post( - subscription: Iptrunk, - callback_route: str, - new_node: Router, - new_lag_member_interfaces: list[dict], - replace_index: int, -) -> State: + subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int +) -> LSOState: """Check Optical POST levels on the trunk.""" extra_vars = { "wfo_ip_trunk_json": json.loads(json_dumps(subscription)), @@ -235,25 +234,24 @@ def check_ip_trunk_optical_levels_post( "check": "optical_post", } - execute_playbook( - playbook_name="iptrunks_checks.yaml", - callback_route=callback_route, - inventory=f"{subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn}\n" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check LLDP on the trunk endpoints") def check_ip_trunk_lldp( - subscription: Iptrunk, - callback_route: str, - new_node: Router, - new_lag_member_interfaces: list[dict], - replace_index: int, -) -> State: + subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int +) -> LSOState: """Check LLDP on the new trunk endpoints.""" extra_vars = { "wfo_ip_trunk_json": json.loads(json_dumps(subscription)), @@ -263,28 +261,30 @@ def check_ip_trunk_lldp( "check": "lldp", } - execute_playbook( - playbook_name="iptrunks_checks.yaml", - callback_route=callback_route, - inventory=f"{subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn}\n" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[DRY RUN] Disable configuration on old router") def disable_old_config_dry( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Perform a dry run of disabling the old configuration on the routers.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -299,29 +299,31 @@ def disable_old_config_dry( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Disable configuration on old router") def disable_old_config_real( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Disable old configuration on the routers.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -336,31 +338,31 @@ def disable_old_config_real( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - return { - "subscription": subscription, + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, } @step("[DRY RUN] Deploy configuration on new router") def deploy_new_config_dry( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Perform a dry run of deploying configuration on the new router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -375,29 +377,31 @@ def deploy_new_config_dry( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deploy configuration on new router") def deploy_new_config_real( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Deploy configuration on the new router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -412,27 +416,25 @@ def deploy_new_config_real( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[DRY RUN] Update BFD on the remaining side") def update_remaining_side_bfd_dry( - subscription: Iptrunk, - callback_route: str, - new_node: Router, - replace_index: int, - process_id: UUIDstr, - tt_number: str, -) -> State: + subscription: Iptrunk, new_node: Router, replace_index: int, process_id: UUIDstr, tt_number: str +) -> LSOState: """Perform a dry run of updating configuration on the remaining router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -444,25 +446,23 @@ def update_remaining_side_bfd_dry( "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " f"- Update BFD config.", } - execute_playbook( - playbook_name="iptrunks_migration.yaml", - callback_route=callback_route, - inventory=subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn, - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Update BFD on the remaining side") def update_remaining_side_bfd_real( - subscription: Iptrunk, - callback_route: str, - new_node: Router, - replace_index: int, - process_id: UUIDstr, - tt_number: str, -) -> State: + subscription: Iptrunk, new_node: Router, replace_index: int, process_id: UUIDstr, tt_number: str +) -> LSOState: """Update configuration on the remaining router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -474,23 +474,21 @@ def update_remaining_side_bfd_real( "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " f"- Update BFD config.", } - execute_playbook( - playbook_name="iptrunks_migration.yaml", - callback_route=callback_route, - inventory=subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn, - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check BFD session over trunk") -def check_ip_trunk_bfd( - subscription: Iptrunk, - callback_route: str, - new_node: Router, - replace_index: int, -) -> State: +def check_ip_trunk_bfd(subscription: Iptrunk, new_node: Router, replace_index: int) -> LSOState: """Check BFD session across the new trunk.""" extra_vars = { "wfo_ip_trunk_json": json.loads(json_dumps(subscription)), @@ -498,14 +496,17 @@ def check_ip_trunk_bfd( "check": "bfd", } - execute_playbook( - playbook_name="iptrunks_checks.yaml", - callback_route=callback_route, - inventory=subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn, - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @inputstep("Wait for confirmation", assignee=Assignee.SYSTEM) @@ -523,35 +524,33 @@ def confirm_continue_move_fiber() -> FormGenerator: @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity( - subscription: Iptrunk, - callback_route: str, - replace_index: int, -) -> State: +def check_ip_trunk_connectivity(subscription: Iptrunk, replace_index: int) -> LSOState: """Check successful connectivity across the new 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[1 - replace_index].iptrunk_side_node.router_fqdn, - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deploy ISIS configuration on new router") def deploy_new_isis( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Deploy :term:`ISIS` configuration.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -566,35 +565,37 @@ def deploy_new_isis( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check ISIS adjacency") -def check_ip_trunk_isis( - subscription: Iptrunk, - callback_route: str, - replace_index: int, -) -> State: +def check_ip_trunk_isis(subscription: Iptrunk, replace_index: int) -> LSOState: """Run an Ansible playbook to confirm :term:`ISIS` adjacency.""" extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "isis"} - execute_playbook( - playbook_name="iptrunks_checks.yaml", - callback_route=callback_route, - inventory=subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn, - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[1 - replace_index].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @inputstep("Wait for confirmation", assignee=Assignee.SYSTEM) @@ -615,10 +616,9 @@ def confirm_continue_restore_isis() -> FormGenerator: def restore_isis_metric( subscription: Iptrunk, process_id: UUIDstr, - callback_route: str, tt_number: str, old_isis_metric: int, -) -> State: +) -> LSOState: """Restore the :term:`ISIS` metric to its original value.""" subscription.iptrunk.iptrunk_isis_metric = old_isis_metric extra_vars = { @@ -630,28 +630,30 @@ def restore_isis_metric( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[DRY RUN] Delete configuration on old router") def delete_old_config_dry( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Perform a dry run of deleting the old configuration.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -666,29 +668,31 @@ def delete_old_config_dry( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Delete configuration on old router") def delete_old_config_real( subscription: Iptrunk, - callback_route: str, new_node: Router, new_lag_interface: str, new_lag_member_interfaces: list[dict], replace_index: int, process_id: UUIDstr, tt_number: str, -) -> State: +) -> LSOState: """Delete old configuration from the routers.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -703,16 +707,19 @@ def delete_old_config_real( f"- Deploy config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks_migration.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" - f"{new_node.router.router_fqdn}\n", - extra_vars=extra_vars, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks_migration.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + new_node.router.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Update IP records in IPAM") diff --git a/gso/workflows/iptrunk/modify_isis_metric.py b/gso/workflows/iptrunk/modify_isis_metric.py index da14d078cea88f0c52256e02ef3dce0429cf7374..d95a6eb633000cce5238e044d747743b77295f8a 100644 --- a/gso/workflows/iptrunk/modify_isis_metric.py +++ b/gso/workflows/iptrunk/modify_isis_metric.py @@ -11,7 +11,7 @@ from orchestrator.workflows.steps import resync, store_process_subscription, uns from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_types.iptrunk import Iptrunk -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.utils.types.tt_number import TTNumber @@ -37,12 +37,7 @@ def modify_iptrunk_subscription(subscription: Iptrunk, isis_metric: int) -> Stat @step("[DRY RUN] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_dry( - subscription: Iptrunk, - process_id: UUIDstr, - callback_route: str, - tt_number: str, -) -> State: +def provision_ip_trunk_isis_iface_dry(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Perform a dry run of deploying the new :term:`ISIS` metric on both sides of the trunk.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -53,24 +48,22 @@ def provision_ip_trunk_isis_iface_dry( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_real( - subscription: Iptrunk, - process_id: UUIDstr, - callback_route: str, - tt_number: str, -) -> State: +def provision_ip_trunk_isis_iface_real(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Deploy the new :term:`ISIS` metric on both sides of the trunk.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -81,15 +74,18 @@ def provision_ip_trunk_isis_iface_real( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @workflow( diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index 6d82090c56d539c3456344ec6c08b1580d33dcf4..0dcc5d83cafecd34161ca2a2b272804c35e85a0b 100644 --- a/gso/workflows/iptrunk/modify_trunk_interface.py +++ b/gso/workflows/iptrunk/modify_trunk_interface.py @@ -21,7 +21,7 @@ from gso.products.product_blocks.iptrunk import ( IptrunkType, ) from gso.products.product_types.iptrunk import Iptrunk -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.utils.helpers import ( available_interfaces_choices, @@ -186,34 +186,63 @@ def determine_change_in_capacity( @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity(subscription: Iptrunk, callback_route: str) -> State: +def check_ip_trunk_connectivity(subscription: Iptrunk) -> LSOState: """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} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Check LLDP on the trunk endpoints") -def check_ip_trunk_lldp(subscription: Iptrunk, callback_route: str) -> State: +def check_ip_trunk_lldp(subscription: Iptrunk) -> LSOState: """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 { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } - return {"subscription": subscription} + +def update_side_members(subscription: Iptrunk, side_index: int, new_members: list[dict]) -> None: + """Update the AE members for a given side without removing unchanged members.""" + # Prepare a dictionary for quick lookup of existing members by name + current_members = subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_ae_members + existing_members_dict = {member.interface_name: member for member in current_members} + + # Iterate over new members and update or add them + for new_member in new_members: + interface_name = new_member["interface_name"] + if interface_name in existing_members_dict: + # Member exists, update details but keep the same subscription ID + existing_member = existing_members_dict[interface_name] + existing_member.interface_description = new_member["interface_description"] + else: + # New member, create a new subscription ID + current_members.append(IptrunkInterfaceBlock.new(subscription_id=uuid4(), **new_member)) + + # Remove members that are no longer in the new members list + subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_ae_members = [ + member for member in current_members if member.interface_name in [m["interface_name"] for m in new_members] + ] @step("Update subscription") @@ -242,12 +271,16 @@ def modify_iptrunk_subscription( for side in subscription.iptrunk.iptrunk_sides ] removed_ae_members = [] - + # Compare previous and current members to determine which ones were removed for side_index in range(2): previous_members = previous_ae_members[side_index] current_members = side_a_ae_members if side_index == 0 else side_b_ae_members - removed_ae_members.append([ae_member for ae_member in previous_members if ae_member not in current_members]) - + removed_ae_members.append([ + ae_member + for ae_member in previous_members + if ae_member["interface_name"] not in [m["interface_name"] for m in current_members] + ]) + # Update the subscription subscription.iptrunk.geant_s_sid = geant_s_sid subscription.iptrunk.iptrunk_description = iptrunk_description subscription.iptrunk.iptrunk_type = iptrunk_type @@ -255,20 +288,9 @@ def modify_iptrunk_subscription( subscription.iptrunk.iptrunk_minimum_links = iptrunk_minimum_links subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid = side_a_ae_geant_a_sid - # Flush the old list of member interfaces - subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.clear() - # And update the list to only include the new member interfaces - for member in side_a_ae_members: - subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.append( - IptrunkInterfaceBlock.new(subscription_id=uuid4(), **member), - ) - + update_side_members(subscription, 0, side_a_ae_members) subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid = side_b_ae_geant_a_sid - subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.clear() - for member in side_b_ae_members: - subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.append( - IptrunkInterfaceBlock.new(subscription_id=uuid4(), **member), - ) + update_side_members(subscription, 1, side_b_ae_members) side_names = sorted([ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name, @@ -285,12 +307,8 @@ def modify_iptrunk_subscription( @step("[DRY RUN] Provision IP trunk interface") def provision_ip_trunk_iface_dry( - subscription: Iptrunk, - process_id: UUIDstr, - callback_route: str, - tt_number: str, - removed_ae_members: list[str], -) -> State: + subscription: Iptrunk, process_id: UUIDstr, tt_number: str, removed_ae_members: list[str] +) -> LSOState: """Perform a dry run of deploying the updated IP trunk.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -302,25 +320,24 @@ def provision_ip_trunk_iface_dry( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Provision IP trunk interface") def provision_ip_trunk_iface_real( - subscription: Iptrunk, - process_id: UUIDstr, - callback_route: str, - tt_number: str, - removed_ae_members: list[str], -) -> State: + subscription: Iptrunk, process_id: UUIDstr, tt_number: str, removed_ae_members: list[str] +) -> LSOState: """Provision the new IP trunk with updated interfaces.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -332,15 +349,18 @@ def provision_ip_trunk_iface_real( f"{subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.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} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } def _netbox_update_interfaces( @@ -439,19 +459,22 @@ def allocate_interfaces_in_netbox_side_b(subscription: Iptrunk, previous_ae_memb @step("Check Optical POST levels on the trunk endpoint") -def check_ip_trunk_optical_levels_post(subscription: Iptrunk, callback_route: str) -> State: +def check_ip_trunk_optical_levels_post(subscription: Iptrunk) -> LSOState: """Check Optical POST levels on the trunk.""" extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "optical_post"} - 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} + return { + "playbook_name": "iptrunks_checks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @workflow( diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py index ac628d393a9c6dd52880ee28ceb39d403f023fd2..549bc3c23c6de32a8a8cb1cf8f1fd667aea9813b 100644 --- a/gso/workflows/iptrunk/terminate_iptrunk.py +++ b/gso/workflows/iptrunk/terminate_iptrunk.py @@ -20,7 +20,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_blocks.iptrunk import IptrunkSideBlock from gso.products.product_types.iptrunk import Iptrunk from gso.services import infoblox -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.utils.helpers import get_router_vendor from gso.utils.shared_enums import Vendor @@ -51,7 +51,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: @step("[DRY RUN] Deprovision IP trunk") -def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr, callback_route: str, tt_number: str) -> State: +def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Perform a dry run of deleting configuration from the routers.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -62,19 +62,22 @@ def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr, callbac f"- Remove config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.yaml", - 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, - callback_route=callback_route, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deprovision IP trunk") -def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, callback_route: str, tt_number: str) -> State: +def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) -> LSOState: """Delete configuration from the routers.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -85,15 +88,18 @@ def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, callba f"- Remove config for {subscription.iptrunk.geant_s_sid}", } - execute_playbook( - playbook_name="iptrunks.yaml", - 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, - callback_route=callback_route, - ) - - return {"subscription": subscription} + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } def _free_up_interfaces_from_netbox(side_block: IptrunkSideBlock) -> None: diff --git a/gso/workflows/iptrunk/validate_iptrunk.py b/gso/workflows/iptrunk/validate_iptrunk.py index bdfc4d3b952eca2e998d46ceab47250a56cfdb21..7832487fba8cddcbef46247ed8ac85f0cc5a3dd1 100644 --- a/gso/workflows/iptrunk/validate_iptrunk.py +++ b/gso/workflows/iptrunk/validate_iptrunk.py @@ -11,24 +11,29 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_types.iptrunk import Iptrunk from gso.services import infoblox -from gso.services.lso_client import anonymous_lso_interaction, execute_playbook +from gso.services.lso_client import LSOState, anonymous_lso_interaction from gso.services.netbox_client import NetboxClient from gso.utils.helpers import get_router_vendor from gso.utils.shared_enums import Vendor @step("Validate IP trunk configuration") -def validate_router_config(subscription: Iptrunk, callback_route: str) -> None: +def validate_router_config(subscription: Iptrunk) -> LSOState: """Run an Ansible playbook that validates the configuration that is present on an active IP trunk.""" extra_vars = {"wfo_trunk_json": json.loads(json_dumps(subscription)), "verb": "validate"} - execute_playbook( - playbook_name="base_config.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 { + "playbook_name": "base_config.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": extra_vars, + } @step("Verify IPAM resources for LAG interfaces") @@ -129,56 +134,71 @@ def verify_netbox_entries(subscription: Iptrunk) -> None: @step("Verify configuration of IPtrunk") -def verify_iptrunk_config(subscription: Iptrunk, callback_route: str) -> None: +def verify_iptrunk_config(subscription: Iptrunk) -> LSOState: """Check for configuration drift on the relevant routers.""" - execute_playbook( - playbook_name="iptrunks.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={ + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": { "wfo_trunk_json": json.loads(json_dumps(subscription)), "verb": "deploy", "dry_run": "true", "config_object": "trunk_interface", "is_verification_workflow": "true", }, - ) + } @step("Check ISIS configuration") -def check_ip_trunk_isis(subscription: Iptrunk, callback_route: str) -> None: +def check_ip_trunk_isis(subscription: Iptrunk) -> LSOState: """Run an Ansible playbook to check for any :term:`ISIS` configuration drift.""" - execute_playbook( - playbook_name="iptrunks.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={ + return { + "playbook_name": "iptrunks.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": { "wfo_trunk_json": json.loads(json_dumps(subscription)), "verb": "deploy", "dry_run": "true", "config_object": "isis_interface", "is_verification_workflow": "true", }, - ) + } @step("Verify TWAMP configuration") -def verify_twamp_config(subscription: Iptrunk, callback_route: str) -> None: +def verify_twamp_config(subscription: Iptrunk) -> LSOState: """Check for configuration drift of TWAMP.""" - execute_playbook( - playbook_name="deploy_twamp.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={ + return { + "playbook_name": "deploy_twamp.yaml", + "inventory": { + "all": { + "hosts": { + subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn: None, + subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn: None, + } + } + }, + "extra_vars": { "subscription": json.loads(json_dumps(subscription)), "verb": "deploy", "dry_run": "true", "is_verification_workflow": "true", }, - ) + } @workflow( diff --git a/gso/workflows/router/promote_p_to_pe.py b/gso/workflows/router/promote_p_to_pe.py index 03d68f099a0a8a373c0d5435e5afdfc0d845112e..cdd6c9dbf809025992a19302a5d53b7aae0e1e72 100644 --- a/gso/workflows/router/promote_p_to_pe.py +++ b/gso/workflows/router/promote_p_to_pe.py @@ -17,9 +17,8 @@ from pydantic import ConfigDict, model_validator from gso.products.product_blocks.router import RouterRole from gso.products.product_types.router import Router -from gso.services import lso_client from gso.services.kentik_client import KentikClient, NewKentikDevice -from gso.services.lso_client import lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.subscriptions import get_all_active_sites from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.shared_enums import Vendor @@ -63,7 +62,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: @step("Evacuate the router by setting isis_overload") -def set_isis_overload(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def set_isis_overload(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Evacuate the router by setting isis overload.""" extra_vars = { "dry_run": False, @@ -72,18 +71,15 @@ def set_isis_overload(subscription: dict[str, Any], callback_route: str, tt_numb "verb": "set_isis_overload", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("[DRY RUN] Deploy PE base config") -def deploy_pe_base_config_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def deploy_pe_base_config_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of adding the base config to the router.""" extra_vars = { "dry_run": True, @@ -94,18 +90,15 @@ def deploy_pe_base_config_dry( "geant_sites": json.loads(json_dumps(get_all_active_sites())), } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deploy PE base config") -def deploy_pe_base_config_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def deploy_pe_base_config_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of adding the base config to the router.""" extra_vars = { "dry_run": False, @@ -116,12 +109,11 @@ def deploy_pe_base_config_real( "geant_sites": json.loads(json_dumps(get_all_active_sites())), } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @inputstep("Prompt EARL insertion", assignee=Assignee.SYSTEM) @@ -173,9 +165,7 @@ def create_kentik_device(subscription: Router) -> State: @step("[DRY RUN] Remove P from all PEs") -def remove_p_from_pe_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def remove_p_from_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of removing the P router from all the PE routers.""" extra_vars = { "dry_run": True, @@ -185,18 +175,15 @@ def remove_p_from_pe_dry( "verb": "remove_p_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } @step("[FOR REAL] Remove P from all PEs") -def remove_p_from_pe_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def remove_p_from_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Remove the P router from all the PE routers.""" extra_vars = { "dry_run": False, @@ -206,18 +193,16 @@ def remove_p_from_pe_real( "verb": "remove_p_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } + @step("[DRY RUN] Deploy routing instances") -def deploy_routing_instances_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def deploy_routing_instances_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of deploying routing instances.""" extra_vars = { "dry_run": True, @@ -226,18 +211,15 @@ def deploy_routing_instances_dry( "verb": "deploy_routing_instances", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("[FOR REAL] Deploy routing instances") -def deploy_routing_instances_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def deploy_routing_instances_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of deploying routing instances.""" extra_vars = { "dry_run": False, @@ -246,18 +228,15 @@ def deploy_routing_instances_real( "verb": "deploy_routing_instances", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("Remove ISIS overload") -def remove_isis_overload( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def remove_isis_overload(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Remove ISIS overload.""" extra_vars = { "dry_run": False, @@ -266,12 +245,11 @@ def remove_isis_overload( "verb": "remove_isis_overload", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("Set router role to PE (Update subscription model)") @@ -282,10 +260,29 @@ def update_subscription_model(subscription: Router) -> State: return {"subscription": subscription} +@step("[DRY RUN] Add all P to this new PE") +def add_all_p_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: + """Perform a dry run of adding all P routers to the PE router.""" + extra_vars = { + "dry_run": True, + "subscription": subscription, + "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Add all P-routers to this new PE", + "verb": "add_all_p_to_pe", + "p_router_list": generate_inventory_for_active_routers( + RouterRole.P, exclude_routers=[subscription["router"]["router_fqdn"]] + )["all"]["hosts"], + } + + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } + + + @step("[DRY RUN] Delete default routes") -def delete_default_routes_dry( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def delete_default_routes_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of deleting the default routes.""" extra_vars = { "dry_run": True, @@ -295,18 +292,15 @@ def delete_default_routes_dry( "verb": "delete_default_routes", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("[FOR REAL] Delete default routes") -def delete_default_routes_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def delete_default_routes_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of deleting the default routes.""" extra_vars = { "dry_run": False, @@ -316,12 +310,11 @@ def delete_default_routes_real( "verb": "delete_default_routes", } - lso_client.execute_playbook( - playbook_name="promote_p_to_pe.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "promote_p_to_pe.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @workflow( diff --git a/gso/workflows/router/terminate_router.py b/gso/workflows/router/terminate_router.py index f7caa6c9936154f3afff8320f5942504f9477414..13cef223c8dfd0160130064d8e29e2290aa54f75 100644 --- a/gso/workflows/router/terminate_router.py +++ b/gso/workflows/router/terminate_router.py @@ -22,10 +22,10 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_blocks.router import RouterRole from gso.products.product_types.router import Router -from gso.services import infoblox, lso_client +from gso.services import infoblox from gso.services.kentik_client import KentikClient from gso.services.librenms_client import LibreNMSClient -from gso.services.lso_client import execute_playbook, lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.settings import load_oss_params from gso.utils.helpers import generate_inventory_for_active_routers @@ -69,9 +69,7 @@ def deprovision_loopback_ips(subscription: Router) -> dict: @step("[DRY RUN] Remove configuration from router") -def remove_config_from_router_dry( - subscription: Router, callback_route: str, process_id: UUIDstr, tt_number: str -) -> None: +def remove_config_from_router_dry(subscription: Router, process_id: UUIDstr, tt_number: str) -> LSOState: """Remove configuration from the router, first as a dry run.""" extra_vars = { "wfo_router_json": json.loads(json_dumps(subscription)), @@ -81,18 +79,15 @@ def remove_config_from_router_dry( f"{subscription.router.router_fqdn}", } - execute_playbook( - playbook_name="base_config.yaml", - callback_route=callback_route, - inventory=subscription.router.router_fqdn, - extra_vars=extra_vars, - ) + return { + "playbook_name": "base_config.yaml", + "inventory": {"all": {"hosts": {subscription.router.router_fqdn: None}}}, + "extra_vars": extra_vars, + } @step("[FOR REAL] Remove configuration from router") -def remove_config_from_router_real( - subscription: Router, callback_route: str, process_id: UUIDstr, tt_number: str -) -> None: +def remove_config_from_router_real(subscription: Router, process_id: UUIDstr, tt_number: str) -> LSOState: """Remove configuration from the router.""" extra_vars = { "wfo_router_json": json.loads(json_dumps(subscription)), @@ -102,12 +97,11 @@ def remove_config_from_router_real( f"{subscription.router.router_fqdn}", } - execute_playbook( - playbook_name="base_config.yaml", # FIX: need to use correct playbook. - callback_route=callback_route, - inventory=subscription.router.router_fqdn, - extra_vars=extra_vars, - ) + return { + "playbook_name": "base_config.yaml", + "inventory": {"all": {"hosts": {subscription.router.router_fqdn: None}}}, + "extra_vars": extra_vars, + } @step("Remove Device from Netbox") @@ -118,7 +112,7 @@ def remove_device_from_netbox(subscription: Router) -> dict[str, Router]: @step("[DRY RUN] Remove P router from all the PE routers") -def remove_p_from_all_pe_dry(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_p_from_all_pe_dry(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of removing the terminated router from all the PE routers.""" extra_vars = { "dry_run": True, @@ -128,16 +122,15 @@ def remove_p_from_all_pe_dry(subscription: Router, callback_route: str, tt_numbe "verb": "remove_p_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } @step("[REAL RUN] Remove P router from all the PE routers") -def remove_p_from_all_pe_real(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_p_from_all_pe_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of removing the terminated router from all the PE routers.""" extra_vars = { "dry_run": False, @@ -147,16 +140,15 @@ def remove_p_from_all_pe_real(subscription: Router, callback_route: str, tt_numb "verb": "remove_p_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } @step("[DRY RUN] Remove PE router from all the PE routers") -def remove_pe_from_all_pe_dry(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_pe_from_all_pe_dry(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of removing the terminated PE router from the PE router mesh.""" extra_vars = { "dry_run": True, @@ -166,18 +158,17 @@ def remove_pe_from_all_pe_dry(subscription: Router, callback_route: str, tt_numb "verb": "remove_pe_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers( + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers( RouterRole.PE, exclude_routers=[subscription.router.router_fqdn] ), - extra_vars=extra_vars, - ) + "extra_vars": extra_vars, + } @step("[REAL RUN] Remove all PE routers from all the PE routers") -def remove_pe_from_all_pe_real(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_pe_from_all_pe_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of removing terminated PE router from PE the router mesh.""" extra_vars = { "dry_run": False, @@ -187,18 +178,17 @@ def remove_pe_from_all_pe_real(subscription: Router, callback_route: str, tt_num "verb": "remove_pe_from_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers( + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers( RouterRole.PE, exclude_routers=[subscription.router.router_fqdn] ), - extra_vars=extra_vars, - ) + "extra_vars": extra_vars, + } @step("[DRY RUN] Remove PE router from all the P routers") -def remove_pe_from_all_p_dry(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_pe_from_all_p_dry(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of removing PE router from all P routers.""" extra_vars = { "dry_run": True, @@ -208,16 +198,15 @@ def remove_pe_from_all_p_dry(subscription: Router, callback_route: str, tt_numbe "verb": "remove_pe_from_p", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.P), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.P), + "extra_vars": extra_vars, + } @step("[REAL RUN] Remove PE router from all P routers") -def remove_pe_from_all_p_real(subscription: Router, callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def remove_pe_from_all_p_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of removing PE router from all P routers.""" extra_vars = { "dry_run": False, @@ -227,12 +216,11 @@ def remove_pe_from_all_p_real(subscription: Router, callback_route: str, tt_numb "verb": "remove_pe_from_p", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.P), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.P), + "extra_vars": extra_vars, + } @step("Remove Device from Librenms") diff --git a/gso/workflows/router/update_ibgp_mesh.py b/gso/workflows/router/update_ibgp_mesh.py index d436af6ea2081c5a0b3e9a9dae8305e0e4b900b9..98f17122773bfbac51a46b2ffa5feac3332cfe30 100644 --- a/gso/workflows/router/update_ibgp_mesh.py +++ b/gso/workflows/router/update_ibgp_mesh.py @@ -14,8 +14,8 @@ from pydantic import ConfigDict, model_validator from gso.products.product_blocks.router import RouterRole from gso.products.product_types.router import Router -from gso.services import librenms_client, lso_client -from gso.services.lso_client import lso_interaction +from gso.services import librenms_client +from gso.services.lso_client import LSOState, lso_interaction from gso.services.subscriptions import get_trunks_that_terminate_on_router from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.types.snmp import SNMPVersion @@ -64,13 +64,11 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: user_input = yield AddBGPSessionForm - return user_input.model_dump() | { - "router_role": subscription.router.router_role, - } + return user_input.model_dump() @step("[DRY RUN] Add P router to iBGP mesh") -def add_p_to_mesh_dry(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def add_p_to_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of adding the new P router to the PE router mesh.""" extra_vars = { "dry_run": True, @@ -79,16 +77,15 @@ def add_p_to_mesh_dry(subscription: dict[str, Any], callback_route: str, tt_numb "verb": "add_p_to_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } @step("[FOR REAL] Add P router to iBGP mesh") -def add_p_to_mesh_real(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None: +def add_p_to_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Add the P router to the mesh of PE routers.""" extra_vars = { "dry_run": False, @@ -97,16 +94,15 @@ def add_p_to_mesh_real(subscription: dict[str, Any], callback_route: str, tt_num "verb": "add_p_to_pe", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=generate_inventory_for_active_routers(RouterRole.PE), - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": generate_inventory_for_active_routers(RouterRole.PE), + "extra_vars": extra_vars, + } @step("[DRY RUN] Add all PE routers to P router iBGP group") -def add_all_pe_to_p_dry(subscription: dict[str, Any], callback_route: str) -> None: +def add_all_pe_to_p_dry(subscription: dict[str, Any]) -> LSOState: """Perform a dry run of adding the list of all PE routers to the new P router.""" extra_vars = { "dry_run": True, @@ -115,18 +111,15 @@ def add_all_pe_to_p_dry(subscription: dict[str, Any], callback_route: str) -> No "verb": "add_pe_to_p", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("[FOR REAL] Add all PE routers to P router iBGP group") -def add_all_pe_to_p_real( - subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr -) -> None: +def add_all_pe_to_p_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Add the list of all PE routers to the new P router.""" extra_vars = { "dry_run": False, @@ -136,23 +129,21 @@ def add_all_pe_to_p_real( "verb": "add_pe_to_p", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("Verify iBGP session health") -def check_ibgp_session(subscription: Router, callback_route: str) -> None: +def check_ibgp_session(subscription: Router) -> LSOState: """Run a playbook using the provisioning proxy, to check the health of the new iBGP session.""" - lso_client.execute_playbook( - playbook_name="check_ibgp.yaml", - callback_route=callback_route, - inventory=subscription.router.router_fqdn, - extra_vars={}, - ) + return { + "playbook_name": "check_ibgp.yaml", + "inventory": {"all": {"hosts": {subscription.router.router_fqdn: None}}}, + "extra_vars": {}, + } @step("Add the router to LibreNMS") diff --git a/gso/workflows/router/validate_router.py b/gso/workflows/router/validate_router.py index aa22b773d6004862aaab0b8c7ec2bf08b89f24be..9e13f521cb4edb062086b696846ff3d8bc17d8f9 100644 --- a/gso/workflows/router/validate_router.py +++ b/gso/workflows/router/validate_router.py @@ -1,11 +1,9 @@ """Router validation workflow. Used in a nightly schedule.""" -import json from typing import Any from orchestrator.targets import Target from orchestrator.utils.errors import ProcessFailureError -from orchestrator.utils.json import json_dumps from orchestrator.workflow import StepList, begin, conditional, done, step, workflow from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form @@ -13,10 +11,10 @@ from pydantic_forms.types import State, UUIDstr from gso.products.product_blocks.router import RouterRole from gso.products.product_types.router import Router -from gso.services import infoblox, lso_client +from gso.services import infoblox from gso.services.kentik_client import KentikClient from gso.services.librenms_client import LibreNMSClient -from gso.services.lso_client import anonymous_lso_interaction, execute_playbook +from gso.services.lso_client import LSOState, anonymous_lso_interaction from gso.services.netbox_client import NetboxClient from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.shared_enums import Vendor @@ -55,7 +53,7 @@ def check_netbox_entry_exists(subscription: Router) -> None: @step("Verify BGP configuration on P router") -def verify_p_ibgp(subscription: dict[str, Any], callback_route: str) -> None: +def verify_p_ibgp(subscription: dict[str, Any]) -> LSOState: """Perform a dry run of adding the list of all PE routers to the new P router.""" extra_vars = { "dry_run": True, @@ -65,12 +63,11 @@ def verify_p_ibgp(subscription: dict[str, Any], callback_route: str) -> None: "is_verification_workflow": "true", } - lso_client.execute_playbook( - playbook_name="update_ibgp_mesh.yaml", - callback_route=callback_route, - inventory=subscription["router"]["router_fqdn"], - extra_vars=extra_vars, - ) + return { + "playbook_name": "update_ibgp_mesh.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": extra_vars, + } @step("Verify correct LibreNMS entry") @@ -100,19 +97,18 @@ def check_kentik_entry_exists(subscription: Router) -> None: @step("Check base config for drift") -def verify_base_config(subscription: Router, callback_route: str) -> None: +def verify_base_config(subscription: dict[str, Any]) -> LSOState: """Workflow step for running a playbook that checks whether base config has drifted.""" - execute_playbook( - playbook_name="base_config.yaml", - callback_route=callback_route, - inventory=subscription.router.router_fqdn, - extra_vars={ - "wfo_router_json": json.loads(json_dumps(subscription)), + return { + "playbook_name": "base_config.yaml", + "inventory": {"all": {"hosts": {subscription["router"]["router_fqdn"]: None}}}, + "extra_vars": { + "wfo_router_json": subscription, "verb": "deploy", "dry_run": "true", "is_verification_workflow": "true", }, - ) + } @workflow( diff --git a/requirements.txt b/requirements.txt index 632c74b3af3c83c1ea442da2e4bf11530f682e7b..433a9e17894886e0b2648cebae089f677c3b0a87 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -orchestrator-core==2.7.4 +orchestrator-core==2.7.5 requests==2.31.0 infoblox-client~=0.6.0 pycountry==23.12.11 diff --git a/setup.py b/setup.py index 32cc5f5ce3450f379d0c47548a799683977205d5..840d33679d74054f70199c0537e6b780fb23bbec 100644 --- a/setup.py +++ b/setup.py @@ -4,14 +4,14 @@ from setuptools import find_packages, setup setup( name="geant-service-orchestrator", - version="2.15", + version="2.19", author="GÉANT Orchestration and Automation Team", author_email="goat@geant.org", description="GÉANT Service Orchestrator", url="https://gitlab.software.geant.org/goat/gap/geant-service-orchestrator", packages=find_packages(), install_requires=[ - "orchestrator-core==2.7.4", + "orchestrator-core==2.7.5", "requests==2.31.0", "infoblox-client~=0.6.0", "pycountry==23.12.11", diff --git a/start-worker.sh b/start-worker.sh index cccd84bff48ebc3e7392e15847e8f898c5120ffb..92cd6304d95db2a697ca1b77e4e705c5b9350b1a 100755 --- a/start-worker.sh +++ b/start-worker.sh @@ -4,4 +4,4 @@ set -o errexit set -o nounset cd /app -python -m celery -A gso.worker worker --loglevel=info --concurrency=1 +python -m celery -A gso.worker worker --loglevel=info --concurrency=1 --pool=solo diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py index 0b7e00e638db87ddb27674d524bcbdde990d6067..267cd3827f7dbd908c472faf545e949fd231ee32 100644 --- a/test/workflows/iptrunk/test_create_iptrunk.py +++ b/test/workflows/iptrunk/test_create_iptrunk.py @@ -101,7 +101,7 @@ def input_form_wizard_data(request, juniper_router_subscription_factory, nokia_r @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.create_iptrunk.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.create_host_by_ip") @@ -162,7 +162,7 @@ def test_successful_iptrunk_creation_with_standard_lso_result( @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.create_iptrunk.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.find_host_by_ip") @@ -199,7 +199,7 @@ def test_iptrunk_creation_fails_when_lso_return_code_is_one( @pytest.mark.parametrize("input_form_wizard_data", [Vendor.JUNIPER], indirect=True) @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.create_iptrunk.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network") @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.create_host_by_ip") diff --git a/test/workflows/iptrunk/test_deploy_twamp.py b/test/workflows/iptrunk/test_deploy_twamp.py index 8584cd99cae310bccf70ac22a6cd377b5672cefa..e65feac79a0a1fd9988eff99fe0bf2e55f68899b 100644 --- a/test/workflows/iptrunk/test_deploy_twamp.py +++ b/test/workflows/iptrunk/test_deploy_twamp.py @@ -12,7 +12,7 @@ from test.workflows import ( @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.deploy_twamp.execute_playbook") +@patch("gso.services.lso_client._send_request") def test_iptrunk_deploy_twamp_success( mock_execute_playbook, iptrunk_subscription_factory, diff --git a/test/workflows/iptrunk/test_modify_isis_metric.py b/test/workflows/iptrunk/test_modify_isis_metric.py index 38f4b4e89e5d178b86c48eaafc32a311f07787c2..26a9bbd490eb4c73728a2e11defd836bf3701316 100644 --- a/test/workflows/iptrunk/test_modify_isis_metric.py +++ b/test/workflows/iptrunk/test_modify_isis_metric.py @@ -12,7 +12,7 @@ from test.workflows import ( @pytest.mark.workflow() -@patch("gso.services.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") def test_iptrunk_modify_isis_metric_success( mock_provision_ip_trunk, iptrunk_subscription_factory, diff --git a/test/workflows/iptrunk/test_terminate_iptrunk.py b/test/workflows/iptrunk/test_terminate_iptrunk.py index 7fcca946895247f644783eb83ed183f334e73321..7319596ffa58936b0f92e2f2dfc948619eb386fd 100644 --- a/test/workflows/iptrunk/test_terminate_iptrunk.py +++ b/test/workflows/iptrunk/test_terminate_iptrunk.py @@ -3,6 +3,7 @@ from unittest.mock import patch import pytest from gso.products import Iptrunk +from gso.products.product_blocks.router import RouterRole from gso.settings import load_oss_params from test.services.conftest import MockedNetboxClient from test.workflows import ( @@ -14,8 +15,7 @@ from test.workflows import ( @pytest.mark.workflow() -@patch("gso.workflows.iptrunk.terminate_iptrunk.execute_playbook") -@patch("gso.utils.workflow_steps.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.iptrunk.terminate_iptrunk.infoblox.delete_network") @patch("gso.services.netbox_client.NetboxClient.delete_interface") @patch("gso.services.netbox_client.NetboxClient.free_interface") @@ -23,17 +23,20 @@ def test_successful_iptrunk_termination( mocked_free_interface, mocked_delete_interface, mock_infoblox_delete_network, - mock_set_isis_to_90k, mock_execute_playbook, iptrunk_subscription_factory, faker, data_config_filename, + nokia_router_subscription_factory, ): # Set up mock return values product_id = iptrunk_subscription_factory() mocked_netbox = MockedNetboxClient() mocked_delete_interface.return_value = mocked_netbox.delete_interface() mocked_free_interface.return_value = mocked_netbox.free_interface() + # Add two more routers to our fake network + nokia_router_subscription_factory(router_role=RouterRole.P) + nokia_router_subscription_factory(router_role=RouterRole.PE) # Run workflow oss_params = load_oss_params() @@ -60,7 +63,6 @@ def test_successful_iptrunk_termination( subscription = Iptrunk.from_subscription(subscription_id) assert subscription.status == "terminated" - assert mock_execute_playbook.call_count == 2 - assert mock_set_isis_to_90k.call_count == 1 + assert mock_execute_playbook.call_count == 3 assert mock_infoblox_delete_network.call_count == 2 assert subscription.iptrunk.iptrunk_isis_metric == oss_params.GENERAL.isis_high_metric diff --git a/test/workflows/iptrunk/test_validate_iptrunk.py b/test/workflows/iptrunk/test_validate_iptrunk.py index 13bcaed9b4be4284a6f1dc5fa4e41410d2f8dab6..6b132abca2e3b2616b2a9c8937fc5e64122837ba 100644 --- a/test/workflows/iptrunk/test_validate_iptrunk.py +++ b/test/workflows/iptrunk/test_validate_iptrunk.py @@ -69,7 +69,7 @@ def _mocked_netbox_client(): @patch("gso.services.infoblox.find_network_by_cidr") @patch("gso.services.infoblox.find_v6_host_by_fqdn") @patch("gso.services.infoblox.find_host_by_fqdn") -@patch("gso.workflows.iptrunk.validate_iptrunk.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.services.netbox_client.NetboxClient.get_interface_by_name_and_device") def test_validate_iptrunk_success( mock_get_interface_by_name, @@ -219,7 +219,7 @@ def test_validate_iptrunk_success( @patch("gso.services.infoblox.find_network_by_cidr") @patch("gso.services.infoblox.find_v6_host_by_fqdn") @patch("gso.services.infoblox.find_host_by_fqdn") -@patch("gso.workflows.iptrunk.validate_iptrunk.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.services.netbox_client.NetboxClient.get_interface_by_name_and_device") def test_validate_iptrunk_skip_legacy_trunks( mock_get_interface_by_name, diff --git a/test/workflows/router/test_create_router.py b/test/workflows/router/test_create_router.py index 83a2e53354eb202e44a665125d154245b4cb826e..a6bf456f3ef249d52817b2381c9cc3fcd40a5c86 100644 --- a/test/workflows/router/test_create_router.py +++ b/test/workflows/router/test_create_router.py @@ -36,7 +36,7 @@ def router_creation_input_form_data(site_subscription_factory, faker): @pytest.mark.workflow() -@patch("gso.utils.workflow_steps.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.router.create_router.NetboxClient.create_device") @patch("gso.workflows.router.create_router.infoblox.hostname_available") @patch("gso.workflows.router.create_router.infoblox.find_host_by_fqdn") @@ -117,7 +117,7 @@ def test_create_nokia_router_success( @pytest.mark.workflow() -@patch("gso.utils.workflow_steps.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.router.create_router.NetboxClient.create_device") @patch("gso.workflows.router.create_router.infoblox.hostname_available") @patch("gso.workflows.router.create_router.infoblox.find_network_by_cidr") diff --git a/test/workflows/router/test_promote_p_to_pe.py b/test/workflows/router/test_promote_p_to_pe.py index 3bd7fdca1a65e0ad7bd0e1df59883cd020e9aca0..5e14dcaffb510fea4cee70f8672e1372c3634e7f 100644 --- a/test/workflows/router/test_promote_p_to_pe.py +++ b/test/workflows/router/test_promote_p_to_pe.py @@ -17,7 +17,7 @@ from test.workflows import ( @pytest.mark.workflow() -@patch("gso.workflows.router.promote_p_to_pe.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.router.promote_p_to_pe.KentikClient") def test_promote_p_to_pe_success( mock_kentik_client, @@ -29,6 +29,9 @@ def test_promote_p_to_pe_success( """Test the successful promotion of a Nokia P router to a PE router.""" mock_kentik_client.return_value = MockedKentikClient router_id = nokia_router_subscription_factory(router_role=RouterRole.P, status=SubscriptionLifecycle.ACTIVE) + # Add two more routers to our fake network + nokia_router_subscription_factory(router_role=RouterRole.P) + nokia_router_subscription_factory(router_role=RouterRole.PE) input_data = [{"subscription_id": router_id}, {"tt_number": faker.tt_number()}] result, process_stat, step_log = run_workflow("promote_p_to_pe", input_data) for _ in range(3): @@ -55,7 +58,7 @@ def test_promote_p_to_pe_juniper_router(juniper_router_subscription_factory, dat @pytest.mark.workflow() -@patch("gso.workflows.router.promote_p_to_pe.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") def test_promote_p_to_pe_nokia_pe_router( mock_execute_playbook, nokia_router_subscription_factory, data_config_filename, faker ): diff --git a/test/workflows/router/test_terminate_router.py b/test/workflows/router/test_terminate_router.py index f2cb638ab1cf5f918184e218c0f2d31d4f65cc87..a5f4fd3d0176113eb3f4dce0ae8c5a6274a51dc0 100644 --- a/test/workflows/router/test_terminate_router.py +++ b/test/workflows/router/test_terminate_router.py @@ -30,6 +30,9 @@ def test_terminate_pe_router_full_success( ): # Prepare mock values and expected results product_id = nokia_router_subscription_factory() + # Add two more routers to our fake network + nokia_router_subscription_factory(router_role=RouterRole.P) + nokia_router_subscription_factory(router_role=RouterRole.PE) router_termination_input_form_data = { "tt_number": faker.tt_number(), "remove_configuration": remove_configuration, @@ -81,6 +84,9 @@ def test_terminate_p_router_full_success( ): # Prepare mock values and expected results product_id = nokia_router_subscription_factory(router_role=RouterRole.P) + # Add two more routers to our fake network + nokia_router_subscription_factory(router_role=RouterRole.P) + nokia_router_subscription_factory(router_role=RouterRole.PE) router_termination_input_form_data = { "tt_number": faker.tt_number(), "remove_configuration": remove_configuration, diff --git a/test/workflows/router/test_update_ibgp_mesh.py b/test/workflows/router/test_update_ibgp_mesh.py index e0cf8209f876730dc15d2add15f7c3cae111d438..b473f2ea31c4b14f33343106535d1f52b79e3705 100644 --- a/test/workflows/router/test_update_ibgp_mesh.py +++ b/test/workflows/router/test_update_ibgp_mesh.py @@ -18,31 +18,21 @@ from test.workflows import ( @pytest.mark.parametrize("trunk_status", [SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE]) -@pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE]) @pytest.mark.workflow() -@patch("gso.workflows.router.update_ibgp_mesh.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.workflows.router.update_ibgp_mesh.librenms_client.LibreNMSClient.add_device") @patch("gso.workflows.router.update_ibgp_mesh.librenms_client.LibreNMSClient.device_exists") def test_update_ibgp_mesh_success( mock_librenms_device_exists, mock_librenms_add_device, mock_execute_playbook, - router_role, trunk_status, iptrunk_subscription_factory, - iptrunk_side_subscription_factory, - nokia_router_subscription_factory, data_config_filename, faker, ): mock_librenms_device_exists.return_value = False - router_a = nokia_router_subscription_factory(router_role=router_role) - router_b = nokia_router_subscription_factory(router_role=router_role) - side_a = iptrunk_side_subscription_factory(iptrunk_side_node=router_a) - side_b = iptrunk_side_subscription_factory(iptrunk_side_node=router_b) - ip_trunk = Iptrunk.from_subscription( - iptrunk_subscription_factory(status=trunk_status, iptrunk_sides=[side_a, side_b]) - ) + ip_trunk = Iptrunk.from_subscription(iptrunk_subscription_factory(status=trunk_status)) ibgp_mesh_input_form_data = { "subscription_id": ip_trunk.iptrunk.iptrunk_sides[0].iptrunk_side_node.owner_subscription_id } @@ -50,8 +40,7 @@ def test_update_ibgp_mesh_success( "update_ibgp_mesh", [ibgp_mesh_input_form_data, {"tt_number": faker.tt_number()}] ) - lso_step_count = 5 if router_role == RouterRole.P else 14 - for _ in range(lso_step_count): + for _ in range(5): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) # Handle two consecutive user input steps @@ -61,7 +50,7 @@ def test_update_ibgp_mesh_success( state = extract_state(result) - assert mock_execute_playbook.call_count == lso_step_count + assert mock_execute_playbook.call_count == 5 assert mock_librenms_add_device.call_count == 1 assert result.status == StepStatus.COMPLETE assert state["subscription"]["router"]["router_access_via_ts"] is False diff --git a/test/workflows/router/test_validate_router.py b/test/workflows/router/test_validate_router.py index 924577e23fa83471e1206a32ea554f5558733ab2..07fc78d74a8297f6d6b2a5f6d458aa1c6eeb5cab 100644 --- a/test/workflows/router/test_validate_router.py +++ b/test/workflows/router/test_validate_router.py @@ -15,7 +15,7 @@ from test.workflows import ( @pytest.mark.workflow() @patch("gso.services.infoblox.find_host_by_fqdn") -@patch("gso.services.lso_client.execute_playbook") +@patch("gso.services.lso_client._send_request") @patch("gso.services.netbox_client.NetboxClient.get_device_by_name") @patch("gso.services.librenms_client.LibreNMSClient.validate_device") @patch("gso.services.kentik_client.KentikClient")