Skip to content
Snippets Groups Projects
Verified Commit 254220a2 authored by Karel van Klink's avatar Karel van Klink :smiley_cat:
Browse files

Update LSO interactions

parent 4e050c1d
No related branches found
No related tags found
No related merge requests found
...@@ -307,7 +307,7 @@ def _import_partners_from_csv(file_path: Path) -> list[dict]: ...@@ -307,7 +307,7 @@ def _import_partners_from_csv(file_path: Path) -> list[dict]:
def _generic_import_product( def _generic_import_product(
file_path: Path, imported_product_type: ProductType, workflow_suffix: str, name_key: str, import_model: type[T] file_path: Path, imported_product_type: ProductType, workflow_suffix: str, name_key: str, import_model: type[T]
) -> None: ) -> None:
"""Import subscriptions from a JSON or YAML file.""" """Import subscriptions from a JSON or YAML file."""
successfully_imported_data = [] successfully_imported_data = []
...@@ -553,4 +553,3 @@ def import_geant_ip(filepath: str = common_filepath_option) -> None: ...@@ -553,4 +553,3 @@ def import_geant_ip(filepath: str = common_filepath_option) -> None:
typer.echo("Successfully created imported GEANT IPs:") typer.echo("Successfully created imported GEANT IPs:")
for item in successfully_imported_data: for item in successfully_imported_data:
typer.echo(f"- {item}") typer.echo(f"- {item}")
...@@ -44,7 +44,7 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs ...@@ -44,7 +44,7 @@ class ServiceBindingPortProvisioning(ServiceBindingPortInactive, lifecycle=[Subs
custom_firewall_filters: bool custom_firewall_filters: bool
geant_sid: str geant_sid: str
sbp_bgp_session_list: list[BGPSessionProvisioning] # type: ignore[assignment] sbp_bgp_session_list: list[BGPSessionProvisioning] # type: ignore[assignment]
edge_port: EdgePortBlockProvisioning # type: ignore[assignment] edge_port: EdgePortBlockProvisioning
class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
...@@ -67,4 +67,4 @@ class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[Subscription ...@@ -67,4 +67,4 @@ class ServiceBindingPort(ServiceBindingPortProvisioning, lifecycle=[Subscription
#: The :term:`BGP` sessions associated with this service binding port. #: The :term:`BGP` sessions associated with this service binding port.
sbp_bgp_session_list: list[BGPSession] # type: ignore[assignment] sbp_bgp_session_list: list[BGPSession] # type: ignore[assignment]
#: The Edge Port on which this :term:`SBP` resides. #: The Edge Port on which this :term:`SBP` resides.
edge_port: EdgePortBlock # type: ignore[assignment] edge_port: EdgePortBlock
...@@ -19,8 +19,7 @@ from pynetbox.models.dcim import Interfaces ...@@ -19,8 +19,7 @@ from pynetbox.models.dcim import Interfaces
from gso.products.product_blocks.edge_port import EdgePortAEMemberBlockInactive, EdgePortType, EncapsulationType from gso.products.product_blocks.edge_port import EdgePortAEMemberBlockInactive, EdgePortType, EncapsulationType
from gso.products.product_types.edge_port import EdgePortInactive, EdgePortProvisioning from gso.products.product_types.edge_port import EdgePortInactive, EdgePortProvisioning
from gso.products.product_types.router import Router from gso.products.product_types.router import Router
from gso.services import lso_client from gso.services.lso_client import LSOState, lso_interaction
from gso.services.lso_client import lso_interaction
from gso.services.netbox_client import NetboxClient from gso.services.netbox_client import NetboxClient
from gso.services.partners import get_partner_by_id from gso.services.partners import get_partner_by_id
from gso.utils.helpers import ( from gso.utils.helpers import (
...@@ -185,9 +184,7 @@ def allocate_interfaces_in_netbox(subscription: EdgePortProvisioning) -> None: ...@@ -185,9 +184,7 @@ def allocate_interfaces_in_netbox(subscription: EdgePortProvisioning) -> None:
@step("[DRY RUN] Create edge port") @step("[DRY RUN] Create edge port")
def create_edge_port_dry( def create_edge_port_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState:
subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
) -> None:
"""Create a new edge port in the network as a dry run.""" """Create a new edge port in the network as a dry run."""
extra_vars = { extra_vars = {
"dry_run": True, "dry_run": True,
...@@ -196,18 +193,15 @@ def create_edge_port_dry( ...@@ -196,18 +193,15 @@ def create_edge_port_dry(
"verb": "create", "verb": "create",
} }
lso_client.execute_playbook( return {
playbook_name="edge_port.yaml", "playbook_name": "edge_port.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("[FOR REAL] Create edge port") @step("[FOR REAL] Create edge port")
def create_edge_port_real( def create_edge_port_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState:
subscription: dict[str, Any], callback_route: str, tt_number: str, process_id: UUIDstr
) -> None:
"""Create a new edge port in the network for real.""" """Create a new edge port in the network for real."""
extra_vars = { extra_vars = {
"dry_run": False, "dry_run": False,
...@@ -216,12 +210,11 @@ def create_edge_port_real( ...@@ -216,12 +210,11 @@ def create_edge_port_real(
"verb": "create", "verb": "create",
} }
lso_client.execute_playbook( return {
playbook_name="edge_port.yaml", "playbook_name": "edge_port.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@workflow( @workflow(
......
...@@ -11,12 +11,12 @@ from orchestrator.workflow import StepList, begin, conditional, done, step ...@@ -11,12 +11,12 @@ from orchestrator.workflow import StepList, begin, conditional, done, step
from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.steps import resync, store_process_subscription, unsync
from orchestrator.workflows.utils import wrap_modify_initial_input_form from orchestrator.workflows.utils import wrap_modify_initial_input_form
from pydantic import AfterValidator, ConfigDict, model_validator from pydantic import AfterValidator, ConfigDict, model_validator
from pydantic_forms.types import FormGenerator, UUIDstr from pydantic_forms.types import FormGenerator, State, UUIDstr
from pydantic_forms.validators import ReadOnlyField, validate_unique_list from pydantic_forms.validators import ReadOnlyField, validate_unique_list
from gso.products.product_blocks.edge_port import EdgePortAEMemberBlock, EncapsulationType from gso.products.product_blocks.edge_port import EdgePortAEMemberBlock, EncapsulationType
from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.edge_port import EdgePort
from gso.services.lso_client import execute_playbook, lso_interaction from gso.services.lso_client import LSOState, lso_interaction
from gso.services.netbox_client import NetboxClient from gso.services.netbox_client import NetboxClient
from gso.services.partners import get_partner_by_id from gso.services.partners import get_partner_by_id
from gso.utils.helpers import ( from gso.utils.helpers import (
...@@ -122,7 +122,7 @@ def modify_edge_port_subscription( ...@@ -122,7 +122,7 @@ def modify_edge_port_subscription(
ae_members: list[dict[str, str]], ae_members: list[dict[str, str]],
ignore_if_down: bool, # noqa: FBT001 ignore_if_down: bool, # noqa: FBT001
description: str | None = None, description: str | None = None,
) -> dict[str, Any]: ) -> State:
"""Modify the edge port subscription with the given parameters.""" """Modify the edge port subscription with the given parameters."""
previous_ae_members = [ previous_ae_members = [
{ {
...@@ -158,10 +158,8 @@ def modify_edge_port_subscription( ...@@ -158,10 +158,8 @@ def modify_edge_port_subscription(
@step("Update interfaces in NetBox") @step("Update interfaces in NetBox")
def update_interfaces_in_netbox( def update_interfaces_in_netbox(
subscription: EdgePort, subscription: EdgePort, removed_ae_members: list[dict], previous_ae_members: list[dict]
removed_ae_members: list[dict], ) -> State:
previous_ae_members: list[dict],
) -> dict[str, Any]:
"""Update the interfaces in NetBox.""" """Update the interfaces in NetBox."""
nbclient = NetboxClient() nbclient = NetboxClient()
# Free removed interfaces # Free removed interfaces
...@@ -186,12 +184,8 @@ def update_interfaces_in_netbox( ...@@ -186,12 +184,8 @@ def update_interfaces_in_netbox(
@step("[DRY RUN] Update edge port configuration.") @step("[DRY RUN] Update edge port configuration.")
def update_edge_port_dry( def update_edge_port_dry(
subscription: dict[str, Any], subscription: dict[str, Any], process_id: UUIDstr, tt_number: str, removed_ae_members: list[dict]
process_id: UUIDstr, ) -> LSOState:
tt_number: str,
callback_route: str,
removed_ae_members: list[dict],
) -> dict[str, Any]:
"""Perform a dry run of updating the edge port configuration.""" """Perform a dry run of updating the edge port configuration."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -203,24 +197,18 @@ def update_edge_port_dry( ...@@ -203,24 +197,18 @@ def update_edge_port_dry(
"removed_ae_members": removed_ae_members, "removed_ae_members": removed_ae_members,
} }
execute_playbook( return {
playbook_name="edge_ports.yaml", "playbook_name": "edge_ports.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]}}},
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "extra_vars": extra_vars,
extra_vars=extra_vars, "subscription": subscription,
) }
return {"subscription": subscription}
@step("[FOR REAL] Update edge port configuration.") @step("[FOR REAL] Update edge port configuration.")
def update_edge_port_real( def update_edge_port_real(
subscription: dict[str, Any], subscription: dict[str, Any], process_id: UUIDstr, tt_number: str, removed_ae_members: list[str]
process_id: UUIDstr, ) -> LSOState:
tt_number: str,
callback_route: str,
removed_ae_members: list[str],
) -> dict[str, Any]:
"""Update the edge port configuration.""" """Update the edge port configuration."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -232,14 +220,12 @@ def update_edge_port_real( ...@@ -232,14 +220,12 @@ def update_edge_port_real(
"removed_ae_members": removed_ae_members, "removed_ae_members": removed_ae_members,
} }
execute_playbook( return {
playbook_name="edge_ports.yaml", "subscription": subscription,
callback_route=callback_route, "playbook_name": "edge_ports.yaml",
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
extra_vars=extra_vars, "extra_vars": extra_vars,
) }
return {"subscription": subscription}
@step("Allocate/Deallocate interfaces in NetBox") @step("Allocate/Deallocate interfaces in NetBox")
......
...@@ -12,7 +12,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form ...@@ -12,7 +12,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form
from pydantic_forms.types import FormGenerator, UUIDstr from pydantic_forms.types import FormGenerator, UUIDstr
from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.edge_port import EdgePort
from gso.services.lso_client import execute_playbook, lso_interaction from gso.services.lso_client import LSOState, lso_interaction
from gso.services.netbox_client import NetboxClient from gso.services.netbox_client import NetboxClient
from gso.utils.types.tt_number import TTNumber from gso.utils.types.tt_number import TTNumber
...@@ -28,9 +28,7 @@ def initial_input_form_generator() -> FormGenerator: ...@@ -28,9 +28,7 @@ def initial_input_form_generator() -> FormGenerator:
@step("[DRY RUN] Remove Edge Port") @step("[DRY RUN] Remove Edge Port")
def remove_edge_port_dry( def remove_edge_port_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> dict[str, Any]:
subscription: dict[str, Any], tt_number: str, process_id: UUIDstr, callback_route: str
) -> dict[str, Any]:
"""Remove an edge port from the network.""" """Remove an edge port from the network."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -39,19 +37,16 @@ def remove_edge_port_dry( ...@@ -39,19 +37,16 @@ def remove_edge_port_dry(
"commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Delete Edge Port", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Delete Edge Port",
} }
execute_playbook( return {
playbook_name="edge_port.yaml", "subscription": subscription,
callback_route=callback_route, "playbook_name": "edge_port.yaml",
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
extra_vars=extra_vars, "extra_vars": extra_vars,
) }
return {"subscription": subscription}
@step("[FOR REAL] Remove Edge Port") @step("[FOR REAL] Remove Edge Port")
def remove_edge_port_real( def remove_edge_port_real(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState:
subscription: dict[str, Any], tt_number: str, process_id: UUIDstr, callback_route: str
) -> None:
"""Remove an edge port from the network.""" """Remove an edge port from the network."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -60,12 +55,12 @@ def remove_edge_port_real( ...@@ -60,12 +55,12 @@ def remove_edge_port_real(
"commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Delete Edge Port", "commit_comment": f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Delete Edge Port",
} }
execute_playbook( return {
playbook_name="edge_port.yaml", "subscription": subscription,
callback_route=callback_route, "playbook_name": "edge_port.yaml",
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
extra_vars=extra_vars, "extra_vars": extra_vars,
) }
@step("Netbox Clean Up") @step("Netbox Clean Up")
......
...@@ -10,7 +10,7 @@ from orchestrator.workflows.steps import resync, store_process_subscription ...@@ -10,7 +10,7 @@ from orchestrator.workflows.steps import resync, store_process_subscription
from orchestrator.workflows.utils import wrap_modify_initial_input_form from orchestrator.workflows.utils import wrap_modify_initial_input_form
from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.edge_port import EdgePort
from gso.services.lso_client import anonymous_lso_interaction, execute_playbook from gso.services.lso_client import LSOState, anonymous_lso_interaction
from gso.services.netbox_client import NetboxClient from gso.services.netbox_client import NetboxClient
...@@ -56,19 +56,18 @@ def verify_netbox_entries(subscription: EdgePort) -> None: ...@@ -56,19 +56,18 @@ def verify_netbox_entries(subscription: EdgePort) -> None:
@step("Check base config for drift") @step("Check base config for drift")
def verify_base_config(subscription: dict[str, Any], callback_route: str) -> None: def verify_base_config(subscription: dict[str, Any]) -> LSOState:
"""Workflow step for running a playbook that checks whether base config has drifted.""" """Workflow step for running a playbook that checks whether base config has drifted."""
execute_playbook( return {
playbook_name="edge_port.yaml", "playbook_name": "edge_port.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": {subscription["edge_port"]["edge_port_node"]["router_fqdn"]: None}}},
inventory=subscription["edge_port"]["edge_port_node"]["router_fqdn"], "extra_vars": {
extra_vars={
"dry_run": True, "dry_run": True,
"subscription": subscription, "subscription": subscription,
"verb": "create", "verb": "create",
"is_verification_workflow": "true", "is_verification_workflow": "true",
}, },
) }
@workflow( @workflow(
......
...@@ -18,7 +18,7 @@ from gso.products.product_blocks.geant_ip import NRENAccessPortInactive ...@@ -18,7 +18,7 @@ from gso.products.product_blocks.geant_ip import NRENAccessPortInactive
from gso.products.product_blocks.service_binding_port import VLAN_ID, ServiceBindingPort from gso.products.product_blocks.service_binding_port import VLAN_ID, ServiceBindingPort
from gso.products.product_types.edge_port import EdgePort from gso.products.product_types.edge_port import EdgePort
from gso.products.product_types.geant_ip import GeantIPInactive from gso.products.product_types.geant_ip import GeantIPInactive
from gso.services.lso_client import execute_playbook, lso_interaction from gso.services.lso_client import LSOState, lso_interaction
from gso.utils.helpers import ( from gso.utils.helpers import (
active_edge_port_selector, active_edge_port_selector,
partner_choice, partner_choice,
...@@ -173,12 +173,8 @@ def initialize_subscription( ...@@ -173,12 +173,8 @@ def initialize_subscription(
@step("[DRY RUN] Deploy service binding port") @step("[DRY RUN] Deploy service binding port")
def provision_sbp_dry( def provision_sbp_dry(
subscription: dict[str, Any], subscription: dict[str, Any], process_id: UUIDstr, tt_number: str, edge_port_fqdn_list: list[str]
callback_route: str, ) -> LSOState:
process_id: UUIDstr,
tt_number: str,
edge_port_fqdn_list: list[str],
) -> None:
"""Perform a dry run of deploying Service Binding Ports.""" """Perform a dry run of deploying Service Binding Ports."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -188,22 +184,17 @@ def provision_sbp_dry( ...@@ -188,22 +184,17 @@ def provision_sbp_dry(
f"Deploy config for {subscription["description"]}", f"Deploy config for {subscription["description"]}",
} }
execute_playbook( return {
playbook_name="manage_sbp.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("[FOR REAL] Deploy service binding port") @step("[FOR REAL] Deploy service binding port")
def provision_sbp_real( def provision_sbp_real(
subscription: dict[str, Any], subscription: dict[str, Any], process_id: UUIDstr, tt_number: str, edge_port_fqdn_list: list[str]
callback_route: str, ) -> LSOState:
process_id: UUIDstr,
tt_number: str,
edge_port_fqdn_list: list[str],
) -> None:
"""Deploy Service Binding Ports.""" """Deploy Service Binding Ports."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -213,35 +204,29 @@ def provision_sbp_real( ...@@ -213,35 +204,29 @@ def provision_sbp_real(
f"Deploy config for {subscription["description"]}", f"Deploy config for {subscription["description"]}",
} }
execute_playbook( return {
playbook_name="manage_sbp.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("Check service binding port functionality") @step("Check service binding port functionality")
def check_sbp_functionality(subscription: dict[str, Any], callback_route: str, edge_port_fqdn_list: list[str]) -> None: def check_sbp_functionality(subscription: dict[str, Any], edge_port_fqdn_list: list[str]) -> LSOState:
"""Check functionality of deployed Service Binding Ports.""" """Check functionality of deployed Service Binding Ports."""
extra_vars = {"subscription": subscription, "verb": "check"} extra_vars = {"subscription": subscription, "verb": "check"}
execute_playbook( return {
playbook_name="manage_sbp.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("[DRY RUN] Deploy BGP peers") @step("[DRY RUN] Deploy BGP peers")
def deploy_bgp_peers_dry( def deploy_bgp_peers_dry(
subscription: dict[str, Any], subscription: dict[str, Any], edge_port_fqdn_list: list[str], tt_number: str, process_id: UUIDstr
callback_route: str, ) -> LSOState:
edge_port_fqdn_list: list[str],
tt_number: str,
process_id: UUIDstr,
) -> None:
"""Perform a dry run of deploying :term:`BGP` peers.""" """Perform a dry run of deploying :term:`BGP` peers."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -251,22 +236,17 @@ def deploy_bgp_peers_dry( ...@@ -251,22 +236,17 @@ def deploy_bgp_peers_dry(
f"Deploying BGP peers for {subscription["description"]}", f"Deploying BGP peers for {subscription["description"]}",
} }
execute_playbook( return {
playbook_name="manage_bgp_peers.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("[FOR REAL] Deploy BGP peers") @step("[FOR REAL] Deploy BGP peers")
def deploy_bgp_peers_real( def deploy_bgp_peers_real(
subscription: dict[str, Any], subscription: dict[str, Any], edge_port_fqdn_list: list[str], tt_number: str, process_id: UUIDstr
callback_route: str, ) -> LSOState:
edge_port_fqdn_list: list[str],
tt_number: str,
process_id: UUIDstr,
) -> None:
"""Deploy :term:`BGP` peers.""" """Deploy :term:`BGP` peers."""
extra_vars = { extra_vars = {
"subscription": subscription, "subscription": subscription,
...@@ -276,25 +256,23 @@ def deploy_bgp_peers_real( ...@@ -276,25 +256,23 @@ def deploy_bgp_peers_real(
f"Deploying BGP peers for {subscription["description"]}", f"Deploying BGP peers for {subscription["description"]}",
} }
execute_playbook( return {
playbook_name="manage_bgp_peers.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("Check BGP peers") @step("Check BGP peers")
def check_bgp_peers(subscription: dict[str, Any], callback_route: str, edge_port_fqdn_list: list[str]) -> None: def check_bgp_peers(subscription: dict[str, Any], edge_port_fqdn_list: list[str]) -> LSOState:
"""Check correct deployment of :term:`BGP` peers.""" """Check correct deployment of :term:`BGP` peers."""
extra_vars = {"subscription": subscription, "verb": "check"} extra_vars = {"subscription": subscription, "verb": "check"}
execute_playbook( return {
playbook_name="manage_bgp_peers.yaml", "playbook_name": "manage_sbp.yaml",
callback_route=callback_route, "inventory": {"all": {"hosts": dict.fromkeys(edge_port_fqdn_list)}},
inventory="\n".join(edge_port_fqdn_list), "extra_vars": extra_vars,
extra_vars=extra_vars, }
)
@step("Update Infoblox") @step("Update Infoblox")
......
"""A creation workflow for adding an existing GEANT IP to the service database.""" """A creation workflow for adding an existing GEANT IP to the service database."""
from uuid import uuid4 from uuid import uuid4
from orchestrator import workflow from orchestrator import workflow
...@@ -10,10 +11,11 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc ...@@ -10,10 +11,11 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc
from pydantic import BaseModel from pydantic import BaseModel
from pydantic_forms.types import UUIDstr from pydantic_forms.types import UUIDstr
from gso.products import EdgePort, ProductName from gso.products import ProductName
from gso.products.product_blocks.bgp_session import IPFamily, BGPSession from gso.products.product_blocks.bgp_session import BGPSession, IPFamily
from gso.products.product_blocks.geant_ip import NRENAccessPortInactive from gso.products.product_blocks.geant_ip import NRENAccessPortInactive
from gso.products.product_blocks.service_binding_port import VLAN_ID, ServiceBindingPort from gso.products.product_blocks.service_binding_port import VLAN_ID, ServiceBindingPort
from gso.products.product_types.edge_port import EdgePort
from gso.products.product_types.geant_ip import ImportedGeantIPInactive from gso.products.product_types.geant_ip import ImportedGeantIPInactive
from gso.services.partners import get_partner_by_name from gso.services.partners import get_partner_by_name
from gso.services.subscriptions import get_product_id_by_name from gso.services.subscriptions import get_product_id_by_name
...@@ -79,8 +81,7 @@ def initialize_subscription(subscription: ImportedGeantIPInactive, initial_input ...@@ -79,8 +81,7 @@ def initialize_subscription(subscription: ImportedGeantIPInactive, initial_input
for service_binding_port in initial_input["service_binding_ports"]: for service_binding_port in initial_input["service_binding_ports"]:
edge_port_subscription = EdgePort.from_subscription(service_binding_port["edge_port"]) edge_port_subscription = EdgePort.from_subscription(service_binding_port["edge_port"])
sbp_bgp_session_list = [ sbp_bgp_session_list = [
BGPSession.new(subscription_id=uuid4(), **session) BGPSession.new(subscription_id=uuid4(), **session) for session in service_binding_port["bgp_peers"]
for session in service_binding_port["bgp_peers"]
] ]
ServiceBindingPort.new( ServiceBindingPort.new(
subscription_id=uuid4(), subscription_id=uuid4(),
...@@ -109,11 +110,11 @@ def initialize_subscription(subscription: ImportedGeantIPInactive, initial_input ...@@ -109,11 +110,11 @@ def initialize_subscription(subscription: ImportedGeantIPInactive, initial_input
def create_imported_geant_ip() -> StepList: def create_imported_geant_ip() -> StepList:
"""Import a GÉANT IP without provisioning it.""" """Import a GÉANT IP without provisioning it."""
return ( return (
begin begin
>> create_subscription >> create_subscription
>> store_process_subscription(Target.CREATE) >> store_process_subscription(Target.CREATE)
>> initialize_subscription >> initialize_subscription
>> set_status(SubscriptionLifecycle.ACTIVE) >> set_status(SubscriptionLifecycle.ACTIVE)
>> resync >> resync
>> done >> done
) )
...@@ -7,9 +7,11 @@ from orchestrator import begin, conditional, done, step, workflow ...@@ -7,9 +7,11 @@ from orchestrator import begin, conditional, done, step, workflow
from orchestrator.forms import FormPage from orchestrator.forms import FormPage
from orchestrator.targets import Target from orchestrator.targets import Target
from orchestrator.types import FormGenerator, UUIDstr from orchestrator.types import FormGenerator, UUIDstr
from orchestrator.workflows.steps import State, resync, store_process_subscription, unsync from orchestrator.workflow import StepList
from orchestrator.workflows.steps import resync, store_process_subscription, unsync
from orchestrator.workflows.utils import wrap_modify_initial_input_form from orchestrator.workflows.utils import wrap_modify_initial_input_form
from pydantic import AfterValidator, BaseModel, ConfigDict, Field, computed_field from pydantic import AfterValidator, BaseModel, ConfigDict, Field, computed_field
from pydantic_forms.types import State
from pydantic_forms.validators import Divider, Label from pydantic_forms.validators import Divider, Label
from gso.products.product_blocks.bgp_session import BGPSession, IPFamily from gso.products.product_blocks.bgp_session import BGPSession, IPFamily
...@@ -106,7 +108,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -106,7 +108,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
if str(access_port.geant_ip_sbp.edge_port.owner_subscription_id) in input_ep_list if str(access_port.geant_ip_sbp.edge_port.owner_subscription_id) in input_ep_list
] ]
added_ap_list = [ added_ap_list = [
(ep, next((ap.nren_ap_type for ap in input_ap_list if str(ap.geant_ip_ep) == ep), None)) (ep, next(ap.nren_ap_type for ap in input_ap_list if str(ap.geant_ip_ep) == ep))
for ep in input_ep_list for ep in input_ep_list
if ep not in existing_ep_list if ep not in existing_ep_list
] ]
...@@ -116,8 +118,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -116,8 +118,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
for access_port_index, ap_entry in enumerate(modified_ap_list): for access_port_index, ap_entry in enumerate(modified_ap_list):
access_port, new_ap_type = ap_entry access_port, new_ap_type = ap_entry
current_sbp = access_port.geant_ip_sbp current_sbp = access_port.geant_ip_sbp
v4_peer = next((peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V4UNICAST in peer.families), None) v4_peer = next(peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V4UNICAST in peer.families)
v6_peer = next((peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V6UNICAST in peer.families), None) v6_peer = next(peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V6UNICAST in peer.families)
class BindingPortModificationForm(FormPage): class BindingPortModificationForm(FormPage):
model_config = ConfigDict( model_config = ConfigDict(
...@@ -131,9 +133,11 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -131,9 +133,11 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
geant_sid: str = current_sbp.geant_sid geant_sid: str = current_sbp.geant_sid
is_tagged: bool = current_sbp.is_tagged is_tagged: bool = current_sbp.is_tagged
vlan_id: VLAN_ID = current_sbp.vlan_id # The SBP model doesn't require these three fields, but in the case of GÉANT IP this will never occur since
ipv4_address: IPv4AddressType = current_sbp.ipv4_address # it's a layer 3 service. The ignore statements are there to put our type checker at ease.
ipv6_address: IPv6AddressType = current_sbp.ipv6_address vlan_id: VLAN_ID = current_sbp.vlan_id # type: ignore[assignment]
ipv4_address: IPv4AddressType = current_sbp.ipv4_address # type: ignore[assignment]
ipv6_address: IPv6AddressType = current_sbp.ipv6_address # type: ignore[assignment]
custom_firewall_filters: bool = current_sbp.custom_firewall_filters custom_firewall_filters: bool = current_sbp.custom_firewall_filters
divider: Divider = Field(None, exclude=True) divider: Divider = Field(None, exclude=True)
v4_bgp_peer: IPv4BGPPeer = IPv4BGPPeer( v4_bgp_peer: IPv4BGPPeer = IPv4BGPPeer(
...@@ -156,8 +160,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -156,8 +160,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
# Second, newly added Edge Ports are configured # Second, newly added Edge Ports are configured
binding_port_inputs = [] binding_port_inputs = []
for ap_index, access_port in enumerate(added_ap_list): for ap_index, access_port_tuple in enumerate(added_ap_list):
edge_port_id, ap_type = access_port edge_port_id, ap_type = access_port_tuple
class BindingPortInputForm(FormPage): class BindingPortInputForm(FormPage):
model_config = ConfigDict( model_config = ConfigDict(
...@@ -204,7 +208,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -204,7 +208,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
@step("Clean up removed Edge Ports") @step("Clean up removed Edge Ports")
def remove_old_sbp_blocks(subscription: GeantIP, removed_access_ports: list[UUIDstr]): def remove_old_sbp_blocks(subscription: GeantIP, removed_access_ports: list[UUIDstr]) -> State:
"""Remove old :term:`SBP` product blocks from the GÉANT IP subscription.""" """Remove old :term:`SBP` product blocks from the GÉANT IP subscription."""
subscription.geant_ip.geant_ip_ap_list = [ subscription.geant_ip.geant_ip_ap_list = [
ap ap
...@@ -221,15 +225,14 @@ def modify_existing_sbp_blocks(subscription: GeantIP, modified_sbp_list: list[di ...@@ -221,15 +225,14 @@ def modify_existing_sbp_blocks(subscription: GeantIP, modified_sbp_list: list[di
for access_port in subscription.geant_ip.geant_ip_ap_list: for access_port in subscription.geant_ip.geant_ip_ap_list:
current_sbp = access_port.geant_ip_sbp current_sbp = access_port.geant_ip_sbp
modified_sbp_data = next( modified_sbp_data = next(
(sbp for sbp in modified_sbp_list if sbp["current_sbp_id"] == str(current_sbp.subscription_instance_id)), sbp for sbp in modified_sbp_list if sbp["current_sbp_id"] == str(current_sbp.subscription_instance_id)
None,
) )
v4_peer = next((peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V4UNICAST in peer.families), None) v4_peer = next(peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V4UNICAST in peer.families)
for attribute in modified_sbp_data["v4_bgp_peer"]: for attribute in modified_sbp_data["v4_bgp_peer"]:
setattr(v4_peer, attribute, modified_sbp_data["v4_bgp_peer"][attribute]) setattr(v4_peer, attribute, modified_sbp_data["v4_bgp_peer"][attribute])
v6_peer = next((peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V6UNICAST in peer.families), None) v6_peer = next(peer for peer in current_sbp.sbp_bgp_session_list if IPFamily.V6UNICAST in peer.families)
for attribute in modified_sbp_data["v6_bgp_peer"]: for attribute in modified_sbp_data["v6_bgp_peer"]:
setattr(v6_peer, attribute, modified_sbp_data["v6_bgp_peer"][attribute]) setattr(v6_peer, attribute, modified_sbp_data["v6_bgp_peer"][attribute])
...@@ -246,7 +249,7 @@ def modify_existing_sbp_blocks(subscription: GeantIP, modified_sbp_list: list[di ...@@ -246,7 +249,7 @@ def modify_existing_sbp_blocks(subscription: GeantIP, modified_sbp_list: list[di
@step("Instantiate new Service Binding Ports") @step("Instantiate new Service Binding Ports")
def create_new_sbp_blocks(subscription: GeantIP, added_service_binding_ports: list[dict[str, Any]]): def create_new_sbp_blocks(subscription: GeantIP, added_service_binding_ports: list[dict[str, Any]]) -> State:
"""Add new :term:`SBP`s to the GÉANT IP subscription.""" """Add new :term:`SBP`s to the GÉANT IP subscription."""
for sbp_input in added_service_binding_ports: for sbp_input in added_service_binding_ports:
edge_port = EdgePort.from_subscription(sbp_input["edge_port_id"]) edge_port = EdgePort.from_subscription(sbp_input["edge_port_id"])
...@@ -277,7 +280,7 @@ def create_new_sbp_blocks(subscription: GeantIP, added_service_binding_ports: li ...@@ -277,7 +280,7 @@ def create_new_sbp_blocks(subscription: GeantIP, added_service_binding_ports: li
initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator), initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator),
target=Target.MODIFY, target=Target.MODIFY,
) )
def modify_geant_ip(): def modify_geant_ip() -> StepList:
"""Modify a GÉANT IP subscription.""" """Modify a GÉANT IP subscription."""
access_ports_are_removed = conditional(lambda state: bool(len(state["removed_access_ports"]) > 0)) access_ports_are_removed = conditional(lambda state: bool(len(state["removed_access_ports"]) > 0))
access_ports_are_modified = conditional(lambda state: bool(len(state["modified_sbp_list"]) > 0)) access_ports_are_modified = conditional(lambda state: bool(len(state["modified_sbp_list"]) > 0))
......
...@@ -49,4 +49,5 @@ def test_create_geant_ip_success( ...@@ -49,4 +49,5 @@ def test_create_geant_ip_success(
] ]
result, process_stat, step_log = run_workflow("create_geant_ip", form_input_data) result, process_stat, step_log = run_workflow("create_geant_ip", form_input_data)
assert process_stat, step_log
assert_complete(result) assert_complete(result)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment