From a305e12f7b05539a1aa937579103d140681b7bdb Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Thu, 26 Aug 2021 10:24:25 +0100 Subject: [PATCH 01/19] Fix Issue: #440 - Cannot generate terraform when NSG have Rules --- visualiser/generators/okitGenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualiser/generators/okitGenerator.py b/visualiser/generators/okitGenerator.py index 5e3ad6f2d..9f01e967a 100644 --- a/visualiser/generators/okitGenerator.py +++ b/visualiser/generators/okitGenerator.py @@ -1399,7 +1399,7 @@ def renderNetworkSecurityGroup(self, resource): # variableName = '{0:s}_security_rule_{1:02d}_description'.format(standardisedName, rule_number) # self.run_variables[variableName] = rule.get("description", "Egress Rule {0:02d}".format(rule_number)) # jinja2_security_rule["description"] = self.formatJinja2Variable(variableName) - jinja2_security_rule["description"] = self.generateJinja2Variable('security_rule_{0:02d}_description'.format(rule_number), rule["description"], standardisedName) + jinja2_security_rule["description"] = self.generateJinja2Variable('security_rule_{0:02d}_description'.format(rule_number), rule.get("description", ""), standardisedName) # Add to Egress Rules used for Jinja template jinja2_security_rules.append(jinja2_security_rule) # Increment rule number From 9f1731b307411ddd20cdeacc4d9fe44ebd01608e Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Thu, 26 Aug 2021 12:14:44 +0100 Subject: [PATCH 02/19] Add Bare Metal install instructions --- containers/services/gunicorn.http.service | 26 ++++++++ containers/services/gunicorn.https.service | 26 ++++++++ ...{gunicorn.service => gunicorn.oci.service} | 0 documentation/Installation.md | 63 ++++++++++++++++++- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 containers/services/gunicorn.http.service create mode 100644 containers/services/gunicorn.https.service rename containers/services/{gunicorn.service => gunicorn.oci.service} (100%) diff --git a/containers/services/gunicorn.http.service b/containers/services/gunicorn.http.service new file mode 100644 index 000000000..3a7d43dcd --- /dev/null +++ b/containers/services/gunicorn.http.service @@ -0,0 +1,26 @@ +# Copyright (c) 2020, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +[Unit] +Description=gunicorn daemon +#Requires=gunicorn.socket +After=network.target + +[Service] +Type=simple +# the specific user that our service will run as +User=root +Group=root +Environment="PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin" +Environment="PYTHONPATH=:/okit/visualiser:/okit/okitweb:/okit" +RuntimeDirectory=gunicorn +WorkingDirectory=/okit/workspace +ExecStart=/usr/local/bin/gunicorn okitweb.wsgi:app --config /okit/config/gunicorn_http.py +ExecReload=/bin/kill -s HUP $MAINPID +KillMode=mixed +TimeoutStopSec=5 +TimeoutStartSec=300 +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/containers/services/gunicorn.https.service b/containers/services/gunicorn.https.service new file mode 100644 index 000000000..913ff6472 --- /dev/null +++ b/containers/services/gunicorn.https.service @@ -0,0 +1,26 @@ +# Copyright (c) 2020, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +[Unit] +Description=gunicorn daemon +#Requires=gunicorn.socket +After=network.target + +[Service] +Type=simple +# the specific user that our service will run as +User=root +Group=root +Environment="PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin" +Environment="PYTHONPATH=:/okit/visualiser:/okit/okitweb:/okit" +RuntimeDirectory=gunicorn +WorkingDirectory=/okit/workspace +ExecStart=/usr/local/bin/gunicorn okitweb.wsgi:app --config /okit/config/gunicorn_https.py +ExecReload=/bin/kill -s HUP $MAINPID +KillMode=mixed +TimeoutStopSec=5 +TimeoutStartSec=300 +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/containers/services/gunicorn.service b/containers/services/gunicorn.oci.service similarity index 100% rename from containers/services/gunicorn.service rename to containers/services/gunicorn.oci.service diff --git a/documentation/Installation.md b/documentation/Installation.md index c018ef79c..36ef60cdf 100644 --- a/documentation/Installation.md +++ b/documentation/Installation.md @@ -295,8 +295,10 @@ sudo bash -c "python3 -m pip install -U setuptools" sudo bash -c "pip3 install --no-cache-dir authlib flask gitpython git-url-parse gunicorn oci openpyxl pandas python-magic pyyaml requests xlsxwriter" # Clone OKIT sudo bash -c "git clone -b master --depth 1 https://github.com/oracle/oci-designer-toolkit.git /okit" -sudo bash -c "mkdir /okit/{log,ssl,workspace}" -# Add additional environment information because append does not appear to work in write_file +sudo bash -c "mkdir -p /okit/{git,local,log,instance/git,instance/local,instance/templates/user,workspace,ssl}" +# Link Reference Architecture Templates to Template Directory +sudo bash -c "ln -sv /okit/okitweb/static/okit/templates/reference_architecture /okit/instance/templates/reference_architecture" +# Add additional environment information sudo bash -c "echo 'export PYTHONPATH=:/okit/visualiser:/okit/okitweb:/okit' >> /etc/bashrc" sudo bash -c "echo 'export OCI_CLI_AUTH=instance_principal' >> /etc/bashrc" sudo bash -c "echo 'export OKIT_VM_COMPARTMENT=`oci-metadata -g compartmentID --value-only`' >> /etc/bashrc" @@ -304,7 +306,7 @@ sudo bash -c "echo 'export OKIT_VM_REGION=`oci-metadata -g region --value-only`' # Generate ssl Self Sign Key sudo bash -c "openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /okit/ssl/okit.key -out /okit/ssl/okit.crt -subj '/C=GB/ST=Berkshire/L=Reading/O=Oracle/OU=OKIT/CN=www.oci_okit.com'" # Copy GUnicorn Service File -sudo bash -c 'sed "s/{COMPARTMENT_OCID}/`oci-metadata -g compartmentID --value-only`/" /okit/containers/services/gunicorn.service > /etc/systemd/system/gunicorn.service' +sudo bash -c 'sed "s/{COMPARTMENT_OCID}/`oci-metadata -g compartmentID --value-only`/" /okit/containers/services/gunicorn.oci.service > /etc/systemd/system/gunicorn.service' sudo bash -c 'sed -i "s/{REGION_IDENTIFIER}/`oci-metadata -g region --value-only`/" /etc/systemd/system/gunicorn.service' # Enable Gunicorn Service sudo systemctl enable gunicorn.service @@ -391,3 +393,58 @@ ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -N -L 8080:127.0.0 ``` Once the tunnel has been created the OKIT Designer BUI can be accessed on [http://localhost:8080/okit/designer](http://localhost:8080/okit/designer). + + + + + + + + + + +## Install on Linux Bare Metal + +If you have a Linux machine and would like to install OKIT directly on to is OS without the need for Docker or Vagrant then +this can be achieved using the following simple instructions. We assume that you have already created the appropriate OCI SDK config +file in ~/.oci and associated ssh keys/config in ~/.ssh. + +The instruction below give 2 options for the server either HTTP or HTTPS and it is up to the user to choose the appropriate +command based on there requirements. + +```bash +# Install Required Packages +sudo bash -c "yum install -y git openssl python-oci-cli oci-utils" +# Install Required Python Modules +sudo bash -c "python3 -m pip install -U pip" +sudo bash -c "python3 -m pip install -U setuptools" +sudo bash -c "pip3 install --no-cache-dir authlib flask gitpython git-url-parse gunicorn oci openpyxl pandas python-magic pyyaml requests xlsxwriter" +# Clone OKIT +sudo bash -c "git clone -b master --depth 1 https://github.com/oracle/oci-designer-toolkit.git /okit" +sudo bash -c "mkdir -p /okit/{git,local,log,instance/git,instance/local,instance/templates/user,workspace,ssl}" +# Link Reference Architecture Templates to Template Directory +sudo bash -c "ln -sv /okit/okitweb/static/okit/templates/reference_architecture /okit/instance/templates/reference_architecture" +# Add additional environment information +sudo bash -c "echo 'export PYTHONPATH=:/okit/visualiser:/okit/okitweb:/okit' >> /etc/bashrc" +# Generate ssl Self Sign Key +sudo bash -c "openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /okit/ssl/okit.key -out /okit/ssl/okit.crt -subj '/C=GB/ST=Berkshire/L=Reading/O=Oracle/OU=OKIT/CN=www.oci_okit.com'" + +############################################################################################################## +##### If HTTPS / 443 Is required ##### +##### Copy GUnicorn Service File (HTTPS) ##### +############################################################################################################## +sudo bash -c 'cp -v /okit/containers/services/gunicorn.https.service > /etc/systemd/system/gunicorn.service' +############################################################################################################## +##### If HTTP / 80 Is required ##### +##### Copy GUnicorn Service File (HTTP) ##### +############################################################################################################## +sudo bash -c 'cp -v /okit/containers/services/gunicorn.http.service > /etc/systemd/system/gunicorn.service' + +# Enable Gunicorn Service +sudo systemctl enable gunicorn.service +sudo systemctl start gunicorn.service +# Open Firewall +sudo firewall-offline-cmd --add-port=80/tcp +sudo firewall-offline-cmd --add-port=443/tcp +sudo systemctl restart firewalld +``` From 82a7be184a2b8bae50fd7d32a017c991c1b53bda Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Thu, 26 Aug 2021 12:43:37 +0100 Subject: [PATCH 03/19] Use specified Compartment not the deploy compartment --- visualiser/templates/terraform/database_system.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualiser/templates/terraform/database_system.jinja2 b/visualiser/templates/terraform/database_system.jinja2 index b7f8fef7f..647ff57b6 100644 --- a/visualiser/templates/terraform/database_system.jinja2 +++ b/visualiser/templates/terraform/database_system.jinja2 @@ -18,7 +18,7 @@ locals { resource "oci_database_db_system" "{{ resource_name }}" { #Required availability_domain = data.oci_identity_availability_domains.AvailabilityDomains.availability_domains[{{ availability_domain | safe }} - 1]["name"] - compartment_id = {{ compartment_ocid }} + compartment_id = {{ compartment_id }} database_edition = {{ database_edition | safe }} db_home { #Required From 9c178984b0d2f505884a9586b521fbd1393c0f48 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Thu, 26 Aug 2021 12:47:06 +0100 Subject: [PATCH 04/19] Update Changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6067818d0..7056035e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Release Notes +## Version 0.26.0 +**Release Date**: 8th September 2021 +### Features +1. + +### Bug Fixes +1. GitHub Issue #440 : Cannot generate terraform when NSG have Rules. +2. Fix issue where DB System were always created in the root deployment compartment not specified sub-compartment. + + ## Version 0.25.1 **Release Date**: 20th August 2021 ### Bug Fixes From 5d1b07d6f6f7f53bb9fc1d8e7486b7aa4dede0d9 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Fri, 27 Aug 2021 15:04:43 +0100 Subject: [PATCH 05/19] Add Network Load Balancer SVG --- .../palette/svg/NetworkLoadBalancerLB.svg | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg diff --git a/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg b/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg new file mode 100644 index 000000000..c377bc9d8 --- /dev/null +++ b/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + From 1cf2aa3f71ec03dd9c8a8c7905700ab619e68706 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 31 Aug 2021 10:35:31 +0100 Subject: [PATCH 06/19] Deprecate Ansible export and make optional --- okitweb/okitWebDesigner.py | 6 +++++- okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg | 4 ++-- okitweb/templates/okit/okit_designer.html | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/okitweb/okitWebDesigner.py b/okitweb/okitWebDesigner.py index 6cae9ed67..ec1b220e6 100644 --- a/okitweb/okitWebDesigner.py +++ b/okitweb/okitWebDesigner.py @@ -169,6 +169,10 @@ def designer(): a2c_mode = (request.args.get('a2c', default='false') == 'true') if a2c_mode: logger.info("<<<<<<<<<<<<<<<<<<<<<<<<<< A2C Mode >>>>>>>>>>>>>>>>>>>>>>>>>>") + # Test if Ansible mode + ansible_mode = (request.args.get('ansible', default='false') == 'true') + if ansible_mode: + logger.info("<<<<<<<<<<<<<<<<<<<<<<<< Ansible Mode >>>>>>>>>>>>>>>>>>>>>>>>") # Read Artifact Model Specific JavaScript Files artefact_model_js_files = sorted(os.listdir(os.path.join(bp.static_folder, 'model', 'js', 'artefacts'))) # Read Artifact View Specific JavaScript Files @@ -220,7 +224,7 @@ def designer(): # okit_templates_groups=template_groups, # okit_template_categories=template_categories, local_okit=local, - developer_mode=developer_mode, experimental_mode=experimental_mode, cd3_mode=cd3_mode, a2c_mode=a2c_mode, pca_mode=pca_mode) + developer_mode=developer_mode, experimental_mode=experimental_mode, cd3_mode=cd3_mode, a2c_mode=a2c_mode, pca_mode=pca_mode, ansible_mode=ansible_mode) # Template Processing diff --git a/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg b/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg index c377bc9d8..c4b75b470 100644 --- a/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg +++ b/okitweb/static/okit/palette/svg/NetworkLoadBalancerLB.svg @@ -1,13 +1,13 @@ + viewBox="0 0 42 42" style="enable-background:new 0 0 42 42;" xml:space="preserve"> - + Terraform + {%- if ansible_mode -%}
  • Ansible
  • + {%- endif -%} {% if local_okit or session['username'] %} - icons / 32 / compute - Created with Sketch. + - - - - + + + - - + + + + \ No newline at end of file diff --git a/okitweb/static/svg/containers.svg b/okitweb/static/svg/containers.svg index 31d069bd7..da0655e85 100644 --- a/okitweb/static/svg/containers.svg +++ b/okitweb/static/svg/containers.svg @@ -1,15 +1,15 @@ - - - - icons / 32 / compute - Created with Sketch. + - - - - + + + - - + + + + \ No newline at end of file diff --git a/okitweb/static/svg/database.svg b/okitweb/static/svg/database.svg index 548923df1..fd34330da 100644 --- a/okitweb/static/svg/database.svg +++ b/okitweb/static/svg/database.svg @@ -1,15 +1,16 @@ - + - - - - + + + - - - + + + + \ No newline at end of file diff --git a/okitweb/static/svg/gateways.svg b/okitweb/static/svg/gateways.svg index b252be102..b5e9ddc0b 100644 --- a/okitweb/static/svg/gateways.svg +++ b/okitweb/static/svg/gateways.svg @@ -1,13 +1,16 @@ -
    {{ palette.add_palette(palette_json) }} - diff --git a/okitweb/templates/okit/propertysheets/policy.html b/okitweb/templates/okit/propertysheets/policy.html new file mode 100644 index 000000000..901e1223c --- /dev/null +++ b/okitweb/templates/okit/propertysheets/policy.html @@ -0,0 +1,9 @@ + +{% extends "okit/propertysheets/base_property_sheet.html" %} +{% block title_block %}Policy{% endblock %} +{% block required_properties_table_rows_block %}{% endblock %} +{% block optional_properties_table_rows_block %}{% endblock %} +{% block optional_properties_block %}{% endblock %} diff --git a/okitweb/templates/okit/valueproposition/policy.html b/okitweb/templates/okit/valueproposition/policy.html new file mode 100644 index 000000000..70d71bede --- /dev/null +++ b/okitweb/templates/okit/valueproposition/policy.html @@ -0,0 +1,5 @@ + +{% extends "okit/valueproposition/oci.html" %} diff --git a/skeletons/okitCodeSkeletonGenerator.py b/skeletons/okitCodeSkeletonGenerator.py index 5534dca47..34ad8a83c 100644 --- a/skeletons/okitCodeSkeletonGenerator.py +++ b/skeletons/okitCodeSkeletonGenerator.py @@ -70,8 +70,8 @@ def processWorkflow(args): #filename = "../okitweb/static/okit/view/js/Additional_View_Functions_For_{0!s:s}.js".format(svg_id) #writeFile(filename, rendered) # ---- SVG - jinja2_template = jinja2_environment.get_template("artefact.svg.jinja2") - rendered = jinja2_template.render(jinja2_variables) + # jinja2_template = jinja2_environment.get_template("artefact.svg.jinja2") + # rendered = jinja2_template.render(jinja2_variables) #logger.info(rendered) filename = "../okitweb/static/okit/palette/hidden/{0!s:s}.svg".format(svg_id) writeFile(filename, rendered) diff --git a/visualiser/facades/ociPolicy.py b/visualiser/facades/ociPolicy.py new file mode 100644 index 000000000..9149c2fd5 --- /dev/null +++ b/visualiser/facades/ociPolicy.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +"""Provide Module Description +""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +__author__ = ["Andrew Hopkinson (Oracle Cloud Solutions A-Team)"] +__version__ = "1.0.0" +__module__ = "ociPolicy" +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# + + +import oci + +from common.okitLogging import getLogger +from facades.ociConnection import OCIPolicyConnection + +# Configure logging +logger = getLogger() + + +class OCIPolicys(OCIPolicyConnection): + def __init__(self, config=None, configfile=None, profile=None, compartment_id=None): + self.compartment_id = compartment_id + self.policys_json = [] + super(OCIPolicys, self).__init__(config=config, configfile=configfile, profile=profile) + + def list(self, compartment_id=None, filter=None): + if compartment_id is None: + compartment_id = self.compartment_id + + # Add filter to only return AVAILABLE Compartments + if filter is None: + filter = {} + + if 'lifecycle_state' not in filter: + filter['lifecycle_state'] = 'AVAILABLE' + + policys = oci.pagination.list_call_get_all_results(self.client.list_policys, compartment_id=compartment_id).data + + # Convert to Json object + policys_json = self.toJson(policys) + logger.debug(str(policys_json)) + + # Filter results + self.policys_json = self.filterJsonObjectList(policys_json, filter) + logger.debug(str(self.policys_json)) + + return self.policys_json From 79d22aef70c53a1909e7a00b09fa7e6a7ea0856f Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Wed, 1 Sep 2021 11:35:55 +0100 Subject: [PATCH 10/19] Update Policy and switch view to use getList functions --- .../static/okit/model/js/artefacts/policy.js | 26 +-- okitweb/static/okit/palette/hidden/Policy.svg | 163 ++++++++++++++++++ .../view/designer/js/artefacts/compartment.js | 2 +- .../okit/view/designer/js/artefacts/policy.js | 20 +-- .../static/okit/view/js/artefacts/policy.js | 163 ++++++++++++++++++ okitweb/static/okit/view/js/okit_view.js | 36 ++-- 6 files changed, 369 insertions(+), 41 deletions(-) create mode 100644 okitweb/static/okit/palette/hidden/Policy.svg create mode 100644 okitweb/static/okit/view/js/artefacts/policy.js diff --git a/okitweb/static/okit/model/js/artefacts/policy.js b/okitweb/static/okit/model/js/artefacts/policy.js index 1c1590594..96fa60eab 100644 --- a/okitweb/static/okit/model/js/artefacts/policy.js +++ b/okitweb/static/okit/model/js/artefacts/policy.js @@ -14,7 +14,7 @@ class Policy extends OkitArtifact { constructor (data={}, okitjson={}) { super(okitjson); // Configure default values - this.display_name = this.generateDefaultName(okitjson.policies.length + 1); + this.display_name = this.generateDefaultName(okitjson.policys.length + 1); this.compartment_id = data.parent_id; /* ** TODO: Add Resource / Artefact specific parameters and default @@ -36,7 +36,7 @@ class Policy extends OkitArtifact { ** Name Generation */ getNamePrefix() { - return super.getNamePrefix() + 'pol'; + return super.getNamePrefix() + 'p'; } /* ** Static Functionality @@ -49,17 +49,17 @@ class Policy extends OkitArtifact { ** Dynamically Add Model Functions */ OkitJson.prototype.newPolicy = function(data) { - this.getPolicies().push(new Policy(data, this)); - return this.getPolicies()[this.getPolicies().length - 1]; + this.getPolicys().push(new Policy(data, this)); + return this.getPolicys()[this.getPolicys().length - 1]; } -OkitJson.prototype.getPolicies = function() { - if (!this.policies) { - this.policies = []; +OkitJson.prototype.getPolicys = function() { + if (!this.policys) { + this.policys = []; } - return this.policies; + return this.policys; } OkitJson.prototype.getPolicy = function(id='') { - for (let artefact of this.getPolicies()) { + for (let artefact of this.getPolicys()) { if (artefact.id === id) { return artefact; } @@ -67,10 +67,10 @@ OkitJson.prototype.getPolicy = function(id='') { return undefined; } OkitJson.prototype.deletePolicy = function(id) { - for (let i = 0; i < this.policies.length; i++) { - if (this.policies[i].id === id) { - this.policies[i].delete(); - this.policies.splice(i, 1); + for (let i = 0; i < this.policys.length; i++) { + if (this.policys[i].id === id) { + this.policys[i].delete(); + this.policys.splice(i, 1); break; } } diff --git a/okitweb/static/okit/palette/hidden/Policy.svg b/okitweb/static/okit/palette/hidden/Policy.svg new file mode 100644 index 000000000..d63d9d6b2 --- /dev/null +++ b/okitweb/static/okit/palette/hidden/Policy.svg @@ -0,0 +1,163 @@ +/* +** Copyright (c) 2020, 2021, Oracle and/or its affiliates. +** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. +*/ +console.info('Loaded Policy View Javascript'); + +/* +** Define Policy View Class +*/ +class PolicyView extends OkitArtefactView { + constructor(artefact=null, json_view) { + if (!json_view.policys) json_view.policys = []; + super(artefact, json_view); + } + // TODO: Return Artefact Parent id e.g. vcn_id for a Internet Gateway + get parent_id() {return this.artefact.vcn_id;} + // TODO: Return Artefact Parent Object e.g. VirtualCloudNetwork for a Internet Gateway + get parent() {return this.getJsonView().getVirtualCloudNetwork(this.parent_id);} + // TODO: If the Resource is within a Subnet but the subnet_iss is not at the top level then raise it with the following functions if not required delete them. + // Direct Subnet Access + get subnet_id() {return this.artefact.primary_mount_target.subnet_id;} + set subnet_id(id) {this.artefact.primary_mount_target.subnet_id = id;} + /* + ** SVG Processing + */ + /* + ** Property Sheet Load function + */ + loadProperties() { + const self = this; + $(jqId(PROPERTIES_PANEL)).load("propertysheets/policy.html", () => {loadPropertiesSheet(self.artefact);}); + } + /* + ** Load and display Value Proposition + */ + loadValueProposition() { + $(jqId(VALUE_PROPOSITION_PANEL)).load("valueproposition/policy.html"); + } + /* + ** Static Functionality + */ + static getArtifactReference() { + return Policy.getArtifactReference(); + } + static getDropTargets() { + // TODO: Return List of Artefact Drop Targets Parent Object Reference Names e.g. VirtualCloudNetwork for a Internet Gateway + return [VirtualCloudNetwork.getArtifactReference()]; + } +} +/* +** Dynamically Add View Functions +*/ +OkitJsonView.prototype.dropPolicyView = function(target) { + let view_artefact = this.newPolicy(); + if (target.type === Compartment.getArtifactReference()) { + view_artefact.artefact.compartment_id = target.id; + } else { + view_artefact.artefact.compartment_id = target.compartment_id; + } + view_artefact.recalculate_dimensions = true; + return view_artefact; +} +OkitJsonView.prototype.newPolicy = function(obj) { + this.getPolicys().push(obj ? new PolicyView(obj, this) : new PolicyView(this.okitjson.newPolicy(), this)); + return this.getPolicys()[this.getPolicys().length - 1]; +} +OkitJsonView.prototype.getPolicys = function() { + if (!this.policys) { + this.policys = []; + } + return this.policys; +} +OkitJsonView.prototype.getPolicy = function(id='') { + for (let artefact of this.getPolicys()) { + if (artefact.id === id) { + return artefact; + } + } + return undefined; +} +OkitJsonView.prototype.loadPolicys = function(policys) { + for (const artefact of policys) { + this.getPolicys().push(new PolicyView(new Policy(artefact, this.okitjson), this)); + } +} +OkitJsonView.prototype.movePolicy = function(id) { + // Build Dialog + const self = this; + let policy = this.getPolicy(id); + $(jqId('modal_dialog_title')).text('Move ' + policy.display_name); + $(jqId('modal_dialog_body')).empty(); + $(jqId('modal_dialog_footer')).empty(); + const table = d3.select(d3Id('modal_dialog_body')).append('div') + .attr('class', 'table okit-table'); + const tbody = table.append('div') + .attr('class', 'tbody'); + // Subnet + let tr = tbody.append('div') + .attr('class', 'tr'); + tr.append('div') + .attr('class', 'td') + .text('Subnet'); + tr.append('div') + .attr('class', 'td') + .append('select') + .attr('id', 'move_policy_subnet_id'); + // Load Subnets + this.loadSubnetsSelect('move_policy_subnet_id'); + $(jqId("move_policy_subnet_id")).val(policy.artefact.subnet_id); + // Submit Button + const submit = d3.select(d3Id('modal_dialog_footer')).append('div').append('button') + .attr('id', 'submit_query_btn') + .attr('type', 'button') + .text('Move') + .on('click', function () { + $(jqId('modal_dialog_wrapper')).addClass('hidden'); + if (policy.artefact.subnet_id !== $(jqId("move_policy_subnet_id")).val()) { + self.getSubnet(policy.artefact.subnet_id).recalculate_dimensions = true; + self.getSubnet($(jqId("move_policy_subnet_id")).val()).recalculate_dimensions = true; + policy.artefact.subnet_id = $(jqId("move_policy_subnet_id")).val(); + policy.artefact.compartment_id = self.getSubnet(policy.artefact.subnet_id).artefact.compartment_id; + } + self.update(this.okitjson); + }); + $(jqId('modal_dialog_wrapper')).removeClass('hidden'); +} +OkitJsonView.prototype.pastePolicy = function(drop_target) { + const clone = this.copied_artefact.artefact.clone(); + clone.display_name += 'Copy'; + if (this.paste_count) {clone.display_name += `-${this.paste_count}`;} + this.paste_count += 1; + clone.id = clone.okit_id; + if (drop_target.getArtifactReference() === Subnet.getArtifactReference()) { + clone.subnet_id = drop_target.id; + clone.compartment_id = drop_target.compartment_id; + } + this.okitjson.policys.push(clone); + this.update(this.okitjson); +} +OkitJsonView.prototype.loadPolicysSelect = function(select_id, empty_option=false) { + $(jqId(select_id)).empty(); + const policy_select = $(jqId(select_id)); + if (empty_option) { + policy_select.append($('
    - -
    -
    - +
    +
    +
    + +
    +
    +
    + +
    + + + + + +
    -
    - - - - -
    diff --git a/okitweb/templates/okit/palette_macros.jinja2 b/okitweb/templates/okit/palette_macros.jinja2 index dd34c26c9..d2394e010 100644 --- a/okitweb/templates/okit/palette_macros.jinja2 +++ b/okitweb/templates/okit/palette_macros.jinja2 @@ -7,11 +7,17 @@ onclick="$('.okit-palette-icon-div').addClass('hidden');$('.{{ target }}').removeClass('hidden');okitSettings.target='{{ target }}';okitSettings.save();">{{ target | upper }} {% endfor %}
    -
    + +
    + +
    {% for group in palette.groups %} {{ add_palette_group(group) }} diff --git a/okitweb/templates/okit/propertysheets/base_property_sheet.html b/okitweb/templates/okit/propertysheets/base_property_sheet.html index 61f0f35ac..5ddd1cbb6 100644 --- a/okitweb/templates/okit/propertysheets/base_property_sheet.html +++ b/okitweb/templates/okit/propertysheets/base_property_sheet.html @@ -4,7 +4,7 @@ --> {% macro properties_input(title, name, type='text', collapsed=False, readonly=False, data={}) -%} {% if type in ['text', 'password', 'email', 'date'] %} - + {% elif type == 'number' %} {% elif type == 'ipv4' %} diff --git a/visualiser/generators/okitGenerator.py b/visualiser/generators/okitGenerator.py index 9f01e967a..a1aef4c5f 100644 --- a/visualiser/generators/okitGenerator.py +++ b/visualiser/generators/okitGenerator.py @@ -149,6 +149,9 @@ def generate(self): # -- Customer Premise Equipments for customer_premise_equipment in self.visualiser_json.get('customer_premise_equipments', []): self.renderCustomerPremiseEquipment(customer_premise_equipment) + # -- Policies + for policy in self.visualiser_json.get('policys', []): + self.renderPolicy(policy) # - Virtual Cloud Network Sub Components # -- Internet Gateways @@ -1546,6 +1549,49 @@ def renderOkeCluster(self, resource): logger.debug(self.create_sequence[-1]) return + def renderPolicy(self, resource): + # Reset Variables + self.initialiseJinja2Variables() + # Read Data + standardisedName = self.standardiseResourceName(resource['display_name']) + resourceName = '{0:s}'.format(standardisedName) + self.jinja2_variables['resource_name'] = resourceName + self.jinja2_variables['output_name'] = resource['display_name'] + # Process Subnet Data + logger.info('Processing Subnet Information {0!s:s}'.format(standardisedName)) + # -- Define Variables + # --- Read / Create + # ---- Read Only + self.jinja2_variables['read_only'] = resource.get('read_only', False) + # ---- Id + self.jinja2_variables["ocid"] = self.formatJinja2Value(resource['id']) + # --- Required + # ---- Compartment Id + self.jinja2_variables["compartment_id"] = self.formatJinja2IdReference(self.standardiseResourceName(self.id_name_map[resource['compartment_id']])) + # ---- Display Name + self.addJinja2Variable("display_name", resource["display_name"], standardisedName) + # ---- Description + self.addJinja2Variable("description", resource.get("description", resource["display_name"]), standardisedName) + # ---- Policy Statements + if len(resource['statements']): + self.jinja2_variables["statements"] = resource['statements'] + else: + self.jinja2_variables.pop("statements", None) + # --- Optional + # ---- Availability Domain + if resource.get("version_date", '') != '': + self.addJinja2Variable("version_date", resource["version_date"], standardisedName) + else: + self.jinja2_variables.pop("version_date", None) + # ---- Tags + self.renderTags(resource) + + # -- Render Template + jinja2_template = self.jinja2_environment.get_template("policy.jinja2") + self.create_sequence.append(jinja2_template.render(self.jinja2_variables)) + logger.debug(self.create_sequence[-1]) + return + def renderRemotePeeringConnection(self, resource): # Reset Variables self.initialiseJinja2Variables() diff --git a/visualiser/query/ociQuery.py b/visualiser/query/ociQuery.py index c1b0dfa1e..dcd64f3aa 100644 --- a/visualiser/query/ociQuery.py +++ b/visualiser/query/ociQuery.py @@ -53,7 +53,7 @@ class OCIQuery(OCIConnection): "FileSystem", "Image", "Instance", - "InstancePool", + # "InstancePool", "InternetGateway", "IPSecConnection", "IpSecConnectionTunnel", @@ -65,6 +65,7 @@ class OCIQuery(OCIConnection): "NetworkSecurityGroup", "NetworkSecurityGroupSecurityRule", "NodePool", + "Policy", "PrivateIp", "PublicIp", "RemotePeeringConnection", @@ -103,6 +104,7 @@ class OCIQuery(OCIConnection): "MySqlDbSystem": "mysql_database_systems", "NatGateway": "nat_gateways", "NetworkSecurityGroup": "network_security_groups", + "Policy": "policys", "RemotePeeringConnection": "remote_peering_connections", "RouteTable": "route_tables", "SecurityList": "security_lists", diff --git a/visualiser/templates/terraform/policy.jinja2 b/visualiser/templates/terraform/policy.jinja2 new file mode 100644 index 000000000..af72e41f7 --- /dev/null +++ b/visualiser/templates/terraform/policy.jinja2 @@ -0,0 +1,42 @@ + +{% if read_only %} +# ------ Read Policy +data "oci_identity_policies" "test_policies" { + #Required + compartment_id = {{ compartment_id }} + filter { + name = "id" + values = [{{ ocid | safe }}] + } +} + +locals { + {{ resource_name }}_id = {{ ocid | safe }} +} +{% else %} +# ------ Create Policy +resource "oci_identity_policy" "{{ resource_name }}" { + provider = oci.home_region + #Required + compartment_id = {{ compartment_id }} + description = {{ description | safe }} + name = {{ display_name | safe }} + statements = [{% for statement in statements %}"{{ statement | safe }}"{% if not loop.last %},{% endif %}{% endfor %}] +# statements = {{ statements | safe }} + + #Optional +{% if version_date is defined %} + version_date = {{ version_date | safe }} +{% endif %} +{% if defined_tags is defined %} + defined_tags = {{ defined_tags | safe }} +{% endif %} +{% if freeform_tags is defined %} + freeform_tags = {{ freeform_tags | safe }} +{% endif %} +} + +locals { + {{ resource_name }}_id = oci_identity_policy.{{ resource_name }}.id +} +{% endif %} From 5311101868dcf92d53ef0031f6eb7ad19bc4c9d2 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Mon, 6 Sep 2021 17:06:01 +0100 Subject: [PATCH 13/19] Update change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b24cc0d..363c24ed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Release Date**: 8th September 2021 ### Features 1. Temporarily deprecate Ansible export by making it command line flag driven (ansible=true) +2. Add Policy Resource to Palette and allow the user to drag them onto the canvas. It assumes that the user understands the policy statement syntax. All policies will be created within the users home region. ### Bug Fixes 1. GitHub Issue #440 : Cannot generate terraform when NSG have Rules. From 83bb80cec7d9cf78009ef3a19f0c25738fc6bc7a Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 11:32:20 +0100 Subject: [PATCH 14/19] Update Development documentation --- documentation/Development.md | 73 ++------------------------ skeletons/okitCodeSkeletonGenerator.py | 8 +-- visualiser/common/okitCommon.py | 15 +++--- 3 files changed, 18 insertions(+), 78 deletions(-) diff --git a/documentation/Development.md b/documentation/Development.md index 273ab8a7d..f09dc60fe 100644 --- a/documentation/Development.md +++ b/documentation/Development.md @@ -56,8 +56,8 @@ python3 okitCodeSkeletonGenerator.py --name "" ```bash python3 okitCodeSkeletonGenerator.py --name "Block Storage Volume" INFO: Writing File: ../okitweb/static/okit/model/js/artefacts/block_storage_volume.js -INFO: Writing File: ../okitweb/static/okit/view/js/artefacts/block_storage_volume.js -INFO: Writing File: ../okitweb/static/okit/palette/hidden/Block_Storage_Volume.svg +INFO: Writing File: ../okitweb/static/okit/view/designer/js/artefacts/block_storage_volume.js +INFO: Writing File: ../okitweb/static/okit/palette/svg/Block_Storage_Volume.svg INFO: Writing File: ../okitweb/templates/okit/propertysheets/block_storage_volume.html INFO: Writing File: ../okitweb/templates/okit/valueproposition/block_storage_volume.html INFO: Writing File: ../visualiser/facade/ociBlockStorageVolume.py @@ -256,7 +256,7 @@ OkitJson.prototype.deleteBlockStorageVolume = function(id) { ### Artefact View JavaScript #### Generated Skeleton -Following generation a view file will be created in the **okitweb/static/okit/view/js/artefacts** directory as shown below. +Following generation a view file will be created in the **okitweb/static/okit/view/designer/js/artefacts** directory as shown below. ```javascript /* ** Copyright (c) 2020, 2021, Oracle and/or its affiliates. @@ -475,7 +475,7 @@ OkitJsonView.prototype.cloneBlockStorageVolume = function(obj) { ### Palette SVG #### Generated Skeleton -Following generation an empty SVG file will be created in the **okitweb/static/okit/palette/hidden** directory as shown below. +Following generation an empty SVG file will be created in the **okitweb/static/okit/palette/svg** directory as shown below. Because this is created in the hidden directory it will not be displayed in the Palette by default but once modified it should be moved to the appropriate palette subdirectory. ```svg @@ -782,9 +782,8 @@ this can be found in the various, existing, ansible templates. ## Updated Files Once the core files for the new Artefact (Resource) have been created the developer will need to integrate these into the -existing functionality by editting a number of common script files. The required edits will be described in the following sections. +existing functionality by editing a number of common script files. The required edits will be described in the following sections. ### Frontend Files -- [OKIT View JavaScript](#okit-view-javascript) - [Designer View JavaScript](#designer-view-javascript) - [OKIT OCI Flask Python](#okit-oci-flask-python) - [OCI Query JavaScript](#oci-query-javascript) @@ -793,68 +792,6 @@ existing functionality by editting a number of common script files. The required - [Connection Python](#connection-python) - [Generator Python](#generator-python) -### OKIT View JavaScript -The ** okitweb/static/okit/view/js/okit_view.js** will need to be modified to include the new Artefact (Resource) in the clear() and -load() function. For our worked example the modifications will be as follows. -```javascript - clear() { - this.compartments = []; - this.autonomous_databases = []; - this.block_storage_volumes = []; - this.customer_premise_equipments = []; - this.database_systems = []; - this.dynamic_routing_gateways = []; - this.fast_connects = []; - this.file_storage_systems = []; - this.instances = []; - this.instance_pools = []; - this.internet_gateways = []; - this.ipsec_connections = []; - this.load_balancers = []; - this.local_peering_gateways = []; - this.mysql_database_systems = []; - this.nat_gateways = []; - this.network_security_groups = []; - this.object_storage_buckets = []; - this.oke_clusters = []; - this.remote_peering_connections = []; - this.route_tables = []; - this.security_lists = []; - this.service_gateways = []; - this.subnets = []; - this.virtual_cloud_networks = []; - this.virtual_network_interfaces = []; - } - - load() { - this.clear(); - for (let artefact of this.okitjson.compartments) {this.newCompartment(artefact);} - for (let artefact of this.okitjson.autonomous_databases) {this.newAutonomousDatabase(artefact);} - for (let artefact of this.okitjson.block_storage_volumes) {this.newBlockStorageVolume(artefact);} - for (let artefact of this.okitjson.customer_premise_equipments) {this.newCustomerPremiseEquipment(artefact);} - for (let artefact of this.okitjson.database_systems) {this.newDatabaseSystem(artefact);} - for (let artefact of this.okitjson.dynamic_routing_gateways) {this.newDynamicRoutingGateway(artefact);} - for (let artefact of this.okitjson.fast_connects) {this.newFastConnect(artefact);} - for (let artefact of this.okitjson.file_storage_systems) {this.newFileStorageSystem(artefact);} - for (let artefact of this.okitjson.instances) {this.newInstance(artefact);} - for (let artefact of this.okitjson.instance_pools) {this.newInstancePool(artefact);} - for (let artefact of this.okitjson.internet_gateways) {this.newInternetGateway(artefact);} - for (let artefact of this.okitjson.ipsec_connections) {this.newIPSecConnection(artefact);} - for (let artefact of this.okitjson.load_balancers) {this.newLoadBalancer(artefact);} - for (let artefact of this.okitjson.local_peering_gateways) {this.newLocalPeeringGateway(artefact);} - for (let artefact of this.okitjson.mysql_database_systems) {this.newMySQLDatabaseSystem(artefact);} - for (let artefact of this.okitjson.nat_gateways) {this.newNATGateway(artefact);} - for (let artefact of this.okitjson.network_security_groups) {this.newNetworkSecurityGroup(artefact);} - for (let artefact of this.okitjson.object_storage_buckets) {this.newObjectStorageBucket(artefact);} - for (let artefact of this.okitjson.oke_clusters) {this.newOkeCluster(artefact);} - for (let artefact of this.okitjson.remote_peering_connections) {this.newRemotePeeringConnection(artefact);} - for (let artefact of this.okitjson.route_tables) {this.newRouteTable(artefact);} - for (let artefact of this.okitjson.security_lists) {this.newSecurityList(artefact);} - for (let artefact of this.okitjson.service_gateways) {this.newServiceGateway(artefact);} - for (let artefact of this.okitjson.subnets) {this.newSubnet(artefact);} - for (let artefact of this.okitjson.virtual_cloud_networks) {this.newVirtualCloudNetwork(artefact);} - } -``` ### Designer View JavaScript The ** okitweb/static/okit/view/designer/js/okit_view.js** will need to be modified to include the new Artefact (Resource) in the draw() function. This code must be placed within the function at an appropriate position after its parent and before its children. diff --git a/skeletons/okitCodeSkeletonGenerator.py b/skeletons/okitCodeSkeletonGenerator.py index 34ad8a83c..62dbf29a5 100644 --- a/skeletons/okitCodeSkeletonGenerator.py +++ b/skeletons/okitCodeSkeletonGenerator.py @@ -61,7 +61,7 @@ def processWorkflow(args): jinja2_template = jinja2_environment.get_template("artefact_view.js.jinja2") rendered = jinja2_template.render(jinja2_variables) #logger.info(rendered) - filename = "../okitweb/static/okit/view/js/artefacts/{0!s:s}.js".format(standardised_name) + filename = "../okitweb/static/okit/view/designer/js/artefacts/{0!s:s}.js".format(standardised_name) writeFile(filename, rendered) # ---- View Functions JavaScript #jinja2_template = jinja2_environment.get_template("view_functions.jinja2") @@ -70,10 +70,10 @@ def processWorkflow(args): #filename = "../okitweb/static/okit/view/js/Additional_View_Functions_For_{0!s:s}.js".format(svg_id) #writeFile(filename, rendered) # ---- SVG - # jinja2_template = jinja2_environment.get_template("artefact.svg.jinja2") - # rendered = jinja2_template.render(jinja2_variables) + jinja2_template = jinja2_environment.get_template("artefact.svg.jinja2") + rendered = jinja2_template.render(jinja2_variables) #logger.info(rendered) - filename = "../okitweb/static/okit/palette/hidden/{0!s:s}.svg".format(svg_id) + filename = "../okitweb/static/okit/palette/svg/{0!s:s}.svg".format(svg_id) writeFile(filename, rendered) # ---- Properties HTML jinja2_template = jinja2_environment.get_template("artefact_properties.html.jinja2") diff --git a/visualiser/common/okitCommon.py b/visualiser/common/okitCommon.py index 1762f2705..773eeb95d 100644 --- a/visualiser/common/okitCommon.py +++ b/visualiser/common/okitCommon.py @@ -172,13 +172,16 @@ def writeMarkdownFile(md_file, contents): return -def writeFile(filename, contents): +def writeFile(filename, contents, overwrite=False): logger.info('Writing File: {0:s}'.format(filename)) - dirname = os.path.dirname(filename) - if not os.path.exists(dirname): - os.makedirs(dirname) - with closing(open(filename, 'w')) as f: - f.write('{0:s}\n'.format(contents)) + if overwrite or not os.path.exists(filename): + dirname = os.path.dirname(filename) + if not os.path.exists(dirname): + os.makedirs(dirname) + with closing(open(filename, 'w')) as f: + f.write('{0:s}\n'.format(contents)) + else: + logger.info('File Already Exists: {0:s}'.format(filename)) return From ad704a95db5fb5f5be351af7eecb69a6ea179743 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 13:05:00 +0100 Subject: [PATCH 15/19] Simplify Draw functionality to detect and draw resources --- .../view/designer/js/artefacts/compartment.js | 3 +- .../okit/view/designer/js/artefacts/subnet.js | 4 +- .../js/artefacts/virtual_cloud_network.js | 4 +- .../view/designer/js/okit_designer_view.js | 57 ++++++++++++++++++- okitweb/static/okit/view/js/okit_view.js | 2 + 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/okitweb/static/okit/view/designer/js/artefacts/compartment.js b/okitweb/static/okit/view/designer/js/artefacts/compartment.js index bad8353bc..7d11032dc 100644 --- a/okitweb/static/okit/view/designer/js/artefacts/compartment.js +++ b/okitweb/static/okit/view/designer/js/artefacts/compartment.js @@ -19,7 +19,7 @@ class CompartmentView extends OkitContainerDesignerArtefactView { } get parent() {return this.getJsonView().getCompartment(this.parent_id);} // get parent() {return this.getJsonView().getCompartment(this.parent_id) ? this.getJsonView().getCompartment(this.parent_id) : this.getJsonView().canvas;} - get children() {return [...this.json_view.getCompartments(), ...this.json_view.getVirtualCloudNetworks(), + get children1() {return [...this.json_view.getCompartments(), ...this.json_view.getVirtualCloudNetworks(), // ...this.json_view.getSubnets(), ...this.json_view.getExadataInfrastructures(), ...this.json_view.getBlockStorageVolumes(), ...this.json_view.getDynamicRoutingGateways(), ...this.json_view.getAutonomousDatabases(), ...this.json_view.getCustomerPremiseEquipments(), @@ -52,6 +52,7 @@ class CompartmentView extends OkitContainerDesignerArtefactView { } cloneChildren(clone) { + console.info('Cloning Compartment Children:', this.children) for (let child of this.children) { child.clone().compartment_id = clone.id; } diff --git a/okitweb/static/okit/view/designer/js/artefacts/subnet.js b/okitweb/static/okit/view/designer/js/artefacts/subnet.js index 9c7c75383..c3b441c63 100644 --- a/okitweb/static/okit/view/designer/js/artefacts/subnet.js +++ b/okitweb/static/okit/view/designer/js/artefacts/subnet.js @@ -23,7 +23,7 @@ class SubnetView extends OkitContainerDesignerArtefactView { } } get parent() {return this.getJsonView().getVirtualCloudNetwork(this.parent_id) ? this.getJsonView().getVirtualCloudNetwork(this.parent_id) : this.getJsonView().getCompartment(this.parent_id);} - get children() {return [...this.json_view.getInstances(), ...this.json_view.getLoadBalancers(), + get children1() {return [...this.json_view.getInstances(), ...this.json_view.getLoadBalancers(), ...this.json_view.getFileStorageSystems(), ...this.json_view.getAutonomousDatabases(), ...this.json_view.getDatabaseSystems(), ...this.json_view.getMysqlDatabaseSystems()].filter(child => child.parent_id === this.artefact.id);} get type_text() {return this.prohibit_public_ip_on_vnic ? `Private ${this.getArtifactReference()}` : `Public ${this.getArtifactReference()}`;} @@ -38,7 +38,9 @@ class SubnetView extends OkitContainerDesignerArtefactView { } cloneChildren(clone) { + console.info('Cloning Subnet Children:', this.children) for (let child of this.children) { + child.clone().compartment_id = clone.compartment_id; child.clone().subnet_id = clone.id; } } diff --git a/okitweb/static/okit/view/designer/js/artefacts/virtual_cloud_network.js b/okitweb/static/okit/view/designer/js/artefacts/virtual_cloud_network.js index 21ed3c867..8f6e93894 100644 --- a/okitweb/static/okit/view/designer/js/artefacts/virtual_cloud_network.js +++ b/okitweb/static/okit/view/designer/js/artefacts/virtual_cloud_network.js @@ -14,7 +14,7 @@ class VirtualCloudNetworkView extends OkitContainerDesignerArtefactView { get parent_id() {return this.artefact.compartment_id;} get parent() {return this.getJsonView().getCompartment(this.parent_id);} - get children() {return [...this.json_view.getSubnets(), ...this.json_view.getInternetGateways(), + get children1() {return [...this.json_view.getSubnets(), ...this.json_view.getInternetGateways(), ...this.json_view.getNatGateways(), ...this.json_view.getRouteTables(), ...this.json_view.getSecurityLists(), ...this.json_view.getDhcpOptions(), ...this.json_view.getNetworkSecurityGroups(), ...this.json_view.getServiceGateways(), ...this.json_view.getDynamicRoutingGateways(), ...this.json_view.getLocalPeeringGateways(), @@ -30,7 +30,9 @@ class VirtualCloudNetworkView extends OkitContainerDesignerArtefactView { } cloneChildren(clone) { + console.info('Cloning VCN Children:', this.children) for (let child of this.children) { + child.clone().compartment_id = clone.compartment_id; child.clone().vcn_id = clone.id; } } diff --git a/okitweb/static/okit/view/designer/js/okit_designer_view.js b/okitweb/static/okit/view/designer/js/okit_designer_view.js index 3904a2811..157844ffc 100644 --- a/okitweb/static/okit/view/designer/js/okit_designer_view.js +++ b/okitweb/static/okit/view/designer/js/okit_designer_view.js @@ -21,6 +21,20 @@ class OkitDesignerJsonView extends OkitJsonView { get display_grid() {return okitSettings.is_display_grid;} + drawContainer(container) { + // const resources = Object.values(this).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []); + // console.info('Resources: ', resources) + // console.info('Container Resources: ', resources.filter((r) => r instanceof OkitContainerArtefactView)) + // console.info('Simple Resources: ', resources.filter((r) => !(r instanceof OkitContainerArtefactView))) + container.draw(); + const children = Object.values(this).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []).filter((r) => r.parent_id === container.id); + console.info('Children: ', children) + console.info('Container Children: ', children.filter((r) => r instanceof OkitContainerArtefactView)) + console.info('Simple Children: ', children.filter((r) => !(r instanceof OkitContainerArtefactView))) + children.filter((r) => r instanceof OkitContainerArtefactView).forEach((e) => this.drawContainer(e)) + children.filter((r) => !(r instanceof OkitContainerArtefactView)).forEach((e) => e.draw()) + } + draw(for_export=false) { console.info('Drawing Designer Canvas'); // Display Json @@ -35,8 +49,48 @@ class OkitDesignerJsonView extends OkitJsonView { } let canvas_svg = this.newCanvas(width, height, for_export); + // Get Canvas Root Containers + Object.values(this).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []).filter((r) => r instanceof OkitContainerArtefactView && (r.parent_id === null || r.parent_id === '' || r.parent_id === 'canvas')).forEach((e) => this.drawContainer(e)) + + // Resize Main Canvas if required + $(jqId("canvas-svg")).children("svg [data-type='" + Compartment.getArtifactReference() + "']").each(function () { + canvas_svg.attr('width', Math.max(Number(canvas_svg.attr('width')), Number(this.getAttribute('width')))); + canvas_svg.attr('height', Math.max(Number(canvas_svg.attr('height')), Number(this.getAttribute('height')))); + canvas_svg.attr('viewBox', '0 0 ' + canvas_svg.attr('width') + ' ' + canvas_svg.attr('height')); + }); + if (selectedArtefact) { + $(jqId(selectedArtefact)).toggleClass('highlight'); + } + + // Draw Connection + this.drawConnections(); + } + + drawConnections() { + Object.values(this).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []).filter((r) => !(r instanceof OkitContainerArtefactView)).forEach((e) => e.drawConnections()) + } + + // TODO: Delete + drawOrigDeprecated(for_export=false) { + console.info('Drawing Designer Canvas'); + // Display Json + this.displayOkitJson(); + // New canvas + let width = 0; + let height = 0; + for (let compartment of this.compartments) { + let dimensions = compartment.dimensions; + width = Math.max(width, dimensions.width); + height = Math.max(height, dimensions.height); + } + let canvas_svg = this.newCanvas(width, height, for_export); + // Draw top Level Canvas // this.canvas.draw(); + const resource_lists = Object.values(this).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []) + console.info('Resources: ', resource_lists) + console.info('Container Resources: ', resource_lists.filter((r) => r instanceof OkitContainerArtefactView)) + console.info('Simple Resources: ', resource_lists.filter((r) => !(r instanceof OkitContainerArtefactView))) // Draw Compartments for (let compartment of this.compartments) { @@ -202,7 +256,8 @@ class OkitDesignerJsonView extends OkitJsonView { this.drawConnections(); } - drawConnections() { + // TODO: Delete + drawConnectionsOrigDeprecated() { // IPSec Connections for (let ipsec_connection of this.ipsec_connections) { ipsec_connection.drawConnections(); diff --git a/okitweb/static/okit/view/js/okit_view.js b/okitweb/static/okit/view/js/okit_view.js index 110964021..c0c29dff4 100644 --- a/okitweb/static/okit/view/js/okit_view.js +++ b/okitweb/static/okit/view/js/okit_view.js @@ -2461,6 +2461,8 @@ class OkitContainerArtefactView extends OkitArtefactView { this._dimensions = {width: 0, height: 0}; } + get children() {return Object.values(this.getJsonView()).filter((val) => Array.isArray(val)).reduce((a, v) => [...a, ...v], []).filter((r) => r.parent_id === this.id)} + // -- SVG Definitions // --- Dimensions get minimum_dimensions() {return {width: 300, height: 150};} From 9fefd56f768fd157059095893ead47cf00735494 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 14:51:42 +0100 Subject: [PATCH 16/19] Update Development Documentation --- documentation/Development.md | 110 ++++------------------------------- visualiser/query/ociQuery.py | 10 ++-- 2 files changed, 17 insertions(+), 103 deletions(-) diff --git a/documentation/Development.md b/documentation/Development.md index f09dc60fe..c260a1e4a 100644 --- a/documentation/Development.md +++ b/documentation/Development.md @@ -1,4 +1,4 @@ -# OCI Designer Toolkit Artefact (Resource) Development +# OCI Designer Toolkit Resource (Artefact) Development The following guide will take you through a step by step process for developing a new Palette Resource / Artefact for use within OKIT. To implement the new Resource / Artefact a number of new Artefact specific files will need to created whilst integration will require modification of core Javascript files. @@ -6,7 +6,7 @@ integration will require modification of core Javascript files. ## Table of Contents 1. [Naming Convention](#naming-convention) -2. [Artefact (Resource) Files](#artefact-resource-files) +2. [Resource (Artefact) Files](#artefact-resource-files) 3. [New Files](#new-files) 1. [Frontend Files](#frontend-files) 2. [Backend Files](#backend-files) @@ -24,12 +24,12 @@ All files must be named as per artifact name with the spaces replaced by undersc to this is the palette SVG where title case should be used instead of lower case. The reason for this is that the palette file name will be manipulated (removing the underscore) and used to dynamically reference all Javascript function names. -## Artefact (Resource) Files +## Resource (Artefact) Files To add an Artefact to OKIT you will need to create number of files that provide the core functionality associated with the Artefact. In addition to fully integrated the new Artefact into the BUI a number of the core JavaScript / Python scripts will need to be updated. The remainder of this document will describe the functionality / files that must be implemented. -For the worked example we will create the ***Block Storage Volume*** Artefact (Resource) and thus describe how the files +For the worked example we will create the ***Block Storage Volume*** Resource (Artefact) and thus describe how the files are generated and then subsequently modified. ## New Files @@ -781,108 +781,22 @@ this can be found in the various, existing, ansible templates. ``` ## Updated Files -Once the core files for the new Artefact (Resource) have been created the developer will need to integrate these into the +Once the core files for the new Resource (Artefact) have been created the developer will need to integrate these into the existing functionality by editing a number of common script files. The required edits will be described in the following sections. ### Frontend Files -- [Designer View JavaScript](#designer-view-javascript) -- [OKIT OCI Flask Python](#okit-oci-flask-python) -- [OCI Query JavaScript](#oci-query-javascript) ### Backend Files -- [Connection Python](#connection-python) +- [OCI Query Python](#oci-query-python) - [Generator Python](#generator-python) -### Designer View JavaScript -The ** okitweb/static/okit/view/designer/js/okit_view.js** will need to be modified to include the new Artefact (Resource) in the -draw() function. This code must be placed within the function at an appropriate position after its parent and before its children. -For our example we would add the following block after the Compartments have been created. -```javascript - // Block Storage Volumes - for (let block_storage_volume of this.block_storage_volumes) { - block_storage_volume.draw(); - } -``` -### OKIT OCI Flask Python -The Flask endpoint Python file **okitweb/okitOci.py** will need to be modified to allow for the querying of the new Artefact (Resource). -This will require that a new condition be implemented within the **ociArtifacts(artifact)** endpoint function that calls the -list method defined within the [Artefact Python Facade](#artefact-python-facade). For our worked example this will be as follows. -```python - elif artifact == 'BlockStorageVolume': - logger.info('---- Processing Block Storage Volumes') - oci_block_storage_volumes = OCIBlockStorageVolumes(config=config, profile=config_profile, compartment_id=query_json['compartment_id']) - response_json = oci_block_storage_volumes.list(filter=query_json.get('block_storage_volume_filter', None)) -``` -### OCI Query JavaScript -To facilitate querying of the new Artefact (Resource) we will need to modify the **okitweb/static/okit/query/oci/js/okit_query.js** file -to include a new query method and update the parents SubComponent query code. For our worked exmple this will mean modifying the -queryCompartmentSubComponents(request). -#### New Query Method -```javascript - queryBlockStorageVolumes(request) { - console.info('------------- Block Storage Volume Query --------------------'); - console.info('------------- Compartment : ' + request.compartment_id); - let me = this; - this.region_query_count[request.region]++; - $.ajax({ - type: 'get', - url: 'oci/artefacts/BlockStorageVolume', - dataType: 'text', - contentType: 'application/json', - data: JSON.stringify(request), - success: function(resp) { - let response_json = JSON.parse(resp); - regionOkitJson[request.region].load({block_storage_volumes: response_json}); - if (request.refresh) {okitJsonView.draw();} - }, - error: function(xhr, status, error) { - console.warn('Status : ' + status); - console.warn('Error : ' + error); - }, - complete: function () { - me.region_query_count[request.region]-- && me.isComplete(); - } - }); - } -``` -#### Update Parent SubComponents Method -```javascript - queryCompartmentSubComponents(request) { - if (request.sub_compartments) { - this.queryCompartments(request); - } - this.queryVirtualCloudNetworks(request); - this.queryBlockStorageVolumes(request); - this.queryCustomerPremiseEquipments(request); - this.queryDynamicRoutingGateways(request); - this.queryAutonomousDatabases(request); - this.queryObjectStorageBuckets(request); - this.queryFastConnects(request); - this.queryInstances(request); - this.queryInstancePools(request); - this.queryIPSecConnections(request); - this.queryRemotePeeringConnections(request); - this.queryDatabaseSystems(request); - this.queryMySQLDatabaseSystems(request); - this.queryFileStorageSystems(request); - this.queryOkeClusters(request); - } -``` -### Connection Python -The visualiser/facades/ociConnection python file will need to be modified to include the new Connection class used within -[Artefact Python Facade](#artefact-python-facade). This will need to define a connect method that uses the appropriate API -client class. -```python -class OCIBlockStorageVolumeConnection(OCIConnection): - def __init__(self, config=None, configfile=None, profile=None): - super(OCIBlockStorageVolumeConnection, self).__init__(config=config, configfile=configfile, profile=profile) - - def connect(self): - self.client = oci.core.BlockstorageClient(config=self.config, signer=self.signer) - return +### OCI Query Python +To facilitate querying of the new Resource (Artefact) we will need to modify the **visualiser/query/ociQuery.py** file +to include the new Resource in the **SUPPORTED_RESOURCES** list and the **DISCOVERY_OKIT_MAP** object. The correct name +to be entered into the **SUPPORTED_RESOURCES** can be identified by looking at the **visualiser/discovery/oci_discovery_client.py** +whilst the entry in the **DISCOVERY_OKIT_MAP** will be used to map the name to the OKIT model list. -``` ### Generator Python -The visualiser/generators/ociGenerator python code will need to be edited to include a Render method for the new Artefact (Resource) +The **visualiser/generators/ociGenerator.py** python code will need to be edited to include a Render method for the new Resource (Artefact) and the existing **generate()** method will need to be modified to call the new Render method. Although the sequence in which resource creation occurs does not matter for terraform it does for other language such as ansible, python or bash. diff --git a/visualiser/query/ociQuery.py b/visualiser/query/ociQuery.py index dcd64f3aa..f01fced78 100644 --- a/visualiser/query/ociQuery.py +++ b/visualiser/query/ociQuery.py @@ -81,7 +81,7 @@ class OCIQuery(OCIConnection): "VnicAttachment", "Vnic" ] - DISCOVER_OKIT_MAP = { + DISCOVERY_OKIT_MAP = { "AutonomousDatabase": "autonomous_databases", #"BootVolume": "block_storage_volumes", "Bucket": "object_storage_buckets", @@ -104,7 +104,7 @@ class OCIQuery(OCIConnection): "MySqlDbSystem": "mysql_database_systems", "NatGateway": "nat_gateways", "NetworkSecurityGroup": "network_security_groups", - "Policy": "policys", + "Policy": "policys", # Yes we know it's spelt incorrectly but the okitCodeSkeletonGenerator.py is simple "RemotePeeringConnection": "remote_peering_connections", "RouteTable": "route_tables", "SecurityList": "security_lists", @@ -176,7 +176,7 @@ def convert(self, discovery_data, compartments): for compartment in response_json["compartments"]: if compartment["compartment_id"] not in compartment_ids: compartment["compartment_id"] = None - map_keys = self.DISCOVER_OKIT_MAP.keys() + map_keys = self.DISCOVERY_OKIT_MAP.keys() for region, resources in discovery_data.items(): logger.info("Processing Region : {0!s:s} {1!s:s}".format(region, resources.keys())) for resource_type, resource_list in resources.items(): @@ -204,8 +204,8 @@ def convert(self, discovery_data, compartments): elif resource_type == "ServiceGateway": resource_list = self.service_gateways(resource_list, resources) # Check Life Cycle State - response_json[self.DISCOVER_OKIT_MAP[resource_type]] = [r for r in resource_list if "lifecycle_state" not in r or r["lifecycle_state"] in self.VALID_LIFECYCLE_STATES] - #response_json[self.DISCOVER_OKIT_MAP[resource_type]] = resource_list + response_json[self.DISCOVERY_OKIT_MAP[resource_type]] = [r for r in resource_list if "lifecycle_state" not in r or r["lifecycle_state"] in self.VALID_LIFECYCLE_STATES] + #response_json[self.DISCOVERY_OKIT_MAP[resource_type]] = resource_list return response_json def dynamic_routing_gateways(self, drgs, resources): From 0bdf704dde77104574f567eaedf866b55288a229 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 14:57:17 +0100 Subject: [PATCH 17/19] Update Version --- Dockerfile | 2 +- README.md | 2 +- containers/docker/Dockerfile | 2 +- okitweb/static/okit/js/okit_console.js | 4 ++-- okitweb/static/okit/json/release.json | 4 ++-- visualiser/facades/ociConnection.py | 2 +- visualiser/generators/okitGenerator.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index d4a90573f..3e732593a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ FROM oraclelinux:7-slim LABEL "provider"="Oracle" \ "issues"="https://github.com/oracle/oci-designer-toolkit/issues" \ - "version"="0.25.1" \ + "version"="0.26.0" \ "description"="OKIT Web Server Container." \ "copyright"="Copyright (c) 2020, 2021, Oracle and/or its affiliates." SHELL ["/bin/bash", "-c"] diff --git a/README.md b/README.md index c0154b7c7..9a335a4a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Oracle Cloud Infrastructure Designer and Visualisation Toolkit [0.25.1](CHANGELOG.md#version-0.25.1) +# Oracle Cloud Infrastructure Designer and Visualisation Toolkit [0.26.0](CHANGELOG.md#version-0.26.0) ```diff + The 0.25.0 release has now moved the templates from the menu to a new side panel and the can be opened by double clicking diff --git a/containers/docker/Dockerfile b/containers/docker/Dockerfile index 5efa59f23..77669bb6b 100644 --- a/containers/docker/Dockerfile +++ b/containers/docker/Dockerfile @@ -5,7 +5,7 @@ FROM oraclelinux:7-slim LABEL "provider"="Oracle" \ "issues"="https://github.com/oracle/oci-designer-toolkit/issues" \ - "version"="0.25.1" \ + "version"="0.26.0" \ "description"="OKIT Web Server Container." \ "copyright"="Copyright (c) 2020, 2021, Oracle and/or its affiliates." SHELL ["/bin/bash", "-c"] diff --git a/okitweb/static/okit/js/okit_console.js b/okitweb/static/okit/js/okit_console.js index 609a0d321..29f6bb493 100644 --- a/okitweb/static/okit/js/okit_console.js +++ b/okitweb/static/okit/js/okit_console.js @@ -4,8 +4,8 @@ */ console.info('Loaded Console Javascript'); -const okitVersion = '0.25.1'; -const okitReleaseDate = '20th August 2021'; +const okitVersion = '0.26.0'; +const okitReleaseDate = '8th September 2021'; // Validation const validate_error_colour = "#ff4d4d"; const validate_warning_colour = "#ffd633"; diff --git a/okitweb/static/okit/json/release.json b/okitweb/static/okit/json/release.json index 86a7b76f8..b3f759957 100644 --- a/okitweb/static/okit/json/release.json +++ b/okitweb/static/okit/json/release.json @@ -1,4 +1,4 @@ { - "release": "0.25.1", - "tag": "v0.25.1" + "release": "0.26.0", + "tag": "v0.26.0" } \ No newline at end of file diff --git a/visualiser/facades/ociConnection.py b/visualiser/facades/ociConnection.py index 2bfd8e41a..3a196cdb0 100644 --- a/visualiser/facades/ociConnection.py +++ b/visualiser/facades/ociConnection.py @@ -25,7 +25,7 @@ class OCIConnection(object): PAGINATION_LIMIT = 1000 - OKIT_VERSION = 'v0.25.0' + OKIT_VERSION = 'v0.26.0' def __init__(self, config=None, configfile=None, profile=None, region=None): self.tenancy_ocid = '' diff --git a/visualiser/generators/okitGenerator.py b/visualiser/generators/okitGenerator.py index a1aef4c5f..54f43dd30 100644 --- a/visualiser/generators/okitGenerator.py +++ b/visualiser/generators/okitGenerator.py @@ -57,7 +57,7 @@ def initialiseJinja2Variables(self): # -- Add Standard Author / Copyright variables self.jinja2_variables["author"] = __author__ self.jinja2_variables["copyright"] = __copyright__ - self.jinja2_variables["okit_version"] = "0.25.1" + self.jinja2_variables["okit_version"] = "0.26.0" def get(self, artifact_type, id): artifact = {}; From f3431f32b052b138ca4872e2b9129c1a9bf2aae9 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 15:08:27 +0100 Subject: [PATCH 18/19] Fix GitHub Issue #447 : Unable to create Object Storage Bucket with OKIT --- visualiser/templates/terraform/object_storage_bucket.jinja2 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/visualiser/templates/terraform/object_storage_bucket.jinja2 b/visualiser/templates/terraform/object_storage_bucket.jinja2 index 955f0e39e..14092ad70 100644 --- a/visualiser/templates/terraform/object_storage_bucket.jinja2 +++ b/visualiser/templates/terraform/object_storage_bucket.jinja2 @@ -3,10 +3,6 @@ data "oci_objectstorage_namespace" "{{ resource_name }}Namespace" { #Optional compartment_id = {{ compartment_id }} - filter { - name = "id" - values = [{{ ocid | safe }}] - } } {% if read_only %} From 722e01b3b95939c1d98d48f69f31a89f603a1f19 Mon Sep 17 00:00:00 2001 From: Andrew Hopkinson Date: Tue, 7 Sep 2021 15:09:24 +0100 Subject: [PATCH 19/19] Fix #447 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 363c24ed0..1f089ac4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Bug Fixes 1. GitHub Issue #440 : Cannot generate terraform when NSG have Rules. 2. Fix issue where DB System were always created in the root deployment compartment not specified sub-compartment. +3. GitHub Issue #447 : Unable to create Object Storage Bucket with OKIT ## Version 0.25.1