diff --git a/gso/workflows/l3_core_service/base_modify_l3_core_service.py b/gso/workflows/l3_core_service/base_modify_l3_core_service.py index 4b04a4c6a2bb0c19fb8189ac1dc382c4af4483ea..62f00f0fb89784329280f36eac686f3b45d23e46 100644 --- a/gso/workflows/l3_core_service/base_modify_l3_core_service.py +++ b/gso/workflows/l3_core_service/base_modify_l3_core_service.py @@ -14,6 +14,7 @@ from gso.products.product_blocks.bgp_session import BGPSession, IPFamily, IPType from gso.products.product_blocks.l3_core_service import AccessPort from gso.products.product_blocks.service_binding_port import BFDSettings, ServiceBindingPort from gso.products.product_types.edge_port import EdgePort +from gso.services.partners import get_partner_by_id from gso.services.subscriptions import generate_unique_id, get_active_edge_port_subscriptions from gso.utils.helpers import partner_choice from gso.utils.shared_enums import APType, SBPType @@ -226,6 +227,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: user_input = yield AddAccessPortForm return { "operation": initial_input.operation, + "tt_number": initial_input.tt_number, "added_access_port": user_input.model_dump(), } @@ -243,6 +245,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: user_input = yield RemoveAccessPortForm return { "operation": initial_input.operation, + "tt_number": initial_input.tt_number, "removed_access_port": user_input.access_port, } @@ -373,6 +376,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: return { "operation": initial_input.operation, "modified_access_port": user_input.access_port, + "tt_number": initial_input.tt_number, "modified_sbp": binding_port_input_form.model_dump(), } @@ -464,3 +468,17 @@ def modify_existing_sbp( current_ap.custom_service_name = modified_sbp["custom_service_name"] return {"subscription": subscription} + + +@step("Populate partner name and edge port FQDN list") +def populate_partner_and_fqdn(subscription: SubscriptionModel) -> dict[str, Any]: + """Populate the partner name and a list of edge port FQDNs for the subscription.""" + edge_port_fqdn_list = [ + ap.sbp.edge_port.node.router_fqdn + for ap in subscription.l3_core.ap_list # type: ignore[attr-defined] + ] + partner_name = get_partner_by_id(subscription.customer_id).name + return { + "edge_port_fqdn_list": edge_port_fqdn_list, + "partner_name": partner_name, + } diff --git a/gso/workflows/l3_core_service/geant_ip/modify_geant_ip.py b/gso/workflows/l3_core_service/geant_ip/modify_geant_ip.py index a2b07c08fceccd7fdeb073be48f16042e97e6c02..a3904e253e523e80850a4183c44f8c29c55bdc59 100644 --- a/gso/workflows/l3_core_service/geant_ip/modify_geant_ip.py +++ b/gso/workflows/l3_core_service/geant_ip/modify_geant_ip.py @@ -5,19 +5,42 @@ from orchestrator.targets import Target from orchestrator.workflow import StepList from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form +from pydantic_forms.core import FormPage +from pydantic_forms.types import FormGenerator, UUIDstr +from gso.services.lso_client import lso_interaction +from gso.workflows.l3_core_service.base_create_l3_core_service import ( + deploy_bgp_peers_dry, + deploy_bgp_peers_real, + provision_sbp_dry, + provision_sbp_real, +) from gso.workflows.l3_core_service.base_modify_l3_core_service import ( Operation, create_new_sbp, initial_input_form_generator, modify_existing_sbp, + populate_partner_and_fqdn, remove_old_sbp, ) +def modify_geant_ip_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: + """Generate the input form for modifying the custom attributes of an existing GÉANT IP subscription.""" + orig_form_gen = initial_input_form_generator(subscription_id) + initial_user_input = yield from orig_form_gen + + class GeantIPExtraForm(FormPage): + update_sbp_config: bool = True + update_bgp_config: bool = True + + geant_ip_extra = yield GeantIPExtraForm + return initial_user_input | geant_ip_extra.model_dump() + + @workflow( "Modify GÉANT IP", - initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator), + initial_input_form=wrap_modify_initial_input_form(modify_geant_ip_input_form_generator), target=Target.MODIFY, ) def modify_geant_ip() -> StepList: @@ -25,6 +48,8 @@ def modify_geant_ip() -> StepList: access_port_is_added = conditional(lambda state: state["operation"] == Operation.ADD) access_port_is_removed = conditional(lambda state: state["operation"] == Operation.REMOVE) access_port_is_modified = conditional(lambda state: state["operation"] == Operation.EDIT) + update_sbp = conditional(lambda state: bool(state["update_sbp_config"])) + update_bgp = conditional(lambda state: bool(state["update_bgp_config"])) return ( begin @@ -33,6 +58,11 @@ def modify_geant_ip() -> StepList: >> access_port_is_added(create_new_sbp) >> access_port_is_removed(remove_old_sbp) >> access_port_is_modified(modify_existing_sbp) + >> populate_partner_and_fqdn + >> update_sbp(lso_interaction(provision_sbp_dry)) + >> update_sbp(lso_interaction(provision_sbp_real)) + >> update_bgp(lso_interaction(deploy_bgp_peers_dry)) + >> update_bgp(lso_interaction(deploy_bgp_peers_real)) >> resync >> done ) diff --git a/gso/workflows/l3_core_service/ias/modify_ias.py b/gso/workflows/l3_core_service/ias/modify_ias.py index 41425074fa5c0899237a04f5d817a23ff6373be8..1ca8b2bb6ae94413466ea18c71f4456dad873e32 100644 --- a/gso/workflows/l3_core_service/ias/modify_ias.py +++ b/gso/workflows/l3_core_service/ias/modify_ias.py @@ -10,11 +10,19 @@ from pydantic_forms.types import FormGenerator, UUIDstr from gso.products.product_blocks.ias import IASFlavor from gso.products.product_types.ias import IAS +from gso.services.lso_client import lso_interaction +from gso.workflows.l3_core_service.base_create_l3_core_service import ( + deploy_bgp_peers_dry, + deploy_bgp_peers_real, + provision_sbp_dry, + provision_sbp_real, +) from gso.workflows.l3_core_service.base_modify_l3_core_service import ( Operation, create_new_sbp, initial_input_form_generator, modify_existing_sbp, + populate_partner_and_fqdn, remove_old_sbp, ) from gso.workflows.l3_core_service.ias.shared import update_ias_subscription_model @@ -31,6 +39,8 @@ def modify_ias_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: class IASExtraForm(FormPage): # TODO: remove type hint workaround ias_flavor: IASFlavor | str = subscription.ias.ias_flavor + update_sbp_config: bool = True + update_bgp_config: bool = True ias_extra = yield IASExtraForm return initial_user_input | ias_extra.model_dump() @@ -46,7 +56,8 @@ def modify_ias() -> StepList: access_port_is_added = conditional(lambda state: state["operation"] == Operation.ADD) access_port_is_removed = conditional(lambda state: state["operation"] == Operation.REMOVE) access_port_is_modified = conditional(lambda state: state["operation"] == Operation.EDIT) - + update_sbp = conditional(lambda state: bool(state["update_sbp_config"])) + update_bgp = conditional(lambda state: bool(state["update_bgp_config"])) return ( begin >> store_process_subscription(Target.MODIFY) @@ -55,6 +66,11 @@ def modify_ias() -> StepList: >> access_port_is_added(create_new_sbp) >> access_port_is_removed(remove_old_sbp) >> access_port_is_modified(modify_existing_sbp) + >> populate_partner_and_fqdn + >> update_sbp(lso_interaction(provision_sbp_dry)) + >> update_sbp(lso_interaction(provision_sbp_real)) + >> update_bgp(lso_interaction(deploy_bgp_peers_dry)) + >> update_bgp(lso_interaction(deploy_bgp_peers_real)) >> resync >> done ) diff --git a/gso/workflows/l3_core_service/lhcone/modify_lhcone.py b/gso/workflows/l3_core_service/lhcone/modify_lhcone.py index da79e86bdef550d3a269e59302b6e3494571f7f2..5bf0559ecbcf3d95b8050dd3941922da2c6e45d9 100644 --- a/gso/workflows/l3_core_service/lhcone/modify_lhcone.py +++ b/gso/workflows/l3_core_service/lhcone/modify_lhcone.py @@ -5,19 +5,42 @@ from orchestrator.targets import Target from orchestrator.workflow import StepList from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form +from pydantic_forms.core import FormPage +from pydantic_forms.types import FormGenerator, UUIDstr +from gso.services.lso_client import lso_interaction +from gso.workflows.l3_core_service.base_create_l3_core_service import ( + deploy_bgp_peers_dry, + deploy_bgp_peers_real, + provision_sbp_dry, + provision_sbp_real, +) from gso.workflows.l3_core_service.base_modify_l3_core_service import ( Operation, create_new_sbp, initial_input_form_generator, modify_existing_sbp, + populate_partner_and_fqdn, remove_old_sbp, ) +def modify_lhcone_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: + """Generate the initial input form for modifying the custom attributes of an existing LHC One subscription.""" + orig_form_gen = initial_input_form_generator(subscription_id) + initial_user_input = yield from orig_form_gen + + class LHCOneExtraForm(FormPage): + update_sbp_config: bool = True + update_bgp_config: bool = True + + lhcone_extra = yield LHCOneExtraForm + return initial_user_input | lhcone_extra.model_dump() + + @workflow( "Modify LHCOne", - initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator), + initial_input_form=wrap_modify_initial_input_form(modify_lhcone_input_form_generator), target=Target.MODIFY, ) def modify_lhcone() -> StepList: @@ -25,6 +48,8 @@ def modify_lhcone() -> StepList: access_port_is_added = conditional(lambda state: state["operation"] == Operation.ADD) access_port_is_removed = conditional(lambda state: state["operation"] == Operation.REMOVE) access_port_is_modified = conditional(lambda state: state["operation"] == Operation.EDIT) + update_sbp = conditional(lambda state: bool(state["update_sbp_config"])) + update_bgp = conditional(lambda state: bool(state["update_bgp_config"])) return ( begin @@ -33,6 +58,11 @@ def modify_lhcone() -> StepList: >> access_port_is_added(create_new_sbp) >> access_port_is_removed(remove_old_sbp) >> access_port_is_modified(modify_existing_sbp) + >> populate_partner_and_fqdn + >> update_sbp(lso_interaction(provision_sbp_dry)) + >> update_sbp(lso_interaction(provision_sbp_real)) + >> update_bgp(lso_interaction(deploy_bgp_peers_dry)) + >> update_bgp(lso_interaction(deploy_bgp_peers_real)) >> resync >> done ) 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 e9a7df9d36f5888a9481b34aff3e3e30e606f1fc..df1f3a522360cc68756e733fec52cd5cde136d22 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 @@ -24,8 +24,16 @@ def test_modify_l3_core_service_remove_edge_port_success(faker, l3_core_service_ if product_name == ProductName.IAS: extra_ias_data = { "ias_flavor": IASFlavor.IASGWS, + "update_sbp_config": True, + "update_bgp_config": True, } input_form_data.append(extra_ias_data) + elif product_name in {ProductName.LHCONE, ProductName.GEANT_IP}: + extra_data = { + "update_sbp_config": True, + "update_bgp_config": True, + } + input_form_data.append(extra_data) elif product_name in {ProductName.R_AND_E_PEER, ProductName.R_AND_E_LHCONE}: extra_r_and_e_data = { "v6_bgp_local_preference": 5555, @@ -101,6 +109,8 @@ def test_modify_l3_core_service_add_new_edge_port_success( if product_name == ProductName.IAS: extra_ias_data = { "ias_flavor": IASFlavor.IASGWS, + "update_sbp_config": True, + "update_bgp_config": True, } input_form_data.append(extra_ias_data) elif product_name in {ProductName.R_AND_E_PEER, ProductName.R_AND_E_LHCONE}: @@ -109,6 +119,12 @@ def test_modify_l3_core_service_add_new_edge_port_success( "v6_bgp_med": "123123", } input_form_data.append(extra_r_and_e_data) + elif product_name in {ProductName.LHCONE, ProductName.GEANT_IP}: + extra_data = { + "update_sbp_config": True, + "update_bgp_config": True, + } + input_form_data.append(extra_data) result, _, _ = run_workflow(L3_MODIFICATION_WF_MAP[product_name], input_form_data) @@ -201,6 +217,8 @@ def test_modify_l3_core_service_modify_edge_port_success( # noqa: PLR0915 if product_name == ProductName.IAS: extra_ias_data = { "ias_flavor": IASFlavor.IASGWS, + "update_sbp_config": True, + "update_bgp_config": True, } input_form_data.append(extra_ias_data) elif product_name in {ProductName.R_AND_E_PEER, ProductName.R_AND_E_LHCONE}: @@ -209,6 +227,12 @@ def test_modify_l3_core_service_modify_edge_port_success( # noqa: PLR0915 "v6_bgp_med": "min-igp", } input_form_data.append(extra_r_and_e_data) + elif product_name in {ProductName.LHCONE, ProductName.GEANT_IP}: + extra_data = { + "update_sbp_config": True, + "update_bgp_config": True, + } + input_form_data.append(extra_data) result, _, _ = run_workflow(L3_MODIFICATION_WF_MAP[product_name], input_form_data)