import ipaddress from orchestrator.forms import FormPage from orchestrator.forms.validators import Label from orchestrator.targets import Target from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr from orchestrator.workflow import StepList, conditional, done, init, step, workflow from orchestrator.workflows.steps import resync, set_status, store_process_subscription, unsync from orchestrator.workflows.utils import wrap_modify_initial_input_form from gso.products.product_types.iptrunk import Iptrunk from gso.services import ipam, provisioning_proxy from gso.services.ipam import V4ServiceNetwork, V6ServiceNetwork from gso.services.provisioning_proxy import pp_interaction def initial_input_form_generator() -> FormGenerator: class TerminateForm(FormPage): termination_label: Label = ( "Please confirm whether configuration should get removed from the A and B sides of the trunk, and whether " "IPAM resources should be released." # type: ignore ) remove_configuration: bool = True clean_up_ipam: bool = True user_input = yield TerminateForm return user_input.dict() @step("Set iptrunk ISIS metric to 9000") def update_isis_metric(subscription: Iptrunk) -> State: subscription.iptrunk.iptrunk_isis_metric = 9000 return {"subscription": subscription} @step("Drain traffic from trunk") def drain_traffic_from_ip_trunk(subscription: Iptrunk, process_id: UUIDstr) -> State: provisioning_proxy.provision_ip_trunk(subscription, process_id, "isis_interface", False) return { "subscription": subscription, "label_text": "This is setting the ISIS metric of the trunk to 9000" "trunk. " "Press refresh to get the results\n" "When traffic is drained, confirm to continue", } @step("Deprovision IP trunk [DRY RUN]") def deprovision_ip_trunk_dry(subscription: Iptrunk, process_id: UUIDstr) -> State: provisioning_proxy.deprovision_ip_trunk(subscription, process_id, True) return { "subscription": subscription, "label_text": "[DRY RUN] Terminating IP trunk, please refresh to get the results of the playbook.", } @step("Deprovision IP trunk [FOR REAL]") def deprovision_ip_trunk_real(subscription: Iptrunk, process_id: UUIDstr) -> State: provisioning_proxy.deprovision_ip_trunk(subscription, process_id, False) return { "subscription": subscription, "label_text": "Terminating IP trunk, please refresh to get the results of the playbook.", } @step("Deprovision IPv4 networks") def deprovision_ip_trunk_ipv4(subscription: Iptrunk) -> dict[str, V4ServiceNetwork | V6ServiceNetwork]: service_network = ipam.delete_network( network=ipaddress.ip_network(subscription.iptrunk.iptrunk_ipv4_network), service_type="TRUNK", ) return {"service_network": service_network} @step("Deprovision IPv6 networks") def deprovision_ip_trunk_ipv6(subscription: Iptrunk) -> dict[str, V4ServiceNetwork | V6ServiceNetwork]: service_network = ipam.delete_network( network=ipaddress.ip_network(subscription.iptrunk.iptrunk_ipv6_network), service_type="TRUNK", ) return {"service_network": service_network} @workflow( "Terminate IPtrunk", initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator), target=Target.TERMINATE, ) def terminate_iptrunk() -> StepList: run_config_steps = conditional(lambda state: state.get("remove_configuration", True)) run_ipam_steps = conditional(lambda state: state.get("clean_up_ipam", True)) config_steps = ( StepList([update_isis_metric]) >> pp_interaction(drain_traffic_from_ip_trunk, 3) >> pp_interaction(deprovision_ip_trunk_dry, 3) >> pp_interaction(deprovision_ip_trunk_real, 3) ) ipam_steps = StepList([deprovision_ip_trunk_ipv4, deprovision_ip_trunk_ipv6]) return ( init >> store_process_subscription(Target.TERMINATE) >> unsync >> run_config_steps(config_steps) >> run_ipam_steps(ipam_steps) >> set_status(SubscriptionLifecycle.TERMINATED) >> resync >> done )