diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ca8d346e..9c98a3b2a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,27 @@
# Release Notes
+## Version 0.12.0
+**Release Date**: 7th October 2020
+### Features
+1. Enhanced feedback for multi region query.
+2. Cache Regions
+3. Cache Compartments for specific Profile.
+4. Add functionality for Customer Premise Equipment.
+5. IPSec Connections added.
+6. Remote peering functionality added but current the user will still need to add the peering id.
+7. Dynamic Routing Gateway simplified and connections created from the new IPSec Connection & Remote Peering Connection.
+8. Database System/Autonomous name displayed on the canvas (ENH REQ: Issue: #120).
+9. Experimental Import from Terraform JSON Format file.
+10. Export to Resource Manage local GitHub directory.
+
+### Bug Fixes
+1. Fix Service Gateway only offers all services when drawn but then provisions Object Storage #107
+2. Fix Service Gateway related route rules do not allow setting a Destination Service #109
+3. Add clean functionality to the json object to remove null / undefined to resolve null element issue in Autonomous Databases.
+4. Update Virtual Cloud Network and Subnet CIDR generation to check existing CIDRs. This resolves the duplicate CIDR issue.
+
+
## Version 0.11.0
**Release Date**: 16th September 2020
### Features
diff --git a/README.md b/README.md
index 1297b1d5b..6374437f2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# OCI Designer Toolkit [0.11.0](CHANGELOG.md#version-0.11.0)
+# OCI Designer Toolkit [0.12.0](CHANGELOG.md#version-0.12.0)
OCI designer toolKIT (OKIT) is a browser based tool that allows the user to [design](https://www.ateam-oracle.com/introduction-to-okit-the-oci-designer-toolkit),
[deploy](https://www.ateam-oracle.com/introduction-to-okit-the-oci-designer-toolkit) and visualise ([introspect/query](https://www.ateam-oracle.com/the-oci-designer-toolkit-query-feature))
diff --git a/containers/docker/Dockerfile b/containers/docker/Dockerfile
index 2f79985f4..d0f922a69 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.11.0" \
+ "version"="0.12.0" \
"description"="OKIT Web Server Container." \
"copyright"="Copyright (c) 2020, Oracle and/or its affiliates."
SHELL ["/bin/bash", "-c"]
diff --git a/documentation/Installation.md b/documentation/Installation.md
index bf4e7fb9c..746201f91 100644
--- a/documentation/Installation.md
+++ b/documentation/Installation.md
@@ -22,7 +22,7 @@ python modules are installed and in addition provide a simple flask server that
## Clone Repository
Before the building either the Docker or Vagrant Images the project will need to be cloned, or downloaded, from the GitHub
Repository (or downloaded). The master branch is always the latest Stable Release but previous releases can be found using
-associated Release tag is in the format vX.Y.Z hence for the version 0.11.0 the Release tag will be **v0.11.0**.
+associated Release tag is in the format vX.Y.Z hence for the version 0.12.0 the Release tag will be **v0.12.0**.
The command shows how this can be cloned to the local machine.
diff --git a/documentation/Usage.md b/documentation/Usage.md
index a0140fe1b..dbc511da2 100644
--- a/documentation/Usage.md
+++ b/documentation/Usage.md
@@ -109,7 +109,7 @@ The hamburger menu in the top left will display a slide out menu with all availa
- Service Gateway
- Local Peering Gateway
- Networking
- - Fast Connect
+ - Fast Connect
- Load Balancer
- Network Security Group
- Route Table
diff --git a/okitweb/okitImport.py b/okitweb/okitImport.py
index 83ab1d3ce..b2ac3daf3 100644
--- a/okitweb/okitImport.py
+++ b/okitweb/okitImport.py
@@ -35,8 +35,8 @@ def parseHclJson():
query_json = json.loads(parsed_query_string)
logJson(query_json)
# Import HCL
- parser = OkitHclJsonParser(query_json)
- response_json = parser.parse()
+ parser = OkitHclJsonParser()
+ response_json = parser.parse(query_json)
logJson(response_json)
return json.dumps(response_json, sort_keys=False, indent=2, separators=(',', ': '))
else:
diff --git a/okitweb/okitOci.py b/okitweb/okitOci.py
index 398f8c9a7..4c06066bd 100644
--- a/okitweb/okitOci.py
+++ b/okitweb/okitOci.py
@@ -30,26 +30,32 @@
from facades.ociBlockStorageVolumes import OCIBlockStorageVolumes
from facades.ociCompartment import OCICompartments
from facades.ociContainer import OCIContainers
+from facades.ociCpeDeviceShapes import OCICpeDeviceShapes
+from facades.ociCustomerPremiseEquipment import OCICustomerPremiseEquipments
from facades.ociDatabaseSystem import OCIDatabaseSystems
from facades.ociDatabaseSystemShape import OCIDatabaseSystemShapes
from facades.ociDatabaseVersion import OCIDatabaseVersions
from facades.ociDynamicRoutingGateway import OCIDynamicRoutingGateways
from facades.ociFastConnect import OCIFastConnects
+from facades.ociFastConnectProviderServices import OCIFastConnectProviderServices
from facades.ociFileStorageSystems import OCIFileStorageSystems
from facades.ociImage import OCIImages
from facades.ociInstance import OCIInstances
from facades.ociInstancePool import OCIInstancePools
from facades.ociInternetGateway import OCIInternetGateways
+from facades.ociIPSecConnection import OCIIPSecConnections
from facades.ociLoadBalancer import OCILoadBalancers
from facades.ociLocalPeeringGateway import OCILocalPeeringGateways
from facades.ociNATGateway import OCINATGateways
from facades.ociNetworkSecurityGroup import OCINetworkSecurityGroups
from facades.ociObjectStorageBuckets import OCIObjectStorageBuckets
from facades.ociRegion import OCIRegions
+from facades.ociRemotePeeringConnection import OCIRemotePeeringConnections
from facades.ociResourceManager import OCIResourceManagers
from facades.ociRouteTable import OCIRouteTables
from facades.ociSecurityList import OCISecurityLists
from facades.ociServiceGateway import OCIServiceGateways
+from facades.ociServices import OCIServices
from facades.ociShape import OCIShapes
from facades.ociSubnet import OCISubnets
from facades.ociTenancy import OCITenancies
@@ -210,6 +216,10 @@ def ociArtifacts(artifact):
logger.info('---- Processing Compartments')
oci_compartments = OCICompartments(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
response_json = oci_compartments.list(filter=query_json.get('compartment_filter', None))
+ elif artifact == 'CustomerPremiseEquipment':
+ logger.info('---- Processing Customer Premise Equipment')
+ oci_cpes = OCICustomerPremiseEquipments(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
+ response_json = oci_cpes.list(filter=query_json.get('cpe_filter', None))
elif artifact == 'DatabaseSystem':
logger.info('---- Processing Database Systems')
oci_database_systems = OCIDatabaseSystems(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
@@ -238,6 +248,10 @@ def ociArtifacts(artifact):
logger.info('---- Processing Internet Gateways')
oci_internet_gateways = OCIInternetGateways(config=config, profile=config_profile, compartment_id=query_json['compartment_id'], vcn_id=query_json['vcn_id'])
response_json = oci_internet_gateways.list(filter=query_json.get('internet_gateway_filter', None))
+ elif artifact == 'IPSecConnection':
+ logger.info('---- Processing IPSec Connections')
+ oci_ipsec_connections = OCIIPSecConnections(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
+ response_json = oci_ipsec_connections.list(filter=query_json.get('ipsec_connection_filter', None))
elif artifact == 'LoadBalancer':
logger.info('---- Processing Load Balancers')
oci_load_balancers = OCILoadBalancers(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
@@ -263,6 +277,10 @@ def ociArtifacts(artifact):
logger.info('---- Processing OKE Clusters')
oke_clusters = OCIContainers(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
response_json = oke_clusters.list(filter=query_json.get('oke_cluster_filter', None))
+ elif artifact == 'RemotePeeringConnection':
+ logger.info('---- Processing Remote Peering Connections')
+ oci_remote_peering_connections = OCIRemotePeeringConnections(config=config, profile=config_profile, compartment_id=query_json['compartment_id'])
+ response_json = oci_remote_peering_connections.list(filter=query_json.get('remote_peering_connection_filter', None))
elif artifact == 'RouteTable':
logger.info('---- Processing Route Tables')
oci_route_tables = OCIRouteTables(config=config, profile=config_profile, compartment_id=query_json['compartment_id'], vcn_id=query_json['vcn_id'])
@@ -295,14 +313,31 @@ def ociArtifacts(artifact):
def dropdownQuery():
if request.method == 'GET':
dropdown_json = {}
+ # Regions
+ oci_regions = OCIRegions()
+ dropdown_json["regions"] = sorted(oci_regions.list(), key=lambda k: k['name'])
+ # Services
+ oci_services = OCIServices()
+ dropdown_json["services"] = sorted(oci_services.list(), key=lambda k: k['name'])
+ # Instance Shapes
oci_shapes = OCIShapes()
dropdown_json["shapes"] = sorted(oci_shapes.list(), key=lambda k: k['sort_key'])
+ # Instance Images
+ oci_images = OCIImages()
+ dropdown_json["images"] = sorted(oci_images.list(), key=lambda k: k['sort_key'])
+ # Database System Shapes
db_system_shapes = OCIDatabaseSystemShapes()
dropdown_json["db_system_shapes"] = sorted(db_system_shapes.list(), key=lambda k: k['shape'])
+ # Database Versions
db_versions = OCIDatabaseVersions()
dropdown_json["db_versions"] = sorted(db_versions.list(), key=lambda k: k['version'])
- oci_images = OCIImages()
- dropdown_json["images"] = sorted(oci_images.list(), key=lambda k: k['sort_key'])
+ # CPE Device Shapes
+ # TODO: Upgrade OCI Python Module
+ #cpe_device_shapes = OCICpeDeviceShapes()
+ #dropdown_json["cpe_device_shapes"] = sorted(cpe_device_shapes.list(), key=lambda k: k['cpe_device_info']['vendor'])
+ # Fast Connect Provider Services
+ fast_connect_provider_services = OCIFastConnectProviderServices()
+ dropdown_json["fast_connect_provider_services"] = sorted(fast_connect_provider_services.list(), key=lambda k: k['provider_name'])
return dropdown_json
else:
return 'Unknown Method', 500
diff --git a/okitweb/okitWebDesigner.py b/okitweb/okitWebDesigner.py
index 1a95d2867..8ade902d7 100644
--- a/okitweb/okitWebDesigner.py
+++ b/okitweb/okitWebDesigner.py
@@ -33,6 +33,7 @@
from generators.okitAnsibleGenerator import OCIAnsibleGenerator
from generators.okitTerraform11Generator import OCITerraform11Generator
from generators.okitTerraformGenerator import OCITerraformGenerator
+from generators.okitResourceManagerGenerator import OCIResourceManagerGenerator
# Configure logging
logger = getLogger()
@@ -224,6 +225,8 @@ def generate(language):
generator = OCIAnsibleGenerator(template_root, destination_dir, request.json, use_vars=use_vars)
elif language == 'terraform11':
generator = OCITerraform11Generator(template_root, destination_dir, request.json)
+ elif language == 'resource-manager':
+ generator = OCIResourceManagerGenerator(template_root, destination_dir, request.json)
generator.generate()
generator.writeFiles()
zipname = generator.createZipArchive(os.path.join(destination_dir, language), "/tmp/okit-{0:s}".format(str(language)))
diff --git a/okitweb/static/okit/css/okit_console.css b/okitweb/static/okit/css/okit_console.css
index 8c99a8304..38f1052d6 100644
--- a/okitweb/static/okit/css/okit_console.css
+++ b/okitweb/static/okit/css/okit_console.css
@@ -835,7 +835,7 @@ li a.parent-item:hover {
height: 80px;
width: 140px;
margin: 50px auto;
- position: relative
+ position: relative;
}
#misshapen-doughnut:before {
@@ -861,6 +861,13 @@ li a.parent-item:hover {
width: 110px
}
+#region_progress {
+ height: 80px;
+ width: 140px;
+ margin: 50px auto;
+ position: relative
+}
+
/*
** Validation
*/
diff --git a/okitweb/static/okit/css/okit_designer.css b/okitweb/static/okit/css/okit_designer.css
index 4f6523c57..c4a6ce47b 100644
--- a/okitweb/static/okit/css/okit_designer.css
+++ b/okitweb/static/okit/css/okit_designer.css
@@ -175,6 +175,29 @@
color: black;
}
+.okit-tab-progress {
+ animation: animate-icing 2.2s linear infinite;
+ background: linear-gradient(#eee, #eee) no-repeat;
+ position: relative;
+}
+
+.okit-tab-progress:before {
+ background: linear-gradient(90deg, #a3f022, #3e9fff);
+ content: "";
+ position: absolute;
+ height: 1.1em;
+ width: 87%;
+ z-index: -1
+}
+
+.okit-tab-progress:after {
+ background-color: #fff;
+ content: "";
+ position: relative;
+ height: 1.1em;
+ width: 87%;
+}
+
.okit-svg-canvas {
display: block;
padding: 0;
@@ -186,7 +209,8 @@
.okit-canvas-details {
display: block;
- padding-bottom: 5px;
+ padding-top: 3px;
+ padding-bottom: 3px;
width: 100%;
overflow: hidden;
}
@@ -321,4 +345,8 @@ rect.highlight {
rect.highlight-vnic {
fill: #00cc00;
-}
\ No newline at end of file
+}
+
+rect.highlight-association {
+ fill: #336600;
+}
diff --git a/okitweb/static/okit/js/okit.js b/okitweb/static/okit/js/okit.js
index 75adddbc8..5771ed472 100644
--- a/okitweb/static/okit/js/okit.js
+++ b/okitweb/static/okit/js/okit.js
@@ -11,6 +11,22 @@ if (typeof JSON.clone !== "function") {
return JSON.parse(JSON.stringify(obj));
};
}
+/*
+** Add Clean function to JSON to remove null & undefined elements
+ */
+if (typeof JSON.clean !== "function") {
+ JSON.clean = obj => {
+ if (Array.isArray(obj)) {
+ return obj
+ .map(v => (v && v instanceof Object) ? JSON.clean(v) : v)
+ .filter(v => !(v == null));
+ } else {
+ return Object.entries(obj)
+ .map(([k, v]) => [k, v && v instanceof Object ? JSON.clean(v) : v])
+ .reduce((a, [k, v]) => (v == null ? a : (a[k]=v, a)), {});
+ }
+ }
+}
let selectedArtefact = null;
@@ -44,6 +60,7 @@ class OkitOCIConfig {
class OkitOCIData {
constructor() {
+ this.compartments = [];
this.load();
}
@@ -58,7 +75,7 @@ class OkitOCIData {
url: 'dropdown/data',
dataType: 'text',
contentType: 'application/json',
- data: JSON.stringify(this),
+ data: JSON.stringify(this.cloneForSave()),
success: function(resp) {
console.info('OKIT Dropdown Data Saved');
},
@@ -69,6 +86,14 @@ class OkitOCIData {
});
}
+ cloneForSave() {
+ let clone = JSON.clone(this);
+ if (developer_mode) {
+ clone.compartments = [];
+ }
+ return clone;
+ }
+
query() {
let me = this;
$.getJSON('oci/dropdown', function(resp) {$.extend(true, me, resp); me.save(); console.info(me);});
@@ -78,6 +103,10 @@ class OkitOCIData {
** Get functions to retrieve drop-down data.
*/
+ getCpeDeviceShapes() {
+ return this.cpe_device_shapes;
+ }
+
getDBSystemShapes(family='') {
if (family === '') {
return this.db_system_shapes;
@@ -141,6 +170,18 @@ class OkitOCIData {
}
return [...new Set(images)].sort((a, b) => b - a);
}
+
+ getRegions() {
+ return this.regions;
+ }
+
+ getCompartments() {
+ return this.compartments;
+ }
+
+ setCompartments(compartments) {
+ this.compartments = compartments;
+ }
}
class OkitSettings {
@@ -157,6 +198,7 @@ class OkitSettings {
this.last_used_region = '';
this.last_used_compartment = '';
this.hide_attached = true;
+ this.highlight_association = true;
this.load();
}
@@ -350,6 +392,24 @@ class OkitSettings {
td.append('label')
.attr('for', 'hide_attached')
.text('Hide Attached Artefacts');
+ // Highlight Associations
+ tr = tbody.append('div').attr('class', 'tr');
+ tr.append('div').attr('class', 'td').text('');
+ td = tr.append('div').attr('class', 'td');
+ td.append('input')
+ .attr('id', 'highlight_association')
+ .attr('name', 'highlight_association')
+ .attr('type', 'checkbox')
+ .property('checked', this.highlight_association)
+ .on('change', function () {
+ if (autosave) {
+ me.highlight_association = $('#highlight_association').is(':checked');
+ me.save();
+ }
+ });
+ td.append('label')
+ .attr('for', 'highlight_association')
+ .text('Highlight Associations');
/*
// Config Profile
tr = tbody.append('div').attr('class', 'tr');
diff --git a/okitweb/static/okit/js/okit_console.js b/okitweb/static/okit/js/okit_console.js
index 6d306fbf0..9b3feffa4 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.11.0';
-const okitReleaseDate = '16th September 2020';
+const okitVersion = '0.12.0';
+const okitReleaseDate = '7th October 2020';
// Validation
const validate_error_colour = "#ff4d4d";
const validate_warning_colour = "#ffd633";
diff --git a/okitweb/static/okit/js/okit_designer.js b/okitweb/static/okit/js/okit_designer.js
index b61316fc9..82cef07ca 100644
--- a/okitweb/static/okit/js/okit_designer.js
+++ b/okitweb/static/okit/js/okit_designer.js
@@ -339,6 +339,10 @@ function displayQueryDialog() {
.attr('id', 'config_profile')
.on('change', () => {
console.info('Profile Select ' + $(jqId('config_profile')).val());
+ okitSettings.profile = $(jqId('config_profile')).val();
+ okitSettings.save();
+ // Clear Existing Compartments
+ okitOciData.setCompartments([]);
loadCompartments();
loadRegions();
});
@@ -419,6 +423,7 @@ function handleQueryOci(e) {
okitSettings.home_region_key = '';
okitSettings.home_region = '';
ociRegions = [];
+ // Load Previous Profile
$(jqId('config_profile')).val(okitSettings.profile);
// Load Compartment Select
loadCompartments();
@@ -429,37 +434,60 @@ function loadCompartments() {
// Clear Select
let select = $(jqId('query_compartment_id'));
$(select).empty();
- select.append($('