From 19aaac4f5a30667052f7ba650999453c2fd73d55 Mon Sep 17 00:00:00 2001 From: Karel van Klink <karel.vanklink@geant.org> Date: Tue, 1 Oct 2024 17:42:53 +0200 Subject: [PATCH] Introduce an LSOState type, but we can't use it in python 3.12 yet --- gso/services/lso_client.py | 14 +++++- gso/utils/workflow_steps.py | 7 +-- gso/workflows/iptrunk/create_iptrunk.py | 14 +++--- gso/workflows/iptrunk/deploy_twamp.py | 10 ++-- gso/workflows/iptrunk/migrate_iptrunk.py | 34 +++++++------- gso/workflows/iptrunk/modify_isis_metric.py | 6 +-- .../iptrunk/modify_trunk_interface.py | 12 ++--- gso/workflows/iptrunk/terminate_iptrunk.py | 6 +-- gso/workflows/iptrunk/validate_iptrunk.py | 11 ++--- gso/workflows/router/promote_p_to_pe.py | 46 +++++++++---------- gso/workflows/router/terminate_router.py | 19 ++++---- gso/workflows/router/update_ibgp_mesh.py | 12 ++--- gso/workflows/router/validate_router.py | 6 +-- 13 files changed, 104 insertions(+), 93 deletions(-) diff --git a/gso/services/lso_client.py b/gso/services/lso_client.py index 2215a7f5..cae5dd9c 100644 --- a/gso/services/lso_client.py +++ b/gso/services/lso_client.py @@ -5,7 +5,7 @@ import json import logging -from typing import Any +from typing import Any, Literal, TypedDict import requests from orchestrator import step @@ -23,6 +23,18 @@ from gso import settings logger = logging.getLogger(__name__) +class _LSOState(TypedDict): # noqa: PYI049 + """An expanded state that must contain at least the required keys for the execution of an Ansible playbook.""" + + playbook_name: str + extra_vars: dict[str, Any] + inventory: dict[Literal["all"], dict[Literal["hosts"], dict[str, Any] | None]] + __extra_values__: Any # This is feature unavailable in python 3.12 + + +LSOState = State # FIXME: Use the above definition when python3.13 is released + + def _send_request(parameters: dict, callback_route: str) -> None: """Send a request to :term:`LSO`. The callback address is derived using the process ID provided. diff --git a/gso/utils/workflow_steps.py b/gso/utils/workflow_steps.py index 5a714e1b..9e3a3509 100644 --- a/gso/utils/workflow_steps.py +++ b/gso/utils/workflow_steps.py @@ -13,6 +13,7 @@ from pydantic_forms.types import FormGenerator from pydantic_forms.validators import Label from gso.products.product_types.iptrunk import Iptrunk +from gso.services.lso_client import LSOState from gso.settings import load_oss_params @@ -22,7 +23,7 @@ def _deploy_base_config( process_id: UUIDstr, *, dry_run: bool, -) -> State: +) -> LSOState: extra_vars = { "wfo_router_json": subscription, "dry_run": dry_run, @@ -50,7 +51,7 @@ def deploy_base_config_real(subscription: dict[str, Any], tt_number: str, proces @step("[FOR REAL] Set ISIS metric to very high value") -def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, 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() @@ -81,7 +82,7 @@ def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) @step("Run show commands after base config install") -def run_checks_after_base_config(subscription: dict[str, Any]) -> State: +def run_checks_after_base_config(subscription: dict[str, Any]) -> LSOState: """Workflow step for running show commands after installing base config.""" return { "playbook_name": "base_config_checks.yaml", diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index 8bb7c993..ae3c6a74 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 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,7 +325,7 @@ def initialize_subscription( @step("[DRY RUN] Provision IP trunk interface") -def provision_ip_trunk_iface_dry(subscription: IptrunkInactive, 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)), @@ -351,7 +351,7 @@ def provision_ip_trunk_iface_dry(subscription: IptrunkInactive, process_id: UUID @step("[FOR REAL] Provision IP trunk interface") -def provision_ip_trunk_iface_real(subscription: IptrunkInactive, 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)), @@ -377,7 +377,7 @@ def provision_ip_trunk_iface_real(subscription: IptrunkInactive, process_id: UUI @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity(subscription: IptrunkInactive) -> 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"} @@ -389,7 +389,7 @@ def check_ip_trunk_connectivity(subscription: IptrunkInactive) -> State: @step("[DRY RUN] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_dry(subscription: IptrunkInactive, 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,7 +415,7 @@ def provision_ip_trunk_isis_iface_dry(subscription: IptrunkInactive, process_id: @step("[FOR REAL] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_real(subscription: IptrunkInactive, 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)), @@ -441,7 +441,7 @@ def provision_ip_trunk_isis_iface_real(subscription: IptrunkInactive, process_id @step("Check ISIS adjacency") -def check_ip_trunk_isis(subscription: IptrunkInactive) -> 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"} diff --git a/gso/workflows/iptrunk/deploy_twamp.py b/gso/workflows/iptrunk/deploy_twamp.py index 36d1644b..b43de54c 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 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, 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)), @@ -58,7 +58,7 @@ def deploy_twamp_dry(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) @step("[FOR REAL] Deploy TWAMP on both sides") -def deploy_twamp_real(subscription: Iptrunk, process_id: UUIDstr, 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)), @@ -83,7 +83,7 @@ def deploy_twamp_real(subscription: Iptrunk, process_id: UUIDstr, tt_number: str @step("Check TWAMP status on both sides") -def check_twamp_status(subscription: Iptrunk) -> State: +def check_twamp_status(subscription: Iptrunk) -> LSOState: """Check TWAMP session.""" extra_vars = { "subscription": json.loads(json_dumps(subscription)), diff --git a/gso/workflows/iptrunk/migrate_iptrunk.py b/gso/workflows/iptrunk/migrate_iptrunk.py index 0077db4e..3c04fb8e 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 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,7 +203,7 @@ 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) -> 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"} @@ -224,7 +224,7 @@ def check_ip_trunk_optical_levels_pre(subscription: Iptrunk) -> State: @step("Check Optical POST levels on the trunk endpoint") def check_ip_trunk_optical_levels_post( subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int -) -> State: +) -> LSOState: """Check Optical POST levels on the trunk.""" extra_vars = { "wfo_ip_trunk_json": json.loads(json_dumps(subscription)), @@ -251,7 +251,7 @@ def check_ip_trunk_optical_levels_post( @step("Check LLDP on the trunk endpoints") def check_ip_trunk_lldp( subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int -) -> State: +) -> LSOState: """Check LLDP on the new trunk endpoints.""" extra_vars = { "wfo_ip_trunk_json": json.loads(json_dumps(subscription)), @@ -284,7 +284,7 @@ def disable_old_config_dry( 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)), @@ -323,7 +323,7 @@ def disable_old_config_real( 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)), @@ -362,7 +362,7 @@ def deploy_new_config_dry( 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)), @@ -401,7 +401,7 @@ def deploy_new_config_real( 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)), @@ -434,7 +434,7 @@ def deploy_new_config_real( @step("[DRY RUN] Update BFD on the remaining side") def update_remaining_side_bfd_dry( subscription: Iptrunk, new_node: Router, replace_index: int, process_id: UUIDstr, tt_number: str -) -> State: +) -> LSOState: """Perform a dry run of updating configuration on the remaining router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -462,7 +462,7 @@ def update_remaining_side_bfd_dry( @step("[FOR REAL] Update BFD on the remaining side") def update_remaining_side_bfd_real( subscription: Iptrunk, new_node: Router, replace_index: int, process_id: UUIDstr, tt_number: str -) -> State: +) -> LSOState: """Update configuration on the remaining router.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -488,7 +488,7 @@ def update_remaining_side_bfd_real( @step("Check BFD session over trunk") -def check_ip_trunk_bfd(subscription: Iptrunk, 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)), @@ -524,7 +524,7 @@ def confirm_continue_move_fiber() -> FormGenerator: @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity(subscription: Iptrunk, 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"} @@ -550,7 +550,7 @@ def deploy_new_isis( 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)), @@ -581,7 +581,7 @@ def deploy_new_isis( @step("Check ISIS adjacency") -def check_ip_trunk_isis(subscription: Iptrunk, 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"} @@ -618,7 +618,7 @@ def restore_isis_metric( process_id: UUIDstr, 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 = { @@ -653,7 +653,7 @@ def delete_old_config_dry( 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)), @@ -692,7 +692,7 @@ def delete_old_config_real( 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)), diff --git a/gso/workflows/iptrunk/modify_isis_metric.py b/gso/workflows/iptrunk/modify_isis_metric.py index daf24ec7..d95a6eb6 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 lso_interaction +from gso.services.lso_client import LSOState, lso_interaction from gso.utils.types.tt_number import TTNumber @@ -37,7 +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, 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)), @@ -63,7 +63,7 @@ def provision_ip_trunk_isis_iface_dry(subscription: Iptrunk, process_id: UUIDstr @step("[FOR REAL] Provision IP trunk ISIS interface") -def provision_ip_trunk_isis_iface_real(subscription: Iptrunk, process_id: UUIDstr, 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)), diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index 350ea64a..0dcc5d83 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 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,7 +186,7 @@ def determine_change_in_capacity( @step("Check IP connectivity of the trunk") -def check_ip_trunk_connectivity(subscription: Iptrunk) -> 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"} @@ -204,7 +204,7 @@ def check_ip_trunk_connectivity(subscription: Iptrunk) -> State: @step("Check LLDP on the trunk endpoints") -def check_ip_trunk_lldp(subscription: Iptrunk) -> 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"} @@ -308,7 +308,7 @@ def modify_iptrunk_subscription( @step("[DRY RUN] Provision IP trunk interface") def provision_ip_trunk_iface_dry( subscription: Iptrunk, process_id: UUIDstr, tt_number: str, removed_ae_members: list[str] -) -> State: +) -> LSOState: """Perform a dry run of deploying the updated IP trunk.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -337,7 +337,7 @@ def provision_ip_trunk_iface_dry( @step("[FOR REAL] Provision IP trunk interface") def provision_ip_trunk_iface_real( subscription: Iptrunk, process_id: UUIDstr, tt_number: str, removed_ae_members: list[str] -) -> State: +) -> LSOState: """Provision the new IP trunk with updated interfaces.""" extra_vars = { "wfo_trunk_json": json.loads(json_dumps(subscription)), @@ -459,7 +459,7 @@ 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) -> 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"} diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py index 9596c6b9..549bc3c2 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 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, 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)), @@ -77,7 +77,7 @@ def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr, tt_numb @step("[FOR REAL] Deprovision IP trunk") -def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, 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)), diff --git a/gso/workflows/iptrunk/validate_iptrunk.py b/gso/workflows/iptrunk/validate_iptrunk.py index 96372192..7832487f 100644 --- a/gso/workflows/iptrunk/validate_iptrunk.py +++ b/gso/workflows/iptrunk/validate_iptrunk.py @@ -8,18 +8,17 @@ 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 -from pydantic_forms.types import State from gso.products.product_types.iptrunk import Iptrunk from gso.services import infoblox -from gso.services.lso_client import anonymous_lso_interaction +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) -> State: +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"} @@ -135,7 +134,7 @@ def verify_netbox_entries(subscription: Iptrunk) -> None: @step("Verify configuration of IPtrunk") -def verify_iptrunk_config(subscription: Iptrunk) -> State: +def verify_iptrunk_config(subscription: Iptrunk) -> LSOState: """Check for configuration drift on the relevant routers.""" return { "playbook_name": "iptrunks.yaml", @@ -158,7 +157,7 @@ def verify_iptrunk_config(subscription: Iptrunk) -> State: @step("Check ISIS configuration") -def check_ip_trunk_isis(subscription: Iptrunk) -> State: +def check_ip_trunk_isis(subscription: Iptrunk) -> LSOState: """Run an Ansible playbook to check for any :term:`ISIS` configuration drift.""" return { "playbook_name": "iptrunks.yaml", @@ -181,7 +180,7 @@ def check_ip_trunk_isis(subscription: Iptrunk) -> State: @step("Verify TWAMP configuration") -def verify_twamp_config(subscription: Iptrunk) -> State: +def verify_twamp_config(subscription: Iptrunk) -> LSOState: """Check for configuration drift of TWAMP.""" return { "playbook_name": "deploy_twamp.yaml", diff --git a/gso/workflows/router/promote_p_to_pe.py b/gso/workflows/router/promote_p_to_pe.py index 66be5635..3bc2e80f 100644 --- a/gso/workflows/router/promote_p_to_pe.py +++ b/gso/workflows/router/promote_p_to_pe.py @@ -18,7 +18,7 @@ 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.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 @@ -48,7 +48,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], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -65,7 +65,7 @@ def set_isis_overload(subscription: dict[str, Any], tt_number: str, process_id: @step("[DRY RUN] Deploy PE base config") -def deploy_pe_base_config_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -84,7 +84,7 @@ def deploy_pe_base_config_dry(subscription: dict[str, Any], tt_number: str, proc @step("[FOR REAL] Deploy PE base config") -def deploy_pe_base_config_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -151,7 +151,7 @@ def create_kentik_device(subscription: Router) -> State: @step("[DRY RUN] Include new PE into SDP mesh on other Nokia PEs") -def update_sdp_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def update_sdp_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run for updating the SDP mesh with the new router.""" extra_vars = { "dry_run": True, @@ -175,7 +175,7 @@ def update_sdp_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id @step("[FOR REAL] Include new PE into SDP mesh on other Nokia PEs") -def update_sdp_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def update_sdp_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Update the SDP mesh for L2 circuits(epipes) config on PE NOKIA routers.""" extra_vars = { "dry_run": False, @@ -199,7 +199,7 @@ def update_sdp_mesh_real(subscription: dict[str, Any], tt_number: str, process_i @step("[DRY RUN] Remove P from all PEs") -def remove_p_from_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -217,7 +217,7 @@ def remove_p_from_pe_dry(subscription: dict[str, Any], tt_number: str, process_i @step("[FOR REAL] Remove P from all PEs") -def remove_p_from_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -235,7 +235,7 @@ def remove_p_from_pe_real(subscription: dict[str, Any], tt_number: str, process_ @step("[DRY RUN] Add PE mesh to PE") -def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of adding list of PE routers into iGEANT/iGEANT6 of promoted router.""" extra_vars = { "dry_run": True, @@ -254,7 +254,7 @@ def add_pe_mesh_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_ @step("[FOR REAL] Add PE mesh to PE") -def add_pe_mesh_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_mesh_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of adding list of PE routers into iGEANT/iGEANT6 of promoted router.""" extra_vars = { "dry_run": False, @@ -273,7 +273,7 @@ def add_pe_mesh_to_pe_real(subscription: dict[str, Any], tt_number: str, process @step("[DRY RUN] Add PE to PE mesh") -def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of adding the promoted router to all PE routers in iGEANT/iGEANT6.""" extra_vars = { "dry_run": True, @@ -291,7 +291,7 @@ def add_pe_to_pe_mesh_dry(subscription: dict[str, Any], tt_number: str, process_ @step("[FOR REAL] Add PE to PE mesh") -def add_pe_to_pe_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_to_pe_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of adding the promoted router to all PE routers in iGEANT/iGEANT6.""" extra_vars = { "dry_run": False, @@ -309,7 +309,7 @@ def add_pe_to_pe_mesh_real(subscription: dict[str, Any], tt_number: str, process @step("Check iBGP session") -def check_pe_ibgp(subscription: dict[str, Any]) -> State: +def check_pe_ibgp(subscription: dict[str, Any]) -> LSOState: """Check the iBGP session.""" extra_vars = { "dry_run": False, @@ -325,7 +325,7 @@ def check_pe_ibgp(subscription: dict[str, Any]) -> State: @step("[DRY RUN] Deploy routing instances") -def deploy_routing_instances_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -342,7 +342,7 @@ def deploy_routing_instances_dry(subscription: dict[str, Any], tt_number: str, p @step("[FOR REAL] Deploy routing instances") -def deploy_routing_instances_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -359,7 +359,7 @@ def deploy_routing_instances_real(subscription: dict[str, Any], tt_number: str, @step("Check L3 services") -def check_l3_services(subscription: dict[str, Any]) -> State: +def check_l3_services(subscription: dict[str, Any]) -> LSOState: """Check L3 services.""" extra_vars = { "dry_run": False, @@ -375,7 +375,7 @@ def check_l3_services(subscription: dict[str, Any]) -> State: @step("Remove ISIS overload") -def remove_isis_overload(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def remove_isis_overload(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Remove ISIS overload.""" extra_vars = { "dry_run": False, @@ -400,7 +400,7 @@ def update_subscription_model(subscription: Router) -> State: @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) -> State: +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, @@ -420,7 +420,7 @@ def add_all_p_to_pe_dry(subscription: dict[str, Any], tt_number: str, process_id @step("[FOR REAL] Add all P to this new PE") -def add_all_p_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_all_p_to_pe_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of adding all P routers to the PE router.""" extra_vars = { "dry_run": False, @@ -440,7 +440,7 @@ def add_all_p_to_pe_real(subscription: dict[str, Any], tt_number: str, process_i @step("[DRY RUN] Add this new PE to all P") -def add_pe_to_all_p_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_to_all_p_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a dry run of adding promoted router to all PE routers in iGEANT/iGEANT6.""" extra_vars = { "dry_run": True, @@ -460,7 +460,7 @@ def add_pe_to_all_p_dry(subscription: dict[str, Any], tt_number: str, process_id @step("[FOR REAL] Add this new PE to all P") -def add_pe_to_all_p_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +def add_pe_to_all_p_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: """Perform a real run of adding promoted router to all PE routers in iGEANT/iGEANT6.""" extra_vars = { "dry_run": False, @@ -480,7 +480,7 @@ def add_pe_to_all_p_real(subscription: dict[str, Any], tt_number: str, process_i @step("[DRY RUN] Delete default routes") -def delete_default_routes_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -498,7 +498,7 @@ def delete_default_routes_dry(subscription: dict[str, Any], tt_number: str, proc @step("[FOR REAL] Delete default routes") -def delete_default_routes_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, diff --git a/gso/workflows/router/terminate_router.py b/gso/workflows/router/terminate_router.py index 421a55c0..13cef223 100644 --- a/gso/workflows/router/terminate_router.py +++ b/gso/workflows/router/terminate_router.py @@ -19,14 +19,13 @@ from orchestrator.workflows.steps import ( unsync, ) from orchestrator.workflows.utils import wrap_modify_initial_input_form -from pydantic_forms.types import State from gso.products.product_blocks.router import RouterRole from gso.products.product_types.router import Router 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 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 @@ -70,7 +69,7 @@ def deprovision_loopback_ips(subscription: Router) -> dict: @step("[DRY RUN] Remove configuration from router") -def remove_config_from_router_dry(subscription: Router, process_id: UUIDstr, tt_number: str) -> State: +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)), @@ -88,7 +87,7 @@ def remove_config_from_router_dry(subscription: Router, process_id: UUIDstr, tt_ @step("[FOR REAL] Remove configuration from router") -def remove_config_from_router_real(subscription: Router, process_id: UUIDstr, tt_number: str) -> State: +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)), @@ -113,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, tt_number: str, process_id: UUIDstr) -> State: +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, @@ -131,7 +130,7 @@ def remove_p_from_all_pe_dry(subscription: Router, tt_number: str, process_id: U @step("[REAL RUN] Remove P router from all the PE routers") -def remove_p_from_all_pe_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> State: +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, @@ -149,7 +148,7 @@ def remove_p_from_all_pe_real(subscription: Router, tt_number: str, process_id: @step("[DRY RUN] Remove PE router from all the PE routers") -def remove_pe_from_all_pe_dry(subscription: Router, tt_number: str, process_id: UUIDstr) -> State: +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, @@ -169,7 +168,7 @@ def remove_pe_from_all_pe_dry(subscription: Router, tt_number: str, process_id: @step("[REAL RUN] Remove all PE routers from all the PE routers") -def remove_pe_from_all_pe_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> State: +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, @@ -189,7 +188,7 @@ def remove_pe_from_all_pe_real(subscription: Router, tt_number: str, process_id: @step("[DRY RUN] Remove PE router from all the P routers") -def remove_pe_from_all_p_dry(subscription: Router, tt_number: str, process_id: UUIDstr) -> State: +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, @@ -207,7 +206,7 @@ def remove_pe_from_all_p_dry(subscription: Router, tt_number: str, process_id: U @step("[REAL RUN] Remove PE router from all P routers") -def remove_pe_from_all_p_real(subscription: Router, tt_number: str, process_id: UUIDstr) -> State: +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, diff --git a/gso/workflows/router/update_ibgp_mesh.py b/gso/workflows/router/update_ibgp_mesh.py index 8f99bb86..9c88704b 100644 --- a/gso/workflows/router/update_ibgp_mesh.py +++ b/gso/workflows/router/update_ibgp_mesh.py @@ -15,7 +15,7 @@ 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 -from gso.services.lso_client import lso_interaction +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 @@ -52,7 +52,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: @step("[DRY RUN] Add P router to iBGP mesh") -def add_p_to_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -69,7 +69,7 @@ def add_p_to_mesh_dry(subscription: dict[str, Any], tt_number: str, process_id: @step("[FOR REAL] Add P router to iBGP mesh") -def add_p_to_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -86,7 +86,7 @@ def add_p_to_mesh_real(subscription: dict[str, Any], tt_number: str, process_id: @step("[DRY RUN] Add all PE routers to P router iBGP group") -def add_all_pe_to_p_dry(subscription: dict[str, Any]) -> State: +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, @@ -103,7 +103,7 @@ def add_all_pe_to_p_dry(subscription: dict[str, Any]) -> State: @step("[FOR REAL] Add all PE routers to P router iBGP group") -def add_all_pe_to_p_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> State: +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, @@ -121,7 +121,7 @@ def add_all_pe_to_p_real(subscription: dict[str, Any], tt_number: str, process_i @step("Verify iBGP session health") -def check_ibgp_session(subscription: Router) -> State: +def check_ibgp_session(subscription: Router) -> LSOState: """Run a playbook using the provisioning proxy, to check the health of the new iBGP session.""" return { "playbook_name": "check_ibgp.yaml", diff --git a/gso/workflows/router/validate_router.py b/gso/workflows/router/validate_router.py index 82c46fc6..9e13f521 100644 --- a/gso/workflows/router/validate_router.py +++ b/gso/workflows/router/validate_router.py @@ -14,7 +14,7 @@ from gso.products.product_types.router import Router 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 +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 @@ -53,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]) -> State: +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, @@ -97,7 +97,7 @@ def check_kentik_entry_exists(subscription: Router) -> None: @step("Check base config for drift") -def verify_base_config(subscription: dict[str, Any]) -> State: +def verify_base_config(subscription: dict[str, Any]) -> LSOState: """Workflow step for running a playbook that checks whether base config has drifted.""" return { "playbook_name": "base_config.yaml", -- GitLab