From 4bf38511435e10e6016ad90435ee57d25e0f0903 Mon Sep 17 00:00:00 2001 From: Karel van Klink <karel.vanklink@geant.org> Date: Fri, 16 Feb 2024 16:12:30 +0100 Subject: [PATCH] reflect lifecycle state changes in workflow steps --- gso/workflows/iptrunk/create_iptrunk.py | 37 +++++++++++++------------ gso/workflows/router/create_router.py | 32 +++++++++++++-------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index a42b60f9..025033b1 100644 --- a/gso/workflows/iptrunk/create_iptrunk.py +++ b/gso/workflows/iptrunk/create_iptrunk.py @@ -17,12 +17,12 @@ from pynetbox.models.dcim import Interfaces from gso.products.product_blocks.iptrunk import ( IptrunkInterfaceBlockInactive, - IptrunkSideBlockProvisioning, + IptrunkSideBlockInactive, IptrunkType, PhyPortCapacity, ) from gso.products.product_blocks.router import RouterVendor -from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning +from gso.products.product_types.iptrunk import IptrunkInactive from gso.products.product_types.router import Router from gso.services import infoblox, subscriptions from gso.services.crm import get_customer_by_name @@ -184,7 +184,7 @@ def create_subscription(product: UUIDstr, customer: str) -> State: @step("Get information from IPAM") -def get_info_from_ipam(subscription: IptrunkProvisioning) -> State: +def get_info_from_ipam(subscription: IptrunkInactive) -> State: """Allocate IP resources in :term:`IPAM`.""" subscription.iptrunk.iptrunk_ipv4_network = infoblox.allocate_v4_network( "TRUNK", @@ -248,7 +248,7 @@ def initialize_subscription( @step("Provision IP trunk interface [DRY RUN]") def provision_ip_trunk_iface_dry( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, process_id: UUIDstr, tt_number: str, @@ -276,7 +276,7 @@ def provision_ip_trunk_iface_dry( @step("Provision IP trunk interface [FOR REAL]") def provision_ip_trunk_iface_real( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, process_id: UUIDstr, tt_number: str, @@ -304,7 +304,7 @@ def provision_ip_trunk_iface_real( @step("Check IP connectivity of the trunk") def check_ip_trunk_connectivity( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, ) -> State: """Check successful connectivity across the new trunk.""" @@ -322,7 +322,7 @@ def check_ip_trunk_connectivity( @step("Provision IP trunk ISIS interface [DRY RUN]") def provision_ip_trunk_isis_iface_dry( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, process_id: UUIDstr, tt_number: str, @@ -350,7 +350,7 @@ def provision_ip_trunk_isis_iface_dry( @step("Provision IP trunk ISIS interface [FOR REAL]") def provision_ip_trunk_isis_iface_real( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, process_id: UUIDstr, tt_number: str, @@ -378,7 +378,7 @@ def provision_ip_trunk_isis_iface_real( @step("Check ISIS adjacency") def check_ip_trunk_isis( - subscription: IptrunkProvisioning, + subscription: IptrunkInactive, callback_route: str, ) -> State: """Run an Ansible playbook to confirm :term:`ISIS` adjacency.""" @@ -395,7 +395,7 @@ def check_ip_trunk_isis( @step("NextBox integration") -def reserve_interfaces_in_netbox(subscription: IptrunkProvisioning) -> State: +def reserve_interfaces_in_netbox(subscription: IptrunkInactive) -> State: """Create the :term:`LAG` interfaces in NetBox and attach the lag interfaces to the physical interfaces.""" nbclient = NetboxClient() for trunk_side in subscription.iptrunk.iptrunk_sides: @@ -427,22 +427,25 @@ def reserve_interfaces_in_netbox(subscription: IptrunkProvisioning) -> State: } -def _allocate_interfaces_in_netbox(iptrunk_side: IptrunkSideBlockProvisioning) -> None: +def _allocate_interfaces_in_netbox(iptrunk_side: IptrunkSideBlockInactive) -> None: for interface in iptrunk_side.iptrunk_side_ae_members: - NetboxClient().allocate_interface( - device_name=iptrunk_side.iptrunk_side_node.router_fqdn, - iface_name=interface.interface_name, - ) + fqdn = iptrunk_side.iptrunk_side_node.router_fqdn + iface_name = interface.interface_name + if not fqdn or not iface_name: + msg = f"FQDN and/or interface name missing in subscription {interface.owner_subscription_id}" + raise ValueError(msg) + + NetboxClient().allocate_interface(device_name=fqdn, iface_name=iface_name) @step("Allocate interfaces in Netbox for side A") -def netbox_allocate_side_a_interfaces(subscription: IptrunkProvisioning) -> None: +def netbox_allocate_side_a_interfaces(subscription: IptrunkInactive) -> None: """Allocate the :term:`LAG` interfaces for the Nokia router on side A.""" _allocate_interfaces_in_netbox(subscription.iptrunk.iptrunk_sides[0]) @step("Allocate interfaces in Netbox for side B") -def netbox_allocate_side_b_interfaces(subscription: IptrunkProvisioning) -> None: +def netbox_allocate_side_b_interfaces(subscription: IptrunkInactive) -> None: """Allocate the :term:`LAG` interfaces for the Nokia router on side B.""" _allocate_interfaces_in_netbox(subscription.iptrunk.iptrunk_sides[1]) diff --git a/gso/workflows/router/create_router.py b/gso/workflows/router/create_router.py index af68b2d3..29a60dbb 100644 --- a/gso/workflows/router/create_router.py +++ b/gso/workflows/router/create_router.py @@ -19,7 +19,7 @@ from gso.products.product_blocks.router import ( RouterVendor, generate_fqdn, ) -from gso.products.product_types.router import RouterInactive, RouterProvisioning +from gso.products.product_types.router import RouterInactive from gso.products.product_types.site import Site from gso.services import infoblox, subscriptions from gso.services.crm import get_customer_by_name @@ -127,17 +127,21 @@ def ipam_allocate_loopback(subscription: RouterInactive) -> State: @step("Create NetBox Device") -def create_netbox_device(subscription: RouterProvisioning) -> State: +def create_netbox_device(subscription: RouterInactive) -> State: """Create a new NOKIA device in Netbox.""" - NetboxClient().create_device( - subscription.router.router_fqdn, - str(subscription.router.router_site.site_tier), - ) + fqdn = subscription.router.router_fqdn + site_tier = subscription.router.router_site.site_tier if subscription.router.router_site else None + if not fqdn or not site_tier: + msg = f"FQDN and/or Site tier missing in router subscription {subscription.subscription_id}!" + raise ValueError(msg) + + NetboxClient().create_device(fqdn, site_tier) + return {"subscription": subscription} @step("Verify IPAM resources for loopback interface") -def verify_ipam_loopback(subscription: RouterProvisioning) -> State: +def verify_ipam_loopback(subscription: RouterInactive) -> State: """Validate the :term:`IPAM` resources for the loopback interface.""" host_record = infoblox.find_host_by_fqdn(f"lo0.{subscription.router.router_fqdn}") if not host_record or str(subscription.subscription_id) not in host_record.comment: @@ -147,17 +151,21 @@ def verify_ipam_loopback(subscription: RouterProvisioning) -> State: @inputstep("Prompt to reboot", assignee=Assignee.SYSTEM) -def prompt_reboot_router(subscription: RouterProvisioning) -> FormGenerator: +def prompt_reboot_router(subscription: RouterInactive) -> FormGenerator: """Wait for confirmation from an operator that the router has been rebooted.""" class RebootPrompt(FormPage): class Config: title = "Please reboot before continuing" - info_label_1: Label = ( - f"Base config has been deployed. Please log in via the console using https://" # type: ignore[assignment] - f"{subscription.router.router_site.site_ts_address}." - ) + if subscription.router.router_site and subscription.router.router_site.site_ts_address: + info_label_1: Label = ( + f"Base config has been deployed. Please log in via the console using https://" # type: ignore[assignment] + f"{subscription.router.router_site.site_ts_address}." + ) + else: + info_label_1 = "Base config has been deployed. Please log in via the console." # type: ignore[assignment] + info_label_2: Label = "Reboot the router, and once it is up again, press submit to continue the workflow." # type: ignore[assignment] yield RebootPrompt -- GitLab