From 30a8cf5dcb63e292305bb842429c68ef69d6c215 Mon Sep 17 00:00:00 2001 From: Debora Benedetto <debora.benedetto@hpe.com> Date: Fri, 15 Jul 2022 16:23:03 +0200 Subject: [PATCH] add ansible plugin and templates --- controller/Orchestrator.py | 6 +- icgparser/ModelParser.py | 32 ++-- input_file_generated/ir.json | 29 +++- .../nginx_openstack/ansible/inventory.j2 | 7 + .../ansible/{nginx.play => nginx.yaml} | 8 +- .../nginx_openstack/config.yaml | 1 + .../nginx_openstack/terraform/main.tf | 164 ------------------ plugin/AnsiblePlugin.py | 53 ++++-- plugin/PluginException.py | 4 + template-location.properties | 2 + templates/ansible/ubuntu/config.tpl | 7 + templates/ansible/ubuntu/inventory.tpl | 7 + templates/ansible/ubuntu/nginx.tpl | 9 +- 13 files changed, 119 insertions(+), 210 deletions(-) create mode 100644 output_file_example/nginx_openstack/ansible/inventory.j2 rename output_file_example/nginx_openstack/ansible/{nginx.play => nginx.yaml} (82%) delete mode 100644 output_files_generated/nginx_openstack/terraform/main.tf create mode 100644 plugin/PluginException.py create mode 100644 templates/ansible/ubuntu/config.tpl create mode 100644 templates/ansible/ubuntu/inventory.tpl diff --git a/controller/Orchestrator.py b/controller/Orchestrator.py index 62897d6..29af7c8 100644 --- a/controller/Orchestrator.py +++ b/controller/Orchestrator.py @@ -30,9 +30,9 @@ def choose_plugin(parameters, template_generated_folder): for step in parameters["steps"]: if step["programming_language"] == "ansible": logging.info("Ansible Plugin chosen") - # metadata_root_folder["iac"].append("ansible") - # input_data = step["data"] - # AnsiblePlugin.create_files(input_data, template_generated_folder) + metadata_root_folder["iac"].append("ansible") + input_data = step["data"] + AnsiblePlugin.create_files(input_data, template_generated_folder) elif step["programming_language"] == "terraform": logging.info("Terraform Plugin chosen") metadata_root_folder["iac"].append("terraform") diff --git a/icgparser/ModelParser.py b/icgparser/ModelParser.py index 1dd5daa..851a20e 100644 --- a/icgparser/ModelParser.py +++ b/icgparser/ModelParser.py @@ -76,7 +76,8 @@ def parse_infrastructural_objects(doml_model): infra_object_step = include_missing_objects_from_infrastructure_layer(infra_object_step) return infra_object_step -def parse_application_layer(doml_model): + +def parse_application_layer(doml_model, infra_object_step): logging.info("DOML parsing: getting active configuration") application_object_step = {"programming_language": "ansible", "data": {}} active_configuration = doml_model.activeConfiguration @@ -84,24 +85,31 @@ def parse_application_layer(doml_model): for deployment in list(active_configuration.deployments): deployment_component_name = deployment.component.name logging.info(f'Parsing deployment for component {deployment_component_name}') - refs = DomlParserUtilities.get_references(deployment) - object_list_representation = [] - for ref in refs: - object_representation = {} - obj = deployment.eGet(ref.name) - object_representation = DomlParserUtilities.save_annotations(obj, object_representation) - object_representation = DomlParserUtilities.save_attributes(obj, object_representation) - object_list_representation.append(object_representation) - - application_object_step["data"][deployment.component.name] = object_list_representation + object_representation = {} + + application_resource = deployment.eGet("component") + ## TODO refactoring + vm = deployment.eGet("node") + try: + for infra_vm in infra_object_step.get("data").get("vms"): + if infra_vm.get("infra_element_name") == vm.name: + object_representation["node"] = infra_vm + except Exception: + logging.error(f"parsing error: no vm {vm.name} found for deployment {deployment_component_name}") + + object_representation = DomlParserUtilities.save_annotations(application_resource, object_representation) + object_representation = DomlParserUtilities.save_attributes(application_resource, object_representation) + + application_object_step["data"][deployment_component_name] = object_representation return application_object_step + 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(model_loaded) - application_step = parse_application_layer(model_loaded) + application_step = parse_application_layer(model_loaded, infra_object_step) intermediate_representation_steps.append(infra_object_step) intermediate_representation_steps.append(application_step) intermediate_representation = { diff --git a/input_file_generated/ir.json b/input_file_generated/ir.json index 5dc101a..d5cd04e 100644 --- a/input_file_generated/ir.json +++ b/input_file_generated/ir.json @@ -97,16 +97,27 @@ }, { "data": { - "nginx": [ - { - "name": "vm1", - "os": "ubuntu-20.04.3" + "nginx": { + "name": "nginx", + "node": { + "credentials": "ssh_key", + "generatedFrom": "v_img", + "group": "sg", + "i1": { + "associated": "sg", + "belongsTo": "net1", + "endPoint": "16.0.0.1", + "name": "i1" + }, + "infra_element_name": "vm1", + "name": "concrete_vm", + "os": "ubuntu-20.04.3", + "vm_flavor": "small", + "vm_key_name": "user1", + "vm_name": "nginx-host" }, - { - "name": "nginx", - "source_code": "/usr/share/nginx/html/index.html" - } - ] + "source_code": "/usr/share/nginx/html/index.html" + } }, "programming_language": "ansible" } diff --git a/output_file_example/nginx_openstack/ansible/inventory.j2 b/output_file_example/nginx_openstack/ansible/inventory.j2 new file mode 100644 index 0000000..c928da8 --- /dev/null +++ b/output_file_example/nginx_openstack/ansible/inventory.j2 @@ -0,0 +1,7 @@ +[vms] +{{ instance_ip }} + +[vms:vars] +ansible_connection=ssh +ansible_user=ubuntu +ansible_ssh_private_key_file={{ ssh_key_file }} diff --git a/output_file_example/nginx_openstack/ansible/nginx.play b/output_file_example/nginx_openstack/ansible/nginx.yaml similarity index 82% rename from output_file_example/nginx_openstack/ansible/nginx.play rename to output_file_example/nginx_openstack/ansible/nginx.yaml index 133c037..00ae616 100644 --- a/output_file_example/nginx_openstack/ansible/nginx.play +++ b/output_file_example/nginx_openstack/ansible/nginx.yaml @@ -1,10 +1,7 @@ --- -- hosts: "{{instance_server_public_key}}" +- hosts: vms gather_facts: no become: yes - vars: - ansible_ssh_private_key_file: "{{instance_server_public_key}}" - ansible_ssh_user: "ubuntu" tasks: - name: Update repositories apt: @@ -27,7 +24,7 @@ - name: Install sample site copy: - dest: "" + dest: "{{ item }}" content: | <!doctype html> <html lang="en"> @@ -42,4 +39,3 @@ with_items: - /var/www/html/index.html - /usr/share/nginx/html/index.html - diff --git a/output_files_generated/nginx_openstack/config.yaml b/output_files_generated/nginx_openstack/config.yaml index 76cd990..6464675 100644 --- a/output_files_generated/nginx_openstack/config.yaml +++ b/output_files_generated/nginx_openstack/config.yaml @@ -1,4 +1,5 @@ --- iac: - terraform +- ansible ... \ No newline at end of file diff --git a/output_files_generated/nginx_openstack/terraform/main.tf b/output_files_generated/nginx_openstack/terraform/main.tf deleted file mode 100644 index eaa7f3d..0000000 --- a/output_files_generated/nginx_openstack/terraform/main.tf +++ /dev/null @@ -1,164 +0,0 @@ -terraform { -required_version = ">= 0.14.0" - required_providers { - openstack = { - source = "terraform-provider-openstack/openstack" - version = "~> 1.35.0" - } - } -} - -# Configure the OpenStack Provider -provider "openstack" { - #user_name = var.openstack_username - #tenant_name = "admin" - #password = var.openstack_password - #auth_url = var.openstack_auth_url - insecure = true -} - -# Retrieve data -data "openstack_networking_network_v2" "external" { - name = "external" -} - -data "openstack_identity_project_v3" "test_tenant" { - name = "admin" -} - -data "openstack_networking_secgroup_v2" "default" { - name = "default" - tenant_id = data.openstack_identity_project_v3.test_tenant.id -} -# Create virtual machine -resource "openstack_compute_instance_v2" "vm1" { - name = "nginx-host" - image_name = "ubuntu-20.04.3" - flavor_name = "small" - key_pair = openstack_compute_keypair_v2.user1.name - network { - port = openstack_networking_port_v2.net1.id - } - - ## AGENTS TO ADD - # this is subject to be moved to IEM as part of its baseline - provisioner "local-exec" { - command = "ansible-galaxy collection install community.general" - } - - # this is subject to be moved to IEM as part of its baseline - provisioner "local-exec" { - command = "ansible-playbook ansible/playbooks/pma/site_requirements.yaml" - } - - # secrets can be taken from environment variables at IEM but these security issues I will leave them to y2, the user can also be problematic ubuntu/root/centos/... - provisioner "local-exec" { - command = "ansible-playbook -u root -i '${openstack_networking_floatingip_v2.vm1_floating_ip.address},' ansible/playbooks/pma/site.yaml --extra-vars '{\"pma_deployment_id\": \"123e4567-e89b-12d3-a456-426614174002\", \"pma_influxdb_bucket\": \"bucket\", \"pma_influxdb_token\": \"piacerePassword\", \"pma_influxdb_org\": \"piacere\", \"pma_influxdb_addr\": \"https://influxdb.pm.ci.piacere.digital.tecnalia.dev\" }'" - } - -} - -# Create ssh keys -resource "openstack_compute_keypair_v2" "user1" { - name = "user1" - # public_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 - } -} - -# 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 -} - -# CREATING SECURITY_GROUP - -resource "openstack_compute_secgroup_v2" "icmp" { - name = "icmp" - description = "Security group rule for port -1" - rule { - from_port = -1 - to_port = -1 - ip_protocol = "icmp" - cidr = "0.0.0.0/0" - } -} - -resource "openstack_compute_secgroup_v2" "http" { - name = "http" - description = "Security group rule for port 80" - rule { - from_port = 80 - to_port = 80 - ip_protocol = "tcp" - cidr = "0.0.0.0/0" - } -} - -resource "openstack_compute_secgroup_v2" "https" { - name = "https" - description = "Security group rule for port 443" - rule { - from_port = 443 - to_port = 443 - ip_protocol = "tcp" - cidr = "0.0.0.0/0" - } -} - -resource "openstack_compute_secgroup_v2" "ssh" { - name = "ssh" - description = "Security group rule for port 22" - rule { - from_port = 22 - to_port = 22 - ip_protocol = "tcp" - cidr = "0.0.0.0/0" - } -} - - diff --git a/plugin/AnsiblePlugin.py b/plugin/AnsiblePlugin.py index 0065bdf..12daa45 100644 --- a/plugin/AnsiblePlugin.py +++ b/plugin/AnsiblePlugin.py @@ -1,20 +1,53 @@ import logging from plugin import TemplateUtils +from plugin.PluginException import PluginResourceNotFoundError + + +def clean_operating_system_name(operating_system): + if "ubuntu" in operating_system: + return "ubuntu" + else: + raise PluginResourceNotFoundError(plugin_name="AnsiblePlugin", resource_name="operating system") + + +def find_operating_system(parameters): + try: + operating_system = parameters.get("node").get("os") + operating_system_name = clean_operating_system_name(operating_system) + return operating_system_name + except Exception: + raise PluginResourceNotFoundError(plugin_name="AnsiblePlugin", resource_name="operating system") + + +def create_inventory_file(parameters, language, operating_system, template_name): + inventory_template_path = TemplateUtils.find_template_path(language, operating_system, template_name) + template = TemplateUtils.read_template(inventory_template_path) + template_filled = TemplateUtils.edit_template(template, parameters) + return template_filled def create_files(parameters, output_path): language = "ansible" - operating_system = parameters["operating_system"] - resources = parameters.keys() - for resource_name in resources: + for resource_name, resource in parameters.items(): logging.info("Creating template for resource '%s'", resource_name) - template_path = TemplateUtils.find_template_path(language, operating_system, resource_name) - if template_path: - #for resource_params in parameters[resource_name]: + operating_system = find_operating_system(resource) + ansible_template_path = TemplateUtils.find_template_path(language, operating_system, resource_name) + if ansible_template_path: + # for resource_params in parameters[resource_name]: resource_params = parameters[resource_name] - output_file_path = output_path + "/".join([language, resource_name]) + ".play" - template = TemplateUtils.read_template(template_path) + + ansible_output_file_path = output_path + "/".join([language, resource_name]) + ".yaml" + inventory_output_file_path = output_path + "/".join([language, "inventory"]) + ".j2" + config_output_file_path = output_path + "/".join([language, "config"]) + ".yaml" + + template = TemplateUtils.read_template(ansible_template_path) template_filled = TemplateUtils.edit_template(template, resource_params) - TemplateUtils.write_template(template_filled, output_file_path) - logging.info("File available at: {}".format(output_path)) + inventory_template_filled = create_inventory_file(resource_params, language, operating_system, "inventory") + config_template_filled = create_inventory_file(resource_params, language, operating_system, "config") + + TemplateUtils.write_template(inventory_template_filled, inventory_output_file_path) + TemplateUtils.write_template(template_filled, ansible_output_file_path) + TemplateUtils.write_template(config_template_filled, config_output_file_path) + + logging.info("File available at: {}".format(output_path)) diff --git a/plugin/PluginException.py b/plugin/PluginException.py new file mode 100644 index 0000000..345ef9a --- /dev/null +++ b/plugin/PluginException.py @@ -0,0 +1,4 @@ +class PluginResourceNotFoundError(Exception): + def __init__(self, plugin_name, resource_name, message = "An error occured in plugin"): + self.message = f"Plugin {plugin_name} Exception: resource {resource_name} not found" + super().__init__(self.message) \ No newline at end of file diff --git a/template-location.properties b/template-location.properties index f6a4c4a..abe0206 100644 --- a/template-location.properties +++ b/template-location.properties @@ -19,6 +19,8 @@ networks = templates/terraform/aws/network.tpl computingGroup = templates/terraform/aws/port_rule.tpl [ansible.ubuntu] +inventory = templates/ansible/ubuntu/inventory.tpl +config = templates/ansible/ubuntu/config.tpl nginx = templates/ansible/ubuntu/nginx.tpl mysql = templates/ansible/ubuntu/mysql.tpl wordpress = templates/ansible/ubuntu/wordpress.tpl diff --git a/templates/ansible/ubuntu/config.tpl b/templates/ansible/ubuntu/config.tpl new file mode 100644 index 0000000..5854518 --- /dev/null +++ b/templates/ansible/ubuntu/config.tpl @@ -0,0 +1,7 @@ +--- +input: + - instance_ip_{{ node.vm_name }} + - instance_server_private_key_{{ node.vm_key_name }} +output: [] +engine: ansible +... diff --git a/templates/ansible/ubuntu/inventory.tpl b/templates/ansible/ubuntu/inventory.tpl new file mode 100644 index 0000000..b82f863 --- /dev/null +++ b/templates/ansible/ubuntu/inventory.tpl @@ -0,0 +1,7 @@ +[{{ "servers_for_" ~ name }}] +instance_ip_{{ node.vm_name }} + +[{{ "servers_for_" ~ name }}:vars] +ansible_connection=ssh +ansible_user={{node.vm_key_name}} +ansible_ssh_private_key_file={% raw %}{{ instance_server_private_key_{% endraw %}{{ node.vm_key_name }} {% raw %}}}{% endraw %} diff --git a/templates/ansible/ubuntu/nginx.tpl b/templates/ansible/ubuntu/nginx.tpl index 05b342b..1d9b287 100644 --- a/templates/ansible/ubuntu/nginx.tpl +++ b/templates/ansible/ubuntu/nginx.tpl @@ -1,10 +1,7 @@ --- -- hosts: {{ address }} +- hosts: {{ "servers_for_" ~ name }} gather_facts: no become: yes - vars: - ansible_ssh_private_key_file: "{{ ssh_key_file }}" - ansible_ssh_user: "{{ ssh_user }}" tasks: - name: Update repositories apt: @@ -27,7 +24,7 @@ - name: Install sample site copy: - dest: "{{ item }}" + dest: {% raw %}"{{ item }}"{%endraw%} content: | <!doctype html> <html lang="en"> @@ -41,5 +38,5 @@ </html> with_items: - /var/www/html/index.html - - /usr/share/nginx/html/index.html + - {{ source_code }} -- GitLab