Skip to content
Snippets Groups Projects
Commit ce96db03 authored by Mohammad Torkashvand's avatar Mohammad Torkashvand
Browse files

add requied code for IAS to R&E Interconnect and its imported version

parent 0e348068
No related branches found
No related tags found
1 merge request!251Draft: add IAS to R&E Interconnect and its imported models and workflows
Pipeline #88359 failed
Showing
with 529 additions and 3 deletions
......@@ -27,6 +27,7 @@ from gso.services.partners import (
get_partner_by_name,
)
from gso.services.subscriptions import (
get_active_pe_router_subscriptions,
get_active_router_subscriptions,
get_active_subscriptions_by_field_and_value,
get_subscriptions,
......@@ -187,6 +188,28 @@ class OpenGearImportModel(BaseModel):
opengear_wan_gateway: IPv4AddressType
class IasToReInterconnectImportModel(BaseModel):
"""Required fields for importing an existing :class:`gso.products.product_types.ias_to_re_interconnect.`."""
partner: str
ipv4_network: ipaddress.IPv4Network
ipv6_network: ipaddress.IPv6Network
router_id: str
@classmethod
def _get_active_pe_routers(cls) -> set[str]:
return {str(router.subscription_id) for router in get_active_pe_router_subscriptions()}
@field_validator("router_id")
def check_if_router_is_available(cls, value: str) -> str:
"""Router must exist in :term:`GSO`."""
if value not in cls._get_active_pe_routers():
msg = f"PE Router {value} not found"
raise ValueError(msg)
return value
T = TypeVar(
"T",
SiteImportModel,
......@@ -195,6 +218,7 @@ T = TypeVar(
SuperPopSwitchImportModel,
OfficeRouterImportModel,
OpenGearImportModel,
IasToReInterconnectImportModel,
)
common_filepath_option = typer.Option(
......@@ -323,6 +347,45 @@ def import_opengear(filepath: str = common_filepath_option) -> None:
)
@app.command()
def import_ias_to_re_interconnect(filepath: str = common_filepath_option) -> None:
"""Import IasToReInterconnect into GSO."""
successfully_imported_data = []
data = _read_data(Path(filepath))
for details in data:
details["partner"] = "GEANT"
key = f"{details["router_id"]}-{details["ipv4_network"]}-{details["ipv6_network"]}"
typer.echo(f"Creating imported IAS to R&E Interconnect: {key}")
try:
initial_data = IasToReInterconnectImportModel(**details)
start_process("create_imported_ias_to_re_interconnect", [initial_data.model_dump()])
successfully_imported_data.append(key)
typer.echo(
f"Successfully created {key}",
)
except ValidationError as e:
typer.echo(f"Validation error: {e}")
typer.echo("Waiting for the dust to settle before moving on the importing new products...")
time.sleep(1)
# Migrate new products from imported to "full" counterpart.
imported_products = get_subscriptions(
[ProductType.IMPORTED_IAS_TO_RE_INTERCONNECT],
lifecycles=[SubscriptionLifecycle.ACTIVE],
includes=["subscription_id"],
)
for subscription_id in imported_products:
typer.echo(f"Importing {subscription_id}")
start_process("import_ias_to_re_interconnect", [subscription_id])
if successfully_imported_data:
typer.echo("Successfully created imported IasToReInterconnects:")
for item in successfully_imported_data:
typer.echo(f"- {item}")
typer.echo("Please validate no more imported IasToReInterconnect products exist anymore in the database.")
@app.command()
def import_iptrunks(filepath: str = common_filepath_option) -> None:
"""Import IP trunks into GSO."""
......
"""Add IAS to R&E Interconnect and its imported products.
Revision ID: 0f7f23d13632
Revises: 41fd1ae225aq
Create Date: 2024-08-07 19:01:47.700755
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = '0f7f23d13632'
down_revision = '41fd1ae225aq'
branch_labels = None
depends_on = None
def upgrade() -> None:
conn = op.get_bind()
conn.execute(sa.text("""
INSERT INTO products (name, description, product_type, tag, status) VALUES ('IAS to R&E Interconnect', 'IAS to R&E Interconnect', 'IasToReInterconnect', 'IAS_TO_RE', 'active') RETURNING products.product_id
"""))
conn.execute(sa.text("""
INSERT INTO products (name, description, product_type, tag, status) VALUES ('Imported IAS to R&E Interconnect', 'Imported IAS to R&E Interconnect', 'ImportedIasToReInterconnect', 'IAS_TO_RE_IMP', 'active') RETURNING products.product_id
"""))
conn.execute(sa.text("""
INSERT INTO product_blocks (name, description, tag, status) VALUES ('IasToReInterconnectBlock', 'IAS to R&E Interconnect', 'IAS_TO_RE', 'active') RETURNING product_blocks.product_block_id
"""))
conn.execute(sa.text("""
INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('IAS to R&E Interconnect')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')))
"""))
conn.execute(sa.text("""
INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock')))
"""))
conn.execute(sa.text("""
INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_network')))
"""))
conn.execute(sa.text("""
INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_network')))
"""))
def downgrade() -> None:
conn = op.get_bind()
conn.execute(sa.text("""
DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_network'))
"""))
conn.execute(sa.text("""
DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_network'))
"""))
conn.execute(sa.text("""
DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_network'))
"""))
conn.execute(sa.text("""
DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_network'))
"""))
conn.execute(sa.text("""
DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock'))
"""))
conn.execute(sa.text("""
DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('RouterBlock'))
"""))
conn.execute(sa.text("""
DELETE FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock'))
"""))
conn.execute(sa.text("""
DELETE FROM product_blocks WHERE product_blocks.name IN ('IasToReInterconnectBlock')
"""))
conn.execute(sa.text("""
DELETE FROM processes WHERE processes.pid IN (SELECT processes_subscriptions.pid FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect'))))
"""))
conn.execute(sa.text("""
DELETE FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect')))
"""))
conn.execute(sa.text("""
DELETE FROM subscription_instances WHERE subscription_instances.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect')))
"""))
conn.execute(sa.text("""
DELETE FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect'))
"""))
conn.execute(sa.text("""
DELETE FROM products WHERE products.name IN ('Imported IAS to R&E Interconnect', 'IAS to R&E Interconnect')
"""))
"""Add IAS to R&E Interconnect and its Imported workflows.
Revision ID: ba1d21f0281a
Revises: 0f7f23d13632
Create Date: 2024-08-07 19:03:59.636996
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = 'ba1d21f0281a'
down_revision = '0f7f23d13632'
branch_labels = None
depends_on = None
from orchestrator.migrations.helpers import create_workflow, delete_workflow
new_workflows = [
{
"name": "create_ias_to_re_interconnect",
"target": "CREATE",
"description": "Create IAS to R&E Interconnect",
"product_type": "IasToReInterconnect"
},
{
"name": "import_ias_to_re_interconnect",
"target": "MODIFY",
"description": "Import IAS to R&E Interconnect",
"product_type": "ImportedIasToReInterconnect"
}
]
def upgrade() -> None:
conn = op.get_bind()
for workflow in new_workflows:
create_workflow(conn, workflow)
def downgrade() -> None:
conn = op.get_bind()
for workflow in new_workflows:
delete_workflow(conn, workflow["name"])
......@@ -51,6 +51,13 @@
"domain_name": ".geantip",
"dns_view": "default",
"network_view": "default"
},
"IAS_TO_RE": {
"V4": {"containers": ["1.1.2.0/24"], "networks": [], "mask": 31},
"V6": {"containers": ["dead:beef::/64"], "networks": [], "mask": 126},
"domain_name": ".geantip",
"dns_view": "default",
"network_view": "default"
}
},
"MONITORING": {
......
......@@ -8,6 +8,7 @@
from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY
from pydantic_forms.types import strEnum
from gso.products.product_types.ias_to_re_interconnect import IasToReInterconnect, ImportedIasToReInterconnect
from gso.products.product_types.iptrunk import ImportedIptrunk, Iptrunk
from gso.products.product_types.lan_switch_interconnect import LanSwitchInterconnect
from gso.products.product_types.office_router import ImportedOfficeRouter, OfficeRouter
......@@ -37,6 +38,8 @@ class ProductName(strEnum):
IMPORTED_OFFICE_ROUTER = "Imported office router"
OPENGEAR = "Opengear"
IMPORTED_OPENGEAR = "Imported Opengear"
IAS_TO_RE_INTERCONNECT = "IAS to R&E Interconnect"
IMPORTED_IAS_TO_RE_INTERCONNECT = "Imported IAS to R&E Interconnect"
class ProductType(strEnum):
......@@ -57,6 +60,8 @@ class ProductType(strEnum):
IMPORTED_OFFICE_ROUTER = ImportedOfficeRouter.__name__
OPENGEAR = Opengear.__name__
IMPORTED_OPENGEAR = Opengear.__name__
IAS_TO_RE_INTERCONNECT = IasToReInterconnect.__name__
IMPORTED_IAS_TO_RE_INTERCONNECT = ImportedIasToReInterconnect.__name__
SUBSCRIPTION_MODEL_REGISTRY.update(
......@@ -76,5 +81,7 @@ SUBSCRIPTION_MODEL_REGISTRY.update(
ProductName.IMPORTED_OFFICE_ROUTER.value: ImportedOfficeRouter,
ProductName.OPENGEAR.value: Opengear,
ProductName.IMPORTED_OPENGEAR.value: ImportedOpengear,
ProductName.IAS_TO_RE_INTERCONNECT.value: IasToReInterconnect,
ProductName.IMPORTED_IAS_TO_RE_INTERCONNECT.value: ImportedIasToReInterconnect,
},
)
"""IAS to R&E Interconnect product block that has all parameters of a subscription throughout its lifecycle."""
import ipaddress
from orchestrator.domain.base import ProductBlockModel
from orchestrator.types import SubscriptionLifecycle
from gso.products.product_blocks.router import RouterBlock, RouterBlockInactive, RouterBlockProvisioning
class IasToReInterconnectBlockInactive(
ProductBlockModel,
lifecycle=[SubscriptionLifecycle.INITIAL],
product_block_name="IasToReInterconnectBlock",
):
"""An inactive IasToReInterconnect."""
ipv4_network: ipaddress.IPv4Network | None = None
ipv6_network: ipaddress.IPv6Network | None = None
router: RouterBlockInactive | None = None
class IasToReInterconnectBlockProvisioning(
IasToReInterconnectBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]
):
"""An IasToReInterconnect that is being provisioned."""
ipv4_network: ipaddress.IPv4Network
ipv6_network: ipaddress.IPv6Network
router: RouterBlockProvisioning
class IasToReInterconnectBlock(IasToReInterconnectBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
"""An IasToReInterconnect."""
#: The IPv4 address block assigned for the interconnect
ipv4_network: ipaddress.IPv4Network
#: The IPv6 address block assigned for the interconnect
ipv6_network: ipaddress.IPv6Network
#: The router associated with the IAS to R&E interconnect
router: RouterBlock
"""The product type for IAS to R&E Interconnect."""
from orchestrator.domain.base import SubscriptionModel
from orchestrator.types import SubscriptionLifecycle
from gso.products.product_blocks.ias_to_re_interconnect import (
IasToReInterconnectBlock,
IasToReInterconnectBlockInactive,
IasToReInterconnectBlockProvisioning,
)
class IasToReInterconnectInactive(SubscriptionModel, is_base=True):
"""An IAS to R&E Interconnect that is inactive."""
ias_to_re_interconnect: IasToReInterconnectBlockInactive
class IasToReInterconnectProvisioning(IasToReInterconnectInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
"""An IAS to R&E Interconnect that is being provisioned."""
ias_to_re_interconnect: IasToReInterconnectBlockProvisioning
class IasToReInterconnect(IasToReInterconnectProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
"""An IAS to R&E Interconnect that is active."""
ias_to_re_interconnect: IasToReInterconnectBlock
class ImportedIasToReInterconnectInactive(SubscriptionModel, is_base=True):
"""An imported IAS to R&E Interconnect that is inactive."""
ias_to_re_interconnect: IasToReInterconnectBlockInactive
class ImportedIasToReInterconnect(
ImportedIasToReInterconnectInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE]
):
"""An imported IAS to R&E Interconnect that is active."""
ias_to_re_interconnect: IasToReInterconnectBlock
......@@ -23,7 +23,8 @@ from orchestrator.types import SubscriptionLifecycle
from orchestrator.workflow import ProcessStatus
from pydantic_forms.types import UUIDstr
from gso.products import ProductName, ProductType
from gso.products import ProductName, ProductType, Router
from gso.products.product_blocks.router import RouterRole
from gso.products.product_types.site import Site
SubscriptionType = dict[str, Any]
......@@ -113,6 +114,21 @@ def get_active_router_subscriptions(includes: list[str] | None = None) -> list[S
)
def get_active_pe_router_subscriptions() -> list[Router]:
"""Retrieve active subscriptions specifically for PE routers.
:return: A list of PE routers.
:rtype: list[Router]
"""
routers = get_subscriptions(
product_types=[ProductType.ROUTER], lifecycles=[SubscriptionLifecycle.ACTIVE], includes=["subscription_id"]
)
subscriptions = [Router.from_subscription(r["subscription_id"]) for r in routers]
return [router for router in subscriptions if router.router.router_role == RouterRole.PE]
def get_provisioning_router_subscriptions(includes: list[str] | None = None) -> list[SubscriptionType]:
"""Retrieve provisioning subscriptions specifically for routers.
......
......@@ -103,6 +103,7 @@ class IPAMParams(BaseSettings):
GEANT_IP: ServiceNetworkParams
SI: ServiceNetworkParams
LT_IAS: ServiceNetworkParams
IAS_TO_RE: ServiceNetworkParams
class MonitoringSNMPV2Params(BaseSettings):
......
......@@ -67,6 +67,8 @@
"import_opengear": "NOT FOR HUMANS -- Finalize import into an OpenGear",
"validate_iptrunk": "Validate IP Trunk configuration",
"validate_router": "Validate router configuration",
"create_ias_to_re_interconnect": "Create IAS to R&E Interconnect",
"import_ias_to_re_interconnect": "NOT FOR HUMANS -- Finalize import into an IAS to R&E Interconnect product",
"task_validate_geant_products": "Validation task for GEANT products",
"task_send_email_notifications": "Send email notifications for failed tasks",
"task_create_partners": "Create partner task",
......
......@@ -66,6 +66,14 @@ LazyWorkflowInstance("gso.workflows.office_router.create_imported_office_router"
LazyWorkflowInstance("gso.workflows.opengear.create_imported_opengear", "create_imported_opengear")
LazyWorkflowInstance("gso.workflows.opengear.import_opengear", "import_opengear")
# IAS to R&E Interconnect workflows
LazyWorkflowInstance(
"gso.workflows.ias_to_re_interconnect.create_ias_to_re_interconnect", "create_ias_to_re_interconnect"
)
LazyWorkflowInstance(
"gso.workflows.ias_to_re_interconnect.import_ias_to_re_interconnect", "import_ias_to_re_interconnect"
)
# Tasks
LazyWorkflowInstance("gso.workflows.tasks.send_email_notifications", "task_send_email_notifications")
LazyWorkflowInstance("gso.workflows.tasks.validate_geant_products", "task_validate_geant_products")
......
"""All workflows that can be executed on IAS to R&E Interconnects."""
"""A creation workflow that deploys a new IAS to R&E Interconnect service."""
import json
from orchestrator.forms import FormPage
from orchestrator.forms.validators import Choice
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, begin, done, 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 ConfigDict, field_validator
from pydantic_forms.validators import ReadOnlyField
from gso.products.product_types.ias_to_re_interconnect import IasToReInterconnectInactive
from gso.products.product_types.router import Router
from gso.services import infoblox, subscriptions
from gso.services.lso_client import execute_playbook, lso_interaction
from gso.services.partners import get_partner_by_name
from gso.utils.helpers import (
validate_tt_number,
)
def initial_input_form_generator(product_name: str) -> FormGenerator:
"""Gather input from the user in three steps."""
routers = {}
for router in subscriptions.get_active_pe_router_subscriptions():
routers[str(router.subscription_id)] = router.description
router_enum_a = Choice("Select a router", zip(routers.keys(), routers.items(), strict=True)) # type: ignore[arg-type]
class CreateIasToReInterconnectForm(FormPage):
model_config = ConfigDict(title=product_name)
tt_number: str
partner: ReadOnlyField("GEANT", default_type=str) # type: ignore[valid-type]
router_id: router_enum_a # type: ignore[valid-type]
@field_validator("tt_number")
def validate_tt_number(cls, tt_number: str) -> str:
return validate_tt_number(tt_number)
initial_user_input = yield CreateIasToReInterconnectForm
return initial_user_input.model_dump()
@step("Create subscription")
def create_subscription(product: UUIDstr, partner: str) -> State:
"""Create a new subscription object in the database."""
subscription = IasToReInterconnectInactive.from_product_id(product, get_partner_by_name(partner)["partner_id"])
return {
"subscription": subscription,
"subscription_id": subscription.subscription_id,
}
@step("Get information from IPAM")
def get_info_from_ipam(subscription: IasToReInterconnectInactive) -> State:
"""Allocate IP resources in :term:`IPAM`."""
subscription.ias_to_re_interconnect.ipv4_network = infoblox.allocate_v4_network(
"IAS_TO_RE", # TODO ask Simone for comment
comment=f"IAS to R&E on {subscription.ias_to_re_interconnect.router.router_fqdn}",
)
subscription.ias_to_re_interconnect.ipv6_network = infoblox.allocate_v6_network(
"IAS_TO_RE", # TODO ask Simone for comment
comment=f"IAS to R&E on {subscription.ias_to_re_interconnect.router.router_fqdn}",
)
return {"subscription": subscription}
def _provision_ias_to_re_interconnect(
callback_route: str,
process_id: UUIDstr,
subscription: IasToReInterconnectInactive,
tt_number: str,
*,
dry_run: bool,
) -> None:
extra_vars = {
"subscription": json.loads(json_dumps(subscription)),
"dry_run": dry_run,
"verb": "deploy",
"commit_comment": (
f"GSO_PROCESS_ID: {process_id} - TT_NUMBER: {tt_number} - Deploy config for IAS to R&E Interconnect"
),
}
execute_playbook(
playbook_name="ias_to_re_interconnects.yaml",
callback_route=callback_route,
inventory=f"{subscription.ias_to_re_interconnect.router.router_fqdn}\n",
extra_vars=extra_vars,
)
@step("[DRY RUN] Provision IAS to R&E Interconnect")
def provision_ias_to_re_interconnect_dry(
subscription: IasToReInterconnectInactive,
callback_route: str,
process_id: UUIDstr,
tt_number: str,
) -> State:
"""Perform a dry run of deploying configuration of the IAS to R&E Interconnect."""
_provision_ias_to_re_interconnect(callback_route, process_id, subscription, tt_number, dry_run=True)
return {"subscription": subscription}
@step("[FOR REAL] Provision IAS to R&E Interconnect interface")
def provision_ias_to_re_interconnect_real(
subscription: IasToReInterconnectInactive,
callback_route: str,
process_id: UUIDstr,
tt_number: str,
) -> State:
"""Deploy IAS to R&E Interconnect configuration."""
_provision_ias_to_re_interconnect(callback_route, process_id, subscription, tt_number, dry_run=False)
return {"subscription": subscription}
@step("Register DNS records for both sides of the trunk")
def register_dns_records(subscription: IasToReInterconnectInactive) -> State:
"""Register :term:`DNS` records for the newly created IasToReInterconnect."""
# TODO Simone will tell me about the format
return {"subscription": subscription}
@step("Initialize subscription")
def initialize_subscription(
subscription: IasToReInterconnectInactive,
router_id: UUIDstr,
) -> State:
"""Take all input from the user, and store it in the database."""
router = Router.from_subscription(router_id).router
subscription.ias_to_re_interconnect.router = router
subscription.description = f"IAS to R&E Interconnect in: {router.router_fqdn}"
return {"subscription": subscription}
@workflow(
"Create IAS to R&E Interconnect",
initial_input_form=wrap_create_initial_input_form(initial_input_form_generator),
target=Target.CREATE,
)
def create_ias_to_re_interconnect() -> StepList:
"""Create a new IAS to R&E Interconnect.
* Create the subscription object in the database
* Gather relevant information from Infoblox
* Deploy configuration, first as a dry run
* Set the subscription to active in the database
"""
return (
begin
>> create_subscription
>> store_process_subscription(Target.CREATE)
>> initialize_subscription
>> get_info_from_ipam
>> lso_interaction(provision_ias_to_re_interconnect_dry)
>> lso_interaction(provision_ias_to_re_interconnect_real)
>> register_dns_records
>> set_status(SubscriptionLifecycle.PROVISIONING)
>> resync
>> done
)
"""A modification workflow for migrating an IasToReInterconnect to an IAS to R&E Interconnect subscription."""
from orchestrator.targets import Target
from orchestrator.types import State, UUIDstr
from orchestrator.workflow import StepList, done, init, step, workflow
from orchestrator.workflows.steps import resync, store_process_subscription, unsync
from orchestrator.workflows.utils import wrap_modify_initial_input_form
from gso.products import IasToReInterconnect, ImportedIasToReInterconnect, ProductName
from gso.services.subscriptions import get_product_id_by_name
@step("Create new IAS to R&E Interconnect subscription")
def import_ias_to_re_interconnect_subscription(subscription_id: UUIDstr) -> State:
"""Take an IasToReInterconnect subscription, and turn it into an IAS to R&E Interconnect subscription."""
old_ias_to_re_interconnect = ImportedIasToReInterconnect.from_subscription(subscription_id)
new_subscription_id = get_product_id_by_name(ProductName.IAS_TO_RE_INTERCONNECT)
new_subscription = IasToReInterconnect.from_other_product(old_ias_to_re_interconnect, new_subscription_id) # type: ignore[arg-type]
return {"subscription": new_subscription}
@workflow(
"Import IAS to R&E Interconnect", target=Target.MODIFY, initial_input_form=wrap_modify_initial_input_form(None)
)
def import_ias_to_re_interconnect() -> StepList:
"""Modify an ImportedIasToReInterconnect subscription into an IasToReInterconnect subscription."""
return (
init
>> store_process_subscription(Target.MODIFY)
>> unsync
>> import_ias_to_re_interconnect_subscription
>> resync
>> done
)
......@@ -48,9 +48,12 @@ from gso.utils.workflow_steps import prompt_sharepoint_checklist_url
def initial_input_form_generator(product_name: str) -> FormGenerator:
"""Gather input from the user in three steps. General information, and information on both sides of the trunk."""
routers = {}
for router in subscriptions.get_active_router_subscriptions(
active_routers = subscriptions.get_active_router_subscriptions(includes=["subscription_id", "description"])
provisioning_routers = subscriptions.get_provisioning_router_subscriptions(
includes=["subscription_id", "description"]
) + subscriptions.get_provisioning_router_subscriptions(includes=["subscription_id", "description"]):
)
for router in active_routers + provisioning_routers:
# Add both provisioning and active routers, since trunks are required for promoting a router to active.
routers[str(router["subscription_id"])] = router["description"]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment