From 3f47469ed449eb5f9e9ab0c2bfd6876666142026 Mon Sep 17 00:00:00 2001
From: Karel van Klink <karel.vanklink@geant.org>
Date: Fri, 24 Nov 2023 17:27:42 +0100
Subject: [PATCH] revert changes to the router model

vendor is moved back into the router product block
---
 gso/api/v1/imports.py                         |  3 +-
 ...-21_6dbd6c4c04b4_add_ip_trunk_workflows.py |  2 +-
 ...11-21_815033570ad7_add_router_workflows.py |  2 +-
 ...pdate_router_model_vendor_from_type_to_.py | 80 +++++++++++++++++++
 gso/products/__init__.py                      |  7 +-
 gso/products/product_blocks/router.py         | 11 +++
 gso/products/product_types/router.py          | 11 ---
 gso/utils/helpers.py                          |  7 +-
 gso/workflows/iptrunk/create_iptrunk.py       |  3 +-
 gso/workflows/iptrunk/migrate_iptrunk.py      | 14 ++--
 .../iptrunk/modify_trunk_interface.py         |  2 +-
 gso/workflows/iptrunk/terminate_iptrunk.py    |  2 +-
 gso/workflows/router/create_router.py         |  8 +-
 gso/workflows/router/terminate_router.py      |  6 +-
 gso/workflows/tasks/import_router.py          | 16 ++--
 test/fixtures.py                              |  5 +-
 test/imports/test_imports.py                  |  3 +-
 test/utils/test_helpers.py                    |  8 +-
 test/workflows/router/test_create_router.py   |  7 +-
 19 files changed, 139 insertions(+), 58 deletions(-)
 create mode 100644 gso/migrations/versions/2023-11-24_0c904cf0b66b_update_router_model_vendor_from_type_to_.py

diff --git a/gso/api/v1/imports.py b/gso/api/v1/imports.py
index 639443b0..f297e249 100644
--- a/gso/api/v1/imports.py
+++ b/gso/api/v1/imports.py
@@ -12,9 +12,8 @@ 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
+from gso.products.product_blocks.router import RouterRole, RouterVendor
 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-11-21_6dbd6c4c04b4_add_ip_trunk_workflows.py b/gso/migrations/versions/2023-11-21_6dbd6c4c04b4_add_ip_trunk_workflows.py
index ef2e8c5f..14165a6f 100644
--- a/gso/migrations/versions/2023-11-21_6dbd6c4c04b4_add_ip_trunk_workflows.py
+++ b/gso/migrations/versions/2023-11-21_6dbd6c4c04b4_add_ip_trunk_workflows.py
@@ -10,7 +10,7 @@ from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = '6dbd6c4c04b4'
-down_revision = '815033570ad7'
+down_revision = '0c31b60487c8'
 branch_labels = None
 depends_on = None
 
diff --git a/gso/migrations/versions/2023-11-21_815033570ad7_add_router_workflows.py b/gso/migrations/versions/2023-11-21_815033570ad7_add_router_workflows.py
index c9f06237..02cb440d 100644
--- a/gso/migrations/versions/2023-11-21_815033570ad7_add_router_workflows.py
+++ b/gso/migrations/versions/2023-11-21_815033570ad7_add_router_workflows.py
@@ -10,7 +10,7 @@ from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = '815033570ad7'
-down_revision = '0c31b60487c8'
+down_revision = '0c904cf0b66b'
 branch_labels = None
 depends_on = None
 
diff --git a/gso/migrations/versions/2023-11-24_0c904cf0b66b_update_router_model_vendor_from_type_to_.py b/gso/migrations/versions/2023-11-24_0c904cf0b66b_update_router_model_vendor_from_type_to_.py
new file mode 100644
index 00000000..7eeb74aa
--- /dev/null
+++ b/gso/migrations/versions/2023-11-24_0c904cf0b66b_update_router_model_vendor_from_type_to_.py
@@ -0,0 +1,80 @@
+"""Update router model - vendor from type to block.
+
+Revision ID: 0c904cf0b66b
+Revises: 6dbd6c4c04b4
+Create Date: 2023-11-24 16:14:48.552842
+
+"""
+import sqlalchemy as sa
+from alembic import op
+
+# revision identifiers, used by Alembic.
+revision = '0c904cf0b66b'
+down_revision = '6dbd6c4c04b4'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+    conn = op.get_bind()
+    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')
+    """))
+    conn.execute(sa.text("""
+INSERT INTO products (name, description, product_type, tag, status) VALUES ('Router', 'A Router', 'Router', 'RTR', 'active') RETURNING products.product_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('vendor', 'Router vendor') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('Router')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock')))
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('vendor')))
+    """))
+
+
+def downgrade() -> None:
+    conn = op.get_bind()
+    conn.execute(sa.text("""
+DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('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 ('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 ('vendor'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM resource_types WHERE resource_types.resource_type IN ('vendor')
+    """))
+    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 ('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 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')
+    """))
diff --git a/gso/products/__init__.py b/gso/products/__init__.py
index a9885110..bd721395 100644
--- a/gso/products/__init__.py
+++ b/gso/products/__init__.py
@@ -16,18 +16,15 @@ from gso.products.product_types.site import Site
 class ProductType(strEnum):
     """An enumerator of available products in :term:`GSO`."""
 
-    SITE = "Site"
-    NOKIA_ROUTER = "Nokia router"
-    JUNIPER_ROUTER = "Juniper router"
     IP_TRUNK = "IP trunk"
     ROUTER = "Router"
+    SITE = "Site"
 
 
 SUBSCRIPTION_MODEL_REGISTRY.update(
     {
         "IP trunk": Iptrunk,
-        "Juniper router": Router,
-        "Nokia router": Router,
+        "Router": Router,
         "Site": Site,
     },
 )
diff --git a/gso/products/product_blocks/router.py b/gso/products/product_blocks/router.py
index fa52b3a0..b3f9e1e9 100644
--- a/gso/products/product_blocks/router.py
+++ b/gso/products/product_blocks/router.py
@@ -21,6 +21,13 @@ class RouterRole(strEnum):
     AMT = "amt"
 
 
+class RouterVendor(strEnum):
+    """Enumerator for the different product vendors that are supported."""
+
+    JUNIPER = "juniper"
+    NOKIA = "nokia"
+
+
 class PortNumber(ConstrainedInt):
     """Constrained integer for valid port numbers.
 
@@ -46,6 +53,7 @@ class RouterBlockInactive(
     router_lo_iso_address: str | None = None
     router_role: RouterRole | None = None
     router_site: SiteBlockInactive | None
+    vendor: RouterVendor | None = None
 
 
 def generate_fqdn(hostname: str, site_name: str, country_code: str) -> str:
@@ -64,6 +72,7 @@ class RouterBlockProvisioning(RouterBlockInactive, lifecycle=[SubscriptionLifecy
     router_lo_iso_address: str | None = None
     router_role: RouterRole | None = None
     router_site: SiteBlockProvisioning | None
+    vendor: RouterVendor
 
 
 class RouterBlock(RouterBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
@@ -85,3 +94,5 @@ class RouterBlock(RouterBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTI
     router_role: RouterRole
     #:  The :class:`Site` that this router resides in. Both physically and computationally.
     router_site: SiteBlock
+    #:  The vendor of a router.
+    vendor: RouterVendor
diff --git a/gso/products/product_types/router.py b/gso/products/product_types/router.py
index dfcf8ba5..d6a59c12 100644
--- a/gso/products/product_types/router.py
+++ b/gso/products/product_types/router.py
@@ -2,7 +2,6 @@
 
 from orchestrator.domain.base import SubscriptionModel
 from orchestrator.types import SubscriptionLifecycle
-from pydantic_forms.types import strEnum
 
 from gso.products.product_blocks.router import (
     RouterBlock,
@@ -11,29 +10,19 @@ from gso.products.product_blocks.router import (
 )
 
 
-class RouterVendor(strEnum):
-    """Enumerator for the different product vendors that are supported."""
-
-    JUNIPER = "juniper"
-    NOKIA = "nokia"
-
-
 class RouterInactive(SubscriptionModel, is_base=True):
     """An inactive router."""
 
-    vendor: RouterVendor
     router: RouterBlockInactive
 
 
 class RouterProvisioning(RouterInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
     """A router that is being provisioned."""
 
-    vendor: RouterVendor
     router: RouterBlockProvisioning
 
 
 class Router(RouterProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
     """A router that is currently active."""
 
-    vendor: RouterVendor
     router: RouterBlock
diff --git a/gso/utils/helpers.py b/gso/utils/helpers.py
index 04dfda72..d41d19c4 100644
--- a/gso/utils/helpers.py
+++ b/gso/utils/helpers.py
@@ -12,8 +12,9 @@ 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, RouterVendor
+from gso.products.product_types.router import Router
 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
@@ -122,7 +123,7 @@ def get_router_vendor(router_id: UUID) -> RouterVendor:
     :return: The vendor of the router.
     :rtype: RouterVendor:
     """
-    return Router.from_subscription(router_id).vendor
+    return Router.from_subscription(router_id).router.vendor
 
 
 def iso_from_ipv4(ipv4_address: IPv4Address) -> str:
@@ -149,7 +150,7 @@ def validate_router_in_netbox(subscription_id: UUIDstr) -> UUIDstr:
     :rtype: :class:`UUIDstr`
     """
     router_type = Router.from_subscription(subscription_id)
-    if router_type.vendor == RouterVendor.NOKIA:
+    if router_type.router.vendor == RouterVendor.NOKIA:
         device = NetboxClient().get_device_by_name(router_type.router.router_fqdn)
         if not device:
             msg = "The selected router does not exist in Netbox."
diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py
index 8b44b451..e488fde3 100644
--- a/gso/workflows/iptrunk/create_iptrunk.py
+++ b/gso/workflows/iptrunk/create_iptrunk.py
@@ -17,8 +17,9 @@ from gso.products.product_blocks.iptrunk import (
     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, RouterVendor
+from gso.products.product_types.router import Router
 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 24b036ba..8dade268 100644
--- a/gso/workflows/iptrunk/migrate_iptrunk.py
+++ b/gso/workflows/iptrunk/migrate_iptrunk.py
@@ -24,8 +24,9 @@ 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, RouterVendor
+from gso.products.product_types.router import Router
 from gso.services import provisioning_proxy
 from gso.services.netbox_client import NetboxClient
 from gso.services.provisioning_proxy import pp_interaction
@@ -493,16 +494,15 @@ def reserve_interfaces_in_netbox(
     new_lag_member_interfaces: list[dict],
 ) -> State:
     """Reserve new interfaces in Netbox."""
-    new_side_type = Router.from_subscription(new_node)
-    new_side_router = new_side_type.router
+    new_side = Router.from_subscription(new_node).router
 
     nbclient = NetboxClient()
-    if new_side_type.vendor == RouterVendor.NOKIA:
+    if new_side.vendor == RouterVendor.NOKIA:
         # Create :term:`LAG` interfaces
         lag_interface: Interfaces = nbclient.create_interface(
             iface_name=new_lag_interface,
             interface_type="lag",
-            device_name=new_side_router.router_fqdn,
+            device_name=new_side.router_fqdn,
             description=str(subscription.subscription_id),
             enabled=True,
         )
@@ -510,13 +510,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.router_fqdn,
+                device_name=new_side.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.router_fqdn,
+                device_name=new_side.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 34873f75..07c8b9de 100644
--- a/gso/workflows/iptrunk/modify_trunk_interface.py
+++ b/gso/workflows/iptrunk/modify_trunk_interface.py
@@ -18,8 +18,8 @@ from gso.products.product_blocks.iptrunk import (
     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
diff --git a/gso/workflows/iptrunk/terminate_iptrunk.py b/gso/workflows/iptrunk/terminate_iptrunk.py
index a380897d..8f8d8d41 100644
--- a/gso/workflows/iptrunk/terminate_iptrunk.py
+++ b/gso/workflows/iptrunk/terminate_iptrunk.py
@@ -15,8 +15,8 @@ from orchestrator.workflows.steps import (
 )
 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 RouterVendor
 from gso.services import infoblox, provisioning_proxy
 from gso.services.netbox_client import NetboxClient
 from gso.services.provisioning_proxy import pp_interaction
diff --git a/gso/workflows/router/create_router.py b/gso/workflows/router/create_router.py
index 96312173..4cb22261 100644
--- a/gso/workflows/router/create_router.py
+++ b/gso/workflows/router/create_router.py
@@ -15,9 +15,10 @@ 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, RouterVendor
+from gso.products.product_types.router import RouterInactive, RouterProvisioning
 from gso.products.product_types.site import Site
 from gso.services import infoblox, provisioning_proxy, subscriptions
 from gso.services.crm import customer_selector
@@ -44,6 +45,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
 
         tt_number: str
         customer: customer_selector()  # type: ignore[valid-type]
+        vendor: RouterVendor
         router_site: _site_selector()  # type: ignore[valid-type]
         hostname: str
         ts_port: PortNumber
@@ -87,6 +89,7 @@ def initialize_subscription(
     ts_port: PortNumber,
     router_site: str,
     router_role: RouterRole,
+    vendor: RouterVendor,
 ) -> State:
     """Initialise the subscription object in the service database."""
     subscription.router.router_ts_port = ts_port
@@ -99,6 +102,7 @@ def initialize_subscription(
     subscription.router.router_fqdn = fqdn
     subscription.router.router_role = router_role
     subscription.router.router_access_via_ts = True
+    subscription.router.vendor = vendor
     subscription.description = f"Router {fqdn}"
 
     subscription = RouterProvisioning.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING)
@@ -151,7 +155,7 @@ def create_netbox_device(subscription: RouterProvisioning) -> State:
 
     HACK: use a conditional instead for execution of this step
     """
-    if subscription.vendor == RouterVendor.NOKIA:
+    if subscription.router.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 b19e92c6..b258cf76 100644
--- a/gso/workflows/router/terminate_router.py
+++ b/gso/workflows/router/terminate_router.py
@@ -16,7 +16,8 @@ from orchestrator.workflows.steps import (
 )
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
 
-from gso.products.product_types.router import Router, RouterVendor
+from gso.products.product_blocks.router import RouterVendor
+from gso.products.product_types.router import Router
 from gso.services import infoblox
 from gso.services.netbox_client import NetboxClient
 
@@ -60,7 +61,8 @@ def remove_config_from_router() -> None:
 @step("Remove Device from NetBox")
 def remove_device_from_netbox(subscription: Router) -> dict[str, Router]:
     """Remove the device from Netbox."""
-    if subscription.vendor == RouterVendor.NOKIA:
+    if subscription.router.vendor == RouterVendor.NOKIA:
+        #  TODO: This should be solved with a conditional
         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 ea3d6acf..3d00a609 100644
--- a/gso/workflows/tasks/import_router.py
+++ b/gso/workflows/tasks/import_router.py
@@ -1,7 +1,6 @@
 """A creation workflow that adds an existing router to the service database."""
 
 import ipaddress
-from uuid import UUID
 
 from orchestrator import workflow
 from orchestrator.forms import FormPage
@@ -12,9 +11,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, generate_fqdn
+from gso.products.product_blocks.router import PortNumber, RouterRole, RouterVendor, generate_fqdn
 from gso.products.product_types import router
-from gso.products.product_types.router import RouterInactive, RouterVendor
+from gso.products.product_types.router import RouterInactive
 from gso.products.product_types.site import Site
 from gso.services import subscriptions
 from gso.services.crm import get_customer_by_name
@@ -35,15 +34,10 @@ def _get_site_by_name(site_name: str) -> Site:
 
 
 @step("Create subscription")
-def create_subscription(customer: str, router_vendor: RouterVendor) -> State:
+def create_subscription(customer: str) -> State:
     """Create a new subscription object."""
     customer_id = get_customer_by_name(customer)["id"]
-    product_id: UUID
-    if router_vendor == RouterVendor.NOKIA:
-        product_id = subscriptions.get_product_id_by_name(ProductType.NOKIA_ROUTER)
-    elif router_vendor == RouterVendor.JUNIPER:
-        product_id = subscriptions.get_product_id_by_name(ProductType.JUNIPER_ROUTER)
-
+    product_id = subscriptions.get_product_id_by_name(ProductType.ROUTER)
     subscription = RouterInactive.from_product_id(product_id, customer_id)
 
     return {
@@ -81,6 +75,7 @@ def initialize_subscription(
     ts_port: PortNumber,
     router_site: str,
     router_role: router_pb.RouterRole,
+    router_vendor: RouterVendor,
     router_lo_ipv4_address: ipaddress.IPv4Address | None = None,
     router_lo_ipv6_address: ipaddress.IPv6Address | None = None,
     router_lo_iso_address: str | None = None,
@@ -97,6 +92,7 @@ def initialize_subscription(
     subscription.router.router_lo_ipv4_address = router_lo_ipv4_address
     subscription.router.router_lo_ipv6_address = router_lo_ipv6_address
     subscription.router.router_lo_iso_address = router_lo_iso_address
+    subscription.router.vendor = router_vendor
 
     subscription = router.RouterProvisioning.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING)
 
diff --git a/test/fixtures.py b/test/fixtures.py
index 786d1842..9827735b 100644
--- a/test/fixtures.py
+++ b/test/fixtures.py
@@ -12,7 +12,7 @@ from gso.products.product_blocks.iptrunk import (
     IptrunkType,
     PhyPortCapacity,
 )
-from gso.products.product_blocks.router import RouterRole
+from gso.products.product_blocks.router import RouterRole, RouterVendor
 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
@@ -97,7 +97,7 @@ def nokia_router_subscription_factory(site_subscription_factory, faker):
         router_lo_iso_address = router_lo_iso_address or faker.word()
         router_site = router_site or site_subscription_factory()
 
-        product_id = subscriptions.get_product_id_by_name(ProductType.NOKIA_ROUTER)
+        product_id = subscriptions.get_product_id_by_name(ProductType.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
@@ -107,6 +107,7 @@ def nokia_router_subscription_factory(site_subscription_factory, faker):
         router_subscription.router.router_lo_iso_address = router_lo_iso_address
         router_subscription.router.router_role = router_role
         router_subscription.router.router_site = Site.from_subscription(router_site).site
+        router_subscription.router.vendor = RouterVendor.NOKIA
 
         router_subscription = SubscriptionModel.from_other_lifecycle(router_subscription, SubscriptionLifecycle.ACTIVE)
         router_subscription.description = description
diff --git a/test/imports/test_imports.py b/test/imports/test_imports.py
index 1d7801e2..7fda2def 100644
--- a/test/imports/test_imports.py
+++ b/test/imports/test_imports.py
@@ -6,9 +6,8 @@ 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
+from gso.products.product_blocks.router import RouterRole, RouterVendor
 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"
diff --git a/test/utils/test_helpers.py b/test/utils/test_helpers.py
index a0f77451..d5fb2282 100644
--- a/test/utils/test_helpers.py
+++ b/test/utils/test_helpers.py
@@ -3,7 +3,7 @@ from unittest.mock import patch
 import pytest
 
 from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock
-from gso.products.product_types.router import RouterVendor
+from gso.products.product_blocks.router import RouterVendor
 from gso.utils.helpers import available_interfaces_choices_including_current_members
 
 
@@ -22,20 +22,20 @@ def mock_netbox_client():
 
 
 def test_non_nokia_router_returns_none(mock_router, faker):
-    mock_router.from_subscription.return_value.vendor = RouterVendor.JUNIPER
+    mock_router.from_subscription.return_value.router.vendor = RouterVendor.JUNIPER
     result = available_interfaces_choices_including_current_members(faker.uuid4(), "10G", [])
     assert result is None
 
 
 def test_nokia_router_with_no_interfaces_returns_empty_choice(mock_router, mock_netbox_client, faker):
-    mock_router.from_subscription.return_value.vendor = RouterVendor.NOKIA
+    mock_router.from_subscription.return_value.router.vendor = RouterVendor.NOKIA
     mock_netbox_client().get_available_interfaces.return_value = iter([])
     result = available_interfaces_choices_including_current_members(faker.uuid4(), "10G", [])
     assert len(result) == 0
 
 
 def test_nokia_router_with_interfaces_returns_choice(mock_router, mock_netbox_client, faker):
-    mock_router.from_subscription.return_value.vendor = RouterVendor.NOKIA
+    mock_router.from_subscription.return_value.router.vendor = RouterVendor.NOKIA
     mock_netbox_client().get_available_interfaces.return_value = iter(
         [
             {"name": "interface1", "module": {"display": "module1"}, "description": "desc1"},
diff --git a/test/workflows/router/test_create_router.py b/test/workflows/router/test_create_router.py
index 3926fa33..71929a91 100644
--- a/test/workflows/router/test_create_router.py
+++ b/test/workflows/router/test_create_router.py
@@ -4,7 +4,7 @@ import pytest
 from infoblox_client import objects
 
 from gso.products import ProductType, Site
-from gso.products.product_blocks.router import RouterRole
+from gso.products.product_blocks.router import RouterRole, RouterVendor
 from gso.products.product_types.router import Router
 from gso.services.crm import customer_selector, get_customer_by_name
 from gso.services.subscriptions import get_product_id_by_name
@@ -28,6 +28,7 @@ def router_creation_input_form_data(site_subscription_factory, faker):
         "hostname": faker.pystr(),
         "ts_port": faker.pyint(),
         "router_role": faker.random_choices(elements=(RouterRole.P, RouterRole.PE, RouterRole.AMT), length=1)[0],
+        "vendor": RouterVendor.NOKIA,
     }
 
 
@@ -48,7 +49,7 @@ def test_create_nokia_router_success(
     data_config_filename,
 ):
     #  Set up mock return values
-    product_id = get_product_id_by_name(ProductType.NOKIA_ROUTER)
+    product_id = get_product_id_by_name(ProductType.ROUTER)
     mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site
     mock_v4 = faker.ipv4()
     mock_v6 = faker.ipv6()
@@ -156,7 +157,7 @@ def test_create_nokia_router_lso_failure(
     )
 
     #  Run workflow
-    product_id = get_product_id_by_name(ProductType.NOKIA_ROUTER)
+    product_id = get_product_id_by_name(ProductType.ROUTER)
     initial_router_data = [{"product": product_id}, router_creation_input_form_data]
     result, process_stat, step_log = run_workflow("create_router", initial_router_data)
 
-- 
GitLab