From 7e409757010987954db91addf8ba8fe6cb08da2e Mon Sep 17 00:00:00 2001 From: Karel van Klink <karel.vanklink@geant.org> Date: Wed, 30 Oct 2024 14:47:51 +0100 Subject: [PATCH] Add BFD configuration to Service binding ports --- .../2024-10-30_c6b82e23297c_add_bfd_to_sbp.py | 50 +++++++++++++++++++ .../product_blocks/service_binding_port.py | 12 +++++ .../create_nren_l3_core_service.py | 3 ++ .../modify_nren_l3_core_service.py | 11 +++- .../fixtures/nren_l3_core_service_fixtures.py | 6 +++ ...st_create_imported_nren_l3_core_service.py | 5 +- .../test_create_nren_l3_core_service.py | 3 ++ .../test_modify_nren_l3_core_service.py | 6 +++ 8 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 gso/migrations/versions/2024-10-30_c6b82e23297c_add_bfd_to_sbp.py diff --git a/gso/migrations/versions/2024-10-30_c6b82e23297c_add_bfd_to_sbp.py b/gso/migrations/versions/2024-10-30_c6b82e23297c_add_bfd_to_sbp.py new file mode 100644 index 00000000..d8fc7e61 --- /dev/null +++ b/gso/migrations/versions/2024-10-30_c6b82e23297c_add_bfd_to_sbp.py @@ -0,0 +1,50 @@ +"""Add BFD to SBP. + +Revision ID: c6b82e23297c +Revises: 7412c5b7ebe4 +Create Date: 2024-10-30 14:39:30.047934 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'c6b82e23297c' +down_revision = '7412c5b7ebe4' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_enabled'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_interval'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_multiplier'))) + """)) + + +def downgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_enabled')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_enabled')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_interval')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_interval')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_multiplier')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_multiplier')) + """)) diff --git a/gso/products/product_blocks/service_binding_port.py b/gso/products/product_blocks/service_binding_port.py index bb90fcc1..19452b2e 100644 --- a/gso/products/product_blocks/service_binding_port.py +++ b/gso/products/product_blocks/service_binding_port.py @@ -30,6 +30,9 @@ class ServiceBindingPortInactive( geant_sid: str | None = None bgp_session_list: list[BGPSessionInactive] = Field(default_factory=list) edge_port: EdgePortBlockInactive | None = None + bfd_enabled: bool = False + bfd_interval: int | None = None + bfd_multiplier: int | None = None class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): @@ -46,6 +49,9 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs geant_sid: str bgp_session_list: list[BGPSessionProvisioning] # type: ignore[assignment] edge_port: EdgePortBlockProvisioning + bfd_enabled: bool + bfd_interval: int | None + bfd_multiplier: int | None class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): @@ -73,3 +79,9 @@ class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[Subscription bgp_session_list: list[BGPSession] # type: ignore[assignment] #: The Edge Port on which this :term:`SBP` resides. edge_port: EdgePortBlock + #: Whether :term:`BFD` is enabled. + bfd_enabled: bool + #: The :term:`BFD` interval, if enabled. + bfd_interval: int | None + #: The :term:`BFD` multiplier, if enabled. + bfd_multiplier: int | None diff --git a/gso/workflows/nren_l3_core_service/create_nren_l3_core_service.py b/gso/workflows/nren_l3_core_service/create_nren_l3_core_service.py index be55ae6a..5c3d2a92 100644 --- a/gso/workflows/nren_l3_core_service/create_nren_l3_core_service.py +++ b/gso/workflows/nren_l3_core_service/create_nren_l3_core_service.py @@ -105,6 +105,9 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: geant_sid: str is_tagged: bool = False + bfd_enabled: bool = False + bfd_interval: int | None = None + bfd_multiplier: int | None = None vlan_id: VLAN_ID ipv4_address: IPv4AddressType ipv4_mask: IPV4Netmask diff --git a/gso/workflows/nren_l3_core_service/modify_nren_l3_core_service.py b/gso/workflows/nren_l3_core_service/modify_nren_l3_core_service.py index afb7d69b..1d092aaf 100644 --- a/gso/workflows/nren_l3_core_service/modify_nren_l3_core_service.py +++ b/gso/workflows/nren_l3_core_service/modify_nren_l3_core_service.py @@ -136,7 +136,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: geant_sid: str = current_sbp.geant_sid is_tagged: bool = current_sbp.is_tagged - # The SBP model doesn't require these three fields, but in the case of GÉANT IP OR IAS this will never + # The SBP model doesn't require these five fields, but in the case of GÉANT IP OR IAS this will never # occur since it's a layer 3 service. The ignore statements are there to put our type checker at ease. vlan_id: VLAN_ID = current_sbp.vlan_id # type: ignore[assignment] ipv4_address: IPv4AddressType = current_sbp.ipv4_address # type: ignore[assignment] @@ -144,6 +144,9 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ipv6_address: IPv6AddressType = current_sbp.ipv6_address # type: ignore[assignment] ipv6_mask: IPV6Netmask = current_sbp.ipv6_mask # type: ignore[assignment] custom_firewall_filters: bool = current_sbp.custom_firewall_filters + bfd_enabled: bool = current_sbp.bfd_enabled + bfd_interval: int | None = current_sbp.bfd_interval + bfd_multiplier: int | None = current_sbp.bfd_multiplier divider: Divider = Field(None, exclude=True) v4_bgp_peer: IPv4BGPPeer = IPv4BGPPeer( **v4_peer.model_dump(exclude=set("families")), @@ -188,6 +191,9 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ipv4_address: IPv4AddressType ipv6_address: IPv6AddressType custom_firewall_filters: bool = False + bfd_enabled: bool = False + bfd_interval: int | None = None + bfd_multiplier: int | None = None divider: Divider = Field(None, exclude=True) v4_bgp_peer: IPv4BGPPeer v6_bgp_peer: IPv6BGPPeer @@ -248,6 +254,9 @@ def modify_existing_sbp_blocks(subscription: NRENL3CoreService, modified_sbp_lis current_sbp.ipv4_address = modified_sbp_data["ipv4_address"] current_sbp.ipv6_address = modified_sbp_data["ipv6_address"] current_sbp.custom_firewall_filters = modified_sbp_data["custom_firewall_filters"] + current_sbp.bfd_enabled = modified_sbp_data["bfd_enabled"] + current_sbp.bfd_interval = modified_sbp_data["bfd_interval"] + current_sbp.bfd_multiplier = modified_sbp_data["bfd_multiplier"] access_port.ap_type = modified_sbp_data["new_ap_type"] return {"subscription": subscription} diff --git a/test/fixtures/nren_l3_core_service_fixtures.py b/test/fixtures/nren_l3_core_service_fixtures.py index d0fd069a..b3622cfd 100644 --- a/test/fixtures/nren_l3_core_service_fixtures.py +++ b/test/fixtures/nren_l3_core_service_fixtures.py @@ -69,7 +69,10 @@ def service_binding_port_factory(faker, bgp_session_subscription_factory, edge_p ipv6_mask: int | None = None, vlan_id: int | None = None, edge_port: EdgePort | None = None, + bfd_interval: int = 2, + bfd_multiplier: int = 2, *, + bfd_enabled: bool = False, custom_firewall_filters: bool = False, is_tagged: bool = False, ): @@ -90,6 +93,9 @@ def service_binding_port_factory(faker, bgp_session_subscription_factory, edge_p bgp_session_subscription_factory(families=[IPFamily.V6UNICAST], peer_address=faker.ipv6()), ], edge_port=edge_port or EdgePort.from_subscription(edge_port_subscription_factory()).edge_port, + bfd_enabled=bfd_enabled, + bfd_interval=bfd_interval, + bfd_multiplier=bfd_multiplier, ) return create_service_binding_port diff --git a/test/workflows/nren_l3_core_service/test_create_imported_nren_l3_core_service.py b/test/workflows/nren_l3_core_service/test_create_imported_nren_l3_core_service.py index 63aab373..bcc0c068 100644 --- a/test/workflows/nren_l3_core_service/test_create_imported_nren_l3_core_service.py +++ b/test/workflows/nren_l3_core_service/test_create_imported_nren_l3_core_service.py @@ -27,9 +27,12 @@ def test_create_imported_nren_l3_core_service_success( "ipv6_address": faker.ipv6(), "ipv6_mask": faker.ipv6_netmask(), "custom_firewall_filters": faker.boolean(), + "bfd_enabled": True, + "bfd_interval": faker.pyint(), + "bfd_multiplier": faker.pyint(), "bgp_peers": [ { - "bfd_enabled": faker.boolean(), + "bfd_enabled": True, "bfd_interval": faker.pyint(), "bfd_multiplier": faker.pyint(), "has_custom_policies": faker.boolean(), diff --git a/test/workflows/nren_l3_core_service/test_create_nren_l3_core_service.py b/test/workflows/nren_l3_core_service/test_create_nren_l3_core_service.py index d8eac84e..cd8d123a 100644 --- a/test/workflows/nren_l3_core_service/test_create_nren_l3_core_service.py +++ b/test/workflows/nren_l3_core_service/test_create_nren_l3_core_service.py @@ -57,6 +57,9 @@ def test_create_nren_l3_core_service_success( "ipv6_address": faker.ipv6(), "ipv6_mask": faker.ipv6_netmask(), "custom_firewall_filters": faker.boolean(), + "bfd_enabled": True, + "bfd_interval": faker.pyint(), + "bfd_multiplier": faker.pyint(), "v4_bgp_peer": base_bgp_peer_input() | {"add_v4_multicast": faker.boolean(), "peer_address": faker.ipv4()}, "v6_bgp_peer": base_bgp_peer_input() | {"add_v6_multicast": faker.boolean(), "peer_address": faker.ipv6()}, }, diff --git a/test/workflows/nren_l3_core_service/test_modify_nren_l3_core_service.py b/test/workflows/nren_l3_core_service/test_modify_nren_l3_core_service.py index 197be36c..d2976494 100644 --- a/test/workflows/nren_l3_core_service/test_modify_nren_l3_core_service.py +++ b/test/workflows/nren_l3_core_service/test_modify_nren_l3_core_service.py @@ -102,6 +102,9 @@ def sbp_input_form_data(faker): "ipv4_address": faker.ipv4(), "ipv6_address": faker.ipv6(), "custom_firewall_filters": True, + "bfd_enabled": True, + "bfd_interval": faker.pyint(), + "bfd_multiplier": faker.pyint(), "v4_bgp_peer": { "bfd_enabled": True, "bfd_interval": faker.pyint(), @@ -262,3 +265,6 @@ def test_modify_nren_l3_core_service_modify_edge_port_success( ) == new_sbp_data[i]["v6_bgp_peer"]["add_v6_multicast"] ) + assert subscription.nren_l3_core_service.nren_ap_list[i].sbp.bfd_enabled == new_sbp_data[i]["bfd_enabled"] + assert subscription.nren_l3_core_service.nren_ap_list[i].sbp.bfd_interval == new_sbp_data[i]["bfd_interval"] + assert subscription.nren_l3_core_service.nren_ap_list[i].sbp.bfd_multiplier == new_sbp_data[i]["bfd_multiplier"] -- GitLab