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

Add IP Trunk validation workflow

parent be7d176d
No related branches found
No related tags found
1 merge request!139Feature/add validation workflows
This commit is part of merge request !139. Comments created here will be created in the context of that merge request.
"""Add IP Trunk validation workflow.
Revision ID: a1a69e7554c4
Revises: 75c63ad44cbb
Create Date: 2024-01-11 15:57:57.534785
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = 'a1a69e7554c4'
down_revision = '75c63ad44cbb'
branch_labels = None
depends_on = None
from orchestrator.migrations.helpers import create_workflow, delete_workflow
new_workflows = [
{
"name": "validate_iptrunk",
"target": "SYSTEM",
"description": "Validate IP trunk configuration",
"product_type": "Iptrunk"
}
]
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"])
......@@ -32,6 +32,7 @@ LazyWorkflowInstance("gso.workflows.iptrunk.migrate_iptrunk", "migrate_iptrunk")
LazyWorkflowInstance("gso.workflows.iptrunk.terminate_iptrunk", "terminate_iptrunk")
LazyWorkflowInstance("gso.workflows.iptrunk.create_imported_iptrunk", "create_imported_iptrunk")
LazyWorkflowInstance("gso.workflows.iptrunk.import_iptrunk", "import_iptrunk")
LazyWorkflowInstance("gso.workflows.iptrunk.validate_iptrunk", "validate_iptrunk")
# Router workflows
LazyWorkflowInstance("gso.workflows.router.activate_router", "activate_router")
......
"""Router validation workflow. Used in a nightly schedule."""
import json
from orchestrator.targets import Target
from orchestrator.utils.errors import ProcessFailureError
from orchestrator.utils.json import json_dumps
from orchestrator.workflow import StepList, done, init, 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 import infoblox
from gso.services.provisioning_proxy import execute_playbook, pp_interaction
@step("Validate IP trunk configuration")
def validate_router_config(subscription: Iptrunk, callback_route: str) -> None:
"""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"}
execute_playbook(
playbook_name="base_config.yaml",
callback_route=callback_route,
inventory=f"{subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}\n"
f"{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}\n",
extra_vars=extra_vars,
)
@step("Verify IPAM resources for LAG interfaces")
def verify_ipam_loopback(subscription: Iptrunk) -> None:
"""Validate the :term:`IPAM` resources for the :term:`LAG` interfaces.
Raises an :class:`orchestrator.utils.errors.ProcessFailureError` if IPAM is configured incorrectly.
"""
ipam_errors = []
ipam_v4_network = infoblox.find_network_by_cidr(subscription.iptrunk.iptrunk_ipv4_network)
ipam_v6_network = infoblox.find_network_by_cidr(subscription.iptrunk.iptrunk_ipv6_network)
if not ipam_v4_network or not ipam_v6_network:
ipam_errors += (
"Missing IP trunk IPAM records, found the following instead.\n"
f"IPv4 expected {subscription.iptrunk.iptrunk_ipv4_network}, actual: {ipam_v4_network}\n"
f"IPv6 expected {subscription.iptrunk.iptrunk_ipv6_network}, actual: {ipam_v6_network}"
)
# Validate both sides of the trunk.
for trunk_side in subscription.iptrunk.iptrunk_sides:
lag_fqdn = f"{trunk_side.iptrunk_side_ae_iface}.{trunk_side.iptrunk_side_node.router_fqdn}"
# Validate both IPv4 and IPv6 records.
for record in [infoblox.find_host_by_fqdn(lag_fqdn), infoblox.find_v6_host_by_fqdn(lag_fqdn)]:
if not record:
ipam_errors += f"Missing IPAM record for LAG interface {lag_fqdn}."
elif subscription.subscription_id not in record.comment:
ipam_errors += f"Found a misconfigured IPAM entry for {lag_fqdn}. Received: {record}"
if ipam_errors:
raise ProcessFailureError(str(ipam_errors))
@workflow(
"Validate IP trunk configuration",
target=Target.SYSTEM,
initial_input_form=wrap_modify_initial_input_form(None),
)
def validate_iptrunk() -> StepList:
"""Validate an existing, active IP Trunk subscription.
* Run an Ansible playbook to verify the configuration is intact.
* Verify that the LAG interfaces are correctly configured in IPAM.
"""
return (
init
>> store_process_subscription(Target.SYSTEM)
>> unsync
>> pp_interaction(validate_router_config)
>> verify_ipam_loopback
>> resync
>> done
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment