diff --git a/api/InfrastructureTemplateController.py b/api/InfrastructureTemplateController.py index c2bc7847bdf658a5d1e4050ea0693921e161abda..fac0f4683560183b1a2e90486ae67a2d492fdb51 100644 --- a/api/InfrastructureTemplateController.py +++ b/api/InfrastructureTemplateController.py @@ -30,7 +30,7 @@ def create_iac_from_doml(data: str = Body(..., media_type="application/xml")): f = open(temp_model_file_path, "w") f.write(data) f.close() - intermediate_representation = ModelParser.parse_model(temp_model_file_path) + intermediate_representation = ModelParser.parse_model(model_path=temp_model_file_path) intermediate_representation = reorganize_info(intermediate_representation) save(intermediate_representation, "input_file_generated/ir.json") template_generated_folder = create_infrastructure_files(intermediate_representation) diff --git a/icgparser/DomlParserUtilities.py b/icgparser/DomlParserUtilities.py index 64ca4e03538b850e4b3ceb64a08256866135100c..9fb3eab593b3bfc41072b4813ca96aaeebee2991 100644 --- a/icgparser/DomlParserUtilities.py +++ b/icgparser/DomlParserUtilities.py @@ -1,8 +1,13 @@ import logging from pyecore.ecore import EOrderedSet, EEnumLiteral +from pyecore.resources import ResourceSet, URI, global_registry +import pyecore.ecore as Ecore # This gets a reference to the Ecore metamodel implementation TO_BE_PARSED_RESOURCES = {} +METAMODEL_SECTIONS = ["doml", "commons", "application", "infrastructure", "concrete", "optimization"] +METAMODEL_DIRECTORY = "icgparser/doml" + def extract_value_from(ecore_object_value): if isinstance(ecore_object_value, EOrderedSet): @@ -63,7 +68,7 @@ def update_missing_parsed_resources(resource, reference, is_to_be_parsed): print(f'update_missing_parsed_resources: skipping {resource_name}') -def save_references_info(from_object, to_object): ## TODO refactoring +def save_references_info(from_object, to_object): ## TODO refactoring refs = from_object.eClass.eAllReferences() for ref in refs: if get_reference_list_if_exists(from_object, ref): @@ -99,3 +104,27 @@ def add_infrastructure_information(infrastructure_element, to_object): def retrieve_missing_parsed_resources(): return TO_BE_PARSED_RESOURCES + + +def load_metamodel(metamodel_directory=METAMODEL_DIRECTORY, is_multiecore=False): + global_registry[Ecore.nsURI] = Ecore + rset = ResourceSet() + if is_multiecore: + logging.info(f"Loading multiecore metamodel from {metamodel_directory}") + for mm_filename in METAMODEL_SECTIONS: + resource = rset.get_resource(URI(f"{metamodel_directory}/{mm_filename}.ecore")) + mm_root = resource.contents[0] # Get the root of the MetaModel (EPackage) + rset.metamodel_registry[mm_root.nsURI] = mm_root + else: + logging.info(f"Loading multiecore metamodel from {metamodel_directory}/doml.ecore") + resource = rset.get_resource(URI(f"{metamodel_directory}/doml.ecore")) + mm_root = resource.contents[0] # Get the root of the MetaModel (EPackage) + rset.metamodel_registry[mm_root.nsURI] = mm_root + for subp in mm_root.eSubpackages: + rset.metamodel_registry[subp.nsURI] = subp + return rset + + +def load_model(model_path, rset): + doml_model_resource = rset.get_resource(URI(model_path)) + return doml_model_resource.contents[0] diff --git a/icgparser/ModelParser.py b/icgparser/ModelParser.py index b814068c0fc1a354667f1a5ccdece5fbde6f8af2..6c7e060abc24277eee1e3587e75afb0f0cbcae51 100644 --- a/icgparser/ModelParser.py +++ b/icgparser/ModelParser.py @@ -14,33 +14,14 @@ # © Copyright 2022 Hewlett Packard Enterprise Development LP # ------------------------------------------------------------------------- import logging -from pyecore.resources import ResourceSet, URI, global_registry -import pyecore.ecore as Ecore # This gets a reference to the Ecore metamodel implementation - from icgparser import DomlParserUtilities from icgparser.DomlParserUtilities import get_reference_list_if_exists - OUTPUT_BASE_DIR_PATH = "output_files_generated/" -DOML_PATH = "icgparser/doml/doml.ecore" - doml_layers = { "active_infrastructure_layer": "activeInfrastructure", } - -def load_model(doml_path, model_path): - global_registry[Ecore.nsURI] = Ecore # Load the Ecore metamodel first - rset = ResourceSet() - resource = rset.get_resource(URI(f"{doml_path}")) - mm_root = resource.contents[0] # Get the root of the MetaModel (EPackage) - rset.metamodel_registry[mm_root.nsURI] = mm_root - for subp in mm_root.eSubpackages: - rset.metamodel_registry[subp.nsURI] = subp - doml_model_resource = rset.get_resource(URI(model_path)) - return doml_model_resource.contents[0] - - def to_camel_case(content): return content[0].lower() + content[1:] @@ -89,15 +70,22 @@ def parse_infrastructural_objects(doml_model): infra_object_step = include_missing_objects_from_infrastructure_layer(infra_object_step) return infra_object_step -def parse_model(model_path): - doml_model = load_model(DOML_PATH, model_path) - model_name = doml_model.name + +def create_intermediate_representation(model_loaded): + model_name = model_loaded.name output_path = OUTPUT_BASE_DIR_PATH + model_name + "/" intermediate_representation_steps = [] - infra_object_step = parse_infrastructural_objects(doml_model) + infra_object_step = parse_infrastructural_objects(model_loaded) intermediate_representation_steps.append(infra_object_step) intermediate_representation = { "output_path": output_path, "steps": intermediate_representation_steps } return intermediate_representation + + +def parse_model(model_path, is_multiecore_metamodel, metamodel_directory): + rset = DomlParserUtilities.load_metamodel(metamodel_directory=metamodel_directory, + is_multiecore=is_multiecore_metamodel) + doml_model = DomlParserUtilities.load_model(model_path, rset) + create_intermediate_representation(doml_model) diff --git a/icgparser/ModelParserOld.py b/icgparser/ModelParserOld.py deleted file mode 100644 index b0c5bb1d3746e7805beaf137376472b82ba16565..0000000000000000000000000000000000000000 --- a/icgparser/ModelParserOld.py +++ /dev/null @@ -1,228 +0,0 @@ -# # ------------------------------------------------------------------------- -# # PIACERE ICG Parser -# # -# # This module has been tested with Python v3.7.4 -# # To use it you must first install PyEcore -# # $ pip install pyecore -# # -# # Usage: python icgparser.py [-h] [-d dir] [-v] [--single] model -# # -h prints usage -# # -d dir loads metamodel from <dir> -# # --single / --single_mmodel use the single (non-split) metamodel -# # model the input model to be translated into the ICG intermediate representation -# # -# # Author: Lorenzo Blasi -# # 23/2/2022 - created -# # © Copyright 2022 Hewlett Packard Enterprise Development LP -# # ------------------------------------------------------------------------- -# import logging -# import sys -# from pyecore.resources import ResourceSet, URI, global_registry -# import pyecore.ecore as Ecore # This gets a reference to the Ecore metamodel implementation -# -# # ------------------------------------------------------------------------- -# # Utility functions to printout the loaded model -# # ------------------------------------------------------------------------- -# newline = "\n" -# spaces = " " -# comment = "#" -# -# -# def write_to(outchannel, line): -# # for now we just print on the console -# if outchannel == "console": -# print(line) -# # if the channel is different we don't print at all -# -# -# def print_obj(obj, level=0): -# # for x in range(level): -# # print(" ", end='') -# class_name = obj.eClass.name -# if class_name == 'Property': -# # print('Class: {0}\t\t{1} = {2}'.format(class_name, obj.key, obj.value)) -# print(f'{comment}{level * spaces}Class: {class_name}\t\t{obj.key} = {obj.value}') -# return False -# if class_name == 'Deployment': -# print( -# f'{comment}{level * spaces}Class: {class_name}\t\tcomponent = {obj.component.eClass.name}/{obj.component.name} node = {obj.node.eClass.name}/{obj.node.name}') -# return False -# try: -# obj_name = obj.name -# print(f'{comment}{level * spaces}Class: {class_name}\t\tObject: {obj_name}') -# return True -# except Exception: -# print(f'{comment}{level * spaces}Class: {class_name}\t\tObject: no name') -# return False -# -# -# def print_contents_recursive(obj, level=0): -# if print_obj(obj, level): -# for x in obj.eContents: -# print_contents_recursive(x, level + 1) -# -# -# # ------------------------------------------------------------------------- -# # Utility functions to produce the output Intermediate Language -# # ------------------------------------------------------------------------- -# # --- Helpers -# def extract_image_name(concretevm_obj): -# # To find the VM image name you could search into the inverse relations of the abstract image generating its related abstract VM, looking for a concrete image object (whose class is VMImage) and extract the value from its contents -# # concretevm_obj is a VirtualMachine (nginx-openstack_v2.doml:81, it should have been a OpenStackVM), -# # concretevm_obj.maps is a VirtualMachine (the abstract one) -# # concretevm_obj.maps.generatedFrom is a VMImage (the abstract one) -# for x in concretevm_obj.maps.generatedFrom._inverse_rels: -# if x[0].eClass.name == 'VMImage': -# return x[0].eContents[0].value -# -# -# def extract_concrete_network_name(abstractnet_obj): -# for x in abstractnet_obj._inverse_rels: -# if x[0].eClass.name == 'Network': -# return x[0].eContents[0].value -# -# -# # --- Handlers -# def model_handler(obj, model_root, level, intermediate_repr): -# # output prefix -# append_in_file(intermediate_repr, -# f'{level * spaces}{{{newline}{level * spaces}{spaces}"output_path": "output_files_generated/{obj.name}/",') -# append_in_file(intermediate_repr, f'{level * spaces}{spaces}"steps": [') -# # handle contents -# for x in obj.eContents: -# handle_obj(x, model_root, level + 2, intermediate_repr) -# # output suffix -# append_in_file(intermediate_repr, f'{level * spaces}{spaces}]') -# append_in_file(intermediate_repr, f'{level * spaces}}}') -# -# -# def concrete_infra_handler(obj, model_root, level, intermediate_repr): -# # output prefix -# append_in_file(intermediate_repr, -# f'{level * spaces}{{{newline}{level * spaces}{spaces}"programming_language": "terraform",') -# # handle contents -# for x in obj.eContents: -# handle_obj(x, model_root, level + 1, intermediate_repr) -# # output suffix -# append_in_file(intermediate_repr, f'{level * spaces}}}') -# -# -# def network_handler(obj, model_root, level, intermediate_repr): -# # ignore the concrete network, since its name has been extracted separately and included in the concrete VM -# logging.warning('Ignoring Network') -# -# -# def property_handler(obj, model_root, level, intermediate_repr): -# key = obj.key -# append_in_file(intermediate_repr, f'{level * spaces}"{key}" : "{obj.value}",') -# -# -# def provider_handler(obj, model_root, level, intermediate_repr): -# # output prefix -# append_in_file(intermediate_repr, -# f'{level * spaces}"data": {{{newline}{level * spaces}{spaces}"provider": "{obj.name}",') -# # handle contents -# for x in obj.eContents: -# handle_obj(x, model_root, level + 1, intermediate_repr) -# # output suffix -# append_in_file(intermediate_repr, f'{level * spaces}}}') -# -# -# def concrete_vm_handler(obj, model_root, level, intermediate_repr): -# # output prefix -# append_in_file(intermediate_repr, f'{level * spaces}"vm": [{{') # VMs can be more than one: I need an example... -# level = level + 1 -# # print(f'{level * spaces}# maps {obj.maps.name}') -# logging.warning(f"Ignoring map {obj.maps.name}") -# # handle contents -# for x in obj.eContents: -# handle_obj(x, model_root, level, intermediate_repr) -# # add other attributes defined elsewhere: image name, address, ... -# append_in_file(intermediate_repr, f'{level * spaces}"image" : "{extract_image_name(obj)}",') -# for iface in obj.maps.ifaces: -# append_in_file(intermediate_repr, f'{level * spaces}"address" : "{iface.endPoint}",') -# append_in_file(intermediate_repr, -# f'{level * spaces}"network_name" : "{extract_concrete_network_name(iface.belongsTo)}"') -# # output suffix -# level = level - 1 -# append_in_file(intermediate_repr, f'{level * spaces}}}]') -# -# -# def vm_image_handler(obj, model_root, level, intermediate_repr): -# # ignore the concrete image, since its image name has been extracted separately and included in the concrete VM -# logging.warning(f'Ignoring VMImage') -# -# -# class_handler = { -# -# "DOMLModel": model_handler, -# "ConcreteInfrastructure": concrete_infra_handler, -# "Network": network_handler, -# "Property": property_handler, -# "RuntimeProvider": provider_handler, -# "VirtualMachine": concrete_vm_handler, # Warning: the class here might change to some concrete VM class -# "VMImage": vm_image_handler -# } -# -# -# def handle_obj(obj, model_root, level, intermediate_repr): -# if obj.eClass.name in class_handler: -# class_handler[obj.eClass.name](obj, model_root, level, intermediate_repr) -# else: -# logging.warning(f'Class {obj.eClass.name} has no handler') -# -# -# # ------------------------------------------------------------------------- -# # Load each part of the DOML metamodel and register them -# # ------------------------------------------------------------------------- -# def load_metamodel(load_split_model, doml_directory="icgparser/doml"): -# global_registry[Ecore.nsURI] = Ecore # Load the Ecore metamodel first -# rset = ResourceSet() -# if load_split_model: -# mm_parts = ["doml", "commons", "application", "infrastructure", "concrete", "optimization"] -# for mm_filename in mm_parts: -# resource = rset.get_resource(URI(f"{doml_directory}/{mm_filename}.ecore")) -# mm_root = resource.contents[0] # Get the root of the MetaModel (EPackage) -# rset.metamodel_registry[mm_root.nsURI] = mm_root -# else: -# resource = rset.get_resource(URI(f"{doml_directory}/doml.ecore")) -# mm_root = resource.contents[0] # Get the root of the MetaModel (EPackage) -# rset.metamodel_registry[mm_root.nsURI] = mm_root -# for subp in mm_root.eSubpackages: -# rset.metamodel_registry[subp.nsURI] = subp -# return rset -# -# -# # ------------------------------------------------------------------------- -# # Finally load the model and print it out -# # ------------------------------------------------------------------------- -# -# def parse_model(model, load_split_model, doml_directory="icgparser/doml"): -# rset = load_metamodel(load_split_model) -# doml_model_resource = rset.get_resource(URI(model)) -# doml_model = doml_model_resource.contents[0] -# single = "single-file (doml.ecore)" -# split = "split" -# dash = "-" -# logging.info(f'{comment}{80 * dash}') -# logging.info(f'{comment} Using {split if load_split_model else single} metamodel from directory {doml_directory}') -# print(f'{comment} Model loaded from file {model}:') -# print(f'{comment}{80 * dash}') -# print_contents_recursive(doml_model) -# print(f'{comment}{80 * dash}{newline}{comment} Generated Intermediate Representation follows:{newline}{comment}') -# intermediate_repr_file_path = "input_file_generated/ir.json" -# create_file("input_file_generated/ir.json") -# handle_obj(doml_model, doml_model, 0, intermediate_repr_file_path) -# -# -# def create_file(file_name): -# f = open(file_name, "w") -# f.write("") -# f.close() -# -# -# def append_in_file(file_name, data): -# f = open(file_name, "a") -# f.write(data) -# f.write("\n") -# f.close() diff --git a/icgparser/ModelPrinter.py b/icgparser/ModelPrinter.py new file mode 100644 index 0000000000000000000000000000000000000000..895a2ad1286d68dbf7823bbd8bd114e134918035 --- /dev/null +++ b/icgparser/ModelPrinter.py @@ -0,0 +1,46 @@ +import logging +import sys +from pyecore.resources import ResourceSet, URI, global_registry +import pyecore.ecore as Ecore # This gets a reference to the Ecore metamodel implementation + +#------------------------------------------------------------------------- +# Utility functions to printout the loaded model +#------------------------------------------------------------------------- +from icgparser import DomlParserUtilities + +def print_obj(obj, level=0): + for x in range(level): + print(" ", end='') + class_name = obj.eClass.name + if class_name == 'Property': + print('Class: {0}\t\t{1} = {2}'.format(class_name, obj.key, obj.value)) + return False + if class_name == 'Deployment': + print('Class: {0}\t\tcomponent = {1}/{2} node = {3}/{4}'.format(class_name, + obj.component.eClass.name, + obj.component.name, + obj.node.eClass.name, + obj.node.name + )) + return False + try: + obj_name = obj.name + print('Class: {0}\t\tObject: {1}'.format(class_name, obj_name)) + return True + except Exception: + print('Class: {0}\t\tObject: no name'.format(class_name)) + return False + + +def print_contents_recursive(obj, level=0): + if print_obj(obj, level): + for x in obj.eContents: + print_contents_recursive(x, level+1) + + +def print_model(model_path, is_multiecore_metamodel, metamodel_directory): + rset = DomlParserUtilities.load_metamodel(metamodel_directory=metamodel_directory, + is_multiecore=is_multiecore_metamodel) + doml_model = DomlParserUtilities.load_model(model_path, rset) + logging.info("Printing model") + print_contents_recursive(doml_model) diff --git a/main.py b/main.py index b06359a31092bdd8caa189614378a7bcc2b06ad6..619fe718dd206e4a1bf5b30fcfb71d03f3ed0760 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,7 @@ from fastapi import FastAPI import api.InfrastructureTemplateController from api.InfrastructureTemplateController import compress_file from controller.PluginOrchestrator import create_infrastructure_files -from icgparser import ModelParser +from icgparser import ModelParser, ModelPrinter fast_api = FastAPI() @@ -56,8 +56,11 @@ for i, param in enumerate(paramlist): model_filename = param if __name__ == '__main__': - ModelParser.parse_model(model_filename, load_split_model, doml_directory) - with open("input_file_generated/ir.json") as json_file: - data = json.load(json_file) - template_generated_folder = create_infrastructure_files(data) - compress_file_folder = compress_file(template_generated_folder, output_file_name) + ModelPrinter.print_model(model_path=model_filename, is_multiecore_metamodel=load_split_model, + metamodel_directory=doml_directory) + # ModelParser.parse_model(model_path=model_filename, is_multiecore_metamodel=load_split_model, + # metamodel_directory=doml_directory) + # with open("input_file_generated/ir.json") as json_file: + # data = json.load(json_file) + # template_generated_folder = create_infrastructure_files(data) + # compress_file_folder = compress_file(template_generated_folder, output_file_name) diff --git a/output_files_generated/nginx_openstack/terraform/main.tf b/output_files_generated/nginx_openstack/terraform/main.tf index 18174964df67311870590ea90e5e5e7cb82d72ef..13429e8716ffbf42de4e816927713043daa4945b 100644 --- a/output_files_generated/nginx_openstack/terraform/main.tf +++ b/output_files_generated/nginx_openstack/terraform/main.tf @@ -35,73 +35,6 @@ data "openstack_networking_secgroup_v2" "default" { name = "default" tenant_id = data.openstack_identity_project_v3.test_tenant.id } -# Create router -resource "openstack_networking_router_v2" "net1_router" { - name = "net1_router" - external_network_id = data.openstack_networking_network_v2.external.id #External network id -} -# Create virtual machine -resource "openstack_compute_instance_v2" "vm1" { - name = "nginx-host" - image_name = "i1" - flavor_name = "small" - key_pair = openstack_compute_keypair_v2.ssh_key.name - network { - port = openstack_networking_port_v2.net1.id - } -} - -# Create ssh keys -resource "openstack_compute_keypair_v2" "ssh_key" { - name = "ubuntu" - public_key = "/home/user1/.ssh/openstack.key" -} - -# Create floating ip -resource "openstack_networking_floatingip_v2" "vm1_floating_ip" { - pool = "external" - # fixed_ip = "" -} - -# Attach floating ip to instance -resource "openstack_compute_floatingip_associate_v2" "vm1_floating_ip_association" { - floating_ip = openstack_networking_floatingip_v2.vm1_floating_ip.address - instance_id = openstack_compute_instance_v2.vm1.id -} - -## Network - -# Create Network -resource "openstack_networking_network_v2" "net1" { - name = "concrete_net" -} - -# Create Subnet -resource "openstack_networking_subnet_v2" "net1_subnet" { - name = "concrete_net_subnet" - network_id = openstack_networking_network_v2.net1.id - cidr = "16.0.0.0/24" - dns_nameservers = ["8.8.8.8", "8.8.8.4"] -} - -# Attach networking port -resource "openstack_networking_port_v2" "net1" { - name = "concrete_net" - network_id = openstack_networking_network_v2.net1.id - admin_state_up = true - security_group_ids = [ - data.openstack_networking_secgroup_v2.default.id #default flavour id - ] - fixed_ip { - subnet_id = openstack_networking_subnet_v2.net1_subnet.id - } -} -# Router interface configuration -resource "openstack_networking_router_interface_v2" "net1_router_interface" { - router_id = openstack_networking_router_v2.net1_router.id - subnet_id = openstack_networking_subnet_v2.net1_subnet.id -} - resource "openstack_compute_secgroup_v2" "out_all" { name = "out_all" description = "Security group rule for port -" @@ -170,3 +103,71 @@ resource "openstack_compute_secgroup_v2" "ssh" { } } +## Network + +# Create Network +resource "openstack_networking_network_v2" "net1" { + name = "concrete_net" +} + +# Create Subnet +resource "openstack_networking_subnet_v2" "net1_subnet" { + name = "concrete_net_subnet" + network_id = openstack_networking_network_v2.net1.id + cidr = "16.0.0.0/24" + dns_nameservers = ["8.8.8.8", "8.8.8.4"] +} + +# Attach networking port +resource "openstack_networking_port_v2" "net1" { + name = "concrete_net" + network_id = openstack_networking_network_v2.net1.id + admin_state_up = true + security_group_ids = [ + data.openstack_networking_secgroup_v2.default.id #default flavour id + ] + fixed_ip { + subnet_id = openstack_networking_subnet_v2.net1_subnet.id + } +} + +# Create router +resource "openstack_networking_router_v2" "net1_router" { + name = "net1_router" + external_network_id = data.openstack_networking_network_v2.external.id #External network id +} +# Router interface configuration +resource "openstack_networking_router_interface_v2" "net1_router_interface" { + router_id = openstack_networking_router_v2.net1_router.id + subnet_id = openstack_networking_subnet_v2.net1_subnet.id +} + +# Create virtual machine +resource "openstack_compute_instance_v2" "vm1" { + name = "nginx-host" + image_name = "i1" + flavor_name = "small" + key_pair = openstack_compute_keypair_v2.ssh_key.name + network { + port = openstack_networking_port_v2.net1.id + } +} + +# Create ssh keys +resource "openstack_compute_keypair_v2" "ssh_key" { + name = "ubuntu" + public_key = "/home/user1/.ssh/openstack.key" +} + +# Create floating ip +resource "openstack_networking_floatingip_v2" "vm1_floating_ip" { + pool = "external" + # fixed_ip = "" +} + +# Attach floating ip to instance +resource "openstack_compute_floatingip_associate_v2" "vm1_floating_ip_association" { + floating_ip = openstack_networking_floatingip_v2.vm1_floating_ip.address + instance_id = openstack_compute_instance_v2.vm1.id +} +