Skip to content
Snippets Groups Projects
Verified Commit f6caeb05 authored by Neda Moeini's avatar Neda Moeini Committed by Karel van Klink
Browse files

Add promote P to PE workflow.

parent e3d42a78
No related branches found
No related tags found
No related merge requests found
"""Add promote P to PE workflows..
Revision ID: 88dd5a44150d
Revises: 41fd1ae225aq
Create Date: 2024-08-07 13:54:44.362435
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '88dd5a44150d'
down_revision = '41fd1ae225aq'
branch_labels = None
depends_on = None
from orchestrator.migrations.helpers import create_workflow, delete_workflow
new_workflows = [
{
"name": "promote_p_to_pe",
"target": "MODIFY",
"description": "Promote P router to PE router",
"product_type": "Router"
}
]
def upgrade() -> None:
conn = op.get_bind()
for workflow in new_workflows:
create_workflow(conn, workflow)
def downgrade() -> None:
conn = op.get_bind()
for workflow in new_workflows:
delete_workflow(conn, workflow["name"])
......@@ -44,6 +44,7 @@ LazyWorkflowInstance("gso.workflows.router.modify_connection_strategy", "modify_
LazyWorkflowInstance("gso.workflows.router.import_router", "import_router")
LazyWorkflowInstance("gso.workflows.router.create_imported_router", "create_imported_router")
LazyWorkflowInstance("gso.workflows.router.validate_router", "validate_router")
LazyWorkflowInstance("gso.workflows.router.promote_p_to_pe", "promote_p_to_pe")
# Site workflows
LazyWorkflowInstance("gso.workflows.site.create_site", "create_site")
......
"""Promote a P router to a PE router."""
from typing import Any
from orchestrator.config.assignee import Assignee
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.utils.errors import ProcessFailureError
from orchestrator.workflow import StepList, begin, 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
from gso.products.product_blocks.router import RouterRole
from gso.products.product_types.router import Router, RouterInactive
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
def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
"""Promote P router to PE router."""
subscription = Router.from_subscription(subscription_id)
class PromotePToPEForm(FormPage):
tt_number: str
@field_validator("tt_number")
def validate_tt_number(cls, tt_number: str) -> str:
return validate_tt_number(tt_number)
user_input = yield PromotePToPEForm
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."""
extra_vars = {
"dry_run": False,
"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("[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:
"""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",
}
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] Deploy PE base config")
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",
}
lso_client.execute_playbook(
playbook_name="promote_p_to_pe.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
extra_vars=extra_vars,
)
@inputstep("Prompt EARL insertion", assignee=Assignee.SYSTEM)
def prompt_insert_in_earl(subscription: dict[str, Any]) -> FormGenerator:
"""Wait for confirmation from an operator that the router has been inserted in EARL."""
class EARLPrompt(FormPage):
model_config = ConfigDict(title="Update RADIUS clients")
info_label: Label = (
f"Please add the router {subscription["router"]["router_fqdn"]} to EARL."
)
yield EARLPrompt
return {}
@step("Create Kentik device")
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
):
msg = "Router object is missing required properties."
raise ProcessFailureError(msg)
kentik_client = KentikClient()
kentik_site = kentik_client.get_site_by_name(subscription.router.router_site.site_name)
if not kentik_site:
msg = f"Site could not be found in Kentik: {subscription.router.router_site.site_name}"
raise ProcessFailureError(msg)
site_tier = subscription.router.router_site.site_tier
new_device = NewKentikDevice(
device_name=subscription.router.router_fqdn,
device_description=str(subscription.subscription_id),
sending_ips=[str(subscription.router.router_lo_ipv4_address)],
site_tier=site_tier,
site_id=kentik_site["id"],
device_snmp_ip=str(subscription.router.router_lo_ipv4_address),
device_bgp_flowspec=False,
device_bgp_neighbor_ip=str(subscription.router.router_lo_ipv4_address),
device_bgp_neighbor_ip6=str(subscription.router.router_lo_ipv6_address),
)
kentik_device = kentik_client.create_device(new_device)
if "error" in kentik_device or "kentik_error" in kentik_device:
raise ProcessFailureError(str(kentik_device))
kentik_device.pop("custom_column_data", None)
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."""
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)
}
lso_client.execute_playbook(
playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
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."""
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)
}
lso_client.execute_playbook(
playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
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:
"""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",
"verb": "add_pe_mesh_to_pe",
"pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
}
lso_client.execute_playbook(
playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
extra_vars=extra_vars,
)
@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:
"""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",
"verb": "add_pe_mesh_to_pe",
"pe_router_list": generate_inventory_for_active_routers(RouterRole.PE)
}
lso_client.execute_playbook(
playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
extra_vars=extra_vars,
)
@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:
"""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.",
"verb": "add_pe_to_pe_mesh",
}
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,
)
@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:
"""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.",
"verb": "add_pe_to_pe_mesh",
}
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,
)
@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."""
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",
}
lso_client.execute_playbook(
playbook_name="check_ibgp.yaml",
callback_route=callback_route,
inventory=subscription["router"]["router_fqdn"],
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:
"""Perform a dry run of deploying routing instances."""
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_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,
)
@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:
"""Perform a real run of deploying routing instances."""
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_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,
)
@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."""
extra_vars = {
"dry_run": True,
"subscription": subscription,
"commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Check L3 services",
"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,
)
@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."""
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",
}
lso_client.execute_playbook(
playbook_name="check_l3_services.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."""
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",
}
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] 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."""
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",
}
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("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] Delete default routes")
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)",
"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,
)
@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:
"""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)",
"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,
)
@workflow(
"Promote P router to PE router",
initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator),
target=Target.MODIFY,
)
def promote_p_to_pe() -> StepList:
"""Promote a P router to a PE router."""
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
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment