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

Add NetBox check to IP trunk validation workflow

parent 7d598c0a
No related branches found
No related tags found
1 merge request!139Feature/add validation workflows
...@@ -8,6 +8,7 @@ from orchestrator.utils.json import json_dumps ...@@ -8,6 +8,7 @@ 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 services.netbox_client import NetboxClient
from workflows.iptrunk.deploy_twamp import deploy_twamp_dry from workflows.iptrunk.deploy_twamp import deploy_twamp_dry
from workflows.iptrunk.migrate_iptrunk import check_ip_trunk_isis from workflows.iptrunk.migrate_iptrunk import check_ip_trunk_isis
from workflows.iptrunk.modify_trunk_interface import provision_ip_trunk_iface_dry from workflows.iptrunk.modify_trunk_interface import provision_ip_trunk_iface_dry
...@@ -15,6 +16,8 @@ from workflows.iptrunk.modify_trunk_interface import provision_ip_trunk_iface_dr ...@@ -15,6 +16,8 @@ from workflows.iptrunk.modify_trunk_interface import provision_ip_trunk_iface_dr
from gso.products.product_types.iptrunk import Iptrunk from gso.products.product_types.iptrunk import Iptrunk
from gso.services import infoblox from gso.services import infoblox
from gso.services.lso_client import anonymous_lso_interaction, execute_playbook from gso.services.lso_client import anonymous_lso_interaction, execute_playbook
from gso.utils.helpers import get_router_vendor
from gso.utils.shared_enums import Vendor
from gso.utils.workflow_steps import detect_configuration_drift from gso.utils.workflow_steps import detect_configuration_drift
...@@ -46,8 +49,8 @@ def verify_ipam_records(subscription: Iptrunk) -> None: ...@@ -46,8 +49,8 @@ def verify_ipam_records(subscription: Iptrunk) -> None:
ipam_errors += [ ipam_errors += [
( (
"Missing IP trunk IPAM records, found the following instead.\n" "Missing IP trunk IPAM records, found the following instead.\n"
f"IPv4 expected {subscription.iptrunk.iptrunk_ipv4_network}, actual: {ipam_v4_network.network}\n" f"IPv4 expected '{subscription.iptrunk.iptrunk_ipv4_network}', actual: '{ipam_v4_network.network}'\n"
f"IPv6 expected {subscription.iptrunk.iptrunk_ipv6_network}, actual: {ipam_v6_network.network}" f"IPv6 expected '{subscription.iptrunk.iptrunk_ipv6_network}', actual: '{ipam_v6_network.network}'"
) )
] ]
...@@ -58,14 +61,14 @@ def verify_ipam_records(subscription: Iptrunk) -> None: ...@@ -58,14 +61,14 @@ def verify_ipam_records(subscription: Iptrunk) -> None:
# Validate IPv4 address allocation # Validate IPv4 address allocation
record = infoblox.find_host_by_fqdn(lag_fqdn) record = infoblox.find_host_by_fqdn(lag_fqdn)
if not record: if not record:
ipam_errors += [f"No IPv4 host record found with FQDN {lag_fqdn}"] ipam_errors += [f"No IPv4 host record found with FQDN '{lag_fqdn}'"]
else: else:
# Allocation inside IPv4 network must be correct # Allocation inside IPv4 network must be correct
if str(side_v4) != record.ipv4addr: if str(side_v4) != record.ipv4addr:
ipam_errors += [ ipam_errors += [
( (
f"Incorrectly allocated host record for FQDN {lag_fqdn}.\n" f"Incorrectly allocated host record for FQDN '{lag_fqdn}'.\n"
f"Expected {side_v4}, actual: {record.ipv4addr}" f"Expected '{side_v4}', actual: '{record.ipv4addr}'"
) )
] ]
...@@ -73,22 +76,22 @@ def verify_ipam_records(subscription: Iptrunk) -> None: ...@@ -73,22 +76,22 @@ def verify_ipam_records(subscription: Iptrunk) -> None:
if record.comment != subscription.subscription_id: if record.comment != subscription.subscription_id:
ipam_errors += [ ipam_errors += [
( (
f"Incorrect host record found for {lag_fqdn} at {side_v4}. Comment should have been equal to" f"Incorrect host record found for '{lag_fqdn}' at '{side_v4}'. Comment should have been equal "
f"subscription ID {subscription.subscription_id}." f"to subscription ID '{subscription.subscription_id}'."
) )
] ]
# Validate IPv6 address allocation # Validate IPv6 address allocation
record = infoblox.find_v6_host_by_fqdn(lag_fqdn) record = infoblox.find_v6_host_by_fqdn(lag_fqdn)
if not record: if not record:
ipam_errors += [f"No IPv6 host record found with FQDN {lag_fqdn}"] ipam_errors += [f"No IPv6 host record found with FQDN '{lag_fqdn}'"]
else: else:
# Allocation inside IPv6 network must be correct # Allocation inside IPv6 network must be correct
if str(side_v6) != record.ipv6addr: if str(side_v6) != record.ipv6addr:
ipam_errors += [ ipam_errors += [
( (
f"Incorrectly allocated host record for FQDN {lag_fqdn}.\n" f"Incorrectly allocated host record for FQDN '{lag_fqdn}'.\n"
f"Expected {side_v6}, actual: {record.ipv6addr}" f"Expected '{side_v6}', actual: '{record.ipv6addr}'"
) )
] ]
...@@ -96,8 +99,8 @@ def verify_ipam_records(subscription: Iptrunk) -> None: ...@@ -96,8 +99,8 @@ def verify_ipam_records(subscription: Iptrunk) -> None:
if record.comment != subscription.subscription_id: if record.comment != subscription.subscription_id:
ipam_errors += [ ipam_errors += [
( (
f"Incorrect host record found for {lag_fqdn} at {side_v6}. Comment should have been equal to" f"Incorrect host record found for '{lag_fqdn}' at '{side_v6}'. Comment should have been equal "
f"subscription ID {subscription.subscription_id}." f"to subscription ID '{subscription.subscription_id}'."
) )
] ]
...@@ -105,9 +108,38 @@ def verify_ipam_records(subscription: Iptrunk) -> None: ...@@ -105,9 +108,38 @@ def verify_ipam_records(subscription: Iptrunk) -> None:
raise ProcessFailureError(message="IPAM misconfiguration(s) found", details=str(ipam_errors)) raise ProcessFailureError(message="IPAM misconfiguration(s) found", details=str(ipam_errors))
@step("Verify Netbox entries") @step("Verify NetBox entries")
def verify_netbox_entries() -> None: def verify_netbox_entries(subscription: Iptrunk):
"""Validate required entries for an IP trunk in Netbox.""" """Validate required entries for an IP trunk in NetBox."""
nbclient = NetboxClient()
netbox_errors = []
for side in subscription.iptrunk.iptrunk_sides:
if get_router_vendor(side.iptrunk_side_node.owner_subscription_id) == Vendor.NOKIA:
# Raises en exception when not found.
interface = nbclient.get_interface_by_name_and_device(
side.iptrunk_side_ae_iface, side.iptrunk_side_node.router_fqdn
)
if interface.description != str(subscription.subscription_id):
netbox_errors += [
(
f"Incorrect description for '{side.iptrunk_side_ae_iface}', expected "
f"'{subscription.subscription_id}' but got '{interface.description}'"
)
]
for member in side.iptrunk_side_ae_members:
interface = nbclient.get_interface_by_name_and_device(
member.interface_name, side.iptrunk_side_node.router_fqdn
)
if interface.description != str(subscription.subscription_id):
netbox_errors += [
(
f"Incorrect description for '{member.interface_name}', expected "
f"'{subscription.subscription_id}' but got '{interface.description}'"
)
]
if netbox_errors:
raise ProcessFailureError(message="NetBox misconfiguration(s) found", details=str(netbox_errors))
@workflow( @workflow(
...@@ -118,8 +150,11 @@ def verify_netbox_entries() -> None: ...@@ -118,8 +150,11 @@ def verify_netbox_entries() -> None:
def validate_iptrunk() -> StepList: def validate_iptrunk() -> StepList:
"""Validate an existing, active IP Trunk subscription. """Validate an existing, active IP Trunk subscription.
* Run an Ansible playbook to verify the configuration is intact.
* Verify that the :term:`LAG` interfaces are correctly configured in :term:`IPAM`. * Verify that the :term:`LAG` interfaces are correctly configured in :term:`IPAM`.
* Check correct configuration of interfaces in NetBox.
* Verify the configuration on both sides of the trunk is intact.
* Check the ISIS metric of the trunk.
* Verify that TWAMP configuration is correct.
""" """
return ( return (
init init
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment