From d21c44bd7aa0af8e1d7dda5a39c3fd303296578c Mon Sep 17 00:00:00 2001 From: Neda Moeini <neda.moeini@geant.org> Date: Mon, 17 Feb 2025 15:38:13 +0100 Subject: [PATCH] Product block and type - 10GGBS - WIP --- gso/products/__init__.py | 8 +++ gso/products/product_blocks/tenggbs.py | 92 ++++++++++++++++++++++++++ gso/products/product_types/tenggbs.py | 42 ++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 gso/products/product_blocks/tenggbs.py create mode 100644 gso/products/product_types/tenggbs.py diff --git a/gso/products/__init__.py b/gso/products/__init__.py index a1f5c1936..fd8c097fb 100644 --- a/gso/products/__init__.py +++ b/gso/products/__init__.py @@ -21,6 +21,7 @@ from gso.products.product_types.site import ImportedSite, Site from gso.products.product_types.super_pop_switch import ImportedSuperPopSwitch, SuperPopSwitch from gso.products.product_types.switch import ImportedSwitch, Switch from gso.products.product_types.vrf import VRF +from gso.products.product_types.tenggbs import TenGGBS, ImportedTenGGBS class ProductName(strEnum): @@ -78,6 +79,9 @@ class ProductName(strEnum): IMPORTED_EXPRESSROUTE = Layer2CircuitServiceType.IMPORTED_EXPRESSROUTE VRF = "VRF" """VRFs.""" + TenGGBS = "TenGGBS" + """10GGBS.""" + IMPORTED_TenGGBS = "Imported TenGGBS" L3_CORE_SERVICE_PRODUCT_TYPE = L3CoreService.__name__ @@ -121,6 +125,8 @@ class ProductType(strEnum): EXPRESSROUTE = L2_CIRCUIT_PRODUCT_TYPE IMPORTED_EXPRESSROUTE = ImportedLayer2Circuit.__name__ VRF = VRF.__name__ + TenGGBS = TenGGBS.__name__ + IMPORTED_TenGGBS = ImportedTenGGBS.__name__ SUBSCRIPTION_MODEL_REGISTRY.update( @@ -159,6 +165,8 @@ SUBSCRIPTION_MODEL_REGISTRY.update( ProductName.EXPRESSROUTE.value: Layer2Circuit, ProductName.IMPORTED_EXPRESSROUTE.value: ImportedLayer2Circuit, ProductName.VRF.value: VRF, + ProductName.TenGGBS.value: TenGGBS, + ProductName.IMPORTED_TenGGBS.value: ImportedTenGGBS, }, ) diff --git a/gso/products/product_blocks/tenggbs.py b/gso/products/product_blocks/tenggbs.py new file mode 100644 index 000000000..bc9c7d15c --- /dev/null +++ b/gso/products/product_blocks/tenggbs.py @@ -0,0 +1,92 @@ +"""10GGBS product block models.""" +from typing import Annotated, TypeVar + +from annotated_types import Len +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle +from orchestrator.types import strEnum +from pydantic import AfterValidator +from pydantic_forms.validators import validate_unique_list +from typing_extensions import Doc + +from gso.products.product_blocks.iptrunk import ( + IptrunkSideBlock, + IptrunkSideBlockInactive, + IptrunkSideBlockProvisioning, +) +from gso.products.product_blocks.layer_2_circuit import ( + Layer2CircuitBlock, + Layer2CircuitBlockInactive, + Layer2CircuitBlockProvisioning, +) + +T = TypeVar("T") + + +class PathRole(strEnum): + """Defines path role types.""" + PRIMARY = "Primary" + """Primary path.""" + SECONDARY = "Secondary" + """Secondary path.""" + + +Paths = Annotated[ + list[T], + AfterValidator(validate_unique_list), + Len(min_length=0), + Doc("A list of TrunkSideBlocks that make up a path."), +] + + +class PathBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="PathBlock" +): + """A path representing an ordered list of adjacent trunk sides.""" + + role: PathRole | None = None + path: Paths[IptrunkSideBlockInactive] + + +class PathBlockProvisioning(PathBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A path that is being provisioned.""" + + role: PathRole | None = None + path: Paths[IptrunkSideBlockProvisioning] + + +class PathBlock(PathBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """An active path.""" + + role: PathRole + path: Paths[IptrunkSideBlock] + + +PathsList = Annotated[ + list[T], + AfterValidator(validate_unique_list), + Doc("A list of paths (1 primary, multiple secondary)."), +] + + +class TenGGBSBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="TenGGBSBlock" +): + """Inactive 10GGBS service model.""" + + l2_circuit: Layer2CircuitBlockInactive + paths: PathsList[PathBlockInactive] | None = None + + +class TenGGBSBlockProvisioning(TenGGBSBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """Provisioning state of 10GGBS.""" + + l2_circuit: Layer2CircuitBlockProvisioning + paths: PathsList[PathBlockProvisioning] | None = None + + +class TenGGBSBlock(TenGGBSBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """Active 10GGBS service model.""" + + l2_circuit: Layer2CircuitBlock + paths: PathsList[PathBlock] | None = None diff --git a/gso/products/product_types/tenggbs.py b/gso/products/product_types/tenggbs.py new file mode 100644 index 000000000..ca7645723 --- /dev/null +++ b/gso/products/product_types/tenggbs.py @@ -0,0 +1,42 @@ +"""The product type for 10GGBS services.""" + +from orchestrator.domain.base import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.tenggbs import ( + TenGGBSBlock, + TenGGBSBlockInactive, + TenGGBSBlockProvisioning, +) + + +class TenGGBSInactive(SubscriptionModel, is_base=True): + """A 10GGBS service that is inactive.""" + + tenggbs: TenGGBSBlockInactive + + +class TenGGBSProvisioning(TenGGBSInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A 10GGBS service that is being provisioned.""" + + tenggbs: TenGGBSBlockProvisioning + + +class TenGGBS(TenGGBSProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A 10GGBS service that is active.""" + + tenggbs: TenGGBSBlock + + +class ImportedTenGGBSInactive(SubscriptionModel, is_base=True): + """An imported 10GGBS service that is inactive.""" + + tenggbs: TenGGBSBlockInactive + + +class ImportedTenGGBS( + ImportedTenGGBSInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE] +): + """An imported 10GGBS service that is active.""" + + tenggbs: TenGGBSBlock -- GitLab