Skip to content
Snippets Groups Projects
Verified Commit 65f9715e authored by Karel van Klink's avatar Karel van Klink :smiley_cat:
Browse files

use conditionals and reformat some code in modify iptrunk interface workflow

parent 8280d82d
No related branches found
No related tags found
No related merge requests found
Pipeline #85179 failed
"""A modification workflow that updates the :term:`LAG` interfaces that are part of an existing IP trunk.""" """A modification workflow that updates the :term:`LAG` interfaces that are part of an existing IP trunk."""
import ipaddress import ipaddress
from uuid import uuid4 from uuid import UUID, uuid4
from orchestrator.forms import FormPage, ReadOnlyField from orchestrator.forms import FormPage, ReadOnlyField
from orchestrator.forms.validators import UniqueConstrainedList from orchestrator.forms.validators import UniqueConstrainedList
from orchestrator.targets import Target from orchestrator.targets import Target
from orchestrator.types import FormGenerator, State, UUIDstr from orchestrator.types import FormGenerator, State, UUIDstr
from orchestrator.workflow import StepList, done, init, step, workflow from orchestrator.workflow import StepList, conditional, 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 pydantic import validator from pydantic import validator
...@@ -15,6 +15,7 @@ from pydantic_forms.validators import Label ...@@ -15,6 +15,7 @@ from pydantic_forms.validators import Label
from gso.products.product_blocks.iptrunk import ( from gso.products.product_blocks.iptrunk import (
IptrunkInterfaceBlock, IptrunkInterfaceBlock,
IptrunkSideBlock,
IptrunkType, IptrunkType,
PhyPortCapacity, PhyPortCapacity,
) )
...@@ -159,22 +160,23 @@ def modify_iptrunk_subscription( ...@@ -159,22 +160,23 @@ def modify_iptrunk_subscription(
) -> State: ) -> State:
"""Modify the subscription in the service database, reflecting the changes to the newly selected interfaces.""" """Modify the subscription in the service database, reflecting the changes to the newly selected interfaces."""
# Prepare the list of removed AE members # Prepare the list of removed AE members
previous_ae_members = {} previous_ae_members = [
removed_ae_members = {} [
for side_index in range(2):
previous_ae_members[side_index] = [
{ {
"interface_name": member.interface_name, "interface_name": member.interface_name,
"interface_description": member.interface_description, "interface_description": member.interface_description,
} }
for member in subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_ae_members for member in side.iptrunk_side_ae_members
] ]
for side in subscription.iptrunk.iptrunk_sides
]
removed_ae_members = []
for side_index in range(2): for side_index in range(2):
previous_members = previous_ae_members[side_index] previous_members = previous_ae_members[side_index]
current_members = side_a_ae_members if side_index == 0 else side_b_ae_members current_members = side_a_ae_members if side_index == 0 else side_b_ae_members
removed_ae_members[side_index] = [ removed_ae_members.append([ae_member for ae_member in previous_members if ae_member not in current_members])
ae_member for ae_member in previous_members if ae_member not in current_members
]
subscription.iptrunk.geant_s_sid = geant_s_sid subscription.iptrunk.geant_s_sid = geant_s_sid
subscription.iptrunk.iptrunk_description = iptrunk_description subscription.iptrunk.iptrunk_description = iptrunk_description
subscription.iptrunk.iptrunk_type = iptrunk_type subscription.iptrunk.iptrunk_type = iptrunk_type
...@@ -250,67 +252,96 @@ def provision_ip_trunk_iface_real( ...@@ -250,67 +252,96 @@ def provision_ip_trunk_iface_real(
return {"subscription": subscription} return {"subscription": subscription}
@step("Update interfaces in Netbox. Reserving interfaces.") def _netbox_update_interfaces(
def update_interfaces_in_netbox(subscription: Iptrunk, removed_ae_members: dict, previous_ae_members: dict) -> State: subscription_id: UUID,
"""Update Netbox such that it contains the new interfaces.""" side_block: IptrunkSideBlock,
removed_ae_members: list[dict],
previous_ae_members: list[dict],
) -> None:
nbclient = NetboxClient() nbclient = NetboxClient()
for index, side in enumerate(subscription.iptrunk.iptrunk_sides):
if get_router_vendor(side.iptrunk_side_node.owner_subscription_id) == RouterVendor.NOKIA:
lag_interface = side.iptrunk_side_ae_iface
router_name = side.iptrunk_side_node.router_fqdn
# Free removed interfaces
for member in removed_ae_members[str(index)]:
nbclient.free_interface(router_name, member["interface_name"])
# Attach physical interfaces to :term:`LAG`
# Update interface description to subscription ID
# Reserve interfaces
for interface in side.iptrunk_side_ae_members:
if any(
ae_member.get("interface_name") == interface.interface_name
for ae_member in previous_ae_members[str(index)]
):
continue
nbclient.attach_interface_to_lag(
device_name=side.iptrunk_side_node.router_fqdn,
lag_name=lag_interface,
iface_name=interface.interface_name,
description=str(subscription.subscription_id),
)
nbclient.reserve_interface(
device_name=side.iptrunk_side_node.router_fqdn,
iface_name=interface.interface_name,
)
return {
"subscription": subscription,
}
# Free removed interfaces
for member in removed_ae_members:
nbclient.free_interface(side_block.iptrunk_side_node.router_fqdn, member["interface_name"])
# Attach physical interfaces to :term:`LAG`
# Update interface description to subscription ID
# Reserve interfaces
for interface in side_block.iptrunk_side_ae_members:
if any(ae_member["interface_name"] == interface.interface_name for ae_member in previous_ae_members):
continue
nbclient.attach_interface_to_lag(
device_name=side_block.iptrunk_side_node.router_fqdn,
lag_name=side_block.iptrunk_side_ae_iface,
iface_name=interface.interface_name,
description=str(subscription_id),
)
nbclient.reserve_interface(
device_name=side_block.iptrunk_side_node.router_fqdn,
iface_name=interface.interface_name,
)
@step("Netbox: Reserve side A interfaces")
def netbox_update_interfaces_side_a(
subscription: Iptrunk, removed_ae_members: list[list[dict]], previous_ae_members: list[list[dict]]
) -> None:
"""Update Netbox such that it contains the new interfaces on side A."""
_netbox_update_interfaces(
subscription.subscription_id,
subscription.iptrunk.iptrunk_sides[0],
removed_ae_members[0],
previous_ae_members[0],
)
@step("Allocate interfaces in Netbox")
def allocate_interfaces_in_netbox(subscription: Iptrunk, previous_ae_members: dict) -> State:
"""Allocate the :term:`LAG` interfaces in NetBox.
Attach the :term:`LAG` interfaces to the physical interfaces detach old ones from the :term:`LAG`. @step("Netbox: Reserve side B interfaces")
def netbox_update_interfaces_side_b(
subscription: Iptrunk, removed_ae_members: list[list[dict]], previous_ae_members: list[list[dict]]
) -> None:
"""Update Netbox such that it contains the new interfaces on side B."""
_netbox_update_interfaces(
subscription.subscription_id,
subscription.iptrunk.iptrunk_sides[1],
removed_ae_members[1],
previous_ae_members[1],
)
def _netbox_allocate_interfaces(side_block: IptrunkSideBlock, previous_ae_members: list[dict]) -> None:
nbclient = NetboxClient()
for interface in side_block.iptrunk_side_ae_members:
if any(ae_member["interface_name"] == interface.interface_name for ae_member in previous_ae_members):
continue
nbclient.allocate_interface(
device_name=side_block.iptrunk_side_node.router_fqdn,
iface_name=interface.interface_name,
)
# detach the old interfaces from lag
nbclient.detach_interfaces_from_lag(
device_name=side_block.iptrunk_side_node.router_fqdn,
lag_name=side_block.iptrunk_side_ae_iface,
)
@step("Netbox: Allocate side A interfaces")
def allocate_interfaces_in_netbox_side_a(subscription: Iptrunk, previous_ae_members: list[list[dict]]) -> None:
"""Allocate the :term:`LAG` interfaces on side A in Netbox.
Attach the :term:`LAG` interface to the physical interface detach old one from the :term:`LAG`.
""" """
for index, side in enumerate(subscription.iptrunk.iptrunk_sides): _netbox_allocate_interfaces(subscription.iptrunk.iptrunk_sides[0], previous_ae_members[0])
nbclient = NetboxClient()
if get_router_vendor(side.iptrunk_side_node.owner_subscription_id) == RouterVendor.NOKIA:
for interface in side.iptrunk_side_ae_members:
if any(
ae_member.get("interface_name") == interface.interface_name
for ae_member in previous_ae_members[str(index)]
):
continue
nbclient.allocate_interface(
device_name=side.iptrunk_side_node.router_fqdn,
iface_name=interface.interface_name,
)
# detach the old interfaces from lag
nbclient.detach_interfaces_from_lag(
device_name=side.iptrunk_side_node.router_fqdn,
lag_name=side.iptrunk_side_ae_iface,
)
return {"subscription": subscription}
@step("Netbox: Allocate side B interfaces")
def allocate_interfaces_in_netbox_side_b(subscription: Iptrunk, previous_ae_members: list[list[dict]]) -> None:
"""Allocate the :term:`LAG` interface on side B in Netbox.
Attach the :term:`LAG` interface to the physical interface detach old one from the :term:`LAG`.
"""
_netbox_allocate_interfaces(subscription.iptrunk.iptrunk_sides[1], previous_ae_members[1])
@workflow( @workflow(
...@@ -326,15 +357,29 @@ def modify_trunk_interface() -> StepList: ...@@ -326,15 +357,29 @@ def modify_trunk_interface() -> StepList:
* Provision the updated version of the IP trunk, first as a dry run * Provision the updated version of the IP trunk, first as a dry run
* Allocate the reserved interfaces in Netbox * Allocate the reserved interfaces in Netbox
""" """
side_a_is_nokia = conditional(
lambda state: get_router_vendor(
state["subscription"]["iptrunk"]["iptrunk_sides"][0]["iptrunk_side_node"]["owner_subscription_id"]
)
== RouterVendor.NOKIA
)
side_b_is_nokia = conditional(
lambda state: get_router_vendor(
state["subscription"]["iptrunk"]["iptrunk_sides"][1]["iptrunk_side_node"]["owner_subscription_id"]
)
== RouterVendor.NOKIA
)
return ( return (
init init
>> store_process_subscription(Target.MODIFY) >> store_process_subscription(Target.MODIFY)
>> unsync >> unsync
>> modify_iptrunk_subscription >> modify_iptrunk_subscription
>> update_interfaces_in_netbox >> side_a_is_nokia(netbox_update_interfaces_side_a)
>> side_b_is_nokia(netbox_update_interfaces_side_b)
>> pp_interaction(provision_ip_trunk_iface_dry) >> pp_interaction(provision_ip_trunk_iface_dry)
>> pp_interaction(provision_ip_trunk_iface_real) >> pp_interaction(provision_ip_trunk_iface_real)
>> allocate_interfaces_in_netbox >> side_a_is_nokia(allocate_interfaces_in_netbox_side_a)
>> side_b_is_nokia(allocate_interfaces_in_netbox_side_b)
>> resync >> resync
>> done >> done
) )
...@@ -138,7 +138,7 @@ def test_iptrunk_modify_trunk_interface_success( ...@@ -138,7 +138,7 @@ def test_iptrunk_modify_trunk_interface_success(
new_side_b_sid = input_form_iptrunk_data[3]["side_b_ae_geant_a_sid"] new_side_b_sid = input_form_iptrunk_data[3]["side_b_ae_geant_a_sid"]
new_side_b_ae_members = input_form_iptrunk_data[3]["side_b_ae_members"] new_side_b_ae_members = input_form_iptrunk_data[3]["side_b_ae_members"]
# Only Nokia interfaces will checked # Only Nokia interfaces will be checked
vendor_side_a = subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.vendor vendor_side_a = subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.vendor
vendor_side_b = subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.vendor vendor_side_b = subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.vendor
num_ifaces = (len(new_side_a_ae_members) if vendor_side_a == RouterVendor.NOKIA else 0) + ( num_ifaces = (len(new_side_a_ae_members) if vendor_side_a == RouterVendor.NOKIA else 0) + (
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment