diff --git a/gso/api/v1/imports.py b/gso/api/v1/imports.py index c99db7736804aaeea9a1fe36d65ef9c3ed472d91..c54ebd6b83a4e08dc7914af85c2dca70368cf3bf 100644 --- a/gso/api/v1/imports.py +++ b/gso/api/v1/imports.py @@ -10,8 +10,9 @@ from pydantic import BaseModel, root_validator, validator from pydantic.fields import ModelField from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity -from gso.products.product_blocks.router import RouterRole, RouterVendor +from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.site import SiteTier +from gso.products.product_types.router import RouterVendor from gso.services import subscriptions from gso.services.crm import CustomerNotFoundError, get_customer_by_name from gso.utils.helpers import ( diff --git a/gso/migrations/versions/2023-08-14_a6eefd32c4f7_add_ip_trunk_workflows.py b/gso/migrations/versions/2023-08-14_a6eefd32c4f7_add_ip_trunk_workflows.py index b341eb7c8c9061959febac45181b1a70028e6236..80050dc7ec8fad8bd3141952a75f4e17f6cf5afe 100644 --- a/gso/migrations/versions/2023-08-14_a6eefd32c4f7_add_ip_trunk_workflows.py +++ b/gso/migrations/versions/2023-08-14_a6eefd32c4f7_add_ip_trunk_workflows.py @@ -10,7 +10,7 @@ from alembic import op # revision identifiers, used by Alembic. revision = 'a6eefd32c4f7' -down_revision = '3657611f0dfc' +down_revision = '91047dd30b40' branch_labels = None depends_on = None diff --git a/gso/migrations/versions/2023-11-08_30bc55e5be3e_modify_router_product_model.py b/gso/migrations/versions/2023-11-08_30bc55e5be3e_modify_router_product_model.py new file mode 100644 index 0000000000000000000000000000000000000000..db514e117bedf08443d362eeae9c3b5e7ae6a8aa --- /dev/null +++ b/gso/migrations/versions/2023-11-08_30bc55e5be3e_modify_router_product_model.py @@ -0,0 +1,83 @@ +"""Modify Router product model. + +Revision ID: 30bc55e5be3e +Revises: 259c320235f5 +Create Date: 2023-11-08 13:58:21.149708 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = '30bc55e5be3e' +down_revision = '259c320235f5' +branch_labels = None +depends_on = None + + +def upgrade() -> 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 ('RouterBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('router_vendor')) + """)) + 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 ('RouterBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('router_vendor')) + """)) + 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 ('router_vendor')) + """)) + conn.execute(sa.text(""" +DELETE FROM resource_types WHERE resource_types.resource_type IN ('router_vendor') + """)) + 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 ('Router')))) + """)) + 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 ('Router'))) + """)) + 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 ('Router'))) + """)) + conn.execute(sa.text(""" +DELETE FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Router')) + """)) + conn.execute(sa.text(""" +DELETE FROM products WHERE products.name IN ('Router') + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Nokia router', 'A Nokia router', 'Router', 'NOKIA_RT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Juniper router', 'A Juniper router', 'Router', 'JUNIPER_RT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO fixed_inputs (name, value, product_id) VALUES ('vendor', 'nokia', (SELECT products.product_id FROM products WHERE products.name IN ('Nokia router'))), ('vendor', 'juniper', (SELECT products.product_id FROM products WHERE products.name IN ('Juniper router'))) + """)) + 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 ('Nokia router')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('Juniper router')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock'))) + """)) + + +def downgrade() -> 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 ('Nokia router', 'Juniper router')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM fixed_inputs WHERE fixed_inputs.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Nokia router', 'Juniper router')) AND fixed_inputs.name = 'vendor' + """)) + 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 ('Nokia router', 'Juniper router')))) + """)) + 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 ('Nokia router', 'Juniper router'))) + """)) + 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 ('Nokia router', 'Juniper router'))) + """)) + conn.execute(sa.text(""" +DELETE FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Nokia router', 'Juniper router')) + """)) + conn.execute(sa.text(""" +DELETE FROM products WHERE products.name IN ('Nokia router', 'Juniper router') + """)) diff --git a/gso/migrations/versions/2023-08-14_3657611f0dfc_add_router_workflows.py b/gso/migrations/versions/2023-11-09_7f46df0f4f95_add_router_workflows.py similarity index 82% rename from gso/migrations/versions/2023-08-14_3657611f0dfc_add_router_workflows.py rename to gso/migrations/versions/2023-11-09_7f46df0f4f95_add_router_workflows.py index 153d5433579308b23e2d06b394b5d9f4a620158e..df3dbf78cacb8ac8132f864a1cec71f90ca127d3 100644 --- a/gso/migrations/versions/2023-08-14_3657611f0dfc_add_router_workflows.py +++ b/gso/migrations/versions/2023-11-09_7f46df0f4f95_add_router_workflows.py @@ -1,16 +1,16 @@ -"""Add Router workflows. +"""Add router workflows. -Revision ID: 3657611f0dfc -Revises: 91047dd30b40 -Create Date: 2023-08-14 15:44:25.616608 +Revision ID: 7f46df0f4f95 +Revises: 30bc55e5be3e +Create Date: 2023-11-09 14:18:38.705753 """ import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. -revision = '3657611f0dfc' -down_revision = '91047dd30b40' +revision = '7f46df0f4f95' +down_revision = '30bc55e5be3e' branch_labels = None depends_on = None diff --git a/gso/products/__init__.py b/gso/products/__init__.py index e6a8c06f8850748b36233be63006a8fa9709d946..28e12c71d5eb524c9db7ca9020ee393adf59e71e 100644 --- a/gso/products/__init__.py +++ b/gso/products/__init__.py @@ -1,8 +1,8 @@ """Module that updates the domain model of :term:`GSO`. Should contain all types of subscriptions. .. warning:: - Whenever a new product type is added, this should be reflected in the :py:class:`gso.products.ProductType` - enumerator. + Whenever a new product is added, this should be reflected in the :py:class:`gso.products.ProductType` enumerator. + This does not hold for adding a new type of already existing product. """ from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY from pydantic_forms.types import strEnum @@ -14,14 +14,16 @@ from gso.products.product_types.site import Site class ProductType(strEnum): SITE = "Site" - ROUTER = "Router" + NOKIA_ROUTER = "Nokia router" + JUNIPER_ROUTER = "Juniper router" IP_TRUNK = "IP trunk" SUBSCRIPTION_MODEL_REGISTRY.update( { "Site": Site, - "Router": Router, + "Nokia router": Router, + "Juniper router": Router, "IP trunk": Iptrunk, } ) diff --git a/gso/services/subscriptions.py b/gso/services/subscriptions.py index 42c57eb244ad20e3c4eaf6dcf27345ce119b9109..f402ed0bcf9b5c859d35a110ff25060826e6d680 100644 --- a/gso/services/subscriptions.py +++ b/gso/services/subscriptions.py @@ -72,7 +72,9 @@ def get_active_router_subscriptions(includes: list[str] | None = None) -> list[S :return: A list of Subscription objects for routers. :rtype: list[Subscription] """ - return get_active_subscriptions(product_type=ProductType.ROUTER, includes=includes) + active_nokia_routers = get_active_subscriptions(product_type=ProductType.NOKIA_ROUTER, includes=includes) + active_juniper_routers = get_active_subscriptions(product_type=ProductType.JUNIPER_ROUTER, includes=includes) + return active_nokia_routers + active_juniper_routers def get_product_id_by_name(product_name: ProductType) -> UUID: diff --git a/gso/utils/helpers.py b/gso/utils/helpers.py index 5e3b149ac45f61168c89a925a3fb0426c48fdf1b..1878255393975201fb4dbe884c04178f84a9bba5 100644 --- a/gso/utils/helpers.py +++ b/gso/utils/helpers.py @@ -10,9 +10,8 @@ from pydantic import BaseModel from pydantic_forms.validators import Choice from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock -from gso.products.product_blocks.router import RouterVendor from gso.products.product_types.iptrunk import Iptrunk -from gso.products.product_types.router import Router +from gso.products.product_types.router import Router, RouterVendor from gso.services import provisioning_proxy from gso.services.netbox_client import NetboxClient from gso.services.subscriptions import get_active_subscriptions_by_field_and_value @@ -46,7 +45,7 @@ def available_interfaces_choices(router_id: UUID, speed: str) -> Choice | None: For Nokia routers, return a list of available interfaces. For Juniper routers, return a string. """ - if Router.from_subscription(router_id).router.router_vendor != RouterVendor.NOKIA: + if get_router_vendor(router_id) != RouterVendor.NOKIA: return None interfaces = { interface["name"]: f"{interface['name']} - {interface['module']['display']} - {interface['description']}" @@ -63,7 +62,7 @@ def available_interfaces_choices_including_current_members( For Nokia routers, return a list of available interfaces. For Juniper routers, return a string. """ - if Router.from_subscription(router_id).router.router_vendor != RouterVendor.NOKIA: + if get_router_vendor(router_id) != RouterVendor.NOKIA: return None available_interfaces = list(NetboxClient().get_available_interfaces(router_id, speed)) available_interfaces.extend( @@ -88,7 +87,7 @@ def available_lags_choices(router_id: UUID) -> Choice | None: For Juniper routers, return a string. """ - if Router.from_subscription(router_id).router.router_vendor != RouterVendor.NOKIA: + if get_router_vendor(router_id) != RouterVendor.NOKIA: return None side_a_ae_iface_list = NetboxClient().get_available_lags(router_id) return Choice("ae iface", zip(side_a_ae_iface_list, side_a_ae_iface_list)) # type: ignore[arg-type] @@ -105,7 +104,7 @@ def get_router_vendor(router_id: UUID) -> str: ------- str: The vendor of the router. """ - return Router.from_subscription(router_id).router.router_vendor + return Router.from_subscription(router_id).vendor def iso_from_ipv4(ipv4_address: IPv4Address) -> str: @@ -131,9 +130,9 @@ def validate_router_in_netbox(subscription_id: UUIDstr) -> UUIDstr | None: ------- UUID: The {term}`UUID` of the router subscription or raises an error. """ - router = Router.from_subscription(subscription_id).router - if router.router_vendor == RouterVendor.NOKIA: - device = NetboxClient().get_device_by_name(router.router_fqdn) + router_type = Router.from_subscription(subscription_id) + if router_type.vendor == RouterVendor.NOKIA: + device = NetboxClient().get_device_by_name(router_type.router.router_fqdn) if not device: raise ValueError("The selected router does not exist in Netbox.") return subscription_id diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index ff83e7c3a464b662ed36bebad5e2546fa48376b0..0df2f45604e26aecae55fa9df5719d4c792fb112 100644 --- a/gso/workflows/iptrunk/create_iptrunk.py +++ b/gso/workflows/iptrunk/create_iptrunk.py @@ -11,9 +11,8 @@ from pydantic import validator from pynetbox.models.dcim import Interfaces from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlockInactive, IptrunkType, PhyPortCapacity -from gso.products.product_blocks.router import RouterVendor from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning -from gso.products.product_types.router import Router +from gso.products.product_types.router import Router, RouterVendor from gso.services import infoblox, provisioning_proxy, subscriptions from gso.services.crm import customer_selector from gso.services.netbox_client import NetboxClient diff --git a/gso/workflows/iptrunk/migrate_iptrunk.py b/gso/workflows/iptrunk/migrate_iptrunk.py index 0d238437f4ec9f8016c0e693be1ea8fd201c13ff..1287aca7ff12ddcd5c12062baacd4ca433098810 100644 --- a/gso/workflows/iptrunk/migrate_iptrunk.py +++ b/gso/workflows/iptrunk/migrate_iptrunk.py @@ -18,9 +18,8 @@ from pydantic_forms.core import ReadOnlyField from pynetbox.models.dcim import Interfaces from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock -from gso.products.product_blocks.router import RouterVendor from gso.products.product_types.iptrunk import Iptrunk -from gso.products.product_types.router import Router +from gso.products.product_types.router import Router, RouterVendor from gso.services import provisioning_proxy from gso.services.netbox_client import NetboxClient from gso.services.provisioning_proxy import pp_interaction @@ -445,15 +444,16 @@ def reserve_interfaces_in_netbox( new_lag_interface: str, new_lag_member_interfaces: list[dict], ) -> State: - new_side = Router.from_subscription(new_node).router + new_side_type = Router.from_subscription(new_node) + new_side_router = new_side_type.router nbclient = NetboxClient() - if new_side.router_vendor == RouterVendor.NOKIA: + if new_side_type.vendor == RouterVendor.NOKIA: # Create LAG interfaces lag_interface: Interfaces = nbclient.create_interface( iface_name=new_lag_interface, type="lag", - device_name=new_side.router_fqdn, + device_name=new_side_router.router_fqdn, description=str(subscription.subscription_id), enabled=True, ) @@ -461,13 +461,13 @@ def reserve_interfaces_in_netbox( # Reserve interfaces for interface in new_lag_member_interfaces: nbclient.attach_interface_to_lag( - device_name=new_side.router_fqdn, + device_name=new_side_router.router_fqdn, lag_name=lag_interface.name, iface_name=interface["interface_name"], description=str(subscription.subscription_id), ) nbclient.reserve_interface( - device_name=new_side.router_fqdn, + device_name=new_side_router.router_fqdn, iface_name=interface["interface_name"], ) return {"subscription": subscription} diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index 908b20e295db94d50b4a52627a924890a98e0c0f..dc48cc8371c2e9f95d9bae78d7be98410d96a151 100644 --- a/gso/workflows/iptrunk/modify_trunk_interface.py +++ b/gso/workflows/iptrunk/modify_trunk_interface.py @@ -13,8 +13,8 @@ from pydantic import validator from pydantic_forms.validators import Label from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkType, PhyPortCapacity -from gso.products.product_blocks.router import RouterVendor from gso.products.product_types.iptrunk import Iptrunk +from gso.products.product_types.router import RouterVendor from gso.services import provisioning_proxy from gso.services.netbox_client import NetboxClient from gso.services.provisioning_proxy import pp_interaction @@ -22,15 +22,16 @@ from gso.utils.helpers import ( LAGMember, available_interfaces_choices, available_interfaces_choices_including_current_members, - validate_iptrunk_unique_interface, + validate_iptrunk_unique_interface, get_router_vendor, ) def initialize_ae_members(subscription: Iptrunk, initial_user_input: dict, side_index: int) -> Type[LAGMember]: """Initialize the list of AE members.""" router = subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_node + router_vendor = get_router_vendor(router.owner_subscription_id) iptrunk_minimum_link = initial_user_input["iptrunk_minimum_links"] - if router.router_vendor == RouterVendor.NOKIA: + if router_vendor == RouterVendor.NOKIA: iptrunk_speed = initial_user_input["iptrunk_speed"] class NokiaLAGMember(LAGMember): diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py index 8bad1c40be738dc532a24688776c7f4fff2677fb..4c1f3fc709f1806280c690afc093e626b15949bc 100644 --- a/gso/workflows/iptrunk/terminate_iptrunk.py +++ b/gso/workflows/iptrunk/terminate_iptrunk.py @@ -8,12 +8,12 @@ from orchestrator.workflow import StepList, conditional, done, init, step, workf from orchestrator.workflows.steps import resync, set_status, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form -from gso.products.product_blocks.router import RouterVendor from gso.products.product_types.iptrunk import Iptrunk +from gso.products.product_types.router import Router, RouterVendor from gso.services import infoblox, provisioning_proxy from gso.services.netbox_client import NetboxClient from gso.services.provisioning_proxy import pp_interaction -from gso.utils.helpers import set_isis_to_90000 +from gso.utils.helpers import set_isis_to_90000, get_router_vendor def initial_input_form_generator() -> FormGenerator: @@ -57,8 +57,9 @@ def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr, callba def free_interfaces_in_netbox(subscription: Iptrunk) -> State: for side in [0, 1]: router = subscription.iptrunk.iptrunk_sides[side].iptrunk_side_node + router_vendor = get_router_vendor(router.owner_subscription_id) router_fqdn = router.router_fqdn - if router.router_vendor == RouterVendor.NOKIA: + if router_vendor == RouterVendor.NOKIA: nbclient = NetboxClient() # Remove physical interfaces from LAGs for member in subscription.iptrunk.iptrunk_sides[side].iptrunk_side_ae_members: diff --git a/gso/workflows/router/create_router.py b/gso/workflows/router/create_router.py index 3f681a0266a2242ff80007ea4eb4769009142827..5bc93583ce9c147b6a329e6bf3b51eb14acc5ccf 100644 --- a/gso/workflows/router/create_router.py +++ b/gso/workflows/router/create_router.py @@ -11,8 +11,8 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc from orchestrator.workflows.utils import wrap_create_initial_input_form from pydantic import validator -from gso.products.product_blocks.router import PortNumber, RouterRole, RouterVendor, generate_fqdn -from gso.products.product_types.router import RouterInactive, RouterProvisioning +from gso.products.product_blocks.router import PortNumber, RouterRole, generate_fqdn +from gso.products.product_types.router import RouterInactive, RouterProvisioning, RouterVendor from gso.products.product_types.site import Site from gso.services import infoblox, provisioning_proxy, subscriptions from gso.services.crm import customer_selector @@ -40,7 +40,6 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: router_site: _site_selector() # type: ignore[valid-type] hostname: str ts_port: PortNumber - router_vendor: RouterVendor router_role: RouterRole is_ias_connected: bool | None = False @@ -77,12 +76,12 @@ def initialize_subscription( subscription: RouterInactive, hostname: str, ts_port: PortNumber, - router_vendor: RouterVendor, + vendor: RouterVendor, router_site: str, router_role: RouterRole, ) -> State: subscription.router.router_ts_port = ts_port - subscription.router.router_vendor = router_vendor + subscription.vendor = vendor subscription.router.router_site = Site.from_subscription(router_site).site fqdn = generate_fqdn( hostname, subscription.router.router_site.site_name, subscription.router.router_site.site_country_code @@ -147,7 +146,7 @@ def provision_router_real( @step("Create NetBox Device") def create_netbox_device(subscription: RouterProvisioning) -> State: - if subscription.router.router_vendor == RouterVendor.NOKIA: + if subscription.vendor == RouterVendor.NOKIA: NetboxClient().create_device( subscription.router.router_fqdn, str(subscription.router.router_site.site_tier), # type: ignore[union-attr] diff --git a/gso/workflows/router/terminate_router.py b/gso/workflows/router/terminate_router.py index 47d09b414c13b94cf93a836da241fcc3c957fa39..f1a5e3107b260d9250357f9cbdf24eb096ea9cd5 100644 --- a/gso/workflows/router/terminate_router.py +++ b/gso/workflows/router/terminate_router.py @@ -9,8 +9,7 @@ from orchestrator.workflow import StepList, conditional, done, init, step, workf from orchestrator.workflows.steps import resync, set_status, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form -from gso.products.product_blocks.router import RouterVendor -from gso.products.product_types.router import Router +from gso.products.product_types.router import Router, RouterVendor from gso.services import infoblox from gso.services.netbox_client import NetboxClient @@ -64,7 +63,7 @@ def remove_config_from_router() -> None: @step("Remove Device from NetBox") def remove_device_from_netbox(subscription: Router) -> dict[str, Router]: - if subscription.router.router_vendor == RouterVendor.NOKIA: + if subscription.vendor == RouterVendor.NOKIA: NetboxClient().delete_device(subscription.router.router_fqdn) return {"subscription": subscription} diff --git a/gso/workflows/tasks/import_router.py b/gso/workflows/tasks/import_router.py index 517261452a81250f7684a02e7660671f3125ada3..59f0a19f4bfcb904ce47259152bb3af3dd126eba 100644 --- a/gso/workflows/tasks/import_router.py +++ b/gso/workflows/tasks/import_router.py @@ -10,9 +10,9 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc from gso.products import ProductType from gso.products.product_blocks import router as router_pb -from gso.products.product_blocks.router import PortNumber, RouterRole, RouterVendor +from gso.products.product_blocks.router import PortNumber, RouterRole from gso.products.product_types import router -from gso.products.product_types.router import RouterInactive +from gso.products.product_types.router import RouterInactive, RouterVendor from gso.products.product_types.site import Site from gso.services import subscriptions from gso.services.crm import get_customer_by_name @@ -33,9 +33,15 @@ def _get_site_by_name(site_name: str) -> Site: @step("Create subscription") -def create_subscription(customer: str) -> State: +def create_subscription(customer: str, router_vendor: RouterVendor) -> State: customer_id = get_customer_by_name(customer)["id"] - product_id: UUID = subscriptions.get_product_id_by_name(ProductType.ROUTER) + if router_vendor == RouterVendor.NOKIA: + product_id: UUID = subscriptions.get_product_id_by_name(ProductType.NOKIA_ROUTER) + elif router_vendor == RouterVendor.JUNIPER: + product_id: UUID = subscriptions.get_product_id_by_name(ProductType.JUNIPER_ROUTER) + else: + raise ValueError(f"Unknown router vendor: {router_vendor}") + subscription = RouterInactive.from_product_id(product_id, customer_id) return { @@ -73,7 +79,6 @@ def initialize_subscription( subscription: RouterInactive, hostname: str, ts_port: PortNumber, - router_vendor: router_pb.RouterVendor, router_site: str, router_role: router_pb.RouterRole, is_ias_connected: bool | None = None, @@ -85,7 +90,6 @@ def initialize_subscription( router_ias_lt_ipv6_network: ipaddress.IPv6Network | None = None, ) -> State: subscription.router.router_ts_port = ts_port - subscription.router.router_vendor = router_vendor subscription.router.router_site = _get_site_by_name(router_site).site fqdn = ( f"{hostname}.{subscription.router.router_site.site_name.lower()}." diff --git a/test/fixtures.py b/test/fixtures.py index 601463de6f392f13b83b2efa7b74b9443255a636..061557ed594e9c32a873ac47f9d94ed2dd8c8e60 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -7,7 +7,7 @@ from orchestrator.types import SubscriptionLifecycle, UUIDstr from gso.products import ProductType from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkSideBlock, IptrunkType, PhyPortCapacity -from gso.products.product_blocks.router import RouterRole, RouterVendor +from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.site import SiteTier from gso.products.product_types.iptrunk import IptrunkInactive from gso.products.product_types.router import Router, RouterInactive @@ -69,7 +69,7 @@ def site_subscription_factory(faker): @pytest.fixture -def router_subscription_factory(site_subscription_factory, faker): +def nokia_router_subscription_factory(site_subscription_factory, faker): def subscription_create( description=None, start_date="2023-05-24T00:00:00+00:00", @@ -82,7 +82,6 @@ def router_subscription_factory(site_subscription_factory, faker): router_si_ipv4_network=None, router_ias_lt_ipv4_network=None, router_ias_lt_ipv6_network=None, - router_vendor=RouterVendor.NOKIA, router_role=RouterRole.PE, router_site=None, router_is_ias_connected=True, @@ -100,7 +99,7 @@ def router_subscription_factory(site_subscription_factory, faker): router_ias_lt_ipv6_network = router_ias_lt_ipv6_network or faker.ipv6_network() router_site = router_site or site_subscription_factory() - product_id = subscriptions.get_product_id_by_name(ProductType.ROUTER) + product_id = subscriptions.get_product_id_by_name(ProductType.NOKIA_ROUTER) router_subscription = RouterInactive.from_product_id(product_id, customer_id=CUSTOMER_ID, insync=True) router_subscription.router.router_fqdn = router_fqdn router_subscription.router.router_ts_port = router_ts_port @@ -111,7 +110,6 @@ def router_subscription_factory(site_subscription_factory, faker): router_subscription.router.router_si_ipv4_network = router_si_ipv4_network router_subscription.router.router_ias_lt_ipv4_network = router_ias_lt_ipv4_network router_subscription.router.router_ias_lt_ipv6_network = router_ias_lt_ipv6_network - router_subscription.router.router_vendor = router_vendor router_subscription.router.router_role = router_role router_subscription.router.router_site = Site.from_subscription(router_site).site router_subscription.router.router_is_ias_connected = router_is_ias_connected @@ -132,7 +130,7 @@ def router_subscription_factory(site_subscription_factory, faker): @pytest.fixture -def iptrunk_side_subscription_factory(router_subscription_factory, faker): +def iptrunk_side_subscription_factory(nokia_router_subscription_factory, faker): def subscription_create( iptrunk_side_node=None, iptrunk_side_ae_iface=None, @@ -140,7 +138,7 @@ def iptrunk_side_subscription_factory(router_subscription_factory, faker): iptrunk_side_ae_members=None, iptrunk_side_ae_members_description=None, ) -> IptrunkSideBlock: - iptrunk_side_node_id = iptrunk_side_node or router_subscription_factory() + iptrunk_side_node_id = iptrunk_side_node or nokia_router_subscription_factory() iptrunk_side_node = Router.from_subscription(iptrunk_side_node_id).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() diff --git a/test/imports/conftest.py b/test/imports/conftest.py index 4a3e9c07a0c70ef31069d0f624c7437553562a16..2e7558dc1910d1a1c5c0a68a23e566dd24337252 100644 --- a/test/imports/conftest.py +++ b/test/imports/conftest.py @@ -1,6 +1,6 @@ from test.fixtures import ( # noqa iptrunk_side_subscription_factory, iptrunk_subscription_factory, - router_subscription_factory, + nokia_router_subscription_factory, site_subscription_factory, ) diff --git a/test/imports/test_imports.py b/test/imports/test_imports.py index 82a8eae6cc75bbe0374a6696b3acd0dc72b15ba9..99015441d64c6f623f853e8a4462fdbe398be6f3 100644 --- a/test/imports/test_imports.py +++ b/test/imports/test_imports.py @@ -6,8 +6,9 @@ from orchestrator.db import SubscriptionTable from orchestrator.services import subscriptions from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity -from gso.products.product_blocks.router import RouterRole, RouterVendor +from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.site import SiteTier +from gso.products.product_types.router import RouterVendor from gso.utils.helpers import iso_from_ipv4 SITE_IMPORT_ENDPOINT = "/api/v1/imports/sites" @@ -16,9 +17,9 @@ IPTRUNK_IMPORT_API_URL = "/api/v1/imports/iptrunks" @pytest.fixture -def iptrunk_data(router_subscription_factory, faker): - router_side_a = router_subscription_factory() - router_side_b = router_subscription_factory() +def iptrunk_data(nokia_router_subscription_factory, faker): + router_side_a = nokia_router_subscription_factory() + router_side_b = nokia_router_subscription_factory() return { "customer": "GÉANT", "geant_s_sid": faker.geant_sid(), diff --git a/test/subscriptions/conftest.py b/test/subscriptions/conftest.py index 425a0e627a4592241e2c3f81cce910255dd34a5e..29926c838ec0667d49ca1d47653f8da1521f500e 100644 --- a/test/subscriptions/conftest.py +++ b/test/subscriptions/conftest.py @@ -1 +1 @@ -from test.fixtures import router_subscription_factory, site_subscription_factory # noqa +from test.fixtures import nokia_router_subscription_factory, site_subscription_factory # noqa diff --git a/test/subscriptions/test_subscriptions.py b/test/subscriptions/test_subscriptions.py index 8e9980996c0486a65759ff820883f403399e684a..d56d2d582c21a89aa255e417a19dc04b38bff6e4 100644 --- a/test/subscriptions/test_subscriptions.py +++ b/test/subscriptions/test_subscriptions.py @@ -3,12 +3,12 @@ from orchestrator.types import SubscriptionLifecycle ROUTER_SUBSCRIPTION_ENDPOINT = "/api/v1/subscriptions/routers" -def test_router_subscriptions_endpoint(test_client, router_subscription_factory): - router_subscription_factory() - router_subscription_factory() - router_subscription_factory() - router_subscription_factory(status=SubscriptionLifecycle.TERMINATED) - router_subscription_factory(status=SubscriptionLifecycle.INITIAL) +def test_router_subscriptions_endpoint(test_client, nokia_router_subscription_factory): + nokia_router_subscription_factory() + nokia_router_subscription_factory() + nokia_router_subscription_factory() + nokia_router_subscription_factory(status=SubscriptionLifecycle.TERMINATED) + nokia_router_subscription_factory(status=SubscriptionLifecycle.INITIAL) response = test_client.get(ROUTER_SUBSCRIPTION_ENDPOINT) diff --git a/test/workflows/conftest.py b/test/workflows/conftest.py index a4b71a738da3818674500075dd7ce910e2c17382..5cea6233f6e43771098404b743a7fef0bd4cccf0 100644 --- a/test/workflows/conftest.py +++ b/test/workflows/conftest.py @@ -4,7 +4,7 @@ from urllib3_mock import Responses from test.fixtures import ( # noqa iptrunk_side_subscription_factory, iptrunk_subscription_factory, - router_subscription_factory, + nokia_router_subscription_factory, site_subscription_factory, ) diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py index 10a87d1253033f7964bb7482db18e6498586d059..69f7487802c580cc878b334ff2053c06b9df7f11 100644 --- a/test/workflows/iptrunk/test_create_iptrunk.py +++ b/test/workflows/iptrunk/test_create_iptrunk.py @@ -42,9 +42,9 @@ def netbox_client_mock(): @pytest.fixture -def input_form_wizard_data(router_subscription_factory, faker): - router_side_a = router_subscription_factory() - router_side_b = router_subscription_factory() +def input_form_wizard_data(nokia_router_subscription_factory, faker): + router_side_a = nokia_router_subscription_factory() + router_side_b = nokia_router_subscription_factory() create_ip_trunk_step = { "tt_number": faker.tt_number(), diff --git a/test/workflows/iptrunk/test_migrate_iptrunk.py b/test/workflows/iptrunk/test_migrate_iptrunk.py index 8285ffb9bb840ec586f0cde12adc0f24c849c4bd..097641b92c23624733f5dadef886af78a8ab97d6 100644 --- a/test/workflows/iptrunk/test_migrate_iptrunk.py +++ b/test/workflows/iptrunk/test_migrate_iptrunk.py @@ -40,7 +40,7 @@ def test_migrate_iptrunk_success( mock_provision_ip_trunk, mock_migrate_ip_trunk, iptrunk_subscription_factory, - router_subscription_factory, + nokia_router_subscription_factory, faker, data_config_filename: PathLike, ): @@ -57,7 +57,7 @@ def test_migrate_iptrunk_success( product_id = iptrunk_subscription_factory() old_subscription = Iptrunk.from_subscription(product_id) - new_router = router_subscription_factory() + new_router = nokia_router_subscription_factory() # Run workflow migrate_form_input = [ diff --git a/test/workflows/router/test_create_router.py b/test/workflows/router/test_create_router.py index 460541a81b11a049aeccfdc307336434e35b7ff6..23a09ed744b7f0858d367b0aa7ff1bc68fa480a3 100644 --- a/test/workflows/router/test_create_router.py +++ b/test/workflows/router/test_create_router.py @@ -4,8 +4,8 @@ import pytest from infoblox_client import objects from gso.products import ProductType, Site -from gso.products.product_blocks.router import RouterRole, RouterVendor -from gso.products.product_types.router import Router +from gso.products.product_blocks.router import RouterRole +from gso.products.product_types.router import Router, RouterVendor from gso.services.crm import customer_selector, get_customer_by_name from gso.services.subscriptions import get_product_id_by_name from test.workflows import ( @@ -27,7 +27,7 @@ def router_creation_input_form_data(site_subscription_factory, faker): "router_site": router_site, "hostname": faker.pystr(), "ts_port": faker.pyint(), - "router_vendor": RouterVendor.NOKIA, + "vendor": RouterVendor.NOKIA, "router_role": faker.random_choices(elements=(RouterRole.P, RouterRole.PE, RouterRole.AMT), length=1)[0], "is_ias_connected": True, } @@ -42,7 +42,7 @@ def router_creation_input_form_data(site_subscription_factory, faker): @patch("gso.workflows.router.create_router.infoblox.allocate_v6_network") @patch("gso.workflows.router.create_router.infoblox.allocate_v4_network") @patch("gso.workflows.router.create_router.infoblox.allocate_host") -def test_create_router_success( +def test_create_nokia_router_success( mock_allocate_host, mock_allocate_v4_network, mock_allocate_v6_network, @@ -56,7 +56,7 @@ def test_create_router_success( data_config_filename, ): # Set up mock return values - product_id = get_product_id_by_name(ProductType.ROUTER) + product_id = get_product_id_by_name(ProductType.NOKIA_ROUTER) mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site mock_v4 = faker.ipv4() mock_v4_net = faker.ipv4_network() @@ -127,7 +127,7 @@ def test_create_router_success( @patch("gso.workflows.router.create_router.infoblox.allocate_v6_network") @patch("gso.workflows.router.create_router.infoblox.allocate_v4_network") @patch("gso.workflows.router.create_router.infoblox.allocate_host") -def test_create_router_lso_failure( +def test_create_nokia_router_lso_failure( mock_allocate_host, mock_allocate_v4_network, mock_allocate_v6_network, @@ -176,7 +176,7 @@ def test_create_router_lso_failure( ) # Run workflow - product_id = get_product_id_by_name(ProductType.ROUTER) + product_id = get_product_id_by_name(ProductType.NOKIA_ROUTER) initial_router_data = [{"product": product_id}, router_creation_input_form_data] result, process_stat, step_log = run_workflow("create_router", initial_router_data) diff --git a/test/workflows/router/test_terminate_router.py b/test/workflows/router/test_terminate_router.py index 1e585a5c70644b1f4736d9ca4b3876f8e16c2021..1b47d79fb4e3fd76819d12c8033d7977645e7655 100644 --- a/test/workflows/router/test_terminate_router.py +++ b/test/workflows/router/test_terminate_router.py @@ -20,12 +20,12 @@ def test_terminate_router_success( mock_delete_host_by_ip, mock_delete_device, router_termination_input_form_data, - router_subscription_factory, + nokia_router_subscription_factory, faker, data_config_filename, ): # Set up active subscription in database - product_id = router_subscription_factory() + product_id = nokia_router_subscription_factory() # Run workflow initial_router_data = [{"subscription_id": product_id}, router_termination_input_form_data] diff --git a/test/workflows/site/test_create_site.py b/test/workflows/site/test_create_site.py index c553d80a677aa0a2c3bbfc69b1ac03504ca5fe04..c019b2a72883c861207c01c74a9be59c63cef111 100644 --- a/test/workflows/site/test_create_site.py +++ b/test/workflows/site/test_create_site.py @@ -47,8 +47,8 @@ def test_site_name_is_incorrect(responses, faker): The site name is a string with 3 upper case letter and one digit. Like: AMS, LON, LON1...LON 9. - This test checks a invalid string for site name. - The validation should throw an exception in case of a invalid string. + This test checks an invalid string for site name. + The validation should throw an exception in case of an invalid string. """ invalid_site_name = "AMST10" expected_exception_msg = f"Enter a valid site name similar looks like AMS, AMS1or LON9. Get: {invalid_site_name}" @@ -71,5 +71,5 @@ def test_site_name_is_incorrect(responses, faker): ] with pytest.raises(FormValidationError) as test_exception: - result, process, step_log = run_workflow("create_site", initial_site_data) + run_workflow("create_site", initial_site_data) assert str(test_exception.value) == expected_exception_msg