-
Mohammad Torkashvand authoredMohammad Torkashvand authored
create_router.py 5.96 KiB
import ipaddress
import re
# noinspection PyProtectedMember
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.workflow import StepList, done, init, step, workflow
from orchestrator.workflows.steps import resync, set_status, store_process_subscription
from orchestrator.workflows.utils import wrap_create_initial_input_form
from gso import repository
from gso.products.product_blocks import router as router_pb
from gso.products.product_types import router
from gso.products.product_types.router import RouterInactive, RouterProvisioning
from gso.products.product_types.site import Site
from gso.services import ipam, provisioning_proxy
from gso.services.provisioning_proxy import pp_interaction
from gso.workflows.utils import customer_selector
def site_selector() -> Choice:
site_subscriptions = {}
for site_id, site_description in repository.all_active_site_subscriptions(
fields=["subscription_id", "description"]
):
site_subscriptions[str(site_id)] = site_description
# noinspection PyTypeChecker
return Choice("Select a site", zip(site_subscriptions.keys(), site_subscriptions.items())) # type: ignore
def initial_input_form_generator(product_name: str) -> FormGenerator:
class CreateRouterForm(FormPage):
class Config:
title = product_name
customer: customer_selector() # type: ignore
router_site: site_selector() # type: ignore
hostname: str
ts_port: int
router_vendor: router_pb.RouterVendor
router_role: router_pb.RouterRole
is_ias_connected: bool
user_input = yield CreateRouterForm
return user_input.dict()
@step("Create subscription")
def create_subscription(product: UUIDstr, customer: UUIDstr) -> State:
subscription = RouterInactive.from_product_id(product, customer)
return {
"subscription": subscription,
"subscription_id": subscription.subscription_id,
}
def iso_from_ipv4(ipv4_address: ipaddress.IPv4Address) -> str:
padded_octets = [f"{x:>03}" for x in str(ipv4_address).split(".")]
joined_octets = "".join(padded_octets)
re_split = ".".join(re.findall("....", joined_octets))
return ".".join(["49.51e5.0001", re_split, "00"])
@step("Get information from IPAM")
def get_info_from_ipam(subscription: RouterProvisioning, is_ias_connected: bool) -> State:
lo0_alias = re.sub(".geant.net", "", subscription.router.router_fqdn)
lo0_name = f"lo0.{lo0_alias}"
lo0_addr = ipam.allocate_host(hostname=lo0_name, service_type="LO", cname_aliases=[lo0_alias])
subscription.router.router_lo_ipv4_address = lo0_addr.v4
subscription.router.router_lo_ipv6_address = lo0_addr.v6
subscription.router.router_lo_iso_address = iso_from_ipv4(subscription.router.router_lo_ipv4_address)
subscription.router.router_is_ias_connected = is_ias_connected
if is_ias_connected is True:
subscription.router.router_si_ipv4_network = ipam.allocate_ipv4_network(
service_type="SI", comment=f"SI for {lo0_name}"
).v4
subscription.router.router_ias_lt_ipv4_network = ipam.allocate_ipv4_network(
service_type="LT_IAS", comment=f"LT for {lo0_name}"
).v4
subscription.router.router_ias_lt_ipv6_network = ipam.allocate_ipv6_network(
service_type="LT_IAS", comment=f"LT for {lo0_name}"
).v6
return {"subscription": subscription}
@step("Initialize subscription")
def initialize_subscription(
subscription: router.RouterInactive,
hostname: str,
ts_port: int,
router_vendor: router_pb.RouterVendor,
router_site: str,
router_role: router_pb.RouterRole,
) -> State:
subscription.router.router_ts_port = ts_port
subscription.router.router_vendor = router_vendor
subscription.router.router_site = Site.from_subscription(router_site).site
fqdn = (
f"{hostname}.{subscription.router.router_site.site_name.lower()}."
f"{subscription.router.router_site.site_country_code.lower()}"
".geant.net"
)
subscription.router.router_fqdn = fqdn
subscription.router.router_role = router_role
subscription.router.router_access_via_ts = True
subscription.description = f"Router {fqdn}"
subscription = router.RouterProvisioning.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING)
return {"subscription": subscription}
@step("Provision router [DRY RUN]")
def provision_router_dry(subscription: RouterProvisioning, process_id: UUIDstr) -> State:
provisioning_proxy.provision_router(subscription, process_id)
return {
"subscription": subscription,
"label_text": (
"Dry run for the deployment of base config on a new router. Deployment is done by the"
" provisioning proxy, please wait for the results to come back before continuing."
),
}
@step("Provision router [FOR REAL]")
def provision_router_real(subscription: RouterProvisioning, process_id: UUIDstr) -> State:
provisioning_proxy.provision_router(subscription, process_id, False)
return {
"subscription": subscription,
"label_text": (
"Deployment of base config for a new router. Deployment is being taken care of by the"
" provisioning proxy, please wait for the results to come back before continuing."
),
}
@workflow(
"Create router",
initial_input_form=wrap_create_initial_input_form(initial_input_form_generator),
target=Target.CREATE,
)
def create_router() -> StepList:
return (
init
>> create_subscription
>> store_process_subscription(Target.CREATE)
>> initialize_subscription
>> get_info_from_ipam
>> pp_interaction(provision_router_dry, 3)
>> pp_interaction(provision_router_real, 3)
>> set_status(SubscriptionLifecycle.ACTIVE)
>> resync
>> done
)