From 0c6ac0a6c304899bd3d7756438b8e71d64e3946a Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Thu, 31 Oct 2024 16:24:09 +0100
Subject: [PATCH] Add modify workflow for Layer2Circuit. WIP

---
 .../l2_circuit/modify_layer_2_circuit.py      | 117 ++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 gso/workflows/l2_circuit/modify_layer_2_circuit.py

diff --git a/gso/workflows/l2_circuit/modify_layer_2_circuit.py b/gso/workflows/l2_circuit/modify_layer_2_circuit.py
new file mode 100644
index 00000000..899035a8
--- /dev/null
+++ b/gso/workflows/l2_circuit/modify_layer_2_circuit.py
@@ -0,0 +1,117 @@
+"""A modification workflow for a Layer 2 Circuit subscription."""
+
+from orchestrator import begin, done, workflow
+from orchestrator.forms import FormPage
+from orchestrator.targets import Target
+from orchestrator.types import FormGenerator, UUIDstr
+from orchestrator.workflow import StepList, step
+from orchestrator.workflows.steps import resync, store_process_subscription, unsync
+from orchestrator.workflows.utils import wrap_modify_initial_input_form
+from pydantic import BaseModel, ConfigDict, Field
+from pydantic_forms.validators import Divider, Label, ReadOnlyField
+
+from gso.products import Layer2Circuit
+from gso.products.product_blocks.layer_2_circuit import Layer2CircuitType
+from gso.services.partners import get_partner_by_id
+from gso.utils.types.interfaces import BandwidthString
+from gso.utils.types.tt_number import TTNumber
+from gso.utils.types.virtual_identifiers import VLAN_ID
+
+
+def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
+    """Get input from the operator about the modifications to be made to a Layer 2 Circuit subscription."""
+    subscription = Layer2Circuit.from_subscription(subscription_id)
+    product_name = subscription.product.name
+
+    class ModifyL2CircuitForm(FormPage):
+        model_config = ConfigDict(title=f"Modify {product_name}")
+        tt_number: TTNumber
+        partner: ReadOnlyField(get_partner_by_id(subscription.customer_id).name, default_type=str)
+        divider: Divider = Field(None, exclude=True)
+
+        layer_2_circuit_type: Layer2CircuitType = subscription.layer_2_circuit.layer_2_circuit_type
+        policer_enabled: bool = subscription.layer_2_circuit.policer_enabled
+
+    layer_2_circuit_input = yield ModifyL2CircuitForm
+
+    class ModifyLayer2CircuitSideA(BaseModel):
+        edge_port: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.edge_port.edge_port_name,
+                                 default_type=str)
+        geant_sid: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.geant_sid, default_type=str)
+        is_tagged: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.is_tagged, default_type=bool)
+        vlan_id: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.vlan_id, default_type=int)
+        custom_firewall_filters: ReadOnlyField(
+            subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.custom_firewall_filters, default_type=bool)
+
+    class ModifyLayer2CircuitSideB(BaseModel):
+        edge_port: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.edge_port.edge_port_name,
+                                 default_type=str)
+        geant_sid: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.geant_sid, default_type=str)
+        is_tagged: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.is_tagged, default_type=bool)
+        vlan_id: ReadOnlyField(subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.vlan_id, default_type=int)
+        custom_firewall_filters: ReadOnlyField(
+            subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.custom_firewall_filters, default_type=bool)
+
+    class ModifyLayer2CircuitServiceSidesPage(FormPage):
+        model_config = ConfigDict(title=f"{product_name} - Configure Edge Ports")
+
+        if layer_2_circuit_input.layer_2_circuit_type == Layer2CircuitType.TAGGED:
+            vlan_range_label: Label = Field("Please set a VLAN range, bounds including.", exclude=True)
+            vlan_range_lower_bound: VLAN_ID
+            vlan_range_upper_bound: VLAN_ID
+        else:
+            vlan_range_lower_bound: ReadOnlyField(None, default_type=int)
+            vlan_range_upper_bound: ReadOnlyField(None, default_type=int)
+
+        vlan_divider: Divider = Field(None, exclude=True)
+
+        if layer_2_circuit_input.policer_enabled:
+            policer_bandwidth: BandwidthString
+        else:
+            policer_bandwidth: ReadOnlyField(None, default_type=str)
+
+        policer_divider: Divider = Field(None, exclude=True)
+
+        layer_2_circuit_side_a: ModifyLayer2CircuitSideA
+        side_divider: Divider = Field(None, exclude=True)
+        layer_2_circuit_side_b: ModifyLayer2CircuitSideB
+
+    layer_2_circuit_sides = yield ModifyLayer2CircuitServiceSidesPage
+
+    return {"product_name": product_name} | layer_2_circuit_input.model_dump() | layer_2_circuit_sides.model_dump()
+
+
+@step("Update Layer 2 Circuit subscription")
+def modify_layer_2_circuit_subscription(
+        subscription: Layer2Circuit,
+        layer_2_circuit_type: Layer2CircuitType,
+        vlan_range_lower_bound: VLAN_ID | None,
+        vlan_range_upper_bound: VLAN_ID | None,
+        policer_enabled: bool,  # noqa: FBT001
+        policer_bandwidth: BandwidthString | None,
+):
+    """Update the Layer 2 Circuit subscription with the new values."""
+    subscription.layer_2_circuit.layer_2_circuit_type = layer_2_circuit_type
+    subscription.layer_2_circuit.vlan_range_lower_bound = vlan_range_lower_bound
+    subscription.layer_2_circuit.vlan_range_upper_bound = vlan_range_upper_bound
+    subscription.layer_2_circuit.policer_enabled = policer_enabled
+    subscription.layer_2_circuit.bandwidth = policer_bandwidth
+
+    return {"subscription": subscription}
+
+
+@workflow(
+    "Modify Layer 2 Circuit Service",
+    initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator),
+    target=Target.MODIFY,
+)
+def modify_layer_2_circuit() -> StepList:
+    """Modify an existing Layer 2 Circuit service subscription."""
+    return (
+            begin
+            >> store_process_subscription(Target.MODIFY)
+            >> unsync
+            >> modify_layer_2_circuit_subscription
+            >> resync
+            >> done
+    )
-- 
GitLab