Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • goat/gap/geant-service-orchestrator
1 result
Show changes
Commits on Source (4)
......@@ -91,5 +91,8 @@
"starttls_enabled": true,
"smtp_username": "username",
"smtp_password": "password"
},
"SHAREPOINT": {
"checklist_site_url": "https://example.sharepoint.com/sites/example-site"
}
}
......@@ -166,6 +166,13 @@ class EmailParams(BaseSettings):
smtp_password: str | None
class SharepointParams(BaseSettings):
"""Settings for different Sharepoint sites."""
# TODO: Stricter typing after Pydantic 2.x upgrade
checklist_site_url: str
class OSSParams(BaseSettings):
"""The set of parameters required for running :term:`GSO`."""
......@@ -177,6 +184,7 @@ class OSSParams(BaseSettings):
CELERY: CeleryParams
THIRD_PARTY_API_KEYS: dict[str, str]
EMAIL: EmailParams
SHAREPOINT: SharepointParams
def load_oss_params() -> OSSParams:
......
......@@ -36,6 +36,7 @@
}
},
"workflow": {
"activate_iptrunk": "Activate IP Trunk",
"activate_router": "Activate router",
"confirm_info": "Please verify this form looks correct.",
"deploy_twamp": "Deploy TWAMP",
......
......@@ -3,12 +3,13 @@
import json
from uuid import uuid4
from orchestrator.config.assignee import Assignee
from orchestrator.forms import FormPage
from orchestrator.forms.validators import Choice, UniqueConstrainedList
from orchestrator.forms.validators import Choice, Label, UniqueConstrainedList
from orchestrator.targets import Target
from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr
from orchestrator.utils.json import json_dumps
from orchestrator.workflow import StepList, conditional, done, init, step, workflow
from orchestrator.workflow import StepList, conditional, done, init, inputstep, step, workflow
from orchestrator.workflows.steps import resync, set_status, store_process_subscription
from orchestrator.workflows.utils import wrap_create_initial_input_form
from pydantic import validator
......@@ -21,7 +22,7 @@ from gso.products.product_blocks.iptrunk import (
IptrunkType,
PhyPortCapacity,
)
from gso.products.product_types.iptrunk import IptrunkInactive
from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning
from gso.products.product_types.router import Router
from gso.services import infoblox, subscriptions
from gso.services.crm import get_customer_by_name
......@@ -472,6 +473,27 @@ def netbox_allocate_side_b_interfaces(subscription: IptrunkInactive) -> None:
_allocate_interfaces_in_netbox(subscription.iptrunk.iptrunk_sides[1])
@inputstep("Prompt for new Sharepoint checklist", assignee=Assignee.SYSTEM)
def prompt_start_new_checklist(subscription: IptrunkProvisioning) -> FormGenerator:
"""Prompt the operator to start a new checklist in Sharepoint for approving this new IP trunk."""
oss_params = load_oss_params()
class SharepointPrompt(FormPage):
class Config:
title = "Start new checklist"
info_label_1: Label = (
f"Visit {oss_params.SHAREPOINT.checklist_site_url} and start a new Sharepoint checklist for an IPtrunk " # type: ignore[assignment]
f"from {subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn} to "
f"{subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}."
)
info_label_2: Label = "Once this is done, click proceed to finish the workflow." # type: ignore[assignment]
yield SharepointPrompt
return {}
@workflow(
"Create IP trunk",
initial_input_form=wrap_create_initial_input_form(initial_input_form_generator),
......@@ -510,6 +532,7 @@ def create_iptrunk() -> StepList:
>> side_a_is_nokia(netbox_allocate_side_a_interfaces)
>> side_b_is_nokia(netbox_allocate_side_b_interfaces)
>> set_status(SubscriptionLifecycle.PROVISIONING)
>> prompt_start_new_checklist
>> resync
>> done
)
......@@ -14,12 +14,13 @@ from pydantic import validator
from pydantic_forms.core import ReadOnlyField
from gso.products.product_blocks.router import RouterRole
from gso.products.product_types.router import RouterInactive
from gso.products.product_types.router import RouterInactive, RouterProvisioning
from gso.products.product_types.site import Site
from gso.services import infoblox, subscriptions
from gso.services.crm import get_customer_by_name
from gso.services.netbox_client import NetboxClient
from gso.services.provisioning_proxy import pp_interaction
from gso.settings import load_oss_params
from gso.utils.helpers import generate_fqdn, iso_from_ipv4
from gso.utils.shared_enums import PortNumber, Vendor
from gso.utils.workflow_steps import deploy_base_config_dry, deploy_base_config_real, run_checks_after_base_config
......@@ -203,6 +204,45 @@ def prompt_insert_in_ims() -> FormGenerator:
return {}
@inputstep("Prompt RADIUS insertion", assignee=Assignee.SYSTEM)
def prompt_insert_in_radius(subscription: RouterInactive) -> FormGenerator:
"""Wait for confirmation from an operator that the router has been inserted in RADIUS."""
class RadiusPrompt(FormPage):
class Config:
title = "Update RADIUS clients"
info_label_1: Label = (
f"Please go to https://kratos.geant.org/add_radius_client and add the {subscription.router.router_fqdn}" # type: ignore[assignment]
f" - {subscription.router.router_lo_ipv4_address} to radius authentication"
)
info_label_2: Label = "This will be functionally checked later during verification work." # type: ignore[assignment]
yield RadiusPrompt
return {}
@inputstep("Prompt for new Sharepoint checklist", assignee=Assignee.SYSTEM)
def prompt_start_new_checklist(subscription: RouterProvisioning) -> FormGenerator:
"""Prompt the operator to start a new checklist in Sharepoint for approving this new router."""
oss_params = load_oss_params()
class SharepointPrompt(FormPage):
class Config:
title = "Start new checklist"
info_label_1: Label = (
f"Visit {oss_params.SHAREPOINT.checklist_site_url} and start a new Sharepoint checklist for "
f"{subscription.router.router_fqdn}." # type: ignore[assignment]
)
info_label_2: Label = "Once this is done, click proceed to finish the workflow." # type: ignore[assignment]
yield SharepointPrompt
return {}
@workflow(
"Create router",
initial_input_form=wrap_create_initial_input_form(initial_input_form_generator),
......@@ -231,9 +271,11 @@ def create_router() -> StepList:
>> prompt_reboot_router
>> prompt_console_login
>> prompt_insert_in_ims
>> prompt_insert_in_radius
>> router_is_nokia(create_netbox_device)
>> pp_interaction(run_checks_after_base_config)
>> set_status(SubscriptionLifecycle.PROVISIONING)
>> prompt_start_new_checklist
>> resync
>> done
)
......@@ -8,12 +8,15 @@ from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
from gso.services.subscriptions import get_product_id_by_name
from gso.utils.helpers import LAGMember
from gso.utils.shared_enums import Vendor
from test import USER_CONFIRM_EMPTY_FORM
from test.services.conftest import MockedNetboxClient
from test.workflows import (
assert_complete,
assert_pp_interaction_failure,
assert_pp_interaction_success,
assert_suspended,
extract_state,
resume_workflow,
run_workflow,
)
......@@ -120,6 +123,9 @@ def test_successful_iptrunk_creation_with_standard_lso_result(
for _ in range(6):
result, step_log = assert_pp_interaction_success(result, process_stat, step_log)
assert_suspended(result)
result, step_log = resume_workflow(process_stat, step_log, input_data=USER_CONFIRM_EMPTY_FORM)
assert_complete(result)
state = extract_state(result)
......@@ -196,4 +202,7 @@ def test_successful_iptrunk_creation_with_juniper_interface_names(
for _ in range(6):
result, step_log = assert_pp_interaction_success(result, process_stat, step_log)
assert_suspended(result)
result, step_log = resume_workflow(process_stat, step_log, input_data=USER_CONFIRM_EMPTY_FORM)
assert_complete(result)
......@@ -87,13 +87,16 @@ def test_create_nokia_router_success(
for _ in range(2):
result, step_log = assert_pp_interaction_success(result, process_stat, step_log)
# Handle three consecutive user input steps
for _ in range(3):
# Handle four consecutive user input steps
for _ in range(4):
assert_suspended(result)
result, step_log = resume_workflow(process_stat, step_log, input_data=USER_CONFIRM_EMPTY_FORM)
result, step_log = assert_pp_interaction_success(result, process_stat, step_log)
assert_suspended(result)
result, step_log = resume_workflow(process_stat, step_log, input_data=USER_CONFIRM_EMPTY_FORM)
assert_complete(result)
state = extract_state(result)
......