diff --git a/gso/migrations/versions/2024-12-18_8a65d0ed588e_add_site_connectivity_check_task.py b/gso/migrations/versions/2024-12-18_8a65d0ed588e_add_site_connectivity_check_task.py new file mode 100644 index 0000000000000000000000000000000000000000..8c3e61e9e66afc45f8fb92c5663b2e41428c8303 --- /dev/null +++ b/gso/migrations/versions/2024-12-18_8a65d0ed588e_add_site_connectivity_check_task.py @@ -0,0 +1,39 @@ +"""Add Site connectivity check task. + +Revision ID: 8a65d0ed588e +Revises: 818d4ffe65df +Create Date: 2024-12-18 14:36:35.886366 + +""" +from uuid import uuid4 + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = '8a65d0ed588e' +down_revision = '818d4ffe65df' +branch_labels = None +depends_on = None + +workflow = { + "name": "task_check_site_connectivity", + "target": "SYSTEM", + "description": "Check Site Connectivity", + "workflow_id": uuid4(), +} + + +def upgrade() -> None: + conn = op.get_bind() + conn.execute( + sa.text( + "INSERT INTO workflows VALUES (:workflow_id, :name, :target, :description, now()) ON CONFLICT DO NOTHING" + ), + workflow, + ) + + +def downgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text("DELETE FROM workflows WHERE name = :name"), {"name": workflow["name"]}) diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json index c62d1c4d0601eeee8a1c4e0553f7685f2f7b4fbd..4dfe84023f01061ec7c45b0f84740827482172a2 100644 --- a/gso/translations/en-GB.json +++ b/gso/translations/en-GB.json @@ -103,6 +103,7 @@ "task_modify_partners": "Modify partner task", "task_delete_partners": "Delete partner task", "task_clean_old_tasks": "Remove old cleanup tasks", + "task_check_site_connectivity": "Check NETCONF connectivity of a Site", "promote_p_to_pe": "Promote P to PE", "create_layer_2_circuit": "Create Layer 2 Circuit", "modify_layer_2_circuit": "Modify Layer 2 Circuit", diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py index cc6725d47cdf05b2a0959920d7f08455987232d3..20e652d4400a387ef852b9751cb27d5037bdbe9f 100644 --- a/gso/workflows/__init__.py +++ b/gso/workflows/__init__.py @@ -107,6 +107,7 @@ LazyWorkflowInstance("gso.workflows.tasks.create_partners", "task_create_partner LazyWorkflowInstance("gso.workflows.tasks.modify_partners", "task_modify_partners") LazyWorkflowInstance("gso.workflows.tasks.delete_partners", "task_delete_partners") LazyWorkflowInstance("gso.workflows.tasks.clean_old_tasks", "task_clean_old_tasks") +LazyWorkflowInstance("gso.workflows.tasks.check_site_connectivity", "task_check_site_connectivity") # Edge port workflows LazyWorkflowInstance("gso.workflows.edge_port.create_edge_port", "create_edge_port") diff --git a/gso/workflows/tasks/check_site_connectivity.py b/gso/workflows/tasks/check_site_connectivity.py new file mode 100644 index 0000000000000000000000000000000000000000..a373d144ce19828133bce7c3be4f9f61e2903a8a --- /dev/null +++ b/gso/workflows/tasks/check_site_connectivity.py @@ -0,0 +1,46 @@ +"""A task for checking site connectivity. + +When a new router is planned to be deployed, it is good practice to verify that the OOB connectivity is functioning +correctly. This task takes a site and a port number as input, and checks whether there is reachability across the OOB +access. +""" + +from orchestrator import workflow +from orchestrator.forms import SubmitFormPage +from orchestrator.targets import Target +from orchestrator.workflow import StepList, begin, done, step +from pydantic import ConfigDict +from pydantic_forms.types import FormGenerator, UUIDstr + +from gso.products.product_types.site import Site +from gso.services.lso_client import LSOState, lso_interaction +from gso.utils.helpers import active_site_selector +from gso.utils.types.ip_address import PortNumber + + +def _initial_input_form_generator() -> FormGenerator: + class CheckSiteConnectivityForm(SubmitFormPage): + model_config = ConfigDict(title="Verify NETCONF connectivity to a Site") + + site: active_site_selector() # type: ignore[valid-type] + port: PortNumber + + user_input = yield CheckSiteConnectivityForm + return user_input.model_dump() + + +@step("Check NETCONF connectivity") +def check_netconf_connectivity(site: UUIDstr, port: PortNumber) -> LSOState: + """Run an Ansible playbook that validates NETCONF connectivity to a Site.""" + site_subscription = Site.from_subscription(site).site + return { + "playbook_name": "gap_ansible/playbooks/check_netconf_connectivity.yaml", + "extra_vars": {"port_number": port}, + "inventory": {"all": {"hosts": {site_subscription.site_ts_address: None}}}, + } + + +@workflow("Check Site Connectivity", _initial_input_form_generator, Target.SYSTEM) +def task_check_site_connectivity() -> StepList: + """Check successful NETCONF connectivity of a Site.""" + return begin >> lso_interaction(check_netconf_connectivity) >> done