From 0c9107634082f28ae16d69c7914d46b03fae3599 Mon Sep 17 00:00:00 2001
From: Karel van Klink <karel.vanklink@geant.org>
Date: Thu, 12 Sep 2024 16:24:34 +0200
Subject: [PATCH] =?UTF-8?q?Update=20edge=20port=20models,=20add=20translat?=
 =?UTF-8?q?ions,=20add=20domain=20model=20migration=20for=20G=C3=89ANT=20I?=
 =?UTF-8?q?P?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 gso/__init__.py                               |  18 +-
 ...3d12_add_g\303\251ant_ip_domain_models.py" | 335 ++++++++++++++++++
 gso/products/product_blocks/bgp_session.py    |  12 +-
 gso/products/product_blocks/edge_port.py      |  41 ++-
 gso/products/product_blocks/geant_ip.py       |  17 +-
 .../product_blocks/service_binding_port.py    |  22 +-
 gso/translations/en-GB.json                   |   7 +-
 gso/utils/types/bgp_session.py                |  33 --
 gso/workflows/edge_port/create_edge_port.py   |   7 +-
 gso/workflows/edge_port/modify_edge_port.py   |  15 +-
 gso/workflows/geant_ip/__init__.py            |   1 +
 gso/workflows/geant_ip/create_geant_ip.py     |   1 +
 12 files changed, 417 insertions(+), 92 deletions(-)
 create mode 100644 "gso/migrations/versions/2024-09-16_aa6dcb493d12_add_g\303\251ant_ip_domain_models.py"
 delete mode 100644 gso/utils/types/bgp_session.py
 create mode 100644 gso/workflows/geant_ip/__init__.py
 create mode 100644 gso/workflows/geant_ip/create_geant_ip.py

diff --git a/gso/__init__.py b/gso/__init__.py
index 333891c3..478efc94 100644
--- a/gso/__init__.py
+++ b/gso/__init__.py
@@ -1,15 +1,13 @@
 """The main entrypoint for :term:`GSO`, and the different ways in which it can be run."""
 
 import os
-from typing import Annotated
 
 import sentry_sdk
-import strawberry
 import typer
 from celery import Celery
 from orchestrator import OrchestratorCore, app_settings
 from orchestrator.cli.main import app as cli_app
-from orchestrator.graphql import DEFAULT_GRAPHQL_MODELS, SCALAR_OVERRIDES
+from orchestrator.graphql import SCALAR_OVERRIDES
 from orchestrator.services.tasks import initialise_celery
 from orchestrator.settings import ExecutorType
 
@@ -21,7 +19,6 @@ from gso.auth.oidc import oidc_instance
 from gso.auth.opa import graphql_opa_instance, opa_instance
 from gso.graphql_api.types import GSO_SCALAR_OVERRIDES
 from gso.settings import load_oss_params
-from gso.utils.types.interfaces import LAGMember
 
 SCALAR_OVERRIDES.update(GSO_SCALAR_OVERRIDES)
 
@@ -38,18 +35,7 @@ def init_gso_app() -> OrchestratorCore:
     app.register_authentication(oidc_instance)
     app.register_authorization(opa_instance)
     app.register_graphql_authorization(graphql_opa_instance)
-
-    @strawberry.experimental.pydantic.type(model=LAGMember)
-    class LAGMemberGraphql:
-        self_reference_block: Annotated["LAGMemberGraphql", strawberry.lazy("gso.utils.types.interfaces")] | None = None
-        interface_name: str
-        interface_description: str
-
-    updated_graphql_models = DEFAULT_GRAPHQL_MODELS | {
-        "LAGMemberGraphql": LAGMemberGraphql,
-    }
-
-    app.register_graphql(graphql_models=updated_graphql_models)
+    app.register_graphql()
     app.include_router(api_router, prefix="/api")
 
     if app_settings.EXECUTOR == ExecutorType.WORKER:
diff --git "a/gso/migrations/versions/2024-09-16_aa6dcb493d12_add_g\303\251ant_ip_domain_models.py" "b/gso/migrations/versions/2024-09-16_aa6dcb493d12_add_g\303\251ant_ip_domain_models.py"
new file mode 100644
index 00000000..bb875384
--- /dev/null
+++ "b/gso/migrations/versions/2024-09-16_aa6dcb493d12_add_g\303\251ant_ip_domain_models.py"
@@ -0,0 +1,335 @@
+"""Add GÉANT IP domain models.
+
+Revision ID: aa6dcb493d12
+Revises: c466b64eccfd
+Create Date: 2024-09-16 10:16:35.889496
+
+"""
+import sqlalchemy as sa
+from alembic import op
+
+# revision identifiers, used by Alembic.
+revision = 'aa6dcb493d12'
+down_revision = 'c466b64eccfd'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+    conn = op.get_bind()
+    conn.execute(sa.text("""
+INSERT INTO products (name, description, product_type, tag, status) VALUES ('GeantIP', 'GÉANT IP service', 'GeantIP', 'G_IP', 'active') RETURNING products.product_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_blocks (name, description, tag, status) VALUES ('EdgePortAEMemberBlock', 'Edge Port LAG Member', 'EDGEPORT_AE_MEMBER', 'active') RETURNING product_blocks.product_block_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_blocks (name, description, tag, status) VALUES ('ServiceBindingPort', 'Service Binding Port', 'SBP', 'active') RETURNING product_blocks.product_block_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_blocks (name, description, tag, status) VALUES ('BGPSession', 'BGP Session', 'BGP_SESSION', 'active') RETURNING product_blocks.product_block_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_blocks (name, description, tag, status) VALUES ('GeantIPBlock', 'GÉANT IP service product block', 'G_IP_BLOCK', 'active') RETURNING product_blocks.product_block_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_blocks (name, description, tag, status) VALUES ('NRENAccessPort', 'NREN Access Port', 'NREN_AP', 'active') RETURNING product_blocks.product_block_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('authentication_key', 'BGP session authentication key') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('geant_sid', 'GÉANT Service ID') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('bfd_enabled', 'BFD enabled') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('send_default_route', 'Use default fallback route') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('nren_ap_type', 'Access Port type, primary, secondary or load balanced') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('multipath_enabled', 'Multipath enabled BGP session') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('peer_address', 'BGP Session peer address') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('sbp_type', 'Service Binding Port type, layer 2 or 3') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('has_custom_policies', 'This BGP session has custom policies') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('ipv4_address', 'IPv4 Address') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('is_multi_hop', 'This BGP session is multi hop') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('bfd_multiplier', 'Bi-directional Forwarding Detection multiplier') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('is_tagged', 'This SBP is tagged') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('families', 'Unicast / Multicast and IPv4 / IPv6') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('custom_firewall_filters', 'This SBP has custom firewall filters') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('ipv6_address', 'IPv6 address') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('bfd_interval', 'BFD interval') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('GeantIP')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('GeantIPBlock')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortAEMemberBlock')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('GeantIPBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('NRENAccessPort')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('NRENAccessPort')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')))
+    """))
+    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 ('EdgePortAEMemberBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_description')))
+    """))
+    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 ('EdgePortAEMemberBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_name')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('authentication_key')))
+    """))
+    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 ('BGPSession')), (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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('send_default_route')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('multipath_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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('peer_address')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('has_custom_policies')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_multi_hop')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('bfd_multiplier')))
+    """))
+    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 ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('families')))
+    """))
+    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 ('BGPSession')), (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 ('vlan_id')))
+    """))
+    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 ('ipv4_address')))
+    """))
+    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 ('geant_sid')))
+    """))
+    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 ('is_tagged')))
+    """))
+    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 ('custom_firewall_filters')))
+    """))
+    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 ('ipv6_address')))
+    """))
+    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 ('sbp_type')))
+    """))
+    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 ('NRENAccessPort')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('nren_ap_type')))
+    """))
+
+
+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 ('EdgePortAEMemberBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_description'))
+    """))
+    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 ('EdgePortAEMemberBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_description'))
+    """))
+    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 ('EdgePortAEMemberBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_name'))
+    """))
+    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 ('EdgePortAEMemberBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('interface_name'))
+    """))
+    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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('authentication_key'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('authentication_key'))
+    """))
+    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 ('BGPSession')) 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 ('BGPSession'))) 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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('send_default_route'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('send_default_route'))
+    """))
+    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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('multipath_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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('multipath_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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('peer_address'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('peer_address'))
+    """))
+    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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('has_custom_policies'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('has_custom_policies'))
+    """))
+    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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_multi_hop'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_multi_hop'))
+    """))
+    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 ('BGPSession')) 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 ('BGPSession'))) 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 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 ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('families'))
+    """))
+    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 ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('families'))
+    """))
+    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 ('BGPSession')) 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 ('BGPSession'))) 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 ('vlan_id'))
+    """))
+    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 ('vlan_id'))
+    """))
+    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 ('ipv4_address'))
+    """))
+    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 ('ipv4_address'))
+    """))
+    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 ('geant_sid'))
+    """))
+    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 ('geant_sid'))
+    """))
+    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 ('is_tagged'))
+    """))
+    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 ('is_tagged'))
+    """))
+    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 ('custom_firewall_filters'))
+    """))
+    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 ('custom_firewall_filters'))
+    """))
+    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 ('ipv6_address'))
+    """))
+    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 ('ipv6_address'))
+    """))
+    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 ('sbp_type'))
+    """))
+    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 ('sbp_type'))
+    """))
+    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 ('NRENAccessPort')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('nren_ap_type'))
+    """))
+    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 ('NRENAccessPort'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('nren_ap_type'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscription_instance_values WHERE subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('authentication_key', 'geant_sid', 'bfd_enabled', 'send_default_route', 'nren_ap_type', 'multipath_enabled', 'peer_address', 'sbp_type', 'has_custom_policies', 'ipv4_address', 'is_multi_hop', 'bfd_multiplier', 'is_tagged', 'families', 'custom_firewall_filters', 'ipv6_address', 'bfd_interval'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM resource_types WHERE resource_types.resource_type IN ('authentication_key', 'geant_sid', 'bfd_enabled', 'send_default_route', 'nren_ap_type', 'multipath_enabled', 'peer_address', 'sbp_type', 'has_custom_policies', 'ipv4_address', 'is_multi_hop', 'bfd_multiplier', 'is_tagged', 'families', 'custom_firewall_filters', 'ipv6_address', 'bfd_interval')
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('GeantIP')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('GeantIPBlock'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortAEMemberBlock'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('GeantIPBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('NRENAccessPort'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('NRENAccessPort')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortAEMemberBlock', 'GeantIPBlock', 'NRENAccessPort', 'ServiceBindingPort', 'BGPSession'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM product_blocks WHERE product_blocks.name IN ('EdgePortAEMemberBlock', 'GeantIPBlock', 'NRENAccessPort', 'ServiceBindingPort', 'BGPSession')
+    """))
+    conn.execute(sa.text("""
+DELETE FROM processes WHERE processes.pid IN (SELECT processes_subscriptions.pid FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('GeantIP'))))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('GeantIP')))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscription_instances WHERE subscription_instances.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('GeantIP')))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('GeantIP'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM products WHERE products.name IN ('GeantIP')
+    """))
diff --git a/gso/products/product_blocks/bgp_session.py b/gso/products/product_blocks/bgp_session.py
index 09d578cf..74083c04 100644
--- a/gso/products/product_blocks/bgp_session.py
+++ b/gso/products/product_blocks/bgp_session.py
@@ -1,13 +1,15 @@
 """:term:`BGP` session product block."""
 
-from ipaddress import IPv4Address, IPv6Address
-
+import strawberry
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle
 from pydantic import Field
 from pydantic_forms.types import strEnum
 
+from gso.utils.types.ip_address import IPAddress
+
 
+@strawberry.enum
 class IPFamily(strEnum):
     """Possible :term:`IP` families of a :term:`BGP` peering."""
 
@@ -20,7 +22,7 @@ class IPFamily(strEnum):
 class BGPSessionInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="BGPSession"):
     """A :term:`BGP` session that is currently inactive. See :class:`BGPSession`."""
 
-    peer_address: IPv4Address | IPv6Address | None = None
+    peer_address: IPAddress | None = None
     bfd_enabled: bool | None = None
     bfd_interval: int | None = None
     bfd_multiplier: int | None = None
@@ -35,7 +37,7 @@ class BGPSessionInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INI
 class BGPSessionProvisioning(BGPSessionInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
     """A :term:`BGP` session that is currently being provisioned. See :class:`BGPSession`."""
 
-    peer_address: IPv4Address | IPv6Address
+    peer_address: IPAddress
     bfd_enabled: bool
     bfd_interval: int | None = None
     bfd_multiplier: int | None = None
@@ -51,7 +53,7 @@ class BGPSession(BGPSessionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE
     """A :term:`BGP` session that is currently deployed in the network."""
 
     #: The peering address of the session.
-    peer_address: IPv4Address | IPv6Address
+    peer_address: IPAddress
     #: Whether :term:`BFD` is enabled.
     bfd_enabled: bool
     #: The :term:`BFD` interval, if enabled.
diff --git a/gso/products/product_blocks/edge_port.py b/gso/products/product_blocks/edge_port.py
index ffa5ea90..27e01558 100644
--- a/gso/products/product_blocks/edge_port.py
+++ b/gso/products/product_blocks/edge_port.py
@@ -6,9 +6,15 @@ domain still managed by GEANT. In other words, an Edge port determines where the
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle, strEnum
+from pydantic import Field
 
 from gso.products.product_blocks.router import RouterBlock, RouterBlockInactive, RouterBlockProvisioning
-from gso.utils.types.interfaces import LAGMember, LAGMemberList, PhysicalPortCapacity
+from gso.products.product_blocks.service_binding_port import (
+    ServiceBindingPort,
+    ServiceBindingPortInactive,
+    ServiceBindingPortProvisioning,
+)
+from gso.utils.types.interfaces import LAGMemberList, PhysicalPortCapacity
 
 
 class EncapsulationType(strEnum):
@@ -34,6 +40,29 @@ class EdgePortType(strEnum):
     RE_INTERCONNECT = "RE_INTERCONNECT"
 
 
+class EdgePortAEMemberBlockInactive(
+    ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="EdgePortAEMemberBlock"
+):
+    """An inactive Edge Port AE interface."""
+
+    interface_name: str | None = None
+    interface_description: str | None = None
+
+
+class EdgePortAEMemberBlockProvisioning(EdgePortAEMemberBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
+    """A provisional Edge Port AE interface."""
+
+    interface_name: str
+    interface_description: str | None = None
+
+
+class EdgePortAEMemberBlock(EdgePortAEMemberBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
+    """An Edge Port AE interface."""
+
+    interface_name: str
+    interface_description: str | None = None
+
+
 class EdgePortBlockInactive(
     ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="EdgePortBlock"
 ):
@@ -50,7 +79,8 @@ class EdgePortBlockInactive(
     edge_port_type: EdgePortType | None = None
     edge_port_ignore_if_down: bool = False
     edge_port_geant_ga_id: str | None = None
-    edge_port_ae_members: LAGMemberList[LAGMember]
+    edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlockInactive]
+    edge_port_sbp_list: list[ServiceBindingPortInactive] = Field(default_factory=list)
 
 
 class EdgePortBlockProvisioning(EdgePortBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
@@ -67,7 +97,8 @@ class EdgePortBlockProvisioning(EdgePortBlockInactive, lifecycle=[SubscriptionLi
     edge_port_type: EdgePortType
     edge_port_ignore_if_down: bool = False
     edge_port_geant_ga_id: str | None = None
-    edge_port_ae_members: LAGMemberList[LAGMember]
+    edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlockProvisioning]  # type: ignore[assignment]
+    edge_port_sbp_list: list[ServiceBindingPortProvisioning]  # type: ignore[assignment]
 
 
 class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
@@ -96,4 +127,6 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle.
     #: The GEANT GA ID associated with this edge port, if any.
     edge_port_geant_ga_id: str | None = None
     #: A list of LAG members associated with this edge port.
-    edge_port_ae_members: LAGMemberList[LAGMember]
+    edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlock]  # type: ignore[assignment]
+    #: A list of Service Binding Ports associated with this Edge Port
+    edge_port_sbp_list: list[ServiceBindingPort]  # type: ignore[assignment]
diff --git a/gso/products/product_blocks/geant_ip.py b/gso/products/product_blocks/geant_ip.py
index 7b7213a3..d57d2dd0 100644
--- a/gso/products/product_blocks/geant_ip.py
+++ b/gso/products/product_blocks/geant_ip.py
@@ -5,11 +5,6 @@ from orchestrator.types import SubscriptionLifecycle
 from pydantic import Field
 
 from gso.products.product_blocks.edge_port import EdgePortBlock, EdgePortBlockInactive, EdgePortBlockProvisioning
-from gso.products.product_blocks.service_binding_port import (
-    ServiceBindingPort,
-    ServiceBindingPortInactive,
-    ServiceBindingPortProvisioning,
-)
 from gso.utils.shared_enums import APType
 
 
@@ -18,22 +13,24 @@ class NRENAccessPortInactive(
 ):
     """An access port for an R&E :term:`NREN` service that is inactive."""
 
-    nren_ap_sbp_list: list[ServiceBindingPortInactive] = Field(default_factory=list)
     nren_ap_type: APType | None = None
+    geant_ip_ep_list: list[EdgePortBlockInactive] = Field(default_factory=list)
 
 
 class NRENAccessPortProvisioning(NRENAccessPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
     """An access port for an R&E :term:`NREN` service that is being provisioned."""
 
-    nren_ap_sbp_list: list[ServiceBindingPortProvisioning]  # type: ignore[assignment]
     nren_ap_type: APType
+    geant_ip_ep_list: list[EdgePortBlockProvisioning]  # type: ignore[assignment]
 
 
 class NRENAccessPort(NRENAccessPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
     """An access port for an R&E :term:`NREN` service."""
 
-    nren_ap_sbp_list: list[ServiceBindingPort]  # type: ignore[assignment]
+    #: The type of Access Port
     nren_ap_type: APType
+    #: The list of Edge Ports where this service terminates.
+    geant_ip_ep_list: list[EdgePortBlock]  # type: ignore[assignment]
 
 
 class GeantIPBlockInactive(
@@ -42,14 +39,12 @@ class GeantIPBlockInactive(
     """A GÉANT IP subscription that is currently inactive. See :class:`GeantIPBlock`."""
 
     geant_ip_ap_list: list[NRENAccessPortInactive] = Field(default_factory=list)
-    geant_ip_ep_list: list[EdgePortBlockInactive] = Field(default_factory=list)
 
 
 class GeantIPBlockProvisioning(GeantIPBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
     """A GÉANT IP subscription that is currently being provisioned. See :class:`GeantIPBlock`."""
 
     geant_ip_ap_list: list[NRENAccessPortProvisioning]  # type: ignore[assignment]
-    geant_ip_ep_list: list[EdgePortBlockProvisioning]  # type: ignore[assignment]
 
 
 class GeantIPBlock(GeantIPBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
@@ -57,5 +52,3 @@ class GeantIPBlock(GeantIPBlockProvisioning, lifecycle=[SubscriptionLifecycle.AC
 
     #: The list of Access Points where this service is present.
     geant_ip_ap_list: list[NRENAccessPort]  # type: ignore[assignment]
-    #: The list of Edge Ports where this service terminates.
-    geant_ip_ep_list: list[EdgePortBlock]  # type: ignore[assignment]
diff --git a/gso/products/product_blocks/service_binding_port.py b/gso/products/product_blocks/service_binding_port.py
index a88c973b..1f031e52 100644
--- a/gso/products/product_blocks/service_binding_port.py
+++ b/gso/products/product_blocks/service_binding_port.py
@@ -3,15 +3,15 @@
 A service binding port is used to logically attach an edge port to a customer service using a :term:`VLAN`.
 """
 
-from ipaddress import IPv4Address, IPv6Address
 from typing import Annotated
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle
 from pydantic import Field
 
+from gso.products.product_blocks.bgp_session import BGPSession, BGPSessionInactive, BGPSessionProvisioning
 from gso.utils.shared_enums import SBPType
-from gso.utils.types.bgp_session import BGPSessionSet
+from gso.utils.types.ip_address import IPv4AddressType, IPv6AddressType
 
 VLAN_ID = Annotated[int, Field(gt=0, lt=4096)]
 
@@ -24,11 +24,11 @@ class ServiceBindingPortInactive(
     is_tagged: bool | None = None
     vlan_id: VLAN_ID | None = None
     sbp_type: SBPType | None = None
-    ipv4_address: IPv4Address | None = None
-    ipv6_address: IPv6Address | None = None
+    ipv4_address: IPv4AddressType | None = None
+    ipv6_address: IPv6AddressType | None = None
     custom_firewall_filters: bool | None = None
     geant_sid: str | None = None
-    sbp_bgp_session_list: BGPSessionSet | None = None
+    sbp_bgp_session_list: list[BGPSessionInactive] = Field(default_factory=list)
 
 
 class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
@@ -37,11 +37,11 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs
     is_tagged: bool
     vlan_id: VLAN_ID | None = None
     sbp_type: SBPType
-    ipv4_address: IPv4Address | None = None
-    ipv6_address: IPv6Address | None = None
+    ipv4_address: IPv4AddressType | None = None
+    ipv6_address: IPv6AddressType | None = None
     custom_firewall_filters: bool
     geant_sid: str
-    sbp_bgp_session_list: BGPSessionSet
+    sbp_bgp_session_list: list[BGPSessionProvisioning]  # type: ignore[assignment]
 
 
 class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
@@ -54,12 +54,12 @@ class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[Subscription
     #: Is this service binding port layer 2 or 3?
     sbp_type: SBPType
     #: If layer 3, IPv4 resources.
-    ipv4_address: IPv4Address | None = None
+    ipv4_address: IPv4AddressType | None = None
     #: If layer 3, IPv6 resources.
-    ipv6_address: IPv6Address | None = None
+    ipv6_address: IPv6AddressType | None = None
     #: Any custom firewall filters that the partner may require.
     custom_firewall_filters: bool
     #: The GÉANT service ID of this binding port.
     geant_sid: str
     #: The :term:`BGP` sessions associated with this service binding port.
-    sbp_bgp_session_list: BGPSessionSet
+    sbp_bgp_session_list: list[BGPSession]  # type: ignore[assignment]
diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json
index f1ede053..63f9e9c2 100644
--- a/gso/translations/en-GB.json
+++ b/gso/translations/en-GB.json
@@ -32,8 +32,7 @@
             "migrate_to_different_site": "Migrating to a different Site",
             "remove_configuration": "Remove configuration from the router",
             "clean_up_ipam": "Clean up related entries in IPAM",
-            "restore_isis_metric": "Restore ISIS metric to original value",
-            "confirm_info": "Please verify this form looks correct."
+            "restore_isis_metric": "Restore ISIS metric to original value"
         }
     },
     "workflow": {
@@ -44,6 +43,7 @@
         "create_router": "Create Router",
         "create_site": "Create Site",
         "create_switch": "Create Switch",
+        "create_edge_port": "Create Edge Port",
         "deploy_twamp": "Deploy TWAMP",
         "migrate_iptrunk": "Migrate IP Trunk",
         "modify_isis_metric": "Modify the ISIS metric",
@@ -51,10 +51,12 @@
         "modify_trunk_interface": "Modify IP Trunk interface",
         "modify_connection_strategy": "Modify connection strategy",
         "modify_router_kentik_license": "Modify device license in Kentik",
+        "modify_edge_port": "Modify Edge Port",
         "terminate_iptrunk": "Terminate IP Trunk",
         "terminate_router": "Terminate Router",
         "terminate_site": "Terminate Site",
         "terminate_switch": "Terminate Switch",
+        "terminate_edge_port": "Terminate Edge Port",
         "redeploy_base_config": "Redeploy base config",
         "update_ibgp_mesh": "Update iBGP mesh",
         "create_imported_site": "NOT FOR HUMANS -- Import existing site",
@@ -72,6 +74,7 @@
         "validate_iptrunk": "Validate IP Trunk configuration",
         "validate_router": "Validate Router configuration",
         "validate_switch": "Validate Switch configuration",
+        "validate_edge_port": "Validate Edge Port",
         "task_validate_geant_products": "Validation task for GEANT products",
         "task_send_email_notifications": "Send email notifications for failed tasks",
         "task_create_partners": "Create partner task",
diff --git a/gso/utils/types/bgp_session.py b/gso/utils/types/bgp_session.py
deleted file mode 100644
index 681ab1c7..00000000
--- a/gso/utils/types/bgp_session.py
+++ /dev/null
@@ -1,33 +0,0 @@
-""":term:`BGP` session sets."""
-
-from typing import Annotated, TypeVar
-
-from annotated_types import Len
-from pydantic import AfterValidator
-
-from gso.products.product_blocks.bgp_session import BGPSession, BGPSessionInactive, BGPSessionProvisioning
-
-BGPSessionTypes = TypeVar("BGPSessionTypes", BGPSessionInactive, BGPSessionProvisioning, BGPSession)
-
-
-def validate_bgp_session_set(bgp_session_set: list[BGPSessionTypes]) -> list[BGPSessionTypes]:
-    """:term:`BGP` sessions grouped together.
-
-    It consists of either a single item, or a pair of IPv4 and v6 sessions. It is not allowed to have two IPv4 or IPv6
-    :term:`BGP` sessions as part of a set.
-    """
-    if any(bgp_session.peer_address is None for bgp_session in bgp_session_set):
-        msg = "BGP session is missing a peer address."
-        raise ValueError(msg)
-    if len(bgp_session_set) == 2 and bgp_session_set[0].peer_address.version == bgp_session_set[1].peer_address.version:  # type: ignore[union-attr] # noqa: PLR2004
-        msg = (
-            "When defining two separate BGP sessions, IP families must differ. "
-            f"Both are IPv{bgp_session_set[0].peer_address.version}."  # type: ignore[union-attr]
-        )
-        raise ValueError(msg)
-    return bgp_session_set
-
-
-BGPSessionSet = Annotated[
-    list[BGPSessionTypes], Len(min_length=1, max_length=2), AfterValidator(validate_bgp_session_set)
-]
diff --git a/gso/workflows/edge_port/create_edge_port.py b/gso/workflows/edge_port/create_edge_port.py
index c961cd7f..ce87d1f5 100644
--- a/gso/workflows/edge_port/create_edge_port.py
+++ b/gso/workflows/edge_port/create_edge_port.py
@@ -1,6 +1,7 @@
 """A creation workflow for adding a new edge port to the network."""
 
 from typing import Annotated, Any, Self
+from uuid import uuid4
 
 from annotated_types import Len
 from orchestrator import step, workflow
@@ -16,7 +17,7 @@ from pydantic import AfterValidator, ConfigDict, model_validator
 from pydantic_forms.validators import validate_unique_list
 from pynetbox.models.dcim import Interfaces
 
-from gso.products.product_blocks.edge_port import EdgePortType, EncapsulationType
+from gso.products.product_blocks.edge_port import EdgePortAEMemberBlockInactive, EdgePortType, EncapsulationType
 from gso.products.product_blocks.router import RouterRole
 from gso.products.product_types.edge_port import EdgePortInactive, EdgePortProvisioning
 from gso.products.product_types.router import Router
@@ -133,7 +134,9 @@ def initialize_subscription(
     subscription.description = f"Edge Port {name} on {router.router_fqdn}, {partner}, {geant_ga_id or ""}"
     subscription.edge_port.edge_port_description = description
     for member in ae_members:
-        subscription.edge_port.edge_port_ae_members.append(LAGMember(**member))
+        subscription.edge_port.edge_port_ae_members.append(
+            EdgePortAEMemberBlockInactive.new(subscription_id=uuid4(), **member)
+        )
     subscription = EdgePortProvisioning.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING)
 
     return {"subscription": subscription}
diff --git a/gso/workflows/edge_port/modify_edge_port.py b/gso/workflows/edge_port/modify_edge_port.py
index 7e280198..0237b143 100644
--- a/gso/workflows/edge_port/modify_edge_port.py
+++ b/gso/workflows/edge_port/modify_edge_port.py
@@ -1,6 +1,7 @@
 """Modify an existing edge port subscription."""
 
 from typing import Annotated, Any, Self
+from uuid import uuid4
 
 from annotated_types import Len
 from orchestrator import workflow
@@ -13,7 +14,7 @@ from pydantic import AfterValidator, ConfigDict, model_validator
 from pydantic_forms.types import FormGenerator, UUIDstr
 from pydantic_forms.validators import ReadOnlyField, validate_unique_list
 
-from gso.products.product_blocks.edge_port import EncapsulationType
+from gso.products.product_blocks.edge_port import EdgePortAEMemberBlock, EncapsulationType
 from gso.products.product_types.edge_port import EdgePort
 from gso.services.lso_client import execute_playbook, lso_interaction
 from gso.services.netbox_client import NetboxClient
@@ -146,7 +147,7 @@ def modify_edge_port_subscription(
     )
     subscription.edge_port.edge_port_ae_members.clear()
     for member in ae_members:
-        subscription.edge_port.edge_port_ae_members.append(LAGMember(**member))
+        subscription.edge_port.edge_port_ae_members.append(EdgePortAEMemberBlock.new(subscription_id=uuid4(), **member))
     subscription.save()
 
     return {
@@ -159,19 +160,19 @@ def modify_edge_port_subscription(
 @step("Update interfaces in NetBox")
 def update_interfaces_in_netbox(
     subscription: EdgePort,
-    removed_ae_members: list[LAGMember],
-    previous_ae_members: list[LAGMember],
+    removed_ae_members: list[dict],
+    previous_ae_members: list[dict],
 ) -> dict[str, Any]:
     """Update the interfaces in NetBox."""
     nbclient = NetboxClient()
     # Free removed interfaces
-    for member in removed_ae_members:
-        nbclient.free_interface(subscription.edge_port.edge_port_node.router_fqdn, member.interface_name)
+    for removed_member in removed_ae_members:
+        nbclient.free_interface(subscription.edge_port.edge_port_node.router_fqdn, removed_member["interface_name"])
     # Attach physical interfaces to :term:`LAG`
     # Update interface description to subscription ID
     # Reserve interfaces
     for member in subscription.edge_port.edge_port_ae_members:
-        if any(prev_member.interface_name == member.interface_name for prev_member in previous_ae_members):
+        if any(prev_member["interface_name"] == member.interface_name for prev_member in previous_ae_members):
             continue
         nbclient.attach_interface_to_lag(
             device_name=subscription.edge_port.edge_port_node.router_fqdn,
diff --git a/gso/workflows/geant_ip/__init__.py b/gso/workflows/geant_ip/__init__.py
new file mode 100644
index 00000000..0a1739e2
--- /dev/null
+++ b/gso/workflows/geant_ip/__init__.py
@@ -0,0 +1 @@
+"""GÉANT IP workflows."""
diff --git a/gso/workflows/geant_ip/create_geant_ip.py b/gso/workflows/geant_ip/create_geant_ip.py
new file mode 100644
index 00000000..651c602e
--- /dev/null
+++ b/gso/workflows/geant_ip/create_geant_ip.py
@@ -0,0 +1 @@
+"""Create a new GÉANT IP subscription."""
-- 
GitLab