diff --git a/gso/api/v1/network.py b/gso/api/v1/network.py index e4a19de9e90475f70261e4bf408498de68a95af9..81a209b7e4365f8a4d3e90573a1160ea02ea1131 100644 --- a/gso/api/v1/network.py +++ b/gso/api/v1/network.py @@ -64,7 +64,7 @@ class IptrunkBlock(OrchestratorBaseModel): iptrunk_capacity: str iptrunk_isis_metric: int iptrunk_sides: list[IptrunkSideBlock] - geant_s_sid: str + gs_id: str class IptrunkSchema(OrchestratorBaseModel): @@ -109,7 +109,7 @@ def network_topology() -> NetworkTopologyDomainModelSchema: "iptrunk_capacity": _calculate_iptrunk_capacity( extended_model["iptrunk"]["iptrunk_sides"], extended_model["iptrunk"]["iptrunk_speed"] ), - "geant_s_sid": extended_model["iptrunk"]["geant_s_sid"], + "gs_id": extended_model["iptrunk"]["gs_id"], "iptrunk_sides": [ { "subscription_instance_id": side["subscription_instance_id"], diff --git a/gso/cli/imports.py b/gso/cli/imports.py index 14a45ad05810386d27abc66cc68129f668e0930c..4c973ace3bd5653e751292c7a078576fb79265ce 100644 --- a/gso/cli/imports.py +++ b/gso/cli/imports.py @@ -40,6 +40,7 @@ from gso.services.subscriptions import ( ) from gso.utils.shared_enums import SBPType, Vendor from gso.utils.types.base_site import BaseSiteValidatorModel +from gso.utils.types.geant_ids import IMPORTED_GA_ID, IMPORTED_GS_ID from gso.utils.types.interfaces import BandwidthString, LAGMember, LAGMemberList, PhysicalPortCapacity from gso.utils.types.ip_address import ( AddressSpace, @@ -116,7 +117,7 @@ class IptrunkImportModel(BaseModel): """Required fields for importing an existing ``gso.products.product_types.iptrunk``.""" partner: str - geant_s_sid: str | None + gs_id: IMPORTED_GS_ID | None iptrunk_type: IptrunkType iptrunk_description: str | None = None iptrunk_speed: PhysicalPortCapacity @@ -124,11 +125,11 @@ class IptrunkImportModel(BaseModel): iptrunk_isis_metric: int side_a_node_id: str side_a_ae_iface: str - side_a_ae_geant_a_sid: str | None + side_a_ga_id: IMPORTED_GA_ID | None side_a_ae_members: LAGMemberList[LAGMember] side_b_node_id: str side_b_ae_iface: str - side_b_ae_geant_a_sid: str | None + side_b_ga_id: IMPORTED_GA_ID | None side_b_ae_members: LAGMemberList[LAGMember] iptrunk_ipv4_network: ipaddress.IPv4Network @@ -197,7 +198,7 @@ class EdgePortImportModel(BaseModel): encapsulation: EncapsulationType name: str minimum_links: int - geant_ga_id: str | None + ga_id: IMPORTED_GA_ID | None mac_address: str | None partner: str enable_lacp: bool @@ -269,7 +270,7 @@ class L3CoreServiceImportModel(BaseModel): edge_port: str ap_type: str - geant_sid: str + gs_id: IMPORTED_GS_ID sbp_type: SBPType = SBPType.L3 is_tagged: bool = False vlan_id: VLAN_ID @@ -349,7 +350,7 @@ class Layer2CircuitServiceImportModel(BaseModel): service_type: Layer2CircuitServiceType partner: str - geant_sid: str + gs_id: IMPORTED_GS_ID vc_id: VC_ID layer_2_circuit_side_a: ServiceBindingPortInput layer_2_circuit_side_b: ServiceBindingPortInput @@ -592,7 +593,7 @@ def import_iptrunks(filepath: str = common_filepath_option) -> None: try: initial_data = IptrunkImportModel( partner="GEANT", - geant_s_sid=trunk["id"], + gs_id=trunk["id"], iptrunk_type=trunk["config"]["common"]["type"], iptrunk_description=trunk["config"]["common"].get("description", ""), iptrunk_speed=trunk["config"]["common"]["link_speed"], @@ -600,11 +601,11 @@ def import_iptrunks(filepath: str = common_filepath_option) -> None: iptrunk_isis_metric=trunk["config"]["common"]["isis_metric"], side_a_node_id=_get_router_subscription_id(trunk["config"]["nodeA"]["name"]) or "", side_a_ae_iface=trunk["config"]["nodeA"]["ae_name"], - side_a_ae_geant_a_sid=trunk["config"]["nodeA"]["port_sid"], + side_a_ga_id=trunk["config"]["nodeA"]["port_ga_id"], side_a_ae_members=trunk["config"]["nodeA"]["members"], side_b_node_id=_get_router_subscription_id(trunk["config"]["nodeB"]["name"]) or "", side_b_ae_iface=trunk["config"]["nodeB"]["ae_name"], - side_b_ae_geant_a_sid=trunk["config"]["nodeB"]["port_sid"], + side_b_ga_id=trunk["config"]["nodeB"]["port_ga_id"], side_b_ae_members=trunk["config"]["nodeB"]["members"], iptrunk_ipv4_network=iptrunk_ipv4_network, iptrunk_ipv6_network=iptrunk_ipv6_network, diff --git a/gso/migrations/versions/2024-12-04_4cc835c615fc_remove_additional_products.py b/gso/migrations/versions/2024-12-04_4cc835c615fc_remove_additional_products.py new file mode 100644 index 0000000000000000000000000000000000000000..969e1e0fc20d437b400a69ef670c46ad5ed0e059 --- /dev/null +++ b/gso/migrations/versions/2024-12-04_4cc835c615fc_remove_additional_products.py @@ -0,0 +1,33 @@ +"""remove additional products. + +Revision ID: 4cc835c615fc +Revises: 28c1723c6a00 +Create Date: 2024-12-04 14:54:22.167158 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = '4cc835c615fc' +down_revision = '28c1723c6a00' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + 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 ('IAS', 'Imported IAS', 'Imported GÉANT IP', 'GÉANT IP')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('NRENL3CoreServiceBlock')) + """)) + 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 ('NRENAccessPort', 'NRENL3CoreServiceBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_blocks WHERE product_blocks.name IN ('NRENAccessPort', 'NRENL3CoreServiceBlock') + """)) + + +def downgrade() -> None: + conn = op.get_bind() + diff --git a/gso/migrations/versions/2024-12-04_e358efe9ab03_rename_iptrunk_and_iptrunk_side_sid_and_.py b/gso/migrations/versions/2024-12-04_e358efe9ab03_rename_iptrunk_and_iptrunk_side_sid_and_.py new file mode 100644 index 0000000000000000000000000000000000000000..63bc63a7415d408708438e1b110e5721c5b50090 --- /dev/null +++ b/gso/migrations/versions/2024-12-04_e358efe9ab03_rename_iptrunk_and_iptrunk_side_sid_and_.py @@ -0,0 +1,35 @@ +"""Rename iptrunk and iptrunk side sid and gid. + +Revision ID: e358efe9ab03 +Revises: 4cc835c615fc +Create Date: 2024-12-04 15:05:46.356709 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'e358efe9ab03' +down_revision = '4cc835c615fc' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +UPDATE resource_types SET resource_type='ga_id' WHERE resource_types.resource_type = 'iptrunk_side_ae_geant_a_sid' + """)) + conn.execute(sa.text(""" +UPDATE resource_types SET resource_type='gs_id' WHERE resource_types.resource_type = 'geant_s_sid' + """)) + + +def downgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +UPDATE resource_types SET resource_type='iptrunk_side_ae_geant_a_sid' WHERE resource_types.resource_type = 'ga_id' + """)) + conn.execute(sa.text(""" +UPDATE resource_types SET resource_type='geant_s_sid' WHERE resource_types.resource_type = 'gs_id' + """)) diff --git a/gso/migrations/versions/2024-12-04_e36b3bd8a45c_rename_edgeport_and_sbp_gs_and_ga_id.py b/gso/migrations/versions/2024-12-04_e36b3bd8a45c_rename_edgeport_and_sbp_gs_and_ga_id.py new file mode 100644 index 0000000000000000000000000000000000000000..180c97ee45b08904fc7c4b4dbd1ea2b6a36d1865 --- /dev/null +++ b/gso/migrations/versions/2024-12-04_e36b3bd8a45c_rename_edgeport_and_sbp_gs_and_ga_id.py @@ -0,0 +1,47 @@ +"""Rename edgeport and sbp gs and ga id. + +Revision ID: e36b3bd8a45c +Revises: e358efe9ab03 +Create Date: 2024-12-04 15:08:30.512126 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'e36b3bd8a45c' +down_revision = 'e358efe9ab03' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +UPDATE product_block_resource_types SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ga_id')) WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')) AND product_block_resource_types.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_ga_id')) + """)) + conn.execute(sa.text(""" +UPDATE product_block_resource_types SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) 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 IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_sid')) + """)) + conn.execute(sa.text(""" +UPDATE subscription_instance_values SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ga_id')) WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock'))) AND subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_ga_id')) + """)) + conn.execute(sa.text(""" +UPDATE subscription_instance_values SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))) AND subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_sid')) + """)) + + +def downgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +UPDATE product_block_resource_types SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_ga_id')) WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')) AND product_block_resource_types.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ga_id')) + """)) + conn.execute(sa.text(""" +UPDATE product_block_resource_types SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_sid')) 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 IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) + """)) + conn.execute(sa.text(""" +UPDATE subscription_instance_values SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_ga_id')) WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock'))) AND subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ga_id')) + """)) + conn.execute(sa.text(""" +UPDATE subscription_instance_values SET resource_type_id=(SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('geant_sid')) WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('ServiceBindingPort'))) AND subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) + """)) diff --git a/gso/migrations/versions/2024-12-05_79192e72131c_add_gs_and_ga_sequences.py b/gso/migrations/versions/2024-12-05_79192e72131c_add_gs_and_ga_sequences.py new file mode 100644 index 0000000000000000000000000000000000000000..2fb7fc2dd3f7f4a8e10b9f7b5ade94b90dca9da7 --- /dev/null +++ b/gso/migrations/versions/2024-12-05_79192e72131c_add_gs_and_ga_sequences.py @@ -0,0 +1,42 @@ +"""Add GS and GA sequences. + +Revision ID: 79192e72131c +Revises: e36b3bd8a45c +Create Date: 2024-12-05 11:11:41.048264 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = '79192e72131c' +down_revision = 'e36b3bd8a45c' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # Create GS ID sequence + op.execute(""" + CREATE SEQUENCE gs_id_seq + START WITH 50000 + INCREMENT BY 1 + MINVALUE 50000 + MAXVALUE 99999 + NO CYCLE; + """) + + # Create GA ID sequence + op.execute(""" + CREATE SEQUENCE ga_id_seq + START WITH 50000 + INCREMENT BY 1 + MINVALUE 50000 + MAXVALUE 99999 + NO CYCLE; + """) + + +def downgrade() -> None: + op.execute("DROP SEQUENCE gs_id_seq") + op.execute("DROP SEQUENCE ga_id_seq") diff --git a/gso/products/product_blocks/edge_port.py b/gso/products/product_blocks/edge_port.py index b3400e0f5274957f9d0570a42e2420519fd01a9d..8f5c4bb1b32926639688b48e853d670de4a0734c 100644 --- a/gso/products/product_blocks/edge_port.py +++ b/gso/products/product_blocks/edge_port.py @@ -72,7 +72,7 @@ class EdgePortBlockInactive( minimum_links: int | None = None edge_port_type: EdgePortType | None = None ignore_if_down: bool = False - geant_ga_id: str | None = None + ga_id: str | None = None edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlockInactive] @@ -89,7 +89,7 @@ class EdgePortBlockProvisioning(EdgePortBlockInactive, lifecycle=[SubscriptionLi minimum_links: int | None = None edge_port_type: EdgePortType ignore_if_down: bool = False - geant_ga_id: str | None = None + ga_id: str | None = None edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlockProvisioning] # type: ignore[assignment] @@ -117,6 +117,6 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle. #: If set to True, the edge port will be ignored if it is down. ignore_if_down: bool = False #: The GEANT GA ID associated with this edge port, if any. - geant_ga_id: str | None = None + ga_id: str | None = None #: A list of LAG members associated with this edge port. edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlock] # type: ignore[assignment] diff --git a/gso/products/product_blocks/iptrunk.py b/gso/products/product_blocks/iptrunk.py index e68911dd1c3b93502ee79d5015e380860b542c72..9ffaa7881826325950d2cd0a08b2ed03bcc9c4a0 100644 --- a/gso/products/product_blocks/iptrunk.py +++ b/gso/products/product_blocks/iptrunk.py @@ -67,7 +67,7 @@ class IptrunkSideBlockInactive( iptrunk_side_node: RouterBlockInactive iptrunk_side_ae_iface: str | None = None - iptrunk_side_ae_geant_a_sid: str | None = None + ga_id: str | None = None iptrunk_side_ae_members: LAGMemberList[IptrunkInterfaceBlockInactive] @@ -76,7 +76,7 @@ class IptrunkSideBlockProvisioning(IptrunkSideBlockInactive, lifecycle=[Subscrip iptrunk_side_node: RouterBlockProvisioning iptrunk_side_ae_iface: str - iptrunk_side_ae_geant_a_sid: str | None = None + ga_id: str | None = None iptrunk_side_ae_members: LAGMemberList[IptrunkInterfaceBlockProvisioning] # type: ignore[assignment] @@ -85,7 +85,7 @@ class IptrunkSideBlock(IptrunkSideBlockProvisioning, lifecycle=[SubscriptionLife iptrunk_side_node: RouterBlock iptrunk_side_ae_iface: str - iptrunk_side_ae_geant_a_sid: str | None = None + ga_id: str | None = None iptrunk_side_ae_members: LAGMemberList[IptrunkInterfaceBlock] # type: ignore[assignment] @@ -96,7 +96,7 @@ class IptrunkBlockInactive( ): """A trunk that's currently inactive, see ``IptrunkBlock``.""" - geant_s_sid: str | None = None + gs_id: str | None = None iptrunk_description: str | None = None iptrunk_type: IptrunkType | None = None iptrunk_speed: PhysicalPortCapacity | None = None @@ -110,7 +110,7 @@ class IptrunkBlockInactive( class IptrunkBlockProvisioning(IptrunkBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): """A trunk that's currently being provisioned, see ``IptrunkBlock``.""" - geant_s_sid: str | None = None + gs_id: str | None = None iptrunk_description: str | None = None iptrunk_type: IptrunkType | None = None iptrunk_speed: PhysicalPortCapacity | None = None @@ -125,7 +125,7 @@ class IptrunkBlock(IptrunkBlockProvisioning, lifecycle=[SubscriptionLifecycle.AC """A trunk that's currently deployed in the network.""" #: GÉANT service ID associated with this trunk. - geant_s_sid: str | None = None + gs_id: str | None = None #: A human-readable description of this trunk. iptrunk_description: str | None = None #: The type of trunk, can be either dark fibre or leased capacity. diff --git a/gso/products/product_blocks/service_binding_port.py b/gso/products/product_blocks/service_binding_port.py index 6fd7467c95808ee42438f2af74a1e0ba05a1609e..5f10b33c54c7ffa373fd555effef6014f5e59a4a 100644 --- a/gso/products/product_blocks/service_binding_port.py +++ b/gso/products/product_blocks/service_binding_port.py @@ -64,7 +64,7 @@ class ServiceBindingPortInactive( ipv6_address: IPv6AddressType | None = None ipv6_mask: IPV6Netmask | None = None custom_firewall_filters: bool | None = None - geant_sid: str | None = None + gs_id: str | None = None bgp_session_list: list[BGPSessionInactive] = Field(default_factory=list) edge_port: EdgePortBlockInactive | None = None v4_bfd_settings: BFDSettingsInactive @@ -82,7 +82,7 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs ipv6_address: IPv6AddressType | None = None ipv6_mask: IPV6Netmask | None = None custom_firewall_filters: bool - geant_sid: str + gs_id: str bgp_session_list: list[BGPSessionProvisioning] # type: ignore[assignment] edge_port: EdgePortBlockProvisioning v4_bfd_settings: BFDSettingsProvisioning @@ -109,7 +109,7 @@ class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[Subscription #: 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 + gs_id: str #: The BGP sessions associated with this service binding port. bgp_session_list: list[BGPSession] # type: ignore[assignment] #: The Edge Port on which this SBP resides. diff --git a/gso/services/subscriptions.py b/gso/services/subscriptions.py index 9185265c09d31a4c6a010336123a407a969404b1..83d88751984a66a5eed4522b55077734ceda303f 100644 --- a/gso/services/subscriptions.py +++ b/gso/services/subscriptions.py @@ -19,6 +19,8 @@ from orchestrator.db import ( from orchestrator.domain import SubscriptionModel from orchestrator.services.subscriptions import query_in_use_by_subscriptions from orchestrator.types import SubscriptionLifecycle, UUIDstr +from sqlalchemy import text +from sqlalchemy.exc import SQLAlchemyError from gso.products import ProductName, ProductType from gso.products.product_types.site import Site @@ -329,3 +331,39 @@ def is_virtual_circuit_id_available(virtual_circuit_id: str) -> bool: True if the virtual circuit ID is unique (not found), False if it exists. """ return is_resource_type_value_unique("virtual_circuit_id", virtual_circuit_id) + + +def generate_unique_gs_id() -> str: + """Generate a unique GS ID using the gs_id_seq database sequence. + + Returns: + str: A unique GS ID in the format `GS-<number>`. + + Raises: + ValueError: If there is an error generating the ID. + """ + try: + new_id = db.session.execute(text("SELECT nextval('gs_id_seq')")).scalar_one() + except SQLAlchemyError as exc: + error_message = f"Error generating GS ID: {exc}" + raise ValueError(error_message) from exc + else: + return f"GS-{new_id}" + + +def generate_unique_ga_id() -> str: + """Generate a unique GA ID using the ga_id_seq database sequence. + + Returns: + str: A unique GA ID in the format `GA-<number>`. + + Raises: + ValueError: If there is an error generating the ID. + """ + try: + new_id = db.session.execute(text("SELECT nextval('ga_id_seq')")).scalar_one() + except SQLAlchemyError as exc: + error_message = f"Error generating GA ID: {exc}" + raise ValueError(error_message) from exc + else: + return f"GA-{new_id}" diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json index f1f66f075835a00fbe3ca5a5cdffa2c515388d0d..2328bba28ce9393d6150743891c3313040daccc3 100644 --- a/gso/translations/en-GB.json +++ b/gso/translations/en-GB.json @@ -40,7 +40,7 @@ "enable_lacp": "Enable LACP", "mac_address": "MAC address", - "geant_ga_id": "GÉANT GA-ID" + "ga_id": "GÉANT GA-ID" } }, "workflow": { diff --git a/gso/utils/types/geant_ids.py b/gso/utils/types/geant_ids.py new file mode 100644 index 0000000000000000000000000000000000000000..72afc7f4113035b28fc8df8d2fe812145e0e7238 --- /dev/null +++ b/gso/utils/types/geant_ids.py @@ -0,0 +1,49 @@ +"""Type definitions for the GA and GS IDs.""" + +from functools import partial +from typing import Annotated, Literal + +from pydantic import AfterValidator + +from gso.services.subscriptions import is_resource_type_value_unique + + +def validate_id(value: str, prefix: Literal["GA", "GS"], field_name: str) -> str: + """Validate that the ID is unique, has the correct prefix, and is within valid constraints. + + Args: + value: The ID value to validate. + prefix: The required prefix for the ID. + field_name: The database field name to check for uniqueness. + + Raises: + ValueError: If the ID is not valid. + + Returns: + str: The validated ID. + """ + min_range = 50000 + max_range = 99999 + if not value.startswith(prefix): + err = f"{field_name} must start with the prefix '{prefix}'." + raise ValueError(err) + + try: + numeric_part = int(value.split("-")[-1]) + except ValueError: + err = f"{field_name} must have a numeric part after the prefix '{prefix}'." + raise ValueError(err) from ValueError + + if min_range <= numeric_part <= max_range: + err = f"{field_name} must not have a numeric part between {min_range} and {max_range}, received {numeric_part}" + raise ValueError(err) + + if not is_resource_type_value_unique(field_name, value): + err = f"{field_name} must be unique, {value} is already in use." + raise ValueError(err) + + return value + + +IMPORTED_GA_ID = Annotated[str, AfterValidator(partial(validate_id, prefix="GA", field_name="ga_id"))] +IMPORTED_GS_ID = Annotated[str, AfterValidator(partial(validate_id, prefix="GS", field_name="gs_id"))] diff --git a/gso/utils/workflow_steps.py b/gso/utils/workflow_steps.py index 721e18452e7f1aaded81a863bdfca514d8a11acd..0250eb8ce83649c8afe8a5d3cf287775eddce705 100644 --- a/gso/utils/workflow_steps.py +++ b/gso/utils/workflow_steps.py @@ -318,7 +318,7 @@ def set_isis_to_max(subscription: Iptrunk, process_id: UUIDstr, tt_number: str) "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { diff --git a/gso/workflows/edge_port/create_edge_port.py b/gso/workflows/edge_port/create_edge_port.py index 2005d7c2601ec59b85c2ff05695f833695288e33..a62c7147531299f8fdad5c822fe9077278cd2397 100644 --- a/gso/workflows/edge_port/create_edge_port.py +++ b/gso/workflows/edge_port/create_edge_port.py @@ -22,6 +22,7 @@ from gso.products.product_types.router import Router from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.services.partners import get_partner_by_id +from gso.services.subscriptions import generate_unique_ga_id from gso.utils.helpers import ( active_pe_router_selector, available_interfaces_choices, @@ -52,7 +53,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: minimum_links: int mac_address: str | None = None ignore_if_down: bool = False - geant_ga_id: str | None = None @model_validator(mode="after") def validate_number_of_members(self) -> Self: @@ -104,7 +104,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: "minimum_links", "mac_address", "ignore_if_down", - "geant_ga_id", "enable_lacp", "edge_port_name", "edge_port_description", @@ -134,7 +133,6 @@ def initialize_subscription( encapsulation: EncapsulationType, name: str, minimum_links: int, - geant_ga_id: str | None, mac_address: str | None, partner: str, enable_lacp: bool, # noqa: FBT001 @@ -152,10 +150,11 @@ def initialize_subscription( subscription.edge_port.edge_port_name = name subscription.edge_port.minimum_links = minimum_links subscription.edge_port.ignore_if_down = ignore_if_down - subscription.edge_port.geant_ga_id = geant_ga_id + ga_id = generate_unique_ga_id() + subscription.edge_port.ga_id = ga_id subscription.edge_port.mac_address = mac_address partner_name = get_partner_by_id(partner).name - subscription.description = f"Edge Port {name} on {router.router_fqdn}, " f"{partner_name}, {geant_ga_id or ""}" + subscription.description = f"Edge Port {name} on {router.router_fqdn}, " f"{partner_name}, {ga_id or ""}" subscription.edge_port.edge_port_description = description for member in ae_members: subscription.edge_port.edge_port_ae_members.append( diff --git a/gso/workflows/edge_port/create_imported_edge_port.py b/gso/workflows/edge_port/create_imported_edge_port.py index 867965c741f2f96b7ae13df2b9b952b45f0056a0..cd5f7a7b164977d188272cb94bbdba366f66982e 100644 --- a/gso/workflows/edge_port/create_imported_edge_port.py +++ b/gso/workflows/edge_port/create_imported_edge_port.py @@ -20,6 +20,7 @@ from gso.products.product_types.router import Router from gso.services.partners import get_partner_by_name from gso.services.subscriptions import get_product_id_by_name from gso.utils.helpers import active_pe_router_selector +from gso.utils.types.geant_ids import IMPORTED_GA_ID from gso.utils.types.interfaces import LAGMember, PhysicalPortCapacity @@ -48,7 +49,7 @@ def initial_input_form_generator() -> FormGenerator: minimum_links: int mac_address: str | None = None ignore_if_down: bool = False - geant_ga_id: str | None = None + ga_id: IMPORTED_GA_ID | None = None description: str | None = None name: str ae_members: Annotated[list[LAGMember], AfterValidator(validate_unique_list)] @@ -67,7 +68,7 @@ def initialize_subscription( encapsulation: EncapsulationType, name: str, minimum_links: int, - geant_ga_id: str | None, + ga_id: IMPORTED_GA_ID | None, mac_address: str | None, partner: str, enable_lacp: bool, # noqa: FBT001 @@ -87,8 +88,8 @@ def initialize_subscription( subscription.edge_port.minimum_links = minimum_links subscription.edge_port.edge_port_type = service_type subscription.edge_port.ignore_if_down = ignore_if_down - subscription.edge_port.geant_ga_id = geant_ga_id - subscription.description = f"Edge Port {name} on {router.router_fqdn}, {partner}, {geant_ga_id or ""}" + subscription.edge_port.ga_id = ga_id + subscription.description = f"Edge Port {name} on {router.router_fqdn}, {partner}, {ga_id or ""}" for member in ae_members: subscription.edge_port.edge_port_ae_members.append( EdgePortAEMemberBlockInactive.new(subscription_id=uuid4(), **member) diff --git a/gso/workflows/edge_port/modify_edge_port.py b/gso/workflows/edge_port/modify_edge_port.py index bce56c745475e4a6e2cd43adb7dc3da77be9cbf5..b176eafcc9450dbbd7d8da0608bd0d13891c3f91 100644 --- a/gso/workflows/edge_port/modify_edge_port.py +++ b/gso/workflows/edge_port/modify_edge_port.py @@ -1,5 +1,6 @@ """Modify an existing edge port subscription.""" +from functools import partial from typing import Annotated, Any, Self from uuid import uuid4 @@ -10,7 +11,7 @@ from orchestrator.targets import Target from orchestrator.workflow import StepList, begin, conditional, done, step from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form -from pydantic import AfterValidator, ConfigDict, model_validator +from pydantic import AfterValidator, ConfigDict, Field, model_validator from pydantic_forms.types import FormGenerator, State, UUIDstr from pydantic_forms.validators import ReadOnlyField, validate_unique_list @@ -26,6 +27,7 @@ from gso.utils.helpers import ( ) from gso.utils.types.interfaces import LAGMember, PhysicalPortCapacity from gso.utils.types.tt_number import TTNumber +from gso.utils.types.unique_field import validate_field_is_unique def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: @@ -43,7 +45,12 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: minimum_links: int | None = subscription.edge_port.minimum_links or None mac_address: str | None = subscription.edge_port.mac_address or None ignore_if_down: bool = subscription.edge_port.ignore_if_down - geant_ga_id: str | None = subscription.edge_port.geant_ga_id or None + ga_id: ( + Annotated[ + str, AfterValidator(partial(validate_field_is_unique, subscription_id)), Field(pattern=r"^GA-\d{5}$") + ] + | None + ) = subscription.edge_port.ga_id or None @model_validator(mode="after") def validate_number_of_members(self) -> Self: @@ -117,7 +124,7 @@ def modify_edge_port_subscription( encapsulation: EncapsulationType, minimum_links: int, mac_address: str | None, - geant_ga_id: str | None, + ga_id: str | None, enable_lacp: bool, # noqa: FBT001 ae_members: list[dict[str, str]], ignore_if_down: bool, # noqa: FBT001 @@ -138,12 +145,12 @@ def modify_edge_port_subscription( subscription.edge_port.minimum_links = minimum_links subscription.edge_port.mac_address = mac_address subscription.edge_port.ignore_if_down = ignore_if_down - subscription.edge_port.geant_ga_id = geant_ga_id + subscription.edge_port.ga_id = ga_id subscription.edge_port.edge_port_description = description subscription.description = ( f"Edge Port {subscription.edge_port.edge_port_name} on" f" {subscription.edge_port.node.router_fqdn}," - f" {get_partner_by_id(subscription.customer_id).name}, {geant_ga_id or ""}" + f" {get_partner_by_id(subscription.customer_id).name}, {ga_id or ""}" ) subscription.edge_port.edge_port_ae_members.clear() partner_name = get_partner_by_id(subscription.customer_id).name diff --git a/gso/workflows/iptrunk/create_imported_iptrunk.py b/gso/workflows/iptrunk/create_imported_iptrunk.py index 5cf9c5f8bfad0b2ff9062e3ec3e058c24b6d9671..722121fe6b04fb120a336b65332c21e69f6d5394 100644 --- a/gso/workflows/iptrunk/create_imported_iptrunk.py +++ b/gso/workflows/iptrunk/create_imported_iptrunk.py @@ -20,6 +20,7 @@ from gso.products.product_types.router import Router from gso.services import subscriptions from gso.services.partners import get_partner_by_name from gso.utils.helpers import active_router_selector +from gso.utils.types.geant_ids import IMPORTED_GA_ID, IMPORTED_GS_ID from gso.utils.types.interfaces import LAGMember, LAGMemberList, PhysicalPortCapacity @@ -30,7 +31,7 @@ def initial_input_form_generator() -> FormGenerator: model_config = ConfigDict(title="Import Iptrunk") partner: str - geant_s_sid: str | None = None + gs_id: IMPORTED_GS_ID | None = None iptrunk_description: str | None = None iptrunk_type: IptrunkType iptrunk_speed: PhysicalPortCapacity @@ -39,12 +40,12 @@ def initial_input_form_generator() -> FormGenerator: side_a_node_id: active_router_selector() # type: ignore[valid-type] side_a_ae_iface: str - side_a_ae_geant_a_sid: str | None = None + side_a_ga_id: IMPORTED_GA_ID | None = None side_a_ae_members: Annotated[list[LAGMember], AfterValidator(validate_unique_list)] side_b_node_id: active_router_selector() # type: ignore[valid-type] side_b_ae_iface: str - side_b_ae_geant_a_sid: str | None = None + side_b_ga_id: IMPORTED_GA_ID | None = None side_b_ae_members: Annotated[list[LAGMember], AfterValidator(validate_unique_list)] iptrunk_ipv4_network: ipaddress.IPv4Network @@ -71,7 +72,7 @@ def create_subscription(partner: str) -> State: @step("Initialize subscription") def initialize_subscription( subscription: ImportedIptrunkInactive, - geant_s_sid: str | None, + gs_id: IMPORTED_GS_ID | None, iptrunk_type: IptrunkType, iptrunk_description: str, iptrunk_speed: PhysicalPortCapacity, @@ -79,15 +80,15 @@ def initialize_subscription( iptrunk_isis_metric: int, side_a_node_id: str, side_a_ae_iface: str, - side_a_ae_geant_a_sid: str | None, + side_a_ga_id: IMPORTED_GA_ID | None, side_a_ae_members: LAGMemberList, side_b_node_id: str, side_b_ae_iface: str, - side_b_ae_geant_a_sid: str | None, + side_b_ga_id: IMPORTED_GA_ID | None, side_b_ae_members: LAGMemberList, ) -> State: """Take all input from the user, and store it in the database.""" - subscription.iptrunk.geant_s_sid = geant_s_sid + subscription.iptrunk.gs_id = gs_id subscription.iptrunk.iptrunk_description = iptrunk_description subscription.iptrunk.iptrunk_type = iptrunk_type subscription.iptrunk.iptrunk_speed = iptrunk_speed @@ -96,7 +97,7 @@ def initialize_subscription( subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node = Router.from_subscription(side_a_node_id).router subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_iface = side_a_ae_iface - subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid = side_a_ae_geant_a_sid + subscription.iptrunk.iptrunk_sides[0].ga_id = side_a_ga_id for member in side_a_ae_members: subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.append( IptrunkInterfaceBlockInactive.new(subscription_id=uuid4(), **member), @@ -104,7 +105,7 @@ def initialize_subscription( subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node = Router.from_subscription(side_b_node_id).router subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_iface = side_b_ae_iface - subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid = side_b_ae_geant_a_sid + subscription.iptrunk.iptrunk_sides[1].ga_id = side_b_ga_id for member in side_b_ae_members: subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.append( IptrunkInterfaceBlockInactive.new(subscription_id=uuid4(), **member), @@ -113,7 +114,7 @@ def initialize_subscription( subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name, subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_site.site_name, ]) - subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, geant_s_sid:{geant_s_sid}" + subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, {gs_id}" return {"subscription": subscription} diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index f8b54c61f43cd303335c1f3eb9fa2057cfee4cc9..962cc5d01ec50c76ef03f82ee0d7b5fdc6c7353c 100644 --- a/gso/workflows/iptrunk/create_iptrunk.py +++ b/gso/workflows/iptrunk/create_iptrunk.py @@ -57,7 +57,11 @@ from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient from gso.services.partners import get_partner_by_name from gso.services.sharepoint import SharePointClient -from gso.services.subscriptions import get_non_terminated_iptrunk_subscriptions +from gso.services.subscriptions import ( + generate_unique_ga_id, + generate_unique_gs_id, + get_non_terminated_iptrunk_subscriptions, +) from gso.settings import load_oss_params from gso.utils.helpers import ( available_interfaces_choices, @@ -86,7 +90,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: tt_number: TTNumber partner: ReadOnlyField("GEANT", default_type=str) # type: ignore[valid-type] - geant_s_sid: str | None = None iptrunk_description: str | None = None iptrunk_type: IptrunkType iptrunk_speed: PhysicalPortCapacity @@ -144,7 +147,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: model_config = ConfigDict(title=f"Provide subscription details for side A of the trunk. ({router_a_fqdn})") side_a_ae_iface: available_lags_choices(router_a) or str # type: ignore[valid-type] - side_a_ae_geant_a_sid: str | None side_a_ae_members: ae_members_side_a_type user_input_side_a = yield CreateIptrunkSideAForm @@ -182,7 +184,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: model_config = ConfigDict(title=f"Provide subscription details for side B of the trunk. ({router_b_fqdn})") side_b_ae_iface: available_lags_choices(router_b) or str # type: ignore[valid-type] - side_b_ae_geant_a_sid: str | None side_b_ae_members: ae_members_side_b user_input_side_b = yield CreateIptrunkSideBForm @@ -196,7 +197,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: ) summary_form_data = input_forms_data | {"side_a_node": router_a_fqdn, "side_b_node": router_b_fqdn} summary_fields = [ - "geant_s_sid", "iptrunk_type", "iptrunk_speed", "iptrunk_description", @@ -204,11 +204,9 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: "side_a_node", "side_a_ae_iface", "side_a_ae_members", - "side_a_ae_geant_a_sid", "side_b_node", "side_b_ae_iface", "side_b_ae_members", - "side_b_ae_geant_a_sid", ] yield from create_summary_form(summary_form_data, product_name, summary_fields) @@ -322,25 +320,23 @@ def ping_all_hosts_v6(new_ipv6_network: str) -> State: @step("Initialize subscription") def initialize_subscription( subscription: IptrunkInactive, - geant_s_sid: str | None, iptrunk_type: IptrunkType, iptrunk_description: str | None, iptrunk_speed: PhysicalPortCapacity, iptrunk_minimum_links: int, side_a_node_id: str, side_a_ae_iface: str, - side_a_ae_geant_a_sid: str | None, side_a_ae_members: list[dict], side_b_node_id: str, side_b_ae_iface: str, - side_b_ae_geant_a_sid: str | None, side_b_ae_members: list[dict], ) -> State: """Take all input from the user, and store it in the database.""" oss_params = load_oss_params() side_a = Router.from_subscription(side_a_node_id).router side_b = Router.from_subscription(side_b_node_id).router - subscription.iptrunk.geant_s_sid = geant_s_sid + gs_id = generate_unique_gs_id() + subscription.iptrunk.gs_id = gs_id subscription.iptrunk.iptrunk_description = iptrunk_description subscription.iptrunk.iptrunk_type = iptrunk_type subscription.iptrunk.iptrunk_speed = iptrunk_speed @@ -349,7 +345,8 @@ def initialize_subscription( subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node = side_a subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_iface = side_a_ae_iface - subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid = side_a_ae_geant_a_sid + side_a_ga_id = generate_unique_ga_id() + subscription.iptrunk.iptrunk_sides[0].ga_id = side_a_ga_id for member in side_a_ae_members: subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.append( IptrunkInterfaceBlockInactive.new(subscription_id=uuid4(), **member), @@ -357,13 +354,14 @@ def initialize_subscription( subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node = side_b subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_iface = side_b_ae_iface - subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid = side_b_ae_geant_a_sid + side_b_ga_id = generate_unique_ga_id() + subscription.iptrunk.iptrunk_sides[1].ga_id = side_b_ga_id for member in side_b_ae_members: subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.append( IptrunkInterfaceBlockInactive.new(subscription_id=uuid4(), **member), ) side_names = sorted([side_a.router_site.site_name, side_b.router_site.site_name]) - subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, geant_s_sid:{geant_s_sid}" + subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, {gs_id}" return {"subscription": subscription} @@ -377,7 +375,7 @@ def provision_ip_trunk_iface_dry(subscription: IptrunkInactive, process_id: UUID "verb": "deploy", "config_object": "trunk_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -403,7 +401,7 @@ def provision_ip_trunk_iface_real(subscription: IptrunkInactive, process_id: UUI "verb": "deploy", "config_object": "trunk_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -441,7 +439,7 @@ def provision_ip_trunk_isis_iface_dry(subscription: IptrunkInactive, process_id: "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -467,7 +465,7 @@ def provision_ip_trunk_isis_iface_real(subscription: IptrunkInactive, process_id "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -574,7 +572,7 @@ def create_new_sharepoint_checklist(subscription: IptrunkProvisioning, tt_number new_list_item_url = SharePointClient().add_list_item( list_name="ip_trunk", fields={ - "Title": f"{subscription.description} - {subscription.iptrunk.geant_s_sid}", + "Title": f"{subscription.description} - {subscription.iptrunk.gs_id}", "TT_NUMBER": tt_number, "GAP_PROCESS_URL": f"{load_oss_params().GENERAL.public_hostname}/workflows/{process_id}", "ACTIVITY_TYPE": "Creation", diff --git a/gso/workflows/iptrunk/migrate_iptrunk.py b/gso/workflows/iptrunk/migrate_iptrunk.py index 5684dd2d10dc042032e1523e54e4b5657ba247c2..7e7f32b45877333447d69453cad37c55da86b12e 100644 --- a/gso/workflows/iptrunk/migrate_iptrunk.py +++ b/gso/workflows/iptrunk/migrate_iptrunk.py @@ -50,7 +50,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: """Gather input from the operator on the new router that the IP trunk should connect to.""" subscription = Iptrunk.from_subscription(subscription_id) form_title = ( - f"Subscription {subscription.iptrunk.geant_s_sid} " + f"Subscription {subscription.iptrunk.gs_id} " f" from {subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}" f" to {subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}" ) @@ -298,7 +298,7 @@ def disable_old_config_dry( "config_object": "deactivate", "dry_run": True, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -337,7 +337,7 @@ def disable_old_config_real( "config_object": "deactivate", "dry_run": False, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -376,7 +376,7 @@ def deploy_new_config_dry( "config_object": "trunk_interface", "dry_run": True, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -415,7 +415,7 @@ def deploy_new_config_real( "config_object": "trunk_interface", "dry_run": False, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -564,7 +564,7 @@ def deploy_new_isis( "config_object": "isis_interface", "dry_run": False, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -629,7 +629,7 @@ def restore_isis_metric( "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -668,7 +668,7 @@ def delete_old_config_dry( "config_object": "delete", "dry_run": True, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -707,7 +707,7 @@ def delete_old_config_real( "config_object": "delete", "dry_run": False, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Deploy config for {subscription.iptrunk.geant_s_sid}", + f"- Deploy config for {subscription.iptrunk.gs_id}", } return { @@ -769,9 +769,7 @@ def update_subscription_model( subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name, subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_site.site_name, ]) - subscription.description = ( - f"IP trunk {side_names[0]} {side_names[1]}, geant_s_sid:{subscription.iptrunk.geant_s_sid}" - ) + subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, {subscription.iptrunk.gs_id}" return {"subscription": subscription} @@ -816,7 +814,7 @@ def create_new_sharepoint_checklist(subscription: Iptrunk, tt_number: str, proce new_list_item_url = SharePointClient().add_list_item( list_name="ip_trunk", fields={ - "Title": f"{subscription.description} - {subscription.iptrunk.geant_s_sid}", + "Title": f"{subscription.description} - {subscription.iptrunk.gs_id}", "TT_NUMBER": tt_number, "GAP_PROCESS_URL": f"{load_oss_params().GENERAL.public_hostname}/workflows/{process_id}", "ACTIVITY_TYPE": "Migration", diff --git a/gso/workflows/iptrunk/modify_isis_metric.py b/gso/workflows/iptrunk/modify_isis_metric.py index 61d2f0908bc80fb12981c276cf2d3d45c7b12944..80d97531e6cc61f53e94d19e2980fd795aa628cf 100644 --- a/gso/workflows/iptrunk/modify_isis_metric.py +++ b/gso/workflows/iptrunk/modify_isis_metric.py @@ -53,7 +53,7 @@ def provision_ip_trunk_isis_iface_dry(subscription: Iptrunk, process_id: UUIDstr "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -79,7 +79,7 @@ def provision_ip_trunk_isis_iface_real(subscription: Iptrunk, process_id: UUIDst "verb": "deploy", "config_object": "isis_interface", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index 9c1be5cd451dadb4a039c869c3f9f67cf32836de..ea2309e4dd7249583f1ddd4472258ecb862697bd 100644 --- a/gso/workflows/iptrunk/modify_trunk_interface.py +++ b/gso/workflows/iptrunk/modify_trunk_interface.py @@ -7,6 +7,7 @@ necessary modifications will be applied. """ import json +from functools import partial from typing import Annotated from uuid import UUID, uuid4 @@ -18,7 +19,7 @@ from orchestrator.utils.json import json_dumps from orchestrator.workflow import StepList, begin, conditional, done, step, workflow from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form -from pydantic import ConfigDict +from pydantic import AfterValidator, ConfigDict, Field from pydantic_forms.validators import Label, ReadOnlyField from gso.products.product_blocks.iptrunk import ( @@ -39,6 +40,7 @@ from gso.utils.shared_enums import Vendor from gso.utils.types.interfaces import JuniperLAGMember, LAGMember, LAGMemberList, PhysicalPortCapacity from gso.utils.types.ip_address import IPv4AddressType, IPv6AddressType from gso.utils.types.tt_number import TTNumber +from gso.utils.types.unique_field import validate_field_is_unique from gso.workflows.iptrunk.migrate_iptrunk import check_ip_trunk_optical_levels_pre from gso.workflows.iptrunk.validate_iptrunk import check_ip_trunk_isis @@ -86,7 +88,12 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: class ModifyIptrunkForm(FormPage): tt_number: TTNumber - geant_s_sid: str | None = subscription.iptrunk.geant_s_sid + gs_id: ( + Annotated[ + str, AfterValidator(partial(validate_field_is_unique, subscription_id)), Field(pattern=r"^GS-\d{5}$") + ] + | None + ) = subscription.iptrunk.gs_id iptrunk_description: str | None = subscription.iptrunk.iptrunk_description iptrunk_type: IptrunkType = subscription.iptrunk.iptrunk_type warning_label: Label = ( @@ -125,7 +132,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn, default_type=str ) side_a_ae_iface: ReadOnlyField(subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_iface, default_type=str) # type: ignore[valid-type] - side_a_ae_geant_a_sid: str | None = subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid + side_a_ga_id: str | None = subscription.iptrunk.iptrunk_sides[0].ga_id side_a_ae_members: ae_members_side_a = ( # type: ignore[valid-type] subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members if initial_user_input.iptrunk_speed == subscription.iptrunk.iptrunk_speed @@ -142,7 +149,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn, default_type=str ) side_b_ae_iface: ReadOnlyField(subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_iface, default_type=str) # type: ignore[valid-type] - side_b_ae_geant_a_sid: str | None = subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid + side_b_ga_id: str | None = subscription.iptrunk.iptrunk_sides[1].ga_id side_b_ae_members: ae_members_side_b = ( # type: ignore[valid-type] subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members if initial_user_input.iptrunk_speed == subscription.iptrunk.iptrunk_speed @@ -254,14 +261,14 @@ def update_side_members(subscription: Iptrunk, side_index: int, new_members: lis @step("Update subscription") def modify_iptrunk_subscription( subscription: Iptrunk, - geant_s_sid: str | None, + gs_id: str | None, iptrunk_type: IptrunkType, iptrunk_description: str | None, iptrunk_speed: PhysicalPortCapacity, iptrunk_minimum_links: int, - side_a_ae_geant_a_sid: str | None, + side_a_ga_id: str | None, side_a_ae_members: list[dict], - side_b_ae_geant_a_sid: str | None, + side_b_ga_id: str | None, side_b_ae_members: list[dict], ) -> State: """Modify the subscription in the service database, reflecting the changes to the newly selected interfaces.""" @@ -287,22 +294,22 @@ def modify_iptrunk_subscription( if ae_member["interface_name"] not in [m["interface_name"] for m in current_members] ]) # Update the subscription - subscription.iptrunk.geant_s_sid = geant_s_sid + subscription.iptrunk.gs_id = gs_id subscription.iptrunk.iptrunk_description = iptrunk_description subscription.iptrunk.iptrunk_type = iptrunk_type subscription.iptrunk.iptrunk_speed = iptrunk_speed subscription.iptrunk.iptrunk_minimum_links = iptrunk_minimum_links - subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid = side_a_ae_geant_a_sid + subscription.iptrunk.iptrunk_sides[0].ga_id = side_a_ga_id update_side_members(subscription, 0, side_a_ae_members) - subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid = side_b_ae_geant_a_sid + subscription.iptrunk.iptrunk_sides[1].ga_id = side_b_ga_id update_side_members(subscription, 1, side_b_ae_members) side_names = sorted([ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name, subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_site.site_name, ]) - subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, geant_s_sid:{geant_s_sid}" + subscription.description = f"IP trunk {side_names[0]} {side_names[1]}, {gs_id}" return { "subscription": subscription, @@ -323,7 +330,7 @@ def provision_ip_trunk_iface_dry( "config_object": "trunk_interface", "removed_ae_members": removed_ae_members, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { @@ -352,7 +359,7 @@ def provision_ip_trunk_iface_real( "config_object": "trunk_interface", "removed_ae_members": removed_ae_members, "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for " - f"{subscription.iptrunk.geant_s_sid}", + f"{subscription.iptrunk.gs_id}", } return { diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py index d008ad88bfcfdbf3484f5056d522deddf565554d..24cb42719a09b5483bdff3d9fb73e819b88e7eef 100644 --- a/gso/workflows/iptrunk/terminate_iptrunk.py +++ b/gso/workflows/iptrunk/terminate_iptrunk.py @@ -70,7 +70,7 @@ def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr, tt_numb "verb": "terminate", "config_object": "trunk_deprovision", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Remove config for {subscription.iptrunk.geant_s_sid}", + f"- Remove config for {subscription.iptrunk.gs_id}", } return { @@ -96,7 +96,7 @@ def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, tt_num "verb": "terminate", "config_object": "trunk_deprovision", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} " - f"- Remove config for {subscription.iptrunk.geant_s_sid}", + f"- Remove config for {subscription.iptrunk.gs_id}", } return { diff --git a/gso/workflows/l2_circuit/create_imported_layer_2_circuit.py b/gso/workflows/l2_circuit/create_imported_layer_2_circuit.py index a0fc39cb3afffb338b939996fb339e8d8659430e..3e5e97c992ce33c7fb0fe5300c0a1f5e0034d072 100644 --- a/gso/workflows/l2_circuit/create_imported_layer_2_circuit.py +++ b/gso/workflows/l2_circuit/create_imported_layer_2_circuit.py @@ -23,6 +23,7 @@ from gso.products.product_types.layer_2_circuit import ( from gso.services.partners import get_partner_by_name from gso.services.subscriptions import get_product_id_by_name from gso.utils.shared_enums import SBPType +from gso.utils.types.geant_ids import IMPORTED_GS_ID from gso.utils.types.interfaces import BandwidthString from gso.utils.types.virtual_identifiers import VC_ID, VLAN_ID @@ -39,7 +40,7 @@ def initial_input_form_generator() -> FormGenerator: service_type: Layer2CircuitServiceType partner: str - geant_sid: str + gs_id: IMPORTED_GS_ID vc_id: VC_ID layer_2_circuit_side_a: ServiceBindingPortInput layer_2_circuit_side_b: ServiceBindingPortInput @@ -91,7 +92,7 @@ def create_subscription(partner: str, service_type: Layer2CircuitServiceType) -> @step("Initialize subscription") def initialize_subscription( subscription: ImportedLayer2CircuitInactive, - geant_sid: str, + gs_id: str, layer_2_circuit_side_a: dict[str, Any], layer_2_circuit_side_b: dict[str, Any], layer_2_circuit_type: Layer2CircuitType, @@ -110,7 +111,7 @@ def initialize_subscription( edge_port=EdgePort.from_subscription(subscription_id=circuit_side_data["edge_port"]).edge_port, sbp_type=SBPType.L2, vlan_id=circuit_side_data["vlan_id"], - geant_sid=geant_sid, + gs_id=gs_id, is_tagged=layer_2_circuit_type == Layer2CircuitType.TAGGED, custom_firewall_filters=False, ) diff --git a/gso/workflows/l2_circuit/create_layer_2_circuit.py b/gso/workflows/l2_circuit/create_layer_2_circuit.py index 0a15fcebc00172a30e223b7c975badbcbd46d144..acf5beefa74860e548d272598d37f10fa3d69221 100644 --- a/gso/workflows/l2_circuit/create_layer_2_circuit.py +++ b/gso/workflows/l2_circuit/create_layer_2_circuit.py @@ -19,6 +19,7 @@ from gso.products.product_blocks.service_binding_port import ServiceBindingPortI from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.layer_2_circuit import Layer2Circuit, Layer2CircuitInactive from gso.services.partners import get_partner_by_name +from gso.services.subscriptions import generate_unique_gs_id from gso.utils.helpers import active_edge_port_selector, generate_unique_vc_id, partner_choice from gso.utils.shared_enums import SBPType from gso.utils.types.interfaces import BandwidthString @@ -69,7 +70,6 @@ def initial_input_generator(product_name: str) -> FormGenerator: vlan_divider: Divider = Field(None, exclude=True) policer_bandwidth: _policer_field(policer_enabled=initial_user_input.policer_enabled) # type: ignore[valid-type] policer_burst_rate: _policer_field(policer_enabled=initial_user_input.policer_enabled) # type: ignore[valid-type] - geant_sid: str layer_2_circuit_side_a: Layer2CircuitSideSelection side_divider: Divider = Field(None, exclude=True) layer_2_circuit_side_b: Layer2CircuitSideSelection @@ -105,17 +105,17 @@ def initialize_subscription( policer_enabled: bool, # noqa: FBT001 policer_bandwidth: BandwidthString | None, policer_burst_rate: BandwidthString | None, - geant_sid: str, ) -> State: """Build a subscription object from all user input.""" layer_2_circuit_sides = [] + gs_id = generate_unique_gs_id() for circuit_side_data in [layer_2_circuit_side_a, layer_2_circuit_side_b]: sbp = ServiceBindingPortInactive.new( uuid4(), edge_port=EdgePort.from_subscription(subscription_id=circuit_side_data["edge_port"]).edge_port, sbp_type=SBPType.L2, vlan_id=circuit_side_data["vlan_id"], - geant_sid=geant_sid, + gs_id=gs_id, is_tagged=layer_2_circuit_type == Layer2CircuitType.TAGGED, custom_firewall_filters=False, ) diff --git a/gso/workflows/l3_core_service/create_imported_l3_core_service.py b/gso/workflows/l3_core_service/create_imported_l3_core_service.py index dd77021bbd511fe6dec291279680e36cf618678d..7280a225e4977aec5cee0245b9aac94b507bf1c2 100644 --- a/gso/workflows/l3_core_service/create_imported_l3_core_service.py +++ b/gso/workflows/l3_core_service/create_imported_l3_core_service.py @@ -21,6 +21,7 @@ from gso.products.product_types.l3_core_service import ImportedL3CoreServiceInac from gso.services.partners import get_partner_by_name from gso.services.subscriptions import get_product_id_by_name from gso.utils.shared_enums import SBPType +from gso.utils.types.geant_ids import IMPORTED_GS_ID from gso.utils.types.ip_address import IPAddress, IPv4AddressType, IPV4Netmask, IPv6AddressType, IPV6Netmask from gso.utils.types.virtual_identifiers import VLAN_ID @@ -50,7 +51,7 @@ def initial_input_form_generator() -> FormGenerator: class ServiceBindingPort(BaseModel): edge_port: UUIDstr ap_type: str - geant_sid: str + gs_id: IMPORTED_GS_ID sbp_type: SBPType = SBPType.L3 is_tagged: bool = False vlan_id: VLAN_ID diff --git a/gso/workflows/l3_core_service/create_l3_core_service.py b/gso/workflows/l3_core_service/create_l3_core_service.py index d4b085c1580d6b98598c133d106509501b9e0b05..cd42c7613a391213ad9908797ef8a3dedb7dc200 100644 --- a/gso/workflows/l3_core_service/create_l3_core_service.py +++ b/gso/workflows/l3_core_service/create_l3_core_service.py @@ -20,6 +20,7 @@ from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.l3_core_service import L3CoreService, L3CoreServiceInactive from gso.services.lso_client import LSOState, lso_interaction from gso.services.partners import get_partner_by_id +from gso.services.subscriptions import generate_unique_gs_id from gso.utils.helpers import ( active_edge_port_selector, partner_choice, @@ -113,7 +114,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: exclude=True, ) - geant_sid: str is_tagged: bool = False vlan_id: VLAN_ID custom_firewall_filters: bool = False @@ -165,6 +165,7 @@ def initialize_subscription( BGPSession.new(subscription_id=uuid4(), rtbh_enabled=True, is_multi_hop=True, **session) for session in binding_port_input["bgp_peers"] ] + sbp_gs_id = generate_unique_gs_id() service_binding_port = ServiceBindingPortInactive.new( subscription_id=uuid4(), v4_bfd_settings=BFDSettings.new(subscription_id=uuid4(), **(binding_port_input.pop("v4_bfd_settings"))), @@ -173,6 +174,7 @@ def initialize_subscription( bgp_session_list=sbp_bgp_session_list, sbp_type=SBPType.L3, edge_port=edge_port_subscription.edge_port, + gs_id=sbp_gs_id, ) subscription.l3_core_service.ap_list.append( AccessPortInactive.new( diff --git a/gso/workflows/l3_core_service/modify_l3_core_service.py b/gso/workflows/l3_core_service/modify_l3_core_service.py index 7dbeb4860ff5c322e1b6714572db2ab4fa6c8815..24b408ab8a11144f3bdccd4f61d1f12b5dbfe5f7 100644 --- a/gso/workflows/l3_core_service/modify_l3_core_service.py +++ b/gso/workflows/l3_core_service/modify_l3_core_service.py @@ -152,7 +152,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: exclude=True, ) - geant_sid: str = current_sbp.geant_sid + gs_id: str = current_sbp.gs_id is_tagged: bool = current_sbp.is_tagged # The SBP model does not 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. @@ -212,7 +212,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: exclude=True, ) - geant_sid: str + gs_id: str is_tagged: bool = False vlan_id: VLAN_ID ipv4_address: IPv4AddressType @@ -279,7 +279,7 @@ def modify_existing_sbp_blocks(subscription: L3CoreService, modified_sbp_list: l current_sbp.bgp_session_list = [v4_peer, v6_peer] current_sbp.vlan_id = modified_sbp_data["vlan_id"] - current_sbp.geant_sid = modified_sbp_data["geant_sid"] + current_sbp.gs_id = modified_sbp_data["gs_id"] current_sbp.is_tagged = modified_sbp_data["is_tagged"] current_sbp.ipv4_address = modified_sbp_data["ipv4_address"] current_sbp.ipv6_address = modified_sbp_data["ipv6_address"] diff --git a/test/cli/test_imports.py b/test/cli/test_imports.py index fa378703d422aa49287eb0ff8f8c5c3794ae677f..571e64b6a4444f319c4ab8df73179894925b10a9 100644 --- a/test/cli/test_imports.py +++ b/test/cli/test_imports.py @@ -62,7 +62,7 @@ def iptrunk_data(temp_file, router_subscription_factory, faker) -> (Path, dict): ipv6_network = ipv6_network or str(faker.ipv6_network(max_subnet=126)) iptrunk_data = { - "id": faker.geant_sid(), + "id": faker.imported_gs_id(), "config": { "common": { "link_speed": PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND, @@ -73,7 +73,7 @@ def iptrunk_data(temp_file, router_subscription_factory, faker) -> (Path, dict): "nodeA": { "name": side_a_node or Router.from_subscription(router_side_a).router.router_fqdn, "ae_name": side_a_ae_name or faker.network_interface(), - "port_sid": faker.geant_sid(), + "port_ga_id": faker.imported_ga_id(), "members": side_a_members or [ { @@ -88,7 +88,7 @@ def iptrunk_data(temp_file, router_subscription_factory, faker) -> (Path, dict): "nodeB": { "name": side_b_node or Router.from_subscription(router_side_b).router.router_fqdn, "ae_name": side_b_ae_name or faker.network_interface(), - "port_sid": faker.geant_sid(), + "port_ga_id": faker.imported_ga_id(), "members": side_b_members or [ { @@ -270,7 +270,7 @@ def edge_port_data(temp_file, faker, router_subscription_factory, partner_factor "encapsulation": EncapsulationType.DOT1Q, "name": "lag34", "minimum_links": 2, - "geant_ga_id": faker.geant_gid(), + "ga_id": faker.imported_ga_id(), "mac_address": faker.mac_address(), "partner": partner_factory()["name"], "enable_lacp": True, @@ -305,7 +305,7 @@ def l3_core_service_data(temp_file, faker, partner_factory, edge_port_subscripti { "edge_port": edge_port_subscription_factory(), "ap_type": "PRIMARY", - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), "ipv4_mask": faker.ipv4_netmask(), @@ -353,7 +353,7 @@ def l3_core_service_data(temp_file, faker, partner_factory, edge_port_subscripti { "edge_port": edge_port_subscription_factory(), "ap_type": "BACKUP", - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), "ipv4_mask": faker.ipv4_netmask(), @@ -414,7 +414,7 @@ def layer_2_circuit_data(temp_file, faker, partner_factory, edge_port_subscripti layer_2_circuit_input_data = { "partner": partner_factory()["name"], "service_type": Layer2CircuitServiceType.GEANT_PLUS, - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "vc_id": generate_unique_vc_id(), "layer_2_circuit_side_a": { "edge_port": edge_port_subscription_factory(), @@ -697,7 +697,7 @@ def test_import_l3_core_service_with_invalid_edge_port( { "edge_port": fake_uuid, "ap_type": "PRIMARY", - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), "ipv4_mask": faker.ipv4_netmask(), @@ -737,7 +737,7 @@ def test_import_l3_core_service_with_invalid_edge_port( { "edge_port": edge_port_subscription_factory(), "ap_type": "BACKUP", - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), "ipv4_mask": faker.ipv4_netmask(), diff --git a/test/conftest.py b/test/conftest.py index da558c8a693e9a71cd2f30ff5832eac42b49684c..4548fe0fadd99957fee38e96fc0874402063f048 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -73,11 +73,21 @@ class FakerProvider(BaseProvider): return f"TT#{random_date}{random_int}" - def geant_gid(self) -> str: - return self.generator.numerify("GID-#####") + def ga_id(self) -> str: + random_int = self.generator.random_int(min=50000, max=99999) + return f"GA-{random_int}" - def geant_sid(self) -> str: - return self.generator.numerify("SID-#####") + def gs_id(self) -> str: + random_int = self.generator.random_int(min=50000, max=99999) + return f"GS-{random_int}" + + def imported_ga_id(self) -> str: + random_int = self.generator.random_int(min=00000, max=50000) + return f"GA-{random_int}" + + def imported_gs_id(self) -> str: + random_int = self.generator.random_int(min=00000, max=50000) + return f"GS-{random_int}" def site_name(self) -> str: site_name = "".join(self.generator.random_letter().upper() for _ in range(3)) diff --git a/test/fixtures/edge_port_fixtures.py b/test/fixtures/edge_port_fixtures.py index 669d42ff90b4e0894ca1d117dde58448daab0903..0ea8744983148d97f4c9920498ea2da8a3b17ff7 100644 --- a/test/fixtures/edge_port_fixtures.py +++ b/test/fixtures/edge_port_fixtures.py @@ -30,7 +30,7 @@ def edge_port_subscription_factory(faker, partner_factory, router_subscription_f member_speed=PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND, minimum_links=None, edge_port_type=EdgePortType.PUBLIC, - geant_ga_id=None, + ga_id=None, edge_port_ae_members=None, status: SubscriptionLifecycle | None = None, *, @@ -52,7 +52,7 @@ def edge_port_subscription_factory(faker, partner_factory, router_subscription_f ) edge_port_subscription.edge_port.edge_port_description = description or faker.text(max_nb_chars=30) - edge_port_subscription.edge_port.geant_ga_id = geant_ga_id or faker.geant_sid() + edge_port_subscription.edge_port.ga_id = ga_id or faker.ga_id() edge_port_subscription.edge_port.node = node or node edge_port_subscription.edge_port.edge_port_name = name or f"lag-{faker.pyint(21, 50)}" edge_port_subscription.edge_port.edge_port_description = edge_port_description or faker.sentence() diff --git a/test/fixtures/iptrunk_fixtures.py b/test/fixtures/iptrunk_fixtures.py index 5044a2e5904c92023e264e9c5f40cac8a82cb773..742e974a98001ee4908f08b6502d7d5ca9ae8c20 100644 --- a/test/fixtures/iptrunk_fixtures.py +++ b/test/fixtures/iptrunk_fixtures.py @@ -21,7 +21,7 @@ def iptrunk_side_subscription_factory(router_subscription_factory, faker): def subscription_create( iptrunk_side_node=None, iptrunk_side_ae_iface=None, - iptrunk_side_ae_geant_a_sid=None, + ga_id=None, iptrunk_side_ae_members=None, iptrunk_side_ae_members_description=None, ) -> IptrunkSideBlock: @@ -31,7 +31,7 @@ def iptrunk_side_subscription_factory(router_subscription_factory, faker): iptrunk_side_node or router_subscription_factory(vendor=Vendor.NOKIA) ).router, iptrunk_side_ae_iface=iptrunk_side_ae_iface or faker.pystr(), - iptrunk_side_ae_geant_a_sid=iptrunk_side_ae_geant_a_sid or faker.geant_sid(), + ga_id=ga_id or faker.ga_id(), iptrunk_side_ae_members=iptrunk_side_ae_members or [ IptrunkInterfaceBlock.new( @@ -56,7 +56,7 @@ def iptrunk_subscription_factory(iptrunk_side_subscription_factory, faker, geant def subscription_create( description=None, start_date="2023-05-24T00:00:00+00:00", - geant_s_sid=None, + gs_id=None, iptrunk_description=None, iptrunk_type=IptrunkType.LEASED, iptrunk_speed=PhysicalPortCapacity.ONE_GIGABIT_PER_SECOND, @@ -84,7 +84,7 @@ def iptrunk_subscription_factory(iptrunk_side_subscription_factory, faker, geant ) description = description or faker.sentence() - geant_s_sid = geant_s_sid or faker.geant_sid() + gs_id = gs_id or faker.gs_id() iptrunk_description = iptrunk_description or faker.sentence() iptrunk_isis_metric = iptrunk_isis_metric or faker.pyint() iptrunk_ipv4_network = iptrunk_ipv4_network or faker.ipv4_network(max_subnet=31) @@ -94,7 +94,7 @@ def iptrunk_subscription_factory(iptrunk_side_subscription_factory, faker, geant iptrunk_side_b = iptrunk_side_subscription_factory() iptrunk_sides = iptrunk_sides or [iptrunk_side_a, iptrunk_side_b] - iptrunk_subscription.iptrunk.geant_s_sid = geant_s_sid + iptrunk_subscription.iptrunk.gs_id = gs_id iptrunk_subscription.iptrunk.iptrunk_description = iptrunk_description iptrunk_subscription.iptrunk.iptrunk_type = iptrunk_type iptrunk_subscription.iptrunk.iptrunk_speed = iptrunk_speed diff --git a/test/fixtures/l3_core_service_fixtures.py b/test/fixtures/l3_core_service_fixtures.py index da94298e8ac6b62507ed61147c80233afed84059..21ea6379595e8860d95e35508ec1b6a6e3cd7721 100644 --- a/test/fixtures/l3_core_service_fixtures.py +++ b/test/fixtures/l3_core_service_fixtures.py @@ -84,7 +84,7 @@ def service_binding_port_factory( ): def create_service_binding_port( bgp_session_list: list[BGPSession] | None = None, - geant_sid: str | None = None, + gs_id: str | None = None, sbp_type: SBPType = SBPType.L3, ipv4_address: str | None = None, ipv4_mask: int | None = None, @@ -108,7 +108,7 @@ def service_binding_port_factory( ipv6_address=ipv6_address or faker.ipv6(), ipv6_mask=ipv6_mask or faker.ipv6_netmask(), custom_firewall_filters=custom_firewall_filters, - geant_sid=geant_sid or faker.geant_sid(), + gs_id=gs_id or faker.gs_id(), bgp_session_list=bgp_session_list or [ bgp_session_subscription_factory(families=[IPFamily.V4UNICAST]), diff --git a/test/fixtures/layer_2_circuit_fixtures.py b/test/fixtures/layer_2_circuit_fixtures.py index 28fd88aeb26dfb63d827e1f4741a819633f6af5c..2b93a37025a3ae728f68d0b869305b20b7474ff8 100644 --- a/test/fixtures/layer_2_circuit_fixtures.py +++ b/test/fixtures/layer_2_circuit_fixtures.py @@ -38,7 +38,7 @@ def layer_2_circuit_subscription_factory(faker, geant_partner, edge_port_subscri vlan_id_side_a: VLAN_ID | None = None, layer_2_circuit_side_b_edgeport: UUIDstr | None = None, vlan_id_side_b: VLAN_ID | None = None, - geant_sid: str | None = None, + gs_id: str | None = None, *, policer_enabled: bool = False, ) -> UUIDstr: @@ -82,7 +82,7 @@ def layer_2_circuit_subscription_factory(faker, geant_partner, edge_port_subscri edge_port=EdgePort.from_subscription(edge_port).edge_port, sbp_type=SBPType.L2, vlan_id=vlan_id, - geant_sid=geant_sid or faker.geant_sid(), + gs_id=gs_id or faker.gs_id(), is_tagged=layer_2_circuit_type == Layer2CircuitType.TAGGED, custom_firewall_filters=False, ) diff --git a/test/workflows/edge_port/test_create_edge_port.py b/test/workflows/edge_port/test_create_edge_port.py index 8066c5e0217668853f7243c1d1cdfe16b4441228..107dab95f2a328b4d1c7746ba0e605a65e255906 100644 --- a/test/workflows/edge_port/test_create_edge_port.py +++ b/test/workflows/edge_port/test_create_edge_port.py @@ -50,7 +50,6 @@ def input_form_wizard_data(request, router_subscription_factory, partner_factory "node": router_subscription_factory(vendor=Vendor.NOKIA), "partner": partner_factory(name="GAAR", email=faker.email())["partner_id"], "service_type": EdgePortType.PUBLIC, - "geant_ga_id": faker.geant_gid(), "enable_lacp": True, "speed": PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND, "encapsulation": EncapsulationType.DOT1Q, @@ -101,9 +100,9 @@ def test_successful_edge_port_creation( subscription = EdgePort.from_subscription(subscription_id) assert subscription.status == "active" - ga_id = input_form_wizard_data[0]["geant_ga_id"] router_fqdn = Router.from_subscription(input_form_wizard_data[0]["node"]).router.router_fqdn - assert subscription.description == f"Edge Port lag-21 on {router_fqdn}, GAAR, {ga_id}" + assert subscription.edge_port.ga_id is not None + assert subscription.description == f"Edge Port lag-21 on {router_fqdn}, GAAR, {subscription.edge_port.ga_id}" assert len(subscription.edge_port.edge_port_ae_members) == 2 assert mock_execute_playbook.call_count == 2 diff --git a/test/workflows/edge_port/test_create_imported_edge_port.py b/test/workflows/edge_port/test_create_imported_edge_port.py index c5590fe4f99c03c38c7a62b7129aa91ef8caef9a..ea5b024e5ef9bdc1de35214e5c487a22979f7b6e 100644 --- a/test/workflows/edge_port/test_create_imported_edge_port.py +++ b/test/workflows/edge_port/test_create_imported_edge_port.py @@ -17,7 +17,7 @@ def imported_edge_port_creation_input_form_data(router_subscription_factory, par "encapsulation": EncapsulationType.DOT1Q, "name": "lag34", "minimum_links": 2, - "geant_ga_id": faker.geant_gid(), + "ga_id": faker.imported_ga_id(), "mac_address": faker.mac_address(), "partner": partner_factory()["name"], "enable_lacp": True, diff --git a/test/workflows/edge_port/test_modify_edge_port.py b/test/workflows/edge_port/test_modify_edge_port.py index a7c824283f031c4dcb14cda53a7c8dfbb35527bb..0f7ed1401db0e4e4fecac754ab938b5f1b246748 100644 --- a/test/workflows/edge_port/test_modify_edge_port.py +++ b/test/workflows/edge_port/test_modify_edge_port.py @@ -1,6 +1,7 @@ from unittest.mock import patch import pytest +from pydantic_forms.exceptions import FormValidationError from gso.products.product_types.edge_port import EdgePort from gso.utils.types.interfaces import PhysicalPortCapacity @@ -21,7 +22,7 @@ def input_form_wizard_data(request, faker, edge_port_subscription_factory, partn {"subscription_id": subscription_id}, { "tt_number": faker.tt_number(), - "geant_ga_id": faker.geant_gid(), + "ga_id": faker.ga_id(), "member_speed": PhysicalPortCapacity.FOUR_HUNDRED_GIGABIT_PER_SECOND, "number_of_members": 1, }, @@ -37,6 +38,22 @@ def input_form_wizard_data(request, faker, edge_port_subscription_factory, partn ] +@pytest.mark.workflow() +@pytest.mark.parametrize("invalid_ga_id", ["GS-11111", "GA-1234", "GA_12345", "GA-100000"]) +def test_modify_edge_port_with_invalid_ga_id( + input_form_wizard_data, faker, invalid_ga_id, iptrunk_side_subscription_factory, iptrunk_subscription_factory +): + input_data = input_form_wizard_data + input_data[1]["ga_id"] = invalid_ga_id + iptrunk_subscription_factory( + iptrunk_sides=[iptrunk_side_subscription_factory(ga_id="GA-11111"), iptrunk_side_subscription_factory()] + ) + + # Run workflow + with pytest.raises(FormValidationError): + run_workflow("modify_edge_port", input_data) + + @pytest.mark.workflow() @patch("gso.services.lso_client._send_request") @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces") @@ -89,7 +106,7 @@ def test_modify_edge_port_with_changing_capacity( assert mocked_attach_interface_to_lag.call_count == 1 assert mocked_free_interface.call_count == 2 assert mocked_detach_interfaces_from_lag.call_count == 1 - assert subscription.edge_port.geant_ga_id == input_form_wizard_data[1]["geant_ga_id"] + assert subscription.edge_port.ga_id == input_form_wizard_data[1]["ga_id"] assert len(subscription.edge_port.edge_port_ae_members) == 1 @@ -100,7 +117,7 @@ def input_form_wizard_without_changing_capacity(request, faker, edge_port_subscr return [ {"subscription_id": subscription_id}, - {"tt_number": faker.tt_number(), "geant_ga_id": faker.geant_gid()}, + {"tt_number": faker.tt_number(), "ga_id": faker.ga_id()}, { "description": faker.sentence(), "ae_members": [ @@ -163,6 +180,6 @@ def test_modify_edge_port_without_changing_capacity( assert mocked_free_interface.call_count == 0 assert mocked_detach_interfaces_from_lag.call_count == 0 - assert subscription.edge_port.geant_ga_id == input_form_wizard_without_changing_capacity[1]["geant_ga_id"] + assert subscription.edge_port.ga_id == input_form_wizard_without_changing_capacity[1]["ga_id"] assert len(subscription.edge_port.edge_port_ae_members) == 2 assert subscription.edge_port.edge_port_description == input_form_wizard_without_changing_capacity[2]["description"] diff --git a/test/workflows/iptrunk/test_create_imported_iptrunk.py b/test/workflows/iptrunk/test_create_imported_iptrunk.py index 25d68d8f9f67906b5251b1312927d2c3203ddbad..deaa2ddd519b8f699633e35d6713414f4e3db8d1 100644 --- a/test/workflows/iptrunk/test_create_imported_iptrunk.py +++ b/test/workflows/iptrunk/test_create_imported_iptrunk.py @@ -16,7 +16,7 @@ from test.workflows import ( def workflow_input_data(faker, router_subscription_factory): return { "partner": "GEANT", - "geant_s_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "iptrunk_description": faker.sentence(), "iptrunk_type": IptrunkType.DARK_FIBER, "iptrunk_speed": PhysicalPortCapacity.FOUR_HUNDRED_GIGABIT_PER_SECOND, @@ -24,13 +24,13 @@ def workflow_input_data(faker, router_subscription_factory): "iptrunk_isis_metric": 10000, "side_a_node_id": router_subscription_factory(), "side_a_ae_iface": faker.network_interface(), - "side_a_ae_geant_a_sid": faker.geant_sid(), + "side_a_ga_id": faker.imported_ga_id(), "side_a_ae_members": [ {"interface_name": faker.network_interface(), "interface_description": faker.sentence()} for _ in range(3) ], "side_b_node_id": router_subscription_factory(), "side_b_ae_iface": faker.network_interface(), - "side_b_ae_geant_a_sid": faker.geant_sid(), + "side_b_ga_id": faker.imported_ga_id(), "side_b_ae_members": [ {"interface_name": faker.network_interface(), "interface_description": faker.sentence()} for _ in range(3) ], diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py index cac63729ec0507232f904074c48bb7c8b5f203a1..d0f9cfa539b3b52600dff506931c3cd0699250ce 100644 --- a/test/workflows/iptrunk/test_create_iptrunk.py +++ b/test/workflows/iptrunk/test_create_iptrunk.py @@ -65,7 +65,6 @@ def input_form_wizard_data(request, router_subscription_factory, faker): create_ip_trunk_step = { "tt_number": faker.tt_number(), - "geant_s_sid": faker.geant_sid(), "iptrunk_type": IptrunkType.DARK_FIBER, "iptrunk_description": faker.sentence(), "iptrunk_speed": PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND, @@ -75,7 +74,6 @@ def input_form_wizard_data(request, router_subscription_factory, faker): create_ip_trunk_side_a_router_name = {"side_a_node_id": router_side_a} create_ip_trunk_side_a_step = { "side_a_ae_iface": "lag-1", - "side_a_ae_geant_a_sid": None, "side_a_ae_members": [ { "interface_name": f"Interface{interface}", @@ -87,7 +85,6 @@ def input_form_wizard_data(request, router_subscription_factory, faker): create_ip_trunk_side_b_router_name = {"side_b_node_id": router_side_b} create_ip_trunk_side_b_step = { "side_b_ae_iface": "lag-4", - "side_b_ae_geant_a_sid": faker.geant_sid(), "side_b_ae_members": side_b_members, } summary_view_step = {} @@ -153,9 +150,8 @@ def test_successful_iptrunk_creation_with_standard_lso_result( subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_site.site_name, ]) assert subscription.status == "provisioning" - assert subscription.description == ( - f"IP trunk {sorted_sides[0]} {sorted_sides[1]}, geant_s_sid:{input_form_wizard_data[0]["geant_s_sid"]}" - ) + assert subscription.iptrunk.gs_id is not None + assert subscription.description == f"IP trunk {sorted_sides[0]} {sorted_sides[1]}, {subscription.iptrunk.gs_id}" assert mock_execute_playbook.call_count == 6 # We search for 6 hosts in total, 2 in a /31 and 4 in a /126 diff --git a/test/workflows/iptrunk/test_modify_trunk_interface.py b/test/workflows/iptrunk/test_modify_trunk_interface.py index 2dcb23e2b00a9b063144e827f434129f5d9411e7..d8a96588a3bc6182fa498b2b50a8e849c646b483 100644 --- a/test/workflows/iptrunk/test_modify_trunk_interface.py +++ b/test/workflows/iptrunk/test_modify_trunk_interface.py @@ -1,6 +1,7 @@ from unittest.mock import patch import pytest +from pydantic_forms.exceptions import FormValidationError from gso.products.product_blocks.iptrunk import IptrunkType from gso.products.product_types.iptrunk import Iptrunk @@ -52,21 +53,21 @@ def input_form_iptrunk_data( product_id = iptrunk_subscription_factory(iptrunk_sides=[side_a_node, side_b_node]) - new_sid = faker.geant_sid() + new_sid = faker.gs_id() new_description = faker.sentence() new_type = IptrunkType.LEASED new_speed = PhysicalPortCapacity.FOUR_HUNDRED_GIGABIT_PER_SECOND new_link_count = 2 - new_side_a_sid = faker.geant_sid() + new_side_a_gid = faker.ga_id() - new_side_b_sid = faker.geant_sid() + new_side_b_gid = faker.ga_id() return [ {"subscription_id": product_id}, { "tt_number": faker.tt_number(), - "geant_s_sid": new_sid, + "gs_id": new_sid, "iptrunk_description": new_description, "iptrunk_type": new_type, "iptrunk_speed": new_speed, @@ -74,11 +75,11 @@ def input_form_iptrunk_data( }, {}, { - "side_a_ae_geant_a_sid": new_side_a_sid, + "side_a_ga_id": new_side_a_gid, "side_a_ae_members": new_side_a_ae_members, }, { - "side_b_ae_geant_a_sid": new_side_b_sid, + "side_b_ga_id": new_side_b_gid, "side_b_ae_members": new_side_b_ae_members, }, ] @@ -135,10 +136,10 @@ def test_iptrunk_modify_trunk_interface_success( assert subscription.status == "active" assert mock_provision_ip_trunk.call_count == lso_interaction_count # Assert all Netbox calls have been made - new_sid = input_form_iptrunk_data[1]["geant_s_sid"] - new_side_a_sid = input_form_iptrunk_data[3]["side_a_ae_geant_a_sid"] + new_sid = input_form_iptrunk_data[1]["gs_id"] + new_side_a_gid = input_form_iptrunk_data[3]["side_a_ga_id"] new_side_a_ae_members = input_form_iptrunk_data[3]["side_a_ae_members"] - new_side_b_sid = input_form_iptrunk_data[4]["side_b_ae_geant_a_sid"] + new_side_b_gid = input_form_iptrunk_data[4]["side_b_ga_id"] new_side_b_ae_members = input_form_iptrunk_data[4]["side_b_ae_members"] # Only Nokia interfaces are checked @@ -164,13 +165,13 @@ def test_iptrunk_modify_trunk_interface_success( subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name, subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_site.site_name, ]) - assert subscription.description == f"IP trunk {side_names[0]} {side_names[1]}, geant_s_sid:{new_sid}" - assert subscription.iptrunk.geant_s_sid == input_form_iptrunk_data[1]["geant_s_sid"] + assert subscription.description == f"IP trunk {side_names[0]} {side_names[1]}, {new_sid}" + assert subscription.iptrunk.gs_id == input_form_iptrunk_data[1]["gs_id"] assert subscription.iptrunk.iptrunk_description == input_form_iptrunk_data[1]["iptrunk_description"] assert subscription.iptrunk.iptrunk_type == input_form_iptrunk_data[1]["iptrunk_type"] assert subscription.iptrunk.iptrunk_speed == input_form_iptrunk_data[1]["iptrunk_speed"] assert subscription.iptrunk.iptrunk_minimum_links == input_form_iptrunk_data[1]["iptrunk_number_of_members"] - 1 - assert subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid == new_side_a_sid + assert subscription.iptrunk.iptrunk_sides[0].ga_id == new_side_a_gid def _find_interface_by_name(interfaces: LAGMemberList, name: str): for interface in interfaces: @@ -185,10 +186,26 @@ def test_iptrunk_modify_trunk_interface_success( == _find_interface_by_name(new_side_a_ae_members, member.interface_name).interface_description ) - assert subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid == new_side_b_sid + assert subscription.iptrunk.iptrunk_sides[1].ga_id == new_side_b_gid for member in subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members: assert ( member.interface_description == _find_interface_by_name(new_side_b_ae_members, member.interface_name).interface_description ) + + +@pytest.mark.workflow() +@pytest.mark.parametrize("invalid_ga_id", ["GA-11111", "GS-1234", "GS_12345", "GS-100000"]) +def test_modify_iptrunk_interface_with_invalid_ga_id( + input_form_iptrunk_data, faker, invalid_ga_id, iptrunk_side_subscription_factory, iptrunk_subscription_factory +): + input_data = input_form_iptrunk_data + input_data[3]["side_a_ga_id"] = invalid_ga_id + iptrunk_subscription_factory( + iptrunk_sides=[iptrunk_side_subscription_factory(ga_id="GA-11111"), iptrunk_side_subscription_factory()] + ) + + # Run workflow + with pytest.raises(FormValidationError): + run_workflow("modify_edge_port", input_data) diff --git a/test/workflows/l2_circuit/test_create_imported_layer_2_circuit.py b/test/workflows/l2_circuit/test_create_imported_layer_2_circuit.py index 0e4e857ef32e9d002cd175176fa1ba7a463ce318..3d0e78709dd4b708af3e46cdd19110611edbbfc4 100644 --- a/test/workflows/l2_circuit/test_create_imported_layer_2_circuit.py +++ b/test/workflows/l2_circuit/test_create_imported_layer_2_circuit.py @@ -28,7 +28,7 @@ def test_create_imported_layer_2_circuit_success( "vc_id": generate_unique_vc_id(), "policer_bandwidth": faker.bandwidth() if policer_enabled else None, "policer_burst_rate": faker.bandwidth() if policer_enabled else None, - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "layer_2_circuit_side_a": {"edge_port": edge_port_a, "vlan_id": faker.vlan_id()}, "layer_2_circuit_side_b": {"edge_port": edge_port_b, "vlan_id": faker.vlan_id()}, } @@ -43,9 +43,7 @@ def test_create_imported_layer_2_circuit_success( assert subscription.layer_2_circuit.virtual_circuit_id == creation_form_input_data[0]["vc_id"] assert len(subscription.layer_2_circuit.layer_2_circuit_sides) == 2 assert subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.is_tagged is True - assert ( - subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.geant_sid == creation_form_input_data[0]["geant_sid"] - ) + assert subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.gs_id == creation_form_input_data[0]["gs_id"] assert ( str(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.edge_port.owner_subscription_id) == creation_form_input_data[0]["layer_2_circuit_side_a"]["edge_port"] diff --git a/test/workflows/l2_circuit/test_create_layer_2_circuit.py b/test/workflows/l2_circuit/test_create_layer_2_circuit.py index c0d1b2df6aae5014f24e0fe4531a4d52a5007411..c14ab1213a41f24414b56046fbeb4a8afef43110 100644 --- a/test/workflows/l2_circuit/test_create_layer_2_circuit.py +++ b/test/workflows/l2_circuit/test_create_layer_2_circuit.py @@ -28,7 +28,6 @@ def layer_2_circuit_input(faker, partner_factory, edge_port_subscription_factory "vlan_range_upper_bound": faker.vlan_id(), "policer_bandwidth": faker.bandwidth() if policer_enabled else None, "policer_burst_rate": faker.bandwidth() if policer_enabled else None, - "geant_sid": faker.geant_sid(), "layer_2_circuit_side_a": {"edge_port": edge_port_a, "vlan_id": faker.vlan_id()}, "layer_2_circuit_side_b": {"edge_port": edge_port_b, "vlan_id": faker.vlan_id()}, }, @@ -56,13 +55,15 @@ def test_create_layer_2_circuit_success( == layer_2_circuit_input[2]["layer_2_circuit_side_a"]["edge_port"] ) assert subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.is_tagged is True - assert subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.geant_sid == layer_2_circuit_input[2]["geant_sid"] + assert ( + subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.gs_id + == subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.gs_id + ) assert ( str(subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.edge_port.owner_subscription_id) == layer_2_circuit_input[2]["layer_2_circuit_side_b"]["edge_port"] ) assert subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.is_tagged is True - assert subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.geant_sid == layer_2_circuit_input[2]["geant_sid"] assert subscription.layer_2_circuit.layer_2_circuit_type == Layer2CircuitType.TAGGED assert subscription.layer_2_circuit.vlan_range_lower_bound == layer_2_circuit_input[2]["vlan_range_lower_bound"] assert subscription.layer_2_circuit.vlan_range_upper_bound == layer_2_circuit_input[2]["vlan_range_upper_bound"] diff --git a/test/workflows/l3_core_service/test_create_imported_l3_core_service.py b/test/workflows/l3_core_service/test_create_imported_l3_core_service.py index 626c62378746d7b3625f490325cc7d362a6b4de1..48ac4b54d40fa6be2e76a3fea17d98c44bda8d33 100644 --- a/test/workflows/l3_core_service/test_create_imported_l3_core_service.py +++ b/test/workflows/l3_core_service/test_create_imported_l3_core_service.py @@ -27,7 +27,7 @@ def test_create_imported_l3_core_service_success( { "edge_port": edge_port_subscription_factory(), "ap_type": "PRIMARY", - "geant_sid": faker.geant_sid(), + "gs_id": faker.imported_gs_id(), "sbp_type": SBPType.L3, "is_tagged": faker.boolean(), "vlan_id": faker.vlan_id(), diff --git a/test/workflows/l3_core_service/test_create_l3_core_service.py b/test/workflows/l3_core_service/test_create_l3_core_service.py index 149fdf202357a583d52d4010eb7007eb7582413d..c26e649443f01d44d024062038d5d7192c54fa3a 100644 --- a/test/workflows/l3_core_service/test_create_l3_core_service.py +++ b/test/workflows/l3_core_service/test_create_l3_core_service.py @@ -49,7 +49,6 @@ def test_create_l3_core_service_success( {"tt_number": faker.tt_number(), "partner": partner["partner_id"]}, {"edge_port": {"edge_port": edge_port_a, "ap_type": APType.PRIMARY}}, { - "geant_sid": faker.geant_sid(), "is_tagged": faker.boolean(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), diff --git a/test/workflows/l3_core_service/test_modify_l3_core_service.py b/test/workflows/l3_core_service/test_modify_l3_core_service.py index 67ff888097afbed5db3403a6ca926cdd00dda54e..dc7f3a510f92ed1d6361f0c1799528dbbe63c523 100644 --- a/test/workflows/l3_core_service/test_modify_l3_core_service.py +++ b/test/workflows/l3_core_service/test_modify_l3_core_service.py @@ -84,7 +84,7 @@ def test_modify_l3_core_service_add_new_edge_port_success( {}, # The existing SBPs are unchanged {}, { # Adding configuration for the new SBP - "geant_sid": faker.geant_sid(), + "gs_id": faker.gs_id(), "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), "ipv6_address": faker.ipv6(), @@ -115,7 +115,7 @@ def test_modify_l3_core_service_add_new_edge_port_success( def sbp_input_form_data(faker): def _generate_form_data(): return { - "geant_sid": faker.geant_sid(), + "gs_id": faker.gs_id(), "is_tagged": True, "vlan_id": faker.vlan_id(), "ipv4_address": faker.ipv4(), @@ -198,7 +198,7 @@ def test_modify_l3_core_service_modify_edge_port_success( assert len(subscription.l3_core_service.ap_list) == 2 for i in range(2): - assert subscription.l3_core_service.ap_list[i].sbp.geant_sid == new_sbp_data[i]["geant_sid"] + assert subscription.l3_core_service.ap_list[i].sbp.gs_id == new_sbp_data[i]["gs_id"] assert subscription.l3_core_service.ap_list[i].sbp.is_tagged == new_sbp_data[i]["is_tagged"] assert subscription.l3_core_service.ap_list[i].sbp.vlan_id == new_sbp_data[i]["vlan_id"] assert str(subscription.l3_core_service.ap_list[i].sbp.ipv4_address) == new_sbp_data[i]["ipv4_address"]