From 9e588369d59cc10c2f50adde93c8e1d8579a239c Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Thu, 8 Aug 2024 13:32:36 +0200
Subject: [PATCH] Improved promote P to PE workflow.

---
 gso/utils/helpers.py                    |   6 +-
 gso/workflows/__init__.py               |   1 +
 gso/workflows/router/promote_p_to_pe.py | 384 ++++++++++++++----------
 3 files changed, 231 insertions(+), 160 deletions(-)

diff --git a/gso/utils/helpers.py b/gso/utils/helpers.py
index cca681a4..13016c76 100644
--- a/gso/utils/helpers.py
+++ b/gso/utils/helpers.py
@@ -306,6 +306,7 @@ def generate_fqdn(hostname: str, site_name: str, country_code: str) -> str:
 def generate_inventory_for_active_routers(
     router_role: RouterRole,
     exclude_routers: list[str] | None = None,
+    router_vendor: Vendor | None = None,
 ) -> dict:
     """Generate an Ansible-compatible inventory for executing playbooks.
 
@@ -313,6 +314,7 @@ def generate_inventory_for_active_routers(
 
     :param RouterRole router_role: The role of the routers to include in the inventory.
     :param list exclude_routers: List of routers to exclude from the inventory.
+    :param Vendor router_vendor: The vendor of the routers to include in the inventory.
     :return: A dictionary representing the inventory of active routers.
     :rtype: dict[str, Any]
     """
@@ -328,7 +330,9 @@ def generate_inventory_for_active_routers(
                     "vendor": str(router.router.vendor),
                 }
                 for router in all_routers
-                if router.router.router_role == router_role and router.router.router_fqdn not in exclude_routers
+                if router.router.router_role == router_role
+                and router.router.router_fqdn not in exclude_routers
+                and (router_vendor is None or router.router.vendor == router_vendor)
             }
         }
     }
diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py
index e7884722..82f876bb 100644
--- a/gso/workflows/__init__.py
+++ b/gso/workflows/__init__.py
@@ -20,6 +20,7 @@ WF_USABLE_MAP.update({
     "terminate_site": ALL_ALIVE_STATES,
     "terminate_router": ALL_ALIVE_STATES,
     "terminate_iptrunk": ALL_ALIVE_STATES,
+    "promote_p_to_pe": [SubscriptionLifecycle.ACTIVE],
 })
 
 #  IP trunk workflows
diff --git a/gso/workflows/router/promote_p_to_pe.py b/gso/workflows/router/promote_p_to_pe.py
index d893c057..6496267a 100644
--- a/gso/workflows/router/promote_p_to_pe.py
+++ b/gso/workflows/router/promote_p_to_pe.py
@@ -8,7 +8,7 @@ from orchestrator.forms.validators import Label
 from orchestrator.targets import Target
 from orchestrator.types import FormGenerator, State, UUIDstr
 from orchestrator.utils.errors import ProcessFailureError
-from orchestrator.workflow import StepList, begin, done, inputstep, step, workflow
+from orchestrator.workflow import StepList, begin, conditional, done, inputstep, step, workflow
 from orchestrator.workflows.steps import resync, store_process_subscription, unsync
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
 from pydantic import ConfigDict, field_validator
@@ -19,6 +19,7 @@ from gso.services import lso_client
 from gso.services.kentik_client import KentikClient, NewKentikDevice
 from gso.services.lso_client import lso_interaction
 from gso.utils.helpers import generate_inventory_for_active_routers, validate_tt_number
+from gso.utils.shared_enums import Vendor
 
 
 def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
@@ -26,6 +27,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
     subscription = Router.from_subscription(subscription_id)
 
     class PromotePToPEForm(FormPage):
+        model_config = ConfigDict(title=f"Promote {subscription.router.router_fqdn} to PE router?")
+
         tt_number: str
 
         @field_validator("tt_number")
@@ -37,29 +40,9 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
     return user_input.model_dump()
 
 
-@step("[DRY RUN] Evacuate the router by setting isis_overload")
-def set_isis_overload_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                          process_id: UUIDstr) -> None:
-    """Perform a dry run of evacuating the router by setting isis overload."""
-    extra_vars = {
-        "dry_run": True,
-        "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Set ISIS overload",
-        "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,
-    )
-
-
-@step("[FOR REAL] Evacuate the router by setting isis_overload")
-def set_isis_overload_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                           process_id: UUIDstr) -> None:
-    """Perform a real run of evacuating the router by setting isis overload."""
+@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:
+    """Evacuate the router by setting isis overload."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
@@ -76,14 +59,16 @@ def set_isis_overload_real(subscription: dict[str, Any], callback_route: str, tt
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a dry run of adding the base config to the router."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - deploy PE base config",
         "verb": "deploy_pe_base_config",
+        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
@@ -95,14 +80,16 @@ def deploy_pe_base_config_dry(subscription: dict[str, Any], callback_route: str,
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a real run of adding the base config to the router."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - deploy PE base config",
         "verb": "deploy_pe_base_config",
+        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
@@ -120,9 +107,7 @@ def prompt_insert_in_earl(subscription: dict[str, Any]) -> FormGenerator:
     class EARLPrompt(FormPage):
         model_config = ConfigDict(title="Update RADIUS clients")
 
-        info_label: Label = (
-            f"Please add the router {subscription["router"]["router_fqdn"]} to EARL."
-        )
+        info_label: Label = f"Please add the router {subscription["router"]["router_fqdn"]} to EARL."
 
     yield EARLPrompt
 
@@ -133,10 +118,10 @@ def prompt_insert_in_earl(subscription: dict[str, Any]) -> FormGenerator:
 def create_kentik_device(subscription: RouterInactive) -> State:
     """Create a new device in Kentik."""
     if not (
-            subscription.router.router_site
-            and subscription.router.router_site.site_name
-            and subscription.router.router_site.site_tier
-            and subscription.router.router_fqdn
+        subscription.router.router_site
+        and subscription.router.router_site.site_name
+        and subscription.router.router_site.site_tier
+        and subscription.router.router_fqdn
     ):
         msg = "Router object is missing required properties."
         raise ProcessFailureError(msg)
@@ -169,59 +154,106 @@ def create_kentik_device(subscription: RouterInactive) -> State:
     return {"kentik_device": kentik_device}
 
 
-@step("[DRY RUN] Remove PE from P")
-def remove_pe_from_p_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                         process_id: UUIDstr) -> None:
-    """Perform a dry run of removing the PE routers from the P router."""
+@step("[DRY RUN] Update SDP mesh")
+def update_sdp_mesh_dry(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None:
+    """Perform a dry run for updating the SDP mesh with the new router."""
+    extra_vars = {
+        "dry_run": True,
+        "subscription": subscription,
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
+        f"Update the SDP mesh for L2circuits(epipes) config on PE NOKIA routers",
+        "verb": "update_sdp_mesh",
+        "pe_router_list": generate_inventory_for_active_routers(router_role=RouterRole.PE, router_vendor=Vendor.NOKIA)[
+            "all"
+        ]["hosts"],
+    }
+
+    lso_client.execute_playbook(
+        playbook_name="update_pe_sdp_mesh.yaml",
+        callback_route=callback_route,
+        inventory=generate_inventory_for_active_routers(RouterRole.PE),
+        extra_vars=extra_vars,
+    )
+
+
+@step("[FOR REAL] Update SDP mesh")
+def update_sdp_mesh_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Update the SDP mesh for L2 circuits(epipes) config on PE NOKIA routers."""
+    extra_vars = {
+        "dry_run": False,
+        "subscription": subscription,
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
+        f"Update the SDP mesh for l2circuits(epipes) config on PE NOKIA routers",
+        "verb": "update_sdp_mesh",
+        "pe_router_list": generate_inventory_for_active_routers(router_role=RouterRole.PE, router_vendor=Vendor.NOKIA)[
+            "all"
+        ]["hosts"],
+    }
+
+    lso_client.execute_playbook(
+        playbook_name="update_pe_sdp_mesh.yaml",
+        callback_route=callback_route,
+        inventory=generate_inventory_for_active_routers(RouterRole.PE),
+        extra_vars=extra_vars,
+    )
+
+
+@step("[DRY RUN] Remove P from P")
+def remove_p_from_pe_dry(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Perform a dry run of removing the P routers from the PE router."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Depopulate P-only neighbour list from the promoted router",
-        "verb": "remove_pe_from_p",
-        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
+        f"Remove P only roter neighbour {subscription["router"]["router_fqdn"]} from P only group",
+        "verb": "remove_p_from_pe",
     }
 
     lso_client.execute_playbook(
         playbook_name="update_ibgp_mesh.yaml",
         callback_route=callback_route,
-        inventory=subscription["router"]["router_fqdn"],
+        inventory=generate_inventory_for_active_routers(RouterRole.PE),
         extra_vars=extra_vars,
     )
 
 
-@step("[FOR REAL] Remove PE from P")
-def remove_pe_from_p_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                          process_id: UUIDstr) -> None:
-    """Remove the PE routers from the P router."""
+@step("[FOR REAL] Remove P from PE")
+def remove_p_from_pe_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Remove the P routers from the PE router."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Depopulate P-only neighbour list from the promoted router",
-        "verb": "remove_pe_from_p",
-        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
+        f"Remove P only roter neighbour {subscription["router"]["router_fqdn"]} from P only group",
+        "verb": "remove_p_from_pe",
     }
 
     lso_client.execute_playbook(
         playbook_name="update_ibgp_mesh.yaml",
         callback_route=callback_route,
-        inventory=subscription["router"]["router_fqdn"],
+        inventory=generate_inventory_for_active_routers(RouterRole.PE),
         extra_vars=extra_vars,
     )
 
 
 @step("[DRY RUN] Add PE mesh to PE")
-def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                          process_id: UUIDstr) -> None:
+def add_pe_mesh_to_pe_dry(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a dry run of adding list of PE routers into iGEANT/iGEANT6 of promoted router."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Add list of PE routers into iGEANT/iGEANT6 of promoted router",
+        f"Add list of PE routers into iGEANT/iGEANT6 of promoted router",
         "verb": "add_pe_mesh_to_pe",
-        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
+        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
@@ -233,16 +265,17 @@ def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], callback_route: str, tt_
 
 
 @step("[FOR REAL] Add PE mesh to PE")
-def add_pe_mesh_to_pe_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                           process_id: UUIDstr) -> None:
+def add_pe_mesh_to_pe_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a real run of adding list of PE routers into iGEANT/iGEANT6 of promoted router."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Add list of PE routers into iGEANT/iGEANT6 of promoted router",
+        f"Add list of PE routers into iGEANT/iGEANT6 of promoted router",
         "verb": "add_pe_mesh_to_pe",
-        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
+        "pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
@@ -254,14 +287,15 @@ def add_pe_mesh_to_pe_real(subscription: dict[str, Any], callback_route: str, tt
 
 
 @step("[DRY RUN] Add PE to PE mesh")
-def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                          process_id: UUIDstr) -> None:
+def add_pe_to_pe_mesh_dry(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a dry run of adding the promoted router to all PE routers in iGEANT/iGEANT6."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Add promoted router to all PE routers in iGEANT/iGEANT.",
+        f"Add promoted router to all PE routers in iGEANT/iGEANT.",
         "verb": "add_pe_to_pe_mesh",
     }
 
@@ -274,14 +308,15 @@ def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], callback_route: str, tt_
 
 
 @step("[FOR REAL] Add PE to PE mesh")
-def add_pe_to_pe_mesh_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                           process_id: UUIDstr) -> None:
+def add_pe_to_pe_mesh_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a real run of adding the promoted router to all PE routers in iGEANT/iGEANT6."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Add promoted router to all PE routers in iGEANT/iGEANT.",
+        f"Add promoted router to all PE routers in iGEANT/iGEANT.",
         "verb": "add_pe_to_pe_mesh",
     }
 
@@ -293,33 +328,12 @@ def add_pe_to_pe_mesh_real(subscription: dict[str, Any], callback_route: str, tt
     )
 
 
-@step("[DRY RUN] Check iBGP session")
-def check_pe_ibgp_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                      process_id: UUIDstr) -> None:
-    """Perform a dry run of checking the iBGP session."""
-    extra_vars = {
-        "dry_run": True,
-        "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Check iBGP session",
-        "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,
-    )
-
-
-@step("[FOR REAL] Check iBGP session")
-def check_pe_ibgp_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                       process_id: UUIDstr) -> None:
-    """Perform a real run of checking the iBGP session."""
+@step("Check iBGP session")
+def check_pe_ibgp(subscription: dict[str, Any], callback_route: str) -> None:
+    """Check the iBGP session."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Check iBGP session",
         "verb": "check_pe_ibgp",
     }
 
@@ -332,8 +346,9 @@ def check_pe_ibgp_real(subscription: dict[str, Any], callback_route: str, tt_num
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a dry run of deploying routing instances."""
     extra_vars = {
         "dry_run": True,
@@ -351,8 +366,9 @@ def deploy_routing_instances_dry(subscription: dict[str, Any], callback_route: s
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a real run of deploying routing instances."""
     extra_vars = {
         "dry_run": False,
@@ -369,14 +385,12 @@ def deploy_routing_instances_real(subscription: dict[str, Any], callback_route:
     )
 
 
-@step("[DRY RUN] Check L3 services")
-def check_l3_services_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                          process_id: UUIDstr) -> None:
-    """Perform a dry run of checking L3 services."""
+@step("Check L3 services")
+def check_l3_services(subscription: dict[str, Any], callback_route: str) -> None:
+    """Check L3 services."""
     extra_vars = {
-        "dry_run": True,
+        "dry_run": False,
         "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Check L3 services",
         "verb": "check_base_ris",
     }
 
@@ -388,80 +402,124 @@ def check_l3_services_dry(subscription: dict[str, Any], callback_route: str, tt_
     )
 
 
-@step("[FOR REAL] Check L3 services")
-def check_l3_services_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                           process_id: UUIDstr) -> None:
-    """Perform a real run of checking L3 services."""
+@step("Remove ISIS overload")
+def remove_isis_overload(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Remove ISIS overload."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Check L3 services",
-        "verb": "check_base_ris",
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Remove ISIS overload",
+        "verb": "remove_isis_overload",
     }
 
     lso_client.execute_playbook(
-        playbook_name="check_l3_services.yaml",
+        playbook_name="promote_p_to_pe.yaml",
         callback_route=callback_route,
         inventory=subscription["router"]["router_fqdn"],
         extra_vars=extra_vars,
     )
 
 
-@step("[DRY RUN] Remove isis overload")
-def remove_isis_overload_dry(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                             process_id: UUIDstr) -> None:
-    """Perform a dry run of removing isis overload."""
+@step("Set router role to PE (Update subscription model)")
+def update_subscription_model(subscription: Router) -> State:
+    """Update the subscription model to set router role to PE."""
+    subscription.router.router_role = RouterRole.PE
+
+    return {"subscription": subscription}
+
+
+@step("[DRY RUN] Add all P to PE")
+def add_all_p_to_pe_dry(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None:
+    """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} - Remove ISIS overload",
-        "verb": "remove_isis_overload",
+        "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)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
-        playbook_name="promote_p_to_pe.yaml",
+        playbook_name="update_ibgp_mesh.yaml",
         callback_route=callback_route,
         inventory=subscription["router"]["router_fqdn"],
         extra_vars=extra_vars,
     )
 
 
-@step("[FOR REAL] Remove isis overload")
-def remove_isis_overload_real(subscription: dict[str, Any], callback_route: str, tt_number: str,
-                              process_id: UUIDstr) -> None:
-    """Perform a real run of removing isis overload."""
+@step("[FOR REAL] Add all P to PE")
+def add_all_p_to_pe_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Perform a real run of adding all P routers to the PE router."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Remove ISIS overload",
-        "verb": "remove_isis_overload",
+        "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)["all"]["hosts"],
     }
 
     lso_client.execute_playbook(
-        playbook_name="promote_p_to_pe.yaml",
+        playbook_name="update_ibgp_mesh.yaml",
         callback_route=callback_route,
         inventory=subscription["router"]["router_fqdn"],
         extra_vars=extra_vars,
     )
 
 
-@step("Set router role to PE (Update subscription model)")
-def update_subscription_model(subscription: Router) -> State:
-    """Update the subscription model to set router role to PE."""
-    subscription.router.router_role = RouterRole.PE
+@step("[DRY RUN] Add PE to all P")
+def add_pe_to_all_p_dry(subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr) -> None:
+    """Perform a dry run of adding promoted router to all PE routers in iGEANT/iGEANT6."""
+    extra_vars = {
+        "dry_run": True,
+        "subscription": subscription,
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
+        f"Add promoted router to all PE routers in iGEANT/iGEANT6",
+        "verb": "add_pe_to_p",
+    }
 
-    return {"subscription": subscription}
+    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,
+    )
+
+
+@step("[FOR REAL] Add PE to all P")
+def add_pe_to_all_p_real(
+    subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
+    """Perform a real run of adding promoted router to all PE routers in iGEANT/iGEANT6."""
+    extra_vars = {
+        "dry_run": False,
+        "subscription": subscription,
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
+        f"Add promoted router to all PE routers in iGEANT/iGEANT6",
+        "verb": "add_pe_to_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,
+    )
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a dry run of deleting the default routes."""
     extra_vars = {
         "dry_run": True,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Delete static default routes (part of P base-config)",
+        f"Delete static default routes (part of P base-config)",
         "verb": "delete_default_routes",
     }
 
@@ -474,14 +532,15 @@ def delete_default_routes_dry(subscription: dict[str, Any], callback_route: str,
 
 
 @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], callback_route: str, tt_number: str, process_id: UUIDstr
+) -> None:
     """Perform a real run of deleting the default routes."""
     extra_vars = {
         "dry_run": False,
         "subscription": subscription,
         "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - "
-                          f"Delete static default routes (part of P base-config)",
+        f"Delete static default routes (part of P base-config)",
         "verb": "delete_default_routes",
     }
 
@@ -500,33 +559,40 @@ def delete_default_routes_real(subscription: dict[str, Any], callback_route: str
 )
 def promote_p_to_pe() -> StepList:
     """Promote a P router to a PE router."""
+    router_is_juniper = conditional(lambda state: state["subscription"]["router"]["vendor"] == Vendor.JUNIPER)
+    router_is_pe = conditional(lambda state: state["subscription"]["router"]["router_role"] == RouterRole.PE)
+
     return (
-            begin
-            >> store_process_subscription(Target.MODIFY)
-            >> unsync
-            >> lso_interaction(set_isis_overload_dry)
-            >> lso_interaction(set_isis_overload_real)
-            >> lso_interaction(deploy_pe_base_config_dry)
-            >> lso_interaction(deploy_pe_base_config_real)
-            >> prompt_insert_in_earl
-            >> create_kentik_device
-            >> lso_interaction(remove_pe_from_p_dry)
-            >> lso_interaction(remove_pe_from_p_real)
-            >> lso_interaction(add_pe_mesh_to_pe_dry)
-            >> lso_interaction(add_pe_mesh_to_pe_real)
-            >> lso_interaction(add_pe_to_pe_mesh_dry)
-            >> lso_interaction(add_pe_to_pe_mesh_real)
-            >> lso_interaction(check_pe_ibgp_dry)
-            >> lso_interaction(check_pe_ibgp_real)
-            >> lso_interaction(deploy_routing_instances_dry)
-            >> lso_interaction(deploy_routing_instances_real)
-            >> lso_interaction(check_l3_services_dry)
-            >> lso_interaction(check_l3_services_real)
-            >> lso_interaction(remove_isis_overload_dry)
-            >> lso_interaction(remove_isis_overload_real)
-            >> update_subscription_model
-            >> lso_interaction(delete_default_routes_dry)
-            >> lso_interaction(delete_default_routes_real)
-            >> resync
-            >> done
+        begin
+        >> store_process_subscription(Target.MODIFY)
+        >> router_is_juniper(done)
+        >> router_is_pe(done)
+        >> unsync
+        >> lso_interaction(set_isis_overload)
+        >> lso_interaction(deploy_pe_base_config_dry)
+        >> lso_interaction(deploy_pe_base_config_real)
+        >> prompt_insert_in_earl
+        >> create_kentik_device
+        >> lso_interaction(update_sdp_mesh_dry)
+        >> lso_interaction(update_sdp_mesh_real)
+        >> lso_interaction(remove_p_from_pe_dry)
+        >> lso_interaction(remove_p_from_pe_real)
+        >> lso_interaction(add_pe_mesh_to_pe_dry)
+        >> lso_interaction(add_pe_mesh_to_pe_real)
+        >> lso_interaction(add_pe_to_pe_mesh_dry)
+        >> lso_interaction(add_pe_to_pe_mesh_real)
+        >> lso_interaction(check_pe_ibgp)
+        >> lso_interaction(deploy_routing_instances_dry)
+        >> lso_interaction(deploy_routing_instances_real)
+        >> lso_interaction(check_l3_services)
+        >> lso_interaction(remove_isis_overload)
+        >> update_subscription_model
+        >> lso_interaction(add_all_p_to_pe_dry)
+        >> lso_interaction(add_all_p_to_pe_real)
+        >> lso_interaction(add_pe_to_all_p_dry)
+        >> lso_interaction(add_pe_to_all_p_real)
+        >> lso_interaction(delete_default_routes_dry)
+        >> lso_interaction(delete_default_routes_real)
+        >> resync
+        >> done
     )
-- 
GitLab