diff --git a/geant_service_orchestrator/workflows/__init__.py b/geant_service_orchestrator/workflows/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d93b338a9c01be9a2e5c3fee0c46f341ef5c98ae --- /dev/null +++ b/geant_service_orchestrator/workflows/__init__.py @@ -0,0 +1,5 @@ +from orchestrator.workflows import LazyWorkflowInstance + +LazyWorkflowInstance("workflows.device.create_device", "create_device") +LazyWorkflowInstance("workflows.device.terminate_device", "terminate_device") +LazyWorkflowInstance("workflows.device.get_facts", "get_facts") diff --git a/geant_service_orchestrator/workflows/device/create_device.py b/geant_service_orchestrator/workflows/device/create_device.py new file mode 100644 index 0000000000000000000000000000000000000000..0e76bafc81ae7b367d73f23cd1aac15c99972c0f --- /dev/null +++ b/geant_service_orchestrator/workflows/device/create_device.py @@ -0,0 +1,131 @@ +# from typing import List, Optional +from uuid import uuid4 + +# from orchestrator.db.models import ProductTable, SubscriptionTable +# from orchestrator.forms.validators import Choice, choice_list +from orchestrator.forms import FormPage +from orchestrator.targets import Target +from orchestrator.types import FormGenerator, State +from orchestrator.types import SubscriptionLifecycle, UUIDstr +from orchestrator.workflow import done, init, step, workflow +from orchestrator.workflows.steps import resync, set_status +from orchestrator.workflows.steps import store_process_subscription +from orchestrator.workflows.utils import wrap_create_initial_input_form + +from products.product_types.device import DeviceInactive, DeviceProvisioning + + +def initial_input_form_generator(product_name: str) -> FormGenerator: + class CreateUserForm(FormPage): + class Config: + title = product_name + + fqdn: str + ts_address: str + ts_port: int + + user_input = yield CreateUserForm + + return user_input.dict() + + +@step("Create subscription") +def create_subscription(product: UUIDstr) -> State: + subscription = DeviceInactive.from_product_id(product, uuid4()) + + return { + "subscription": subscription, + "subscription_id": subscription.subscription_id, + } + + +@step("Get information from IPAM ") +def get_info_from_ipam(subscription: DeviceInactive) -> State: + subscription.device.lo_ipv4_address = "10.10.10.10" + subscription.device.lo_ipv6_address = "fc00:798:aa:1::10" + subscription.device.lo_iso_address = "49.51e5.0001.0620.4009.6047.00" + subscription.device.si_ipv4_network = "192.168.0.0/31" + subscription.device.ias_lt_ipv4_network = "192.168.1.0/31" + subscription.device.ias_lt_ipv6_network = "fc00:798:1::150/126" + + return {"subscription": subscription} + + +@step("get information about SNMP") +def get_snmp_info(subscription: DeviceInactive) -> State: + subscription.device.site_country = "Spain" + subscription.device.site_city = "Barcelona" + subscription.device.site_country_code = "ES" + subscription.device.site_latitude = "41.3743" + subscription.device.site_longitude = "2.1328" + subscription.device.snmp_location = ( + "BARCELONA,SPAIN,[41.3743,2.1328]" # TODO: Duplicated data? + ) + + return {"subscription": subscription} + + +@step("Initialize subscription") +def initialize_subscription( + subscription: DeviceInactive, fqdn: str, ts_address: str, ts_port: str +) -> State: + subscription.device.fqdn = fqdn + subscription.device.ts_address = ts_address + subscription.device.ts_port = ts_port + subscription.description = f"Device {fqdn} type \ + ({subscription.device_type})" + subscription = DeviceProvisioning.from_other_lifecycle( + subscription, SubscriptionLifecycle.PROVISIONING + ) + + return {"subscription": subscription} + + +@step("Provision device") +def provision_device( + subscription: DeviceProvisioning, fqdn: str, ts_address: str, ts_port: str +) -> State: + import ansible_runner + + r = ansible_runner.run( + private_data_dir="/opt", + playbook="base_config.yaml", + inventory=subscription.device.fqdn, + extravars={ + "lo_ipv4_address": subscription.device.lo_ipv4_address, + "lo_ipv6_address": subscription.device.lo_ipv6_address, + "lo_iso_address": subscription.device.lo_iso_address, + "snmp_location": subscription.device.snmp_location, + "si_ipv4_network": subscription.device.si_ipv4_network, + "lt_ipv4_network": subscription.device.ias_lt_ipv4_network, + "lt_ipv6_network": subscription.device.ias_lt_ipv6_network, + "site_country_code": subscription.device.site_country_code, + "verb": "deploy", + }, + ) + out = r.stdout.read() + out_splitted = out.splitlines() + + return {"output": out_splitted} + # return {"subscription": subscription, "status": "ciao", "pippo": "pluto"} + + +@workflow( + "Create Device", + initial_input_form=wrap_create_initial_input_form( + initial_input_form_generator), + target=Target.CREATE, +) +def create_device(): + return ( + init + >> create_subscription + >> store_process_subscription(Target.CREATE) + >> get_info_from_ipam + >> get_snmp_info + >> initialize_subscription + >> provision_device + >> set_status(SubscriptionLifecycle.ACTIVE) + >> resync + >> done + ) diff --git a/geant_service_orchestrator/workflows/device/get_facts.py b/geant_service_orchestrator/workflows/device/get_facts.py new file mode 100644 index 0000000000000000000000000000000000000000..6cc1cbe21da2acb7e90af1a306bf7855e507af30 --- /dev/null +++ b/geant_service_orchestrator/workflows/device/get_facts.py @@ -0,0 +1,60 @@ +from orchestrator.forms import FormPage +from orchestrator.forms.validators import Label +from orchestrator.targets import Target +# from orchestrator.types import SubscriptionLifecycle +from orchestrator.types import InputForm, UUIDstr +from orchestrator.workflow import done, init, step, workflow +# from orchestrator.workflows.steps import ( +# resync, +# set_status, +# store_process_subscription, +# unsync, +# ) +from orchestrator.workflows.utils import wrap_modify_initial_input_form + +from products import Device + + +def initial_input_form_generator( + subscription_id: UUIDstr, organisation: UUIDstr +) -> InputForm: + subscription = Device.from_subscription(subscription_id) + + class TerminateForm(FormPage): + are_you_sure: Label = ( + f"Are you sure you want to get facts from \ + {subscription.description}?" + ) + + return TerminateForm + + +@step("Get facts") +def get_facts(subscription_id) -> None: + subscription = Device.from_subscription(subscription_id) + import ansible_runner + + r = ansible_runner.run( + private_data_dir="/opt", + playbook="get_facts.yaml", + inventory=subscription.device.fqdn, + ) + out = r.stdout.read() + out_splitted = out.splitlines() + + return {"output": out_splitted} + + +@workflow( + "Get Facts from Device", + initial_input_form=wrap_modify_initial_input_form( + initial_input_form_generator), + target=Target.SYSTEM, +) +def get_facts_from_device(): + return ( + init + >> get_facts + # >> resync + >> done + ) diff --git a/geant_service_orchestrator/workflows/device/terminate_device.py b/geant_service_orchestrator/workflows/device/terminate_device.py new file mode 100644 index 0000000000000000000000000000000000000000..2ea80d0e5b9ad407bb66c3ce00e5c95710208459 --- /dev/null +++ b/geant_service_orchestrator/workflows/device/terminate_device.py @@ -0,0 +1,53 @@ +from orchestrator.forms import FormPage +from orchestrator.forms.validators import Label +from orchestrator.targets import Target +from orchestrator.types import InputForm, SubscriptionLifecycle, UUIDstr +from orchestrator.workflow import done, init, step, workflow +from orchestrator.workflows.steps import ( + resync, + set_status, + store_process_subscription, + unsync, +) +from orchestrator.workflows.utils import wrap_modify_initial_input_form + +from products import Device + + +def initial_input_form_generator(subscription_id: UUIDstr) -> InputForm: + subscription = Device.from_subscription(subscription_id) + + class TerminateForm(FormPage): + are_you_sure: Label = ( + f"Are you sure you want to remove {subscription.description}?" + ) # type:ignore + + return TerminateForm + + +def _deprovision_in_user_management_system(fqdn: str) -> str: + pass + + +@step("Deprovision device") +def deprovision_user(subscription: Device) -> None: + # _deprovision_in_user_management_system(subscription.user.user_id) + pass + + +@workflow( + "Terminate device", + initial_input_form=wrap_modify_initial_input_form( + initial_input_form_generator), + target=Target.TERMINATE, +) +def terminate_user(): + return ( + init + >> store_process_subscription(Target.TERMINATE) + >> unsync + >> deprovision_user + >> set_status(SubscriptionLifecycle.TERMINATED) + >> resync + >> done + )