diff --git a/gso/workflows/l2_circuit/migrate_layer_2_circuit.py b/gso/workflows/l2_circuit/migrate_layer_2_circuit.py index d6d4a8f8a7c1529385544cb96055a31ecaaa4e31..70a91e5aaaf24c274ca510bb9121e3b2ac37a882 100644 --- a/gso/workflows/l2_circuit/migrate_layer_2_circuit.py +++ b/gso/workflows/l2_circuit/migrate_layer_2_circuit.py @@ -26,7 +26,7 @@ from orchestrator.forms import FormPage, SubmitFormPage from orchestrator.forms.validators import Choice, Label from orchestrator.targets import Target from orchestrator.utils.errors import ProcessFailureError -from orchestrator.workflow import StepList, begin, done +from orchestrator.workflow import StepList, begin, conditional, done from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form from pydantic import ConfigDict, Field @@ -75,6 +75,11 @@ def input_form_generator(subscription_id: UUIDstr) -> FormGenerator: label_a: Label = Field("Are we migrating to a different site?", exclude=True) migrate_to_different_site: bool = False + label_b: Label = Field("Execute Ansible playbooks on the OLD side of the circuit?", exclude=True) + run_old_side_ansible: bool = True + label_c: Label = Field("Execute Ansible playbooks on the NEW side of the circuit?", exclude=True) + run_new_side_ansible: bool = True + initial_user_input = yield MigrateL2CircuitForm replace_side_partner = get_partner_by_id(EdgePort.from_subscription(initial_user_input.replace_side).customer_id) @@ -87,6 +92,8 @@ def input_form_generator(subscription_id: UUIDstr) -> FormGenerator: return { "tt_number": initial_user_input.tt_number, + "run_old_side_ansible": initial_user_input.run_old_side_ansible, + "run_new_side_ansible": initial_user_input.run_new_side_ansible, "subscription": subscription, "subscription_id": subscription_id, "old_edge_port": initial_user_input.replace_side, @@ -124,19 +131,22 @@ def update_subscription_model(subscription: Layer2Circuit, old_edge_port: UUIDst ) def migrate_layer_2_circuit() -> StepList: """Migrate a Layer 2 Circuit.""" + run_old_side_ansible = conditional(lambda state: state["run_old_side_ansible"]) + run_new_side_ansible = conditional(lambda state: state["run_new_side_ansible"]) + return ( begin >> store_process_subscription(Target.MODIFY) >> unsync - >> generate_fqdn_list - >> extract_partner_name_from_edge_port - >> lso_interaction(terminate_l2circuit_dry) - >> lso_interaction(terminate_l2circuit_real) + >> run_old_side_ansible(generate_fqdn_list) + >> run_old_side_ansible(extract_partner_name_from_edge_port) + >> run_old_side_ansible(lso_interaction(terminate_l2circuit_dry)) + >> run_old_side_ansible(lso_interaction(terminate_l2circuit_real)) >> update_subscription_model - >> generate_fqdn_list - >> extract_partner_name_from_edge_port - >> lso_interaction(provision_l2circuit_dry) - >> lso_interaction(provision_l2circuit_real) + >> run_new_side_ansible(generate_fqdn_list) + >> run_new_side_ansible(extract_partner_name_from_edge_port) + >> run_new_side_ansible(lso_interaction(provision_l2circuit_dry)) + >> run_new_side_ansible(lso_interaction(provision_l2circuit_real)) >> resync >> done ) diff --git a/gso/workflows/l2_circuit/modify_layer_2_circuit.py b/gso/workflows/l2_circuit/modify_layer_2_circuit.py index 120ba474de4d3bc306b6b3c6a025a4310be02110..ae879037c0700a515ca7d2507fbad6eba7d83715 100644 --- a/gso/workflows/l2_circuit/modify_layer_2_circuit.py +++ b/gso/workflows/l2_circuit/modify_layer_2_circuit.py @@ -3,7 +3,7 @@ from orchestrator import begin, done, workflow from orchestrator.forms import FormPage, SubmitFormPage from orchestrator.targets import Target -from orchestrator.workflow import StepList, step +from orchestrator.workflow import StepList, conditional, 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 @@ -43,6 +43,9 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: policer_enabled: bool = subscription.layer_2_circuit.policer_enabled custom_service_name: str | None = subscription.layer_2_circuit.custom_service_name + label: Label = Field("Should this workflow execute Ansible playbooks on routers?", exclude=True) + run_ansible_steps: bool = True + layer_2_circuit_input = yield ModifyL2CircuitForm class ModifyLayer2CircuitServiceSidesPage(SubmitFormPage): @@ -134,15 +137,17 @@ def modify_layer_2_circuit_subscription( ) def modify_layer_2_circuit() -> StepList: """Modify an existing Layer 2 Circuit service subscription.""" + run_ansible_steps = conditional(lambda state: state["run_ansible_steps"]) + return ( begin >> store_process_subscription(Target.MODIFY) >> unsync - >> generate_fqdn_list - >> extract_partner_name_from_edge_port + >> run_ansible_steps(generate_fqdn_list) + >> run_ansible_steps(extract_partner_name_from_edge_port) >> modify_layer_2_circuit_subscription - >> lso_interaction(provision_l2circuit_dry) - >> lso_interaction(provision_l2circuit_real) + >> run_ansible_steps(lso_interaction(provision_l2circuit_dry)) + >> run_ansible_steps(lso_interaction(provision_l2circuit_real)) >> resync >> done ) diff --git a/gso/workflows/l2_circuit/terminate_layer_2_circuit.py b/gso/workflows/l2_circuit/terminate_layer_2_circuit.py index 223523b55b786151d9a3e6653d68eb0163281665..bab755eb824c8d92f0ed1e91d815eaf6a9df1fb4 100644 --- a/gso/workflows/l2_circuit/terminate_layer_2_circuit.py +++ b/gso/workflows/l2_circuit/terminate_layer_2_circuit.py @@ -4,10 +4,12 @@ from orchestrator import begin, workflow from orchestrator.forms import SubmitFormPage from orchestrator.targets import Target from orchestrator.types import SubscriptionLifecycle -from orchestrator.workflow import StepList, done +from orchestrator.workflow import StepList, conditional, done from orchestrator.workflows.steps import resync, set_status, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form +from pydantic import Field from pydantic_forms.types import FormGenerator, UUIDstr +from pydantic_forms.validators import Label from gso.products.product_types.layer_2_circuit import Layer2Circuit from gso.services.lso_client import lso_interaction @@ -26,6 +28,9 @@ def _input_form_generator(subscription_id: UUIDstr) -> FormGenerator: class TerminateForm(SubmitFormPage): tt_number: TTNumber + label: Label = Field("Should this workflow run Ansible playbooks to remove configuration from routers?") + run_ansible_steps: bool = True + user_input = yield TerminateForm return {"subscription": layer_2_circuit} | user_input.model_dump() @@ -37,14 +42,16 @@ def _input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ) def terminate_layer_2_circuit() -> StepList: """Terminate a Layer 2 Circuit subscription.""" + run_ansible_steps = conditional(lambda state: state["run_ansible_steps"]) + return ( begin >> store_process_subscription(Target.TERMINATE) >> unsync - >> generate_fqdn_list - >> extract_partner_name_from_edge_port - >> lso_interaction(terminate_l2circuit_dry) - >> lso_interaction(terminate_l2circuit_real) + >> run_ansible_steps(generate_fqdn_list) + >> run_ansible_steps(extract_partner_name_from_edge_port) + >> run_ansible_steps(lso_interaction(terminate_l2circuit_dry)) + >> run_ansible_steps(lso_interaction(terminate_l2circuit_real)) >> set_status(SubscriptionLifecycle.TERMINATED) >> resync >> done diff --git a/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py b/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py index efc1c8495cf6d37e309ef4f68724f18133fe9f9c..9c016cd28a5abbbd1a3d9cfd8572eeb78c5fedff 100644 --- a/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py +++ b/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py @@ -10,9 +10,13 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr @pytest.mark.workflow() @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES) +@pytest.mark.parametrize("run_old_side_ansible", [False, True]) +@pytest.mark.parametrize("run_new_side_ansible", [False, True]) @patch("gso.services.lso_client._send_request") def test_migrate_layer_2_circuit( mock_lso_interaction, + run_new_side_ansible, + run_old_side_ansible, layer_2_circuit_service_type, layer_2_circuit_subscription_factory, edge_port_subscription_factory, @@ -33,13 +37,19 @@ def test_migrate_layer_2_circuit( "tt_number": faker.tt_number(), "replace_side": old_edge_port.subscription_id, "migrate_to_different_site": False, + "run_old_side_ansible": run_old_side_ansible, + "run_new_side_ansible": run_new_side_ansible, }, {"new_edge_port": new_edge_port.subscription_id}, ] result, process_stat, step_log = run_workflow("migrate_layer_2_circuit", initial_layer_2_circuit_data) - for _ in range(4): + lso_step_count = 0 + lso_step_count += 2 if run_old_side_ansible else 0 + lso_step_count += 2 if run_new_side_ansible else 0 + + for _ in range(lso_step_count): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) assert_complete(result) @@ -48,7 +58,7 @@ def test_migrate_layer_2_circuit( subscription_id = state["subscription_id"] subscription = Layer2Circuit.from_subscription(subscription_id) assert subscription.status == "active" - assert mock_lso_interaction.call_count == 4 + assert mock_lso_interaction.call_count == lso_step_count replaced_edge_port = subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.edge_port assert replaced_edge_port.model_dump(exclude="edge_port_ae_members") == new_edge_port.edge_port.model_dump( diff --git a/test/workflows/l2_circuit/test_modify_layer_2_circuit.py b/test/workflows/l2_circuit/test_modify_layer_2_circuit.py index da4dcb6c8dffbef64ff2d7ef5ab1df1a18cd3761..e4f4dcce33efeabe2dac11c54a41b014577ab0de 100644 --- a/test/workflows/l2_circuit/test_modify_layer_2_circuit.py +++ b/test/workflows/l2_circuit/test_modify_layer_2_circuit.py @@ -9,11 +9,13 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES) +@pytest.mark.parametrize("run_ansible_steps", [False, True]) @pytest.mark.workflow() @patch("gso.services.lso_client._send_request") def test_modify_layer_2_circuit_change_policer_bandwidth( mock_lso_interaction, layer_2_circuit_service_type, + run_ansible_steps, layer_2_circuit_subscription_factory, faker, partner_factory, @@ -26,6 +28,7 @@ def test_modify_layer_2_circuit_change_policer_bandwidth( "layer_2_circuit_type": Layer2CircuitType.VLAN, "policer_enabled": False, "custom_service_name": faker.sentence(), + "run_ansible_steps": run_ansible_steps, }, { "vlan_range_lower_bound": subscription.layer_2_circuit.vlan_range_lower_bound, @@ -38,12 +41,14 @@ def test_modify_layer_2_circuit_change_policer_bandwidth( ] result, process_stat, step_log = run_workflow("modify_layer_2_circuit", input_form_data) - for _ in range(2): + lso_step_count = 2 if run_ansible_steps else 0 + + for _ in range(lso_step_count): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) subscription = Layer2Circuit.from_subscription(str(subscription.subscription_id)) assert_complete(result) - assert mock_lso_interaction.call_count == 2 + assert mock_lso_interaction.call_count == lso_step_count assert subscription.status == SubscriptionLifecycle.ACTIVE assert subscription.layer_2_circuit.policer_enabled is False assert subscription.layer_2_circuit.bandwidth is None @@ -63,11 +68,13 @@ def test_modify_layer_2_circuit_change_policer_bandwidth( @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES) +@pytest.mark.parametrize("run_ansible_steps", [False, True]) @pytest.mark.workflow() @patch("gso.services.lso_client._send_request") def test_modify_layer_2_circuit_change_circuit_type( mock_lso_interaction, layer_2_circuit_service_type, + run_ansible_steps, layer_2_circuit_subscription_factory, faker, partner_factory, @@ -78,6 +85,7 @@ def test_modify_layer_2_circuit_change_circuit_type( { "tt_number": faker.tt_number(), "layer_2_circuit_type": Layer2CircuitType.ETHERNET, + "run_ansible_steps": run_ansible_steps, }, { "vlan_range_lower_bound": None, @@ -89,13 +97,15 @@ def test_modify_layer_2_circuit_change_circuit_type( ] result, process_stat, step_log = run_workflow("modify_layer_2_circuit", input_form_data) - for _ in range(2): + lso_step_count = 2 if run_ansible_steps else 0 + + for _ in range(lso_step_count): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) assert_complete(result) state = extract_state(result) subscription = Layer2Circuit.from_subscription(state["subscription_id"]) - assert mock_lso_interaction.call_count == 2 + assert mock_lso_interaction.call_count == lso_step_count assert subscription.status == SubscriptionLifecycle.ACTIVE assert subscription.layer_2_circuit.vlan_range_lower_bound is None assert subscription.layer_2_circuit.vlan_range_upper_bound is None diff --git a/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py b/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py index 2d5a26606f26c37836f4f51719cc0993e42a30b4..55deedededc9c3c43ef3ca56d6145508cbf7f5d4 100644 --- a/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py +++ b/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py @@ -8,17 +8,23 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr @pytest.mark.workflow() @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES) +@pytest.mark.parametrize("run_ansible_steps", [True, False]) @patch("gso.services.lso_client._send_request") def test_terminate_layer_2_circuit( - mock_lso_interaction, layer_2_circuit_service_type, layer_2_circuit_subscription_factory, faker + mock_lso_interaction, layer_2_circuit_service_type, run_ansible_steps, layer_2_circuit_subscription_factory, faker ): subscription_id = str( layer_2_circuit_subscription_factory(layer_2_circuit_service_type=layer_2_circuit_service_type).subscription_id ) - initial_layer_2_circuit_data = [{"subscription_id": subscription_id}, {"tt_number": faker.tt_number()}] + initial_layer_2_circuit_data = [ + {"subscription_id": subscription_id}, + {"tt_number": faker.tt_number(), "run_ansible_steps": run_ansible_steps}, + ] result, process_stat, step_log = run_workflow("terminate_layer_2_circuit", initial_layer_2_circuit_data) - for _ in range(2): + lso_step_count = 2 if run_ansible_steps else 0 + + for _ in range(lso_step_count): result, step_log = assert_lso_interaction_success(result, process_stat, step_log) assert_complete(result) @@ -27,4 +33,4 @@ def test_terminate_layer_2_circuit( subscription_id = state["subscription_id"] subscription = Layer2Circuit.from_subscription(subscription_id) assert subscription.status == "terminated" - assert mock_lso_interaction.call_count == 2 + assert mock_lso_interaction.call_count == lso_step_count