diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py index c5e4e97faaf11c65a6cab597e1563e31ba74e7f5..fb72c6573b9cd77a3ffc85253efbc303ca9db1d1 100644 --- a/gso/workflows/__init__.py +++ b/gso/workflows/__init__.py @@ -4,14 +4,16 @@ init class that imports all workflows into GSO. from orchestrator.workflows import LazyWorkflowInstance LazyWorkflowInstance("gso.workflows.device.create_device", "create_device") -LazyWorkflowInstance("gso.workflows.device.terminate_device", - "terminate_device") +LazyWorkflowInstance( + "gso.workflows.device.terminate_device", "terminate_device" +) LazyWorkflowInstance("gso.workflows.device.get_facts", "get_facts") LazyWorkflowInstance("gso.workflows.iptrunk.create_iptrunk", "create_iptrunk") -LazyWorkflowInstance("gso.workflows.iptrunk.terminate_iptrunk", - "terminate_iptrunk") -LazyWorkflowInstance("gso.workflows.iptrunk.modify_isis_metric", - "modify_isis_metric") -LazyWorkflowInstance("gso.workflows.iptrunk.modify_generic", - "modify_generic") +LazyWorkflowInstance( + "gso.workflows.iptrunk.terminate_iptrunk", "terminate_iptrunk" +) +LazyWorkflowInstance( + "gso.workflows.iptrunk.modify_isis_metric", "modify_isis_metric" +) +LazyWorkflowInstance("gso.workflows.iptrunk.modify_generic", "modify_generic") LazyWorkflowInstance("gso.workflows.site.create_site", "create_site") diff --git a/gso/workflows/device/get_facts.py b/gso/workflows/device/get_facts.py index 024631740dfbfacd229a1d442d26c0d274af5e8e..a50caee3a8fe3eba6811107615d1eca0f2ea58c4 100644 --- a/gso/workflows/device/get_facts.py +++ b/gso/workflows/device/get_facts.py @@ -1,9 +1,11 @@ from orchestrator.forms import FormPage from orchestrator.forms.validators import Label from orchestrator.targets import Target + # from orchestrator.types import SubscriptionLifecycle from orchestrator.types import InputForm, UUIDstr from orchestrator.workflow import done, init, step, workflow + # from orchestrator.workflows.steps import ( # resync, # set_status, @@ -21,10 +23,8 @@ def initial_input_form_generator( subscription = Device.from_subscription(subscription_id) class TerminateForm(FormPage): - are_you_sure: Label = ( - f"Are you sure you want to get facts from \ + are_you_sure: Label = f"Are you sure you want to get facts from \ {subscription.description}?" - ) return TerminateForm @@ -48,7 +48,8 @@ def get_facts(subscription_id) -> None: @workflow( "Get Facts from Device", initial_input_form=wrap_modify_initial_input_form( - initial_input_form_generator), + initial_input_form_generator + ), target=Target.SYSTEM, ) def get_facts_from_device(): diff --git a/gso/workflows/iptrunk/modify_generic.py b/gso/workflows/iptrunk/modify_generic.py new file mode 100644 index 0000000000000000000000000000000000000000..9c3c633c352be9c555ca6afa39d92b58bb3ffcfe --- /dev/null +++ b/gso/workflows/iptrunk/modify_generic.py @@ -0,0 +1,240 @@ +import ipaddress +from orchestrator.forms import FormPage, ReadOnlyField +from orchestrator.targets import Target +from orchestrator.types import FormGenerator, State +from orchestrator.types import UUIDstr +from orchestrator.workflow import done, init, step, workflow +from orchestrator.workflows.steps import resync +from orchestrator.workflows.steps import store_process_subscription, unsync +from orchestrator.workflows.utils import wrap_modify_initial_input_form +from orchestrator.forms.validators import Choice, UniqueConstrainedList +from gso.products.product_blocks.iptrunk import IptrunkType +from gso.products.product_blocks import PhyPortCapacity + +from gso.products.product_types.iptrunk import ( + Iptrunk, +) +from gso.services import provisioning_proxy +from gso.services.provisioning_proxy import ( + confirm_pp_results, + await_pp_results, +) + + +def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: + subscription = Iptrunk.from_subscription(subscription_id) + + class ModifyIptrunkForm(FormPage): + geant_s_sid: str = subscription.iptrunk.geant_s_sid + iptrunk_description: str = subscription.iptrunk.iptrunk_description + iptrunk_type: IptrunkType = subscription.iptrunk.iptrunk_type + iptrunk_speed: PhyPortCapacity = subscription.iptrunk.iptrunk_speed + iptrunk_minimum_links: int = subscription.iptrunk.iptrunk_minimum_links + iptrunk_isis_metric: int = ReadOnlyField( + subscription.iptrunk.iptrunk_isis_metric + ) + iptrunk_ipv4_network: ipaddress.IPv4Network = ReadOnlyField( + subscription.iptrunk.iptrunk_ipv4_network + ) + iptrunk_ipv6_network: ipaddress.IPv6Network = ReadOnlyField( + subscription.iptrunk.iptrunk_ipv6_network + ) + + initial_user_input = yield ModifyIptrunkForm + + class AeMembersListA(UniqueConstrainedList[str]): + min_items = initial_user_input.iptrunk_minimum_links + + class ModifyIptrunkSideAForm(FormPage): + class Config: + title = "Provide subscription details for side A of the trunk." + + iptrunk_sideA_node: str = ReadOnlyField( + subscription.iptrunk.iptrunk_sideA_node.device_fqdn + ) + iptrunk_sideA_ae_iface: str = ReadOnlyField( + subscription.iptrunk.iptrunk_sideA_ae_iface + ) + iptrunk_sideA_ae_geant_a_sid: str = ( + subscription.iptrunk.iptrunk_sideA_ae_geant_a_sid + ) + iptrunk_sideA_ae_members: AeMembersListA = ( + subscription.iptrunk.iptrunk_sideA_ae_members + ) + iptrunk_sideA_ae_members_descriptions: AeMembersListA = ( + subscription.iptrunk.iptrunk_sideA_ae_members_description + ) + + user_input_side_a = yield ModifyIptrunkSideAForm + + class AeMembersListB(UniqueConstrainedList[str]): + min_items = len(user_input_side_a.iptrunk_sideA_ae_members) + max_items = len(user_input_side_a.iptrunk_sideA_ae_members) + + class ModifyIptrunkSideBForm(FormPage): + class Config: + title = "Provide subscription details for side B of the trunk." + + iptrunk_sideB_node: str = ReadOnlyField( + subscription.iptrunk.iptrunk_sideB_node.device_fqdn + ) + iptrunk_sideB_ae_iface: str = ReadOnlyField( + subscription.iptrunk.iptrunk_sideB_ae_iface + ) + iptrunk_sideB_ae_geant_a_sid: str = ( + subscription.iptrunk.iptrunk_sideB_ae_geant_a_sid + ) + iptrunk_sideB_ae_members: AeMembersListB = ( + subscription.iptrunk.iptrunk_sideB_ae_members + ) + iptrunk_sideB_ae_members_descriptions: AeMembersListB = ( + subscription.iptrunk.iptrunk_sideB_ae_members_description + ) + + user_input_side_b = yield ModifyIptrunkSideBForm + + return ( + initial_user_input.dict() + | user_input_side_a.dict() + | user_input_side_b.dict() + ) + + +@step("Update subscription") +def modify_iptrunk_subscription( + subscription: Iptrunk, + geant_s_sid: str, + iptrunk_type: IptrunkType, + iptrunk_description: str, + iptrunk_speed: str, + iptrunk_minimum_links: int, + iptrunk_sideA_ae_geant_a_sid: str, + iptrunk_sideA_ae_members: list[str], + iptrunk_sideA_ae_members_descriptions: list[str], + iptrunk_sideB_ae_geant_a_sid: str, + iptrunk_sideB_ae_members: list[str], + iptrunk_sideB_ae_members_descriptions: list[str], +) -> State: + subscription.iptrunk.geant_s_sid = geant_s_sid + subscription.iptrunk.iptrunk_description = iptrunk_description + subscription.iptrunk.iptrunk_type = iptrunk_type + subscription.iptrunk.iptrunk_speed = iptrunk_speed + subscription.iptrunk.iptrunk_minimum_links = iptrunk_minimum_links + + subscription.iptrunk.iptrunk_sideA_ae_geant_a_sid = ( + iptrunk_sideA_ae_geant_a_sid + ) + subscription.iptrunk.iptrunk_sideA_ae_members = iptrunk_sideA_ae_members + subscription.iptrunk.iptrunk_sideA_ae_members_description = ( + iptrunk_sideA_ae_members_descriptions + ) + + subscription.iptrunk.iptrunk_sideB_ae_geant_a_sid = ( + iptrunk_sideB_ae_geant_a_sid + ) + subscription.iptrunk.iptrunk_sideB_ae_members = iptrunk_sideB_ae_members + subscription.iptrunk.iptrunk_sideB_ae_members_description = ( + iptrunk_sideB_ae_members_descriptions + ) + + subscription.description = f"IP trunk, geant_s_sid:{geant_s_sid}" + + return {"subscription": subscription} + + +@step("Provision IP trunk interface [DRY RUN]") +def provision_ip_trunk_iface_dry( + subscription: Iptrunk, process_id: UUIDstr +) -> State: + provisioning_proxy.provision_ip_trunk( + subscription, process_id, "trunk_interface" + ) + + return { + "subscription": subscription, + "label_text": ( + "Provision of the Trunk interface [DRY] " + "Please refresh to get the results of the playbook" + ), + } + + +@step("Provision IP trunk interface [FOR REAL]") +def provision_ip_trunk_iface_real( + subscription: Iptrunk, process_id: UUIDstr +) -> State: + provisioning_proxy.provision_ip_trunk( + subscription, process_id, "trunk_interface", False + ) + + return { + "subscription": subscription, + "label_text": ( + "Provision of the Trunk interface [REAL] " + "Please refresh to get the results of the playbook" + ), + } + + +@step("Provision IP trunk LLDP interface [DRY RUN]") +def provision_ip_trunk_lldp_iface_dry( + subscription: Iptrunk, process_id: UUIDstr +) -> State: + provisioning_proxy.provision_ip_trunk( + subscription, process_id, "lldp_interface" + ) + + return { + "subscription": subscription, + "label_text": ( + "Provision of the LLDP interface [DRY]" + "Please refresh to get the results of the playbook" + ), + } + + +@step("Provision IP trunk LLDP interface [FOR REAL]") +def provision_ip_trunk_lldp_iface_real( + subscription: Iptrunk, process_id: UUIDstr +) -> State: + provisioning_proxy.provision_ip_trunk( + subscription, process_id, "lldp_interface", False + ) + + return { + "subscription": subscription, + "label_text": ( + "Provision of the LLDP interface [REAL]" + "Please refresh to get the results of the playbook" + ), + } + + +@workflow( + "Modify IP trunk", + initial_input_form=wrap_modify_initial_input_form( + initial_input_form_generator + ), + target=Target.MODIFY, +) +def modify_generic(): + return ( + init + >> store_process_subscription(Target.MODIFY) + >> unsync + >> modify_iptrunk_subscription + >> provision_ip_trunk_iface_dry + >> await_pp_results + >> confirm_pp_results + >> provision_ip_trunk_iface_real + >> await_pp_results + >> confirm_pp_results + >> provision_ip_trunk_lldp_iface_dry + >> await_pp_results + >> confirm_pp_results + >> provision_ip_trunk_lldp_iface_real + >> await_pp_results + >> confirm_pp_results + >> resync + >> done + ) diff --git a/gso/workflows/site/create_site.py b/gso/workflows/site/create_site.py index aa92be43b8c11bdddf0aa99e819f45916447ffb1..0773d71c3ccdea5103211dabd94358d73201658b 100644 --- a/gso/workflows/site/create_site.py +++ b/gso/workflows/site/create_site.py @@ -45,16 +45,16 @@ def create_subscription(product: UUIDstr) -> State: @step("Initialize subscription") def initialize_subscription( - subscription: site.SiteInactive, - site_name: str, - site_city: str, - site_country: str, - site_country_code: str, - site_latitude: float, - site_longitude: float, - site_bgp_community_id: int, - site_internal_id: int, - site_tier: site_pb.SiteTier + subscription: site.SiteInactive, + site_name: str, + site_city: str, + site_country: str, + site_country_code: str, + site_latitude: float, + site_longitude: float, + site_bgp_community_id: int, + site_internal_id: int, + site_tier: site_pb.SiteTier, ) -> State: subscription.site.site_name = site_name subscription.site.site_city = site_city @@ -78,16 +78,17 @@ def initialize_subscription( @workflow( "Create Site", initial_input_form=wrap_create_initial_input_form( - initial_input_form_generator), + initial_input_form_generator + ), target=Target.CREATE, ) def create_site(): return ( - init - >> create_subscription - >> store_process_subscription(Target.CREATE) - >> initialize_subscription - >> set_status(SubscriptionLifecycle.ACTIVE) - >> resync - >> done + init + >> create_subscription + >> store_process_subscription(Target.CREATE) + >> initialize_subscription + >> set_status(SubscriptionLifecycle.ACTIVE) + >> resync + >> done )