Skip to content
Snippets Groups Projects
Commit 2f863981 authored by Karel van Klink's avatar Karel van Klink :smiley_cat: Committed by Neda Moeini
Browse files

Update router validation workflow

parent ce6d11e4
No related branches found
No related tags found
1 merge request!139Feature/add validation workflows
...@@ -6,6 +6,7 @@ from typing import Any ...@@ -6,6 +6,7 @@ from typing import Any
from orchestrator import inputstep, step from orchestrator import inputstep, step
from orchestrator.config.assignee import Assignee from orchestrator.config.assignee import Assignee
from orchestrator.types import State, UUIDstr from orchestrator.types import State, UUIDstr
from orchestrator.utils.errors import ProcessFailureError
from orchestrator.utils.json import json_dumps from orchestrator.utils.json import json_dumps
from pydantic import ConfigDict from pydantic import ConfigDict
from pydantic_forms.core import FormPage from pydantic_forms.core import FormPage
...@@ -121,3 +122,15 @@ def prompt_sharepoint_checklist_url(checklist_url: str) -> FormGenerator: ...@@ -121,3 +122,15 @@ def prompt_sharepoint_checklist_url(checklist_url: str) -> FormGenerator:
yield SharepointPrompt yield SharepointPrompt
return {} return {}
@step("Detect configuration drift")
def detect_configuration_drift(callback_result: dict) -> None:
"""Inspect the diff for deploying configuration, to make sure there is no drift."""
if callback_result["return_code"] != 0:
# If deployment never was successful in the first place, raise an exception.
raise ProcessFailureError(message="Provisioning proxy failure", details=callback_result)
output_lines = callback_result["output"]
if any(str.startswith(line, "-") or str.startswith(line, "+") for line in callback_result["output"]):
raise ProcessFailureError(message="Configuration drift detected", details=output_lines)
"""Router validation workflow. Used in a nightly schedule.""" """Router validation workflow. Used in a nightly schedule."""
import json
from orchestrator.targets import Target from orchestrator.targets import Target
from orchestrator.utils.errors import ProcessFailureError from orchestrator.utils.errors import ProcessFailureError
from orchestrator.utils.json import json_dumps
from orchestrator.workflow import StepList, done, init, step, workflow from orchestrator.workflow import StepList, done, init, step, workflow
from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.steps import resync, store_process_subscription, unsync
from orchestrator.workflows.utils import wrap_modify_initial_input_form from orchestrator.workflows.utils import wrap_modify_initial_input_form
from workflows.router.update_ibgp_mesh import add_p_to_mesh_dry
from gso.products.product_types.router import Router from gso.products.product_types.router import Router
from gso.services import infoblox from gso.services import infoblox
from gso.services.lso_client import execute_playbook, lso_interaction from gso.services.librenms_client import LibreNMSClient
from gso.services.lso_client import anonymous_lso_interaction
from gso.services.netbox_client import NetboxClient
from gso.utils.workflow_steps import deploy_base_config_dry, detect_configuration_drift
@step("Verify IPAM resources for loopback interface") @step("Verify IPAM resources for loopback interface")
...@@ -26,17 +27,26 @@ def verify_ipam_loopback(subscription: Router) -> None: ...@@ -26,17 +27,26 @@ def verify_ipam_loopback(subscription: Router) -> None:
raise ProcessFailureError(msg) raise ProcessFailureError(msg)
@step("Validate router configuration") @step("Verify correct Netbox entry")
def validate_router_config(subscription: Router, callback_route: str) -> None: def verify_netbox_entry(subscription: Router) -> None:
"""Run an Ansible playbook that validates the configuration that is present on an active Router.""" """Validate the Netbox entry for a Router.
extra_vars = {"wfo_router": json.loads(json_dumps(subscription)), "verb": "validate"}
execute_playbook( This will only ensure existence of the node itself in Netbox. Validation of separate interfaces takes places in
playbook_name="base_config.yaml", other subscriptions' validation workflows.
callback_route=callback_route, """
inventory=subscription.router.router_fqdn, client = NetboxClient()
extra_vars=extra_vars, # Try and fetch the host, which will raise an exception on failure.
) client.get_device_by_name(subscription.router.router_fqdn)
@step("Verify correct LibreNMS entry")
def verify_librenms_entry(subscription: Router) -> None:
"""Validate the LibreNMS entry for a Router.
Raises an HTTP error 404 when the device is not present in LibreNMS.
"""
client = LibreNMSClient()
client.get_device(subscription.router.router_fqdn)
@workflow( @workflow(
...@@ -48,14 +58,20 @@ def validate_router() -> StepList: ...@@ -48,14 +58,20 @@ def validate_router() -> StepList:
"""Validate an existing, active Router subscription. """Validate an existing, active Router subscription.
* Verify that the loopback interface is correctly configured in :term:`IPAM`. * Verify that the loopback interface is correctly configured in :term:`IPAM`.
* Verify that the router is correctly configured in Netbox.
* Verify that the router is correctly configured in LibreNMS.
* Redeploy base config to verify the configuration is intact. * Redeploy base config to verify the configuration is intact.
* Validate configuration of the iBGP mesh
""" """
return ( return (
init init
>> store_process_subscription(Target.SYSTEM) >> store_process_subscription(Target.SYSTEM)
>> unsync >> unsync
>> verify_ipam_loopback >> verify_ipam_loopback
>> lso_interaction(validate_router_config) >> verify_netbox_entry
>> verify_librenms_entry
>> anonymous_lso_interaction(deploy_base_config_dry, detect_configuration_drift)
>> anonymous_lso_interaction(add_p_to_mesh_dry, detect_configuration_drift)
>> resync >> resync
>> done >> 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