diff --git a/gso/gso-services-config.json b/gso/gso-services-config.json index dc53bbff599587fca2e09d47af0b2f8fe82b4b02..364ec44e692e9a15de4b4dc3926f15686e336f4e 100644 --- a/gso/gso-services-config.json +++ b/gso/gso-services-config.json @@ -1,13 +1,13 @@ { "IP_TRUNK": { - "VERSION": { + "version": { "1.0": "Base Version", - "1.1":" Minor Upgrade" + "1.1": "Minor Upgrade" }, "default_version": "1.0" }, "GEANT_IP": { - "VERSION": { + "version": { "1.0": "Base Version", "2.0": "Major Upgrade" }, diff --git a/gso/products/product_blocks/iptrunk.py b/gso/products/product_blocks/iptrunk.py index 1c6cb4a666cb8c1a8b865898405445cdb1c66631..eaaab57fe1931338198235f3d2ecfccf7be803fc 100644 --- a/gso/products/product_blocks/iptrunk.py +++ b/gso/products/product_blocks/iptrunk.py @@ -4,6 +4,8 @@ import ipaddress from typing import Annotated from annotated_types import Len +from orchestrator.domain.base import ProductBlockModel, T +from orchestrator.types import SubscriptionLifecycle from pydantic import AfterValidator from pydantic_forms.types import strEnum from pydantic_forms.validators import validate_unique_list @@ -15,8 +17,6 @@ from gso.products.product_blocks.router import ( RouterBlockProvisioning, ) from gso.utils.types.interfaces import LAGMemberList, PhysicalPortCapacity -from orchestrator.domain.base import ProductBlockModel, T -from orchestrator.types import SubscriptionLifecycle class IptrunkType(strEnum): diff --git a/gso/settings.py b/gso/settings.py index 2059a6023cf580bd04f43a83ec8ef247e2ec0f37..65af78ac8f44daa35b9678be7036f9e14cf8fc6f 100644 --- a/gso/settings.py +++ b/gso/settings.py @@ -253,12 +253,13 @@ def load_oss_params() -> OSSParams: class ServiceConfig(BaseSettings): """Configurations for base gso service.""" - version: dict[str, str] + version: dict[str, str] default_version: str class GSOServiceConfig(BaseSettings): """Configuration for the GSO service.""" + IP_TRUNK: ServiceConfig GEANT_IP: ServiceConfig diff --git a/gso/workflows/iptrunk/create_imported_iptrunk.py b/gso/workflows/iptrunk/create_imported_iptrunk.py index d65dee7535f876293f2f16117e94dd4da41b5df9..4c45751b9f2ba05fc65a89953d719215f509743d 100644 --- a/gso/workflows/iptrunk/create_imported_iptrunk.py +++ b/gso/workflows/iptrunk/create_imported_iptrunk.py @@ -4,6 +4,12 @@ import ipaddress from typing import Annotated from uuid import uuid4 +from orchestrator import workflow +from orchestrator.forms import SubmitFormPage +from orchestrator.targets import Target +from orchestrator.types import SubscriptionLifecycle +from orchestrator.workflow import StepList, begin, done, step +from orchestrator.workflows.steps import resync, set_status, store_process_subscription from pydantic import AfterValidator, ConfigDict from pydantic_forms.types import FormGenerator, State from pydantic_forms.validators import validate_unique_list @@ -17,12 +23,6 @@ from gso.services.partners import get_partner_by_name from gso.utils.helpers import active_router_selector from gso.utils.types.geant_ids import IMPORTED_GA_ID, IMPORTED_GS_ID from gso.utils.types.interfaces import LAGMember, LAGMemberList, PhysicalPortCapacity -from orchestrator import workflow -from orchestrator.forms import SubmitFormPage -from orchestrator.targets import Target -from orchestrator.types import SubscriptionLifecycle -from orchestrator.workflow import StepList, begin, done, step -from orchestrator.workflows.steps import resync, set_status, store_process_subscription def initial_input_form_generator() -> FormGenerator: @@ -39,7 +39,6 @@ def initial_input_form_generator() -> FormGenerator: iptrunk_minimum_links: int iptrunk_isis_metric: int iptrunk_description_suffix: str | None = None - iptrunk_config_version: str | None = None side_a_node_id: active_router_selector() # type: ignore[valid-type] side_a_ae_iface: str @@ -90,7 +89,6 @@ def initialize_subscription( side_b_ae_iface: str, side_b_ga_id: IMPORTED_GA_ID | None, side_b_ae_members: LAGMemberList, - iptrunk_config_version: str | None, ) -> State: """Take all input from the user, and store it in the database.""" subscription.iptrunk.gs_id = gs_id @@ -100,7 +98,6 @@ def initialize_subscription( subscription.iptrunk.iptrunk_isis_metric = iptrunk_isis_metric subscription.iptrunk.iptrunk_minimum_links = iptrunk_minimum_links subscription.iptrunk.iptrunk_description_suffix = iptrunk_description_suffix - subscription.iptrunk.iptrunk_config_version = iptrunk_config_version subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node = Router.from_subscription(side_a_node_id).router subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_iface = side_a_ae_iface diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py index 72f6a6c9a3e933496c14a0b1f4b1ca2aca824491..cb9f832310370699c89bc2f5ad0a1a4899e6033f 100644 --- a/gso/workflows/iptrunk/create_iptrunk.py +++ b/gso/workflows/iptrunk/create_iptrunk.py @@ -31,6 +31,15 @@ from typing import Annotated from uuid import uuid4 from annotated_types import Len +from orchestrator.forms import FormPage +from orchestrator.forms.validators import Choice, Label +from orchestrator.targets import Target +from orchestrator.types import SubscriptionLifecycle +from orchestrator.utils.errors import ProcessFailureError +from orchestrator.utils.json import json_dumps +from orchestrator.workflow import StepList, begin, conditional, done, step, step_group, workflow +from orchestrator.workflows.steps import resync, set_status, store_process_subscription +from orchestrator.workflows.utils import wrap_create_initial_input_form from ping3 import ping from pydantic import ConfigDict from pydantic_forms.types import FormGenerator, State, UUIDstr @@ -53,7 +62,7 @@ from gso.services.subscriptions import ( generate_unique_id, get_non_terminated_iptrunk_subscriptions, ) -from gso.settings import load_oss_params +from gso.settings import load_gso_service_config, load_oss_params from gso.utils.helpers import ( available_interfaces_choices, available_lags_choices, @@ -66,15 +75,6 @@ from gso.utils.types.netbox_router import NetboxEnabledRouter from gso.utils.types.tt_number import TTNumber from gso.utils.workflow_steps import prompt_sharepoint_checklist_url from gso.workflows.shared import create_summary_form -from orchestrator.forms import FormPage -from orchestrator.forms.validators import Choice, Label -from orchestrator.targets import Target -from orchestrator.types import SubscriptionLifecycle -from orchestrator.utils.errors import ProcessFailureError -from orchestrator.utils.json import json_dumps -from orchestrator.workflow import StepList, begin, conditional, done, step, step_group, workflow -from orchestrator.workflows.steps import resync, set_status, store_process_subscription -from orchestrator.workflows.utils import wrap_create_initial_input_form def initial_input_form_generator(product_name: str) -> FormGenerator: @@ -85,6 +85,10 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: ) + subscriptions.get_provisioning_router_subscriptions(includes=["subscription_id", "description"]) routers = {str(router["subscription_id"]): router["description"] for router in active_and_provisioning_routers} + # Get version choices from config + iptrunk_versions = list(load_gso_service_config().IP_TRUNK.version.keys()) + iptrunk_version_choices = Choice("Select version", [(v, v) for v in iptrunk_versions]) # type: ignore[arg-type] + class CreateIptrunkForm(FormPage): model_config = ConfigDict(title=product_name) @@ -95,7 +99,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: iptrunk_speed: PhysicalPortCapacity iptrunk_number_of_members: int iptrunk_description_suffix: str | None = None - iptrunk_config_version: str | None = None + iptrunk_config_version: iptrunk_version_choices # type: ignore[valid-type] initial_user_input = yield CreateIptrunkForm recommended_minimum_links = calculate_recommended_minimum_links( @@ -329,7 +333,7 @@ def initialize_subscription( iptrunk_speed: PhysicalPortCapacity, iptrunk_minimum_links: int, iptrunk_description_suffix: str | None, - iptrunk_config_version: str | None, + iptrunk_config_version: str, side_a_node_id: str, side_a_ae_iface: str, side_a_ae_members: list[dict], diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py index 793c1bc00f10d36ad5ea9375866860e7e73c9ab0..391832078f8ffa8a83016b33748fb536d032128f 100644 --- a/gso/workflows/iptrunk/modify_trunk_interface.py +++ b/gso/workflows/iptrunk/modify_trunk_interface.py @@ -12,9 +12,15 @@ from typing import Annotated from uuid import UUID, uuid4 from annotated_types import Len +from orchestrator.forms import FormPage, SubmitFormPage +from orchestrator.targets import Target +from orchestrator.utils.json import json_dumps +from orchestrator.workflow import StepList, begin, conditional, done, step, workflow +from orchestrator.workflows.steps import resync, store_process_subscription, unsync +from orchestrator.workflows.utils import wrap_modify_initial_input_form from pydantic import AfterValidator, ConfigDict, Field from pydantic_forms.types import FormGenerator, State, UUIDstr -from pydantic_forms.validators import Label, ReadOnlyField +from pydantic_forms.validators import Choice, Label, ReadOnlyField from gso.products.product_blocks.iptrunk import ( IptrunkInterfaceBlock, @@ -24,7 +30,7 @@ from gso.products.product_blocks.iptrunk import ( from gso.products.product_types.iptrunk import Iptrunk from gso.services.lso_client import LSOState, lso_interaction from gso.services.netbox_client import NetboxClient -from gso.settings import ServiceConfig, load_gso_service_config +from gso.settings import load_gso_service_config from gso.utils.helpers import ( available_interfaces_choices, available_interfaces_choices_including_current_members, @@ -38,12 +44,6 @@ from gso.utils.types.tt_number import TTNumber from gso.utils.types.unique_field import validate_field_is_unique from gso.workflows.iptrunk.migrate_iptrunk import check_ip_trunk_optical_levels_pre from gso.workflows.iptrunk.validate_iptrunk import check_ip_trunk_isis -from orchestrator.forms import FormPage, SubmitFormPage -from orchestrator.targets import Target -from orchestrator.utils.json import json_dumps -from orchestrator.workflow import StepList, begin, conditional, done, step, workflow -from orchestrator.workflows.steps import resync, store_process_subscription, unsync -from orchestrator.workflows.utils import wrap_modify_initial_input_form def initialize_ae_members( @@ -87,6 +87,10 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: """Gather input from the operator on the interfaces that should be modified.""" subscription = Iptrunk.from_subscription(subscription_id) + # Get version choices from config (single-select dropdown) + iptrunk_versions = list(load_gso_service_config().IP_TRUNK.version.keys()) + iptrunk_version_choices = Choice("Select version", [(v, v) for v in iptrunk_versions]) # type: ignore[arg-type] + class ModifyIptrunkForm(FormPage): tt_number: TTNumber gs_id: ( @@ -95,10 +99,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ] | None ) = subscription.iptrunk.gs_id - iptrunk_description: str | None = subscription.iptrunk.iptrunk_description - iptrunk_config_version: load_gso_service_config().IP_TRUNK.version | str \ - = subscription.iptrunk.iptrunk_config_version + iptrunk_config_version: iptrunk_version_choices = subscription.iptrunk.iptrunk_config_version # type: ignore[valid-type] iptrunk_type: IptrunkType | str = subscription.iptrunk.iptrunk_type # FIXME: remove str workaround warning_label: Label = ( "Changing the PhyPortCapacity will result in the deletion of all AE members. " @@ -272,7 +274,7 @@ def modify_iptrunk_subscription( iptrunk_speed: PhysicalPortCapacity, iptrunk_minimum_links: int, iptrunk_description_suffix: str | None, - iptrunk_config_version: ServiceConfig.version, + iptrunk_config_version: str, side_a_ga_id: str | None, side_a_ae_members: list[dict], side_b_ga_id: str | None, @@ -539,8 +541,8 @@ def modify_trunk_interface() -> StepList: >> capacity_has_changed(lso_interaction(check_ip_trunk_connectivity)) >> capacity_has_changed(lso_interaction(check_ip_trunk_isis)) >> modify_iptrunk_subscription - # >> side_a_is_nokia(netbox_update_interfaces_side_a) - # >> side_b_is_nokia(netbox_update_interfaces_side_b) + >> side_a_is_nokia(netbox_update_interfaces_side_a) + >> side_b_is_nokia(netbox_update_interfaces_side_b) >> lso_interaction(provision_ip_trunk_iface_dry) >> lso_interaction(provision_ip_trunk_iface_real) >> side_a_is_nokia(allocate_interfaces_in_netbox_side_a) diff --git a/test/workflows/iptrunk/test_create_imported_iptrunk.py b/test/workflows/iptrunk/test_create_imported_iptrunk.py index 7add53de932149b0f7006bece952b25e22396fc6..7f83775bb0d8ba1309bc008a8440f90b541e0f53 100644 --- a/test/workflows/iptrunk/test_create_imported_iptrunk.py +++ b/test/workflows/iptrunk/test_create_imported_iptrunk.py @@ -23,7 +23,6 @@ def workflow_input_data(faker, router_subscription_factory): "iptrunk_minimum_links": 2, "iptrunk_isis_metric": 10000, "iptrunk_description_suffix": faker.word(), - "iptrunk_config_version": "1.0", "side_a_node_id": str(router_subscription_factory().subscription_id), "side_a_ae_iface": faker.nokia_lag_interface_name(), "side_a_ga_id": faker.imported_ga_id(), diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py index c18577249f98e24a698dfd2456a205bf91cdc180..33c9640aa5c25d6f59ea5a81af53d0150dd7dee4 100644 --- a/test/workflows/iptrunk/test_create_iptrunk.py +++ b/test/workflows/iptrunk/test_create_iptrunk.py @@ -74,7 +74,7 @@ def input_form_wizard_data(request, router_subscription_factory, faker): "iptrunk_speed": PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND, "iptrunk_number_of_members": 2, "iptrunk_description_suffix": faker.word(), - "iptrunk_config_version": "1.0" + "iptrunk_config_version": "1.0", } create_ip_trunk_confirm_step = {"iptrunk_minimum_links": 1} create_ip_trunk_side_a_router_name = {"side_a_node_id": router_side_a} diff --git a/test/workflows/iptrunk/test_modify_trunk_interface.py b/test/workflows/iptrunk/test_modify_trunk_interface.py index 4e72fbd72893222cd5f6fc516c12dfc08e7b27ca..7c11c95518cf002c25c5178966b5f1706028cdfb 100644 --- a/test/workflows/iptrunk/test_modify_trunk_interface.py +++ b/test/workflows/iptrunk/test_modify_trunk_interface.py @@ -121,6 +121,7 @@ def input_form_iptrunk_data( "iptrunk_speed": new_speed, "iptrunk_number_of_members": new_link_count, "iptrunk_description_suffix": faker.word(), + "iptrunk_config_version": "1.0", }, {}, {