From 899b5dd141eff534aa071abd5aa63643a457f19d Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 2 Apr 2019 09:03:49 +0000
Subject: [PATCH 01/13] Added instructions for setting up the devel environment
---
README.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/README.md b/README.md
index 30a16aede..4babbcac6 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,19 @@ cd orchestrator-dashboard
docker build -f docker/Dockerfile -t orchestrator-dashboard .
```
+## How to setup a development environment
+```
+git clone https://github.com/maricaantonacci/orchestrator-dashboard.git
+cd orchestrator-dashboard
+python3 -m venv venv
+source venv/source/activate
+pip install -r requirements.txt
+```
+
+Start the dashboard app:
+```
+FLASK_app=orchdashboard flask run --host=0.0.0.0 --cert cert.pem --key privkey.pem --port 443
+```
From df7c5af6d81ab8cea3b9c8675620373f1814b7d1 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 2 Apr 2019 09:04:37 +0000
Subject: [PATCH 02/13] Added bootstrap-confirmation folder
---
.../Bootstrap-Confirmation-2/.editorconfig | 8 +
.../Bootstrap-Confirmation-2/.gitignore | 4 +
.../Bootstrap-Confirmation-2/Gruntfile.js | 106 ++++
.../Bootstrap-Confirmation-2/README.md | 26 +
.../bootstrap-confirmation.js | 465 ++++++++++++++++++
.../bootstrap-confirmation.min.js | 7 +
.../Bootstrap-Confirmation-2/bower.json | 37 ++
.../example/index.html | 210 ++++++++
.../Bootstrap-Confirmation-2/package.json | 47 ++
9 files changed, 910 insertions(+)
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/.editorconfig
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/.gitignore
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/Gruntfile.js
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/README.md
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.js
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.min.js
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/bower.json
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/example/index.html
create mode 100644 app/static/bootstrap/Bootstrap-Confirmation-2/package.json
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/.editorconfig b/app/static/bootstrap/Bootstrap-Confirmation-2/.editorconfig
new file mode 100644
index 000000000..0daf12d6f
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/.editorconfig
@@ -0,0 +1,8 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/.gitignore b/app/static/bootstrap/Bootstrap-Confirmation-2/.gitignore
new file mode 100644
index 000000000..b733c45a3
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/.gitignore
@@ -0,0 +1,4 @@
+/.idea
+/*.iml
+/bower_components
+/node_modules
\ No newline at end of file
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/Gruntfile.js b/app/static/bootstrap/Bootstrap-Confirmation-2/Gruntfile.js
new file mode 100644
index 000000000..a45322fc1
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/Gruntfile.js
@@ -0,0 +1,106 @@
+module.exports = function(grunt) {
+ require('jit-grunt')(grunt);
+
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+
+ banner: '/*!\n' +
+ ' * Bootstrap Confirmation <%= pkg.version %>\n' +
+ ' * Copyright 2013 Nimit Suwannagate \n' +
+ ' * Copyright 2014-<%= grunt.template.today("yyyy") %> Damien "Mistic" Sorel \n' +
+ ' * Licensed under the Apache License, Version 2.0\n' +
+ ' */',
+
+ // serve folder content
+ connect: {
+ dev: {
+ options: {
+ port: 9000,
+ livereload: true
+ }
+ }
+ },
+
+ // watchers
+ watch: {
+ options: {
+ livereload: true
+ },
+ dev: {
+ files: ['bootstrap-confirmation.js', 'example/**'],
+ tasks: []
+ }
+ },
+
+ // open example
+ open: {
+ dev: {
+ path: 'http://localhost:<%= connect.dev.options.port%>/example/index.html'
+ }
+ },
+
+ // replace version number
+ replace: {
+ dist: {
+ options: {
+ patterns: [
+ {
+ match: /(Confirmation\.VERSION = ').*(';)/,
+ replacement: '$1<%= pkg.version %>$2'
+ }
+ ]
+ },
+ files: {
+ 'bootstrap-confirmation.js': [
+ 'bootstrap-confirmation.js'
+ ]
+ }
+ }
+ },
+
+ // compress js
+ uglify: {
+ options: {
+ banner: '<%= banner %>\n',
+ mangle: {
+ except: ['$']
+ }
+ },
+ dist: {
+ files: {
+ 'bootstrap-confirmation.min.js': [
+ 'bootstrap-confirmation.js'
+ ]
+ }
+ }
+ },
+
+ // jshint tests
+ jshint: {
+ lib: {
+ files: {
+ src: [
+ 'bootstrap-confirmation.js'
+ ]
+ }
+ }
+ }
+ }
+ );
+
+ grunt.registerTask('default', [
+ 'replace',
+ 'uglify'
+ ]);
+
+ grunt.registerTask('test', [
+ 'jshint'
+ ]);
+
+ grunt.registerTask('serve', [
+ 'connect',
+ 'open',
+ 'watch'
+ ]);
+
+};
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/README.md b/app/static/bootstrap/Bootstrap-Confirmation-2/README.md
new file mode 100644
index 000000000..1b9f3ca03
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/README.md
@@ -0,0 +1,26 @@
+# Bootstrap-Confirmation
+
+[![npm version](https://img.shields.io/npm/v/bootstrap-confirmation2.svg?style=flat-square)](https://www.npmjs.com/package/bootstrap-confirmation2)
+[![jsDelivr CDN](https://data.jsdelivr.com/v1/package/npm/bootstrap-confirmation2/badge)](https://www.jsdelivr.com/package/npm/bootstrap-confirmation2)
+[![Build Status](https://img.shields.io/travis/mistic100/Bootstrap-Confirmation/master.svg?style=flat-square)](https://travis-ci.org/mistic100/Bootstrap-Confirmation)
+[![Dependencies Status](https://david-dm.org/mistic100/Bootstrap-Confirmation/status.svg?style=flat-square)](https://david-dm.org/mistic100/Bootstrap-Confirmation)
+
+Bootstrap plugin for on-place confirm boxes using Popover.
+
+## Documentation
+
+[bootstrap-confirmation.js.org](http://bootstrap-confirmation.js.org)
+
+## Installation
+
+#### Bootstrap 4
+
+```
+npm install bootstrap-confirmation2
+```
+
+#### Bootstrap 3
+
+```
+npm install bootstrap-confirmation2@2.x.x
+```
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.js b/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.js
new file mode 100644
index 000000000..dae63b6eb
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.js
@@ -0,0 +1,465 @@
+/*!
+ * Bootstrap Confirmation
+ * Copyright 2013 Nimit Suwannagate
+ * Copyright 2014-2019 Damien "Mistic" Sorel
+ * Licensed under the Apache License, Version 2.0
+ */
+
+(function($) {
+ 'use strict';
+
+ var activeConfirmation;
+
+ // Confirmation extends popover.js
+ if (!$.fn.popover) {
+ throw new Error('Confirmation requires popover.js');
+ }
+
+ // CONFIRMATION PUBLIC CLASS DEFINITION
+ // ===============================
+ var Confirmation = function(element, options) {
+ this.init(element, options);
+ };
+
+ Confirmation.VERSION = '2.4.4';
+
+ /**
+ * Map between keyboard events "keyCode|which" and "key"
+ */
+ Confirmation.KEYMAP = {
+ 13: 'Enter',
+ 27: 'Escape',
+ 39: 'ArrowRight',
+ 40: 'ArrowDown'
+ };
+
+ Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
+ placement: 'top',
+ title: 'Are you sure?',
+ trigger: 'click',
+ confirmationEvent: undefined,
+ popout: false,
+ singleton: false,
+ copyAttributes: 'href target',
+ buttons: null,
+ onConfirm: $.noop,
+ onCancel: $.noop,
+ btnOkClass: 'btn-xs btn-primary',
+ btnOkIcon: 'glyphicon glyphicon-ok',
+ btnOkLabel: 'Yes',
+ btnCancelClass: 'btn-xs btn-default',
+ btnCancelIcon: 'glyphicon glyphicon-remove',
+ btnCancelLabel: 'No',
+ // @formatter:off
+ // href="#" allows the buttons to be focused
+ template: '' +
+ '
' +
+ '
' +
+ '
' +
+ '
'
+ // @formatter:on
+ });
+
+ if (Confirmation.DEFAULTS.whiteList) {
+ Confirmation.DEFAULTS.whiteList['*'].push('data-apply', 'data-dismiss');
+ }
+
+ Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
+ Confirmation.prototype.constructor = Confirmation;
+
+ /**
+ * Expose defaults
+ * @returns {object}
+ */
+ Confirmation.prototype.getDefaults = function() {
+ return Confirmation.DEFAULTS;
+ };
+
+ /**
+ * Init the component
+ * @param element {jQuery}
+ * @param options {object}
+ */
+ Confirmation.prototype.init = function(element, options) {
+ $.fn.popover.Constructor.prototype.init.call(this, 'confirmation', element, options);
+
+ if ((this.options.popout || this.options.singleton) && !options.rootSelector) {
+ throw new Error('The rootSelector option is required to use popout and singleton features since jQuery 3.');
+ }
+
+ // keep trace of selectors
+ this.options._isDelegate = false;
+ if (options.selector) { // container of buttons
+ this.options._selector = this._options._selector = options.rootSelector + ' ' + options.selector;
+ }
+ else if (options._selector) { // children of container
+ this.options._selector = options._selector;
+ this.options._isDelegate = true;
+ }
+ else { // standalone
+ this.options._selector = options.rootSelector;
+ }
+
+ if (this.options.confirmationEvent === undefined) {
+ this.options.confirmationEvent = this.options.trigger;
+ }
+
+ var self = this;
+
+ if (!this.options.selector) {
+ // store copied attributes
+ this.options._attributes = {};
+ if (this.options.copyAttributes) {
+ if (typeof this.options.copyAttributes === 'string') {
+ this.options.copyAttributes = this.options.copyAttributes.split(' ');
+ }
+ }
+ else {
+ this.options.copyAttributes = [];
+ }
+
+ this.options.copyAttributes.forEach(function(attr) {
+ this.options._attributes[attr] = this.$element.attr(attr);
+ }, this);
+
+ // cancel original event
+ this.$element.on(this.options.trigger, function(e, ack) {
+ if (!ack) {
+ e.preventDefault();
+ e.stopPropagation();
+ e.stopImmediatePropagation();
+ }
+ });
+
+ // manage singleton
+ this.$element.on('show.bs.confirmation', function(e) {
+ if (self.options.singleton) {
+ // close all other popover already initialized
+ $(self.options._selector).not($(this)).filter(function() {
+ return $(this).data('bs.confirmation') !== undefined;
+ }).confirmation('hide');
+ }
+ });
+ }
+ else {
+ // cancel original event
+ this.$element.on(this.options.trigger, this.options.selector, function(e, ack) {
+ if (!ack) {
+ e.preventDefault();
+ e.stopPropagation();
+ e.stopImmediatePropagation();
+ }
+ });
+ }
+
+ if (!this.options._isDelegate) {
+ // manage popout
+ this.eventBody = false;
+ this.uid = this.$element[0].id || this.getUID('group_');
+
+ this.$element.on('shown.bs.confirmation', function(e) {
+ if (self.options.popout && !self.eventBody) {
+ self.eventBody = $('body').on('click.bs.confirmation.' + self.uid, function(e) {
+ if ($(self.options._selector).is(e.target) || $(self.options._selector).has(e.target).length > 0) {
+ return;
+ }
+
+ // close all popover already initialized
+ $(self.options._selector).filter(function() {
+ return $(this).data('bs.confirmation') !== undefined;
+ }).confirmation('hide');
+
+ $('body').off('click.bs.' + self.uid);
+ self.eventBody = false;
+ });
+ }
+ });
+ }
+ };
+
+ /**
+ * Overrides, always show
+ * @returns {boolean}
+ */
+ Confirmation.prototype.hasContent = function() {
+ return true;
+ };
+
+ /**
+ * Sets the popover content
+ */
+ Confirmation.prototype.setContent = function() {
+ var self = this;
+ var $tip = this.tip();
+ var title = this.getTitle();
+ var content = this.getContent();
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
+
+ $tip.find('.confirmation-content').toggle(!!content).children().detach().end()[
+ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content);
+
+ $tip.on('click', function(e) {
+ e.stopPropagation();
+ });
+
+ if (this.options.buttons) {
+ // configure custom buttons
+ var $group = $tip.find('.confirmation-buttons .btn-group').empty();
+
+ this.options.buttons.forEach(function(button) {
+ $group.append(
+ $('')
+ .addClass(button.class || 'btn btn-xs btn-default')
+ .html(button.label || '')
+ .attr(button.attr || {})
+ .prepend($('').addClass(button.icon), ' ')
+ .one('click', function(e) {
+ if ($(this).attr('href') === '#') {
+ e.preventDefault();
+ }
+
+ if (button.onClick) {
+ button.onClick.call(self.$element);
+ }
+
+ if (button.cancel) {
+ self.getOnCancel().call(self.$element, button.value);
+ self.$element.trigger('canceled.bs.confirmation', [button.value]);
+ }
+ else {
+ self.getOnConfirm().call(self.$element, button.value);
+ self.$element.trigger('confirmed.bs.confirmation', [button.value]);
+ }
+
+ if (self.inState) { // Bootstrap 3.3.5
+ self.inState.click = false;
+ }
+
+ self.hide();
+ })
+ );
+ }, this);
+ }
+ else {
+ // configure 'ok' button
+ $tip.find('[data-apply="confirmation"]')
+ .addClass(this.options.btnOkClass)
+ .html(this.options.btnOkLabel)
+ .attr(this.options._attributes)
+ .prepend($('').addClass(this.options.btnOkIcon), ' ')
+ .off('click')
+ .one('click', function(e) {
+ if ($(this).attr('href') === '#') {
+ e.preventDefault();
+ }
+
+ self.getOnConfirm().call(self.$element);
+ self.$element.trigger('confirmed.bs.confirmation');
+
+ self.$element.trigger(self.options.confirmationEvent, [true]);
+
+ self.hide();
+ });
+
+ // configure 'cancel' button
+ $tip.find('[data-dismiss="confirmation"]')
+ .addClass(this.options.btnCancelClass)
+ .html(this.options.btnCancelLabel)
+ .prepend($('').addClass(this.options.btnCancelIcon), ' ')
+ .off('click')
+ .one('click', function(e) {
+ e.preventDefault();
+
+ self.getOnCancel().call(self.$element);
+ self.$element.trigger('canceled.bs.confirmation');
+
+ if (self.inState) { // Bootstrap 3.3.5
+ self.inState.click = false;
+ }
+
+ self.hide();
+ });
+ }
+
+ $tip.removeClass('fade top bottom left right in');
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) {
+ $tip.find('.popover-title').hide();
+ }
+
+ // bind key navigation
+ activeConfirmation = this;
+ $(window)
+ .off('keyup.bs.confirmation')
+ .on('keyup.bs.confirmation', this._onKeyup.bind(this));
+ };
+
+ /**
+ * Remove key binding on destroy
+ */
+ Confirmation.prototype.destroy = function() {
+ if (activeConfirmation === this) {
+ activeConfirmation = undefined;
+ $(window).off('keyup.bs.confirmation');
+ }
+ $.fn.popover.Constructor.prototype.destroy.call(this);
+ };
+
+ /**
+ * Remove key binding on hide
+ */
+ Confirmation.prototype.hide = function() {
+ if (activeConfirmation === this) {
+ activeConfirmation = undefined;
+ $(window).off('keyup.bs.confirmation');
+ }
+ $.fn.popover.Constructor.prototype.hide.call(this);
+ };
+
+ /**
+ * Navigate through buttons with keyboard
+ * @param event
+ * @private
+ */
+ Confirmation.prototype._onKeyup = function(event) {
+ if (!this.$tip) {
+ activeConfirmation = undefined;
+ $(window).off('keyup.bs.confirmation');
+ return;
+ }
+
+ var key = event.key || Confirmation.KEYMAP[event.keyCode || event.which];
+
+ var $group = this.$tip.find('.confirmation-buttons .btn-group');
+ var $active = $group.find('.active');
+ var $next;
+
+ switch (key) {
+ case 'Escape':
+ this.hide();
+ break;
+
+ case 'ArrowRight':
+ if ($active.length && $active.next().length) {
+ $next = $active.next();
+ }
+ else {
+ $next = $group.children().first();
+ }
+ $active.removeClass('active');
+ $next.addClass('active').focus();
+ break;
+
+ case 'ArrowLeft':
+ if ($active.length && $active.prev().length) {
+ $next = $active.prev();
+ }
+ else {
+ $next = $group.children().last();
+ }
+ $active.removeClass('active');
+ $next.addClass('active').focus();
+ break;
+ }
+ };
+
+ /**
+ * Gets the on-confirm callback
+ * @returns {function}
+ */
+ Confirmation.prototype.getOnConfirm = function() {
+ if (this.$element.attr('data-on-confirm')) {
+ return getFunctionFromString(this.$element.attr('data-on-confirm'));
+ }
+ else {
+ return this.options.onConfirm;
+ }
+ };
+
+ /**
+ * Gets the on-cancel callback
+ * @returns {function}
+ */
+ Confirmation.prototype.getOnCancel = function() {
+ if (this.$element.attr('data-on-cancel')) {
+ return getFunctionFromString(this.$element.attr('data-on-cancel'));
+ }
+ else {
+ return this.options.onCancel;
+ }
+ };
+
+ /**
+ * Generates an anonymous function from a function name
+ * function name may contain dots (.) to navigate through objects
+ * root context is window
+ */
+ function getFunctionFromString(functionName) {
+ var context = window;
+ var namespaces = functionName.split('.');
+ var func = namespaces.pop();
+
+ for (var i = 0, l = namespaces.length; i < l; i++) {
+ context = context[namespaces[i]];
+ }
+
+ return function() {
+ context[func].call(this);
+ };
+ }
+
+
+ // CONFIRMATION PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.confirmation;
+
+ $.fn.confirmation = function(option) {
+ var options = (typeof option == 'object' && option) || {};
+ options.rootSelector = this.selector || options.rootSelector; // this.selector removed in jQuery > 3
+
+ return this.each(function() {
+ var $this = $(this);
+ var data = $this.data('bs.confirmation');
+
+ if (!data && option == 'destroy') {
+ return;
+ }
+ if (!data) {
+ $this.data('bs.confirmation', (data = new Confirmation(this, options)));
+ }
+ if (typeof option == 'string') {
+ data[option]();
+
+ if (option == 'hide' && data.inState) { //data.inState doesn't exist in Bootstrap < 3.3.5
+ data.inState.click = false;
+ }
+ }
+ });
+ };
+
+ $.fn.confirmation.Constructor = Confirmation;
+
+
+ // CONFIRMATION NO CONFLICT
+ // ===================
+
+ $.fn.confirmation.noConflict = function() {
+ $.fn.confirmation = old;
+ return this;
+ };
+
+}(jQuery));
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.min.js b/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.min.js
new file mode 100644
index 000000000..1e6837358
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/bootstrap-confirmation.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap Confirmation 2.4.4
+ * Copyright 2013 Nimit Suwannagate
+ * Copyright 2014-2019 Damien "Mistic" Sorel
+ * Licensed under the Apache License, Version 2.0
+ */
+!function($){"use strict";function a(a){for(var b=window,c=a.split("."),d=c.pop(),e=0,f=c.length;e'}),c.DEFAULTS.whiteList&&c.DEFAULTS.whiteList["*"].push("data-apply","data-dismiss"),c.prototype=$.extend({},$.fn.popover.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.init=function(a,b){if($.fn.popover.Constructor.prototype.init.call(this,"confirmation",a,b),(this.options.popout||this.options.singleton)&&!b.rootSelector)throw new Error("The rootSelector option is required to use popout and singleton features since jQuery 3.");this.options._isDelegate=!1,b.selector?this.options._selector=this._options._selector=b.rootSelector+" "+b.selector:b._selector?(this.options._selector=b._selector,this.options._isDelegate=!0):this.options._selector=b.rootSelector,void 0===this.options.confirmationEvent&&(this.options.confirmationEvent=this.options.trigger);var c=this;this.options.selector?this.$element.on(this.options.trigger,this.options.selector,function(a,b){b||(a.preventDefault(),a.stopPropagation(),a.stopImmediatePropagation())}):(this.options._attributes={},this.options.copyAttributes?"string"==typeof this.options.copyAttributes&&(this.options.copyAttributes=this.options.copyAttributes.split(" ")):this.options.copyAttributes=[],this.options.copyAttributes.forEach(function(a){this.options._attributes[a]=this.$element.attr(a)},this),this.$element.on(this.options.trigger,function(a,b){b||(a.preventDefault(),a.stopPropagation(),a.stopImmediatePropagation())}),this.$element.on("show.bs.confirmation",function(a){c.options.singleton&&$(c.options._selector).not($(this)).filter(function(){return void 0!==$(this).data("bs.confirmation")}).confirmation("hide")})),this.options._isDelegate||(this.eventBody=!1,this.uid=this.$element[0].id||this.getUID("group_"),this.$element.on("shown.bs.confirmation",function(a){c.options.popout&&!c.eventBody&&(c.eventBody=$("body").on("click.bs.confirmation."+c.uid,function(a){$(c.options._selector).is(a.target)||$(c.options._selector).has(a.target).length>0||($(c.options._selector).filter(function(){return void 0!==$(this).data("bs.confirmation")}).confirmation("hide"),$("body").off("click.bs."+c.uid),c.eventBody=!1)}))}))},c.prototype.hasContent=function(){return!0},c.prototype.setContent=function(){var a=this,c=this.tip(),d=this.getTitle(),e=this.getContent();if(c.find(".popover-title")[this.options.html?"html":"text"](d),c.find(".confirmation-content").toggle(!!e).children().detach().end()[this.options.html?"string"==typeof e?"html":"append":"text"](e),c.on("click",function(a){a.stopPropagation()}),this.options.buttons){var f=c.find(".confirmation-buttons .btn-group").empty();this.options.buttons.forEach(function(b){f.append($('').addClass(b["class"]||"btn btn-xs btn-default").html(b.label||"").attr(b.attr||{}).prepend($("").addClass(b.icon)," ").one("click",function(c){"#"===$(this).attr("href")&&c.preventDefault(),b.onClick&&b.onClick.call(a.$element),b.cancel?(a.getOnCancel().call(a.$element,b.value),a.$element.trigger("canceled.bs.confirmation",[b.value])):(a.getOnConfirm().call(a.$element,b.value),a.$element.trigger("confirmed.bs.confirmation",[b.value])),a.inState&&(a.inState.click=!1),a.hide()}))},this)}else c.find('[data-apply="confirmation"]').addClass(this.options.btnOkClass).html(this.options.btnOkLabel).attr(this.options._attributes).prepend($("").addClass(this.options.btnOkIcon)," ").off("click").one("click",function(b){"#"===$(this).attr("href")&&b.preventDefault(),a.getOnConfirm().call(a.$element),a.$element.trigger("confirmed.bs.confirmation"),a.$element.trigger(a.options.confirmationEvent,[!0]),a.hide()}),c.find('[data-dismiss="confirmation"]').addClass(this.options.btnCancelClass).html(this.options.btnCancelLabel).prepend($("").addClass(this.options.btnCancelIcon)," ").off("click").one("click",function(b){b.preventDefault(),a.getOnCancel().call(a.$element),a.$element.trigger("canceled.bs.confirmation"),a.inState&&(a.inState.click=!1),a.hide()});c.removeClass("fade top bottom left right in"),c.find(".popover-title").html()||c.find(".popover-title").hide(),b=this,$(window).off("keyup.bs.confirmation").on("keyup.bs.confirmation",this._onKeyup.bind(this))},c.prototype.destroy=function(){b===this&&(b=void 0,$(window).off("keyup.bs.confirmation")),$.fn.popover.Constructor.prototype.destroy.call(this)},c.prototype.hide=function(){b===this&&(b=void 0,$(window).off("keyup.bs.confirmation")),$.fn.popover.Constructor.prototype.hide.call(this)},c.prototype._onKeyup=function(a){if(!this.$tip)return b=void 0,void $(window).off("keyup.bs.confirmation");var d,e=a.key||c.KEYMAP[a.keyCode||a.which],f=this.$tip.find(".confirmation-buttons .btn-group"),g=f.find(".active");switch(e){case"Escape":this.hide();break;case"ArrowRight":d=g.length&&g.next().length?g.next():f.children().first(),g.removeClass("active"),d.addClass("active").focus();break;case"ArrowLeft":d=g.length&&g.prev().length?g.prev():f.children().last(),g.removeClass("active"),d.addClass("active").focus()}},c.prototype.getOnConfirm=function(){return this.$element.attr("data-on-confirm")?a(this.$element.attr("data-on-confirm")):this.options.onConfirm},c.prototype.getOnCancel=function(){return this.$element.attr("data-on-cancel")?a(this.$element.attr("data-on-cancel")):this.options.onCancel};var d=$.fn.confirmation;$.fn.confirmation=function(a){var b="object"==typeof a&&a||{};return b.rootSelector=this.selector||b.rootSelector,this.each(function(){var d=$(this),e=d.data("bs.confirmation");(e||"destroy"!=a)&&(e||d.data("bs.confirmation",e=new c(this,b)),"string"==typeof a&&(e[a](),"hide"==a&&e.inState&&(e.inState.click=!1)))})},$.fn.confirmation.Constructor=c,$.fn.confirmation.noConflict=function(){return $.fn.confirmation=d,this}}(jQuery);
\ No newline at end of file
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/bower.json b/app/static/bootstrap/Bootstrap-Confirmation-2/bower.json
new file mode 100644
index 000000000..718da5907
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/bower.json
@@ -0,0 +1,37 @@
+{
+ "name": "bootstrap-confirmation2",
+ "homepage": "http://bootstrap-confirmation.js.org",
+ "description": "Bootstrap plugin for on-place confirm boxes using Popover",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "Nimit Suwannagate",
+ "email": "ethaizone@hotmail.com"
+ },
+ {
+ "name": "Damien \"Mistic\" Sorel",
+ "email": "contact@git.strangeplanet.fr",
+ "homepage": "http://www.strangeplanet.fr"
+ }
+ ],
+ "main": "bootstrap-confirmation.js",
+ "keywords": [
+ "bootstrap",
+ "confirmation",
+ "popup"
+ ],
+ "dependencies" : {
+ "bootstrap": ">=3.2.0 <4"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mistic100/Bootstrap-Confirmation.git"
+ },
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ]
+}
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/example/index.html b/app/static/bootstrap/Bootstrap-Confirmation-2/example/index.html
new file mode 100644
index 000000000..139c7a2f7
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/example/index.html
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+ Bootstrap Confirmation
+
+
+
+
+
+
+
+
+
+
+
+
Basic
+
+
+
+
+
+
+
+
+
Customize
+
+
+
+
+
+
+
Directions
+
+
+
+
+
+
+
+
+
+
Singleton
+
+
+
+
+
+
+
+
Popout
+
+
+
+
+
+
+
+
Delegation
+
+
+
+
+
+
+
+
Custom event
+
+
+
+
+
+
+
Custom buttons
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/static/bootstrap/Bootstrap-Confirmation-2/package.json b/app/static/bootstrap/Bootstrap-Confirmation-2/package.json
new file mode 100644
index 000000000..72adf24ed
--- /dev/null
+++ b/app/static/bootstrap/Bootstrap-Confirmation-2/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "bootstrap-confirmation2",
+ "version": "2.4.4",
+ "homepage": "http://bootstrap-confirmation.js.org",
+ "description": "Bootstrap plugin for on-place confirm boxes using Popover",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "Nimit Suwannagate",
+ "email": "ethaizone@hotmail.com"
+ },
+ {
+ "name": "Damien \"Mistic\" Sorel",
+ "email": "contact@git.strangeplanet.fr",
+ "homepage": "http://www.strangeplanet.fr"
+ }
+ ],
+ "main": "bootstrap-confirmation.js",
+ "keywords": [
+ "bootstrap",
+ "confirmation",
+ "popup"
+ ],
+ "peerDependencies": {
+ "bootstrap": ">=3.2.0 <4"
+ },
+ "devDependencies": {
+ "grunt": "^1.0.0",
+ "grunt-contrib-connect": "^1.0.0",
+ "grunt-contrib-jshint": "^1.0.0",
+ "grunt-contrib-uglify": "^1.0.0",
+ "grunt-contrib-watch": "^1.0.0",
+ "grunt-open": "^0.2.3",
+ "grunt-replace": "^1.0.1",
+ "jit-grunt": "^0.10.0"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mistic100/Bootstrap-Confirmation.git"
+ },
+ "bugs": {
+ "url": "https://github.com/mistic100/Bootstrap-Confirmation/issues"
+ },
+ "scripts": {
+ "test": "grunt test"
+ }
+}
From f6b87996391425a75980b1a5cf1ecff71dbdbe73 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 2 Apr 2019 09:07:18 +0000
Subject: [PATCH 03/13] Added pagination and delete confirmation
---
app/routes.py | 21 +++--
app/static/{ => images}/orchestrator-logo.png | Bin
app/templates/base.html | 4 +
app/templates/createdep.html | 12 ++-
app/templates/deployments.html | 75 ++++++++++++++++--
app/templates/home.html | 2 +-
app/templates/settings.html | 32 ++++++++
7 files changed, 132 insertions(+), 14 deletions(-)
rename app/static/{ => images}/orchestrator-logo.png (100%)
create mode 100644 app/templates/settings.html
diff --git a/app/routes.py b/app/routes.py
index 51dc413ae..9dfcc08cc 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -1,4 +1,4 @@
-from app import app, iam_blueprint
+from app import app, iam_blueprint, iam_base_url
from flask import json, current_app, render_template, request, redirect, url_for, flash, session
import requests, json
import yaml
@@ -30,15 +30,21 @@ def avatar(email, size):
orchestratorUrl = app.config.get('ORCHESTRATOR_URL')
-#@app.route('/')
+@app.route('/settings')
+def show_settings():
+ if not iam_blueprint.session.authorized:
+ return redirect(url_for('login'))
+ return render_template('settings.html', orchestrator_url=orchestratorUrl, iam_url=iam_base_url)
+
@app.route('/login')
def login():
session.clear()
return render_template('home.html')
-@app.route('/dashboard')
+@app.route('/dashboard/')
+@app.route('/')
@app.route('/')
-def home():
+def home(page=0):
if not iam_blueprint.session.authorized:
return redirect(url_for('login'))
@@ -53,7 +59,7 @@ def home():
headers = {'Authorization': 'bearer %s' % (access_token)}
- url = orchestratorUrl + "/deployments?createdBy=me"
+ url = orchestratorUrl + "/deployments?createdBy=me&page=" + str(page)
response = requests.get(url, headers=headers)
deployments = {}
@@ -61,7 +67,9 @@ def home():
flash("Error retrieving deployment list: \n" + response.text, 'warning')
else:
deployments = response.json()["content"]
- return render_template('deployments.html', deployments=deployments)
+ pages=response.json()['page']['totalPages']
+ app.logger.debug(pages)
+ return render_template('deployments.html', deployments=deployments, tot_pages=pages, current_page=page)
@@ -162,3 +170,4 @@ def logout():
iam_blueprint.session.get("/logout")
# del iam_blueprint.session.token
return redirect(url_for('login'))
+
diff --git a/app/static/orchestrator-logo.png b/app/static/images/orchestrator-logo.png
similarity index 100%
rename from app/static/orchestrator-logo.png
rename to app/static/images/orchestrator-logo.png
diff --git a/app/templates/base.html b/app/templates/base.html
index c72ac5825..4cf64acb5 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -7,6 +7,7 @@
+
-
+
diff --git a/app/templates/settings.html b/app/templates/settings.html
new file mode 100644
index 000000000..5a0017ada
--- /dev/null
+++ b/app/templates/settings.html
@@ -0,0 +1,32 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
+
+
Settings
+
+
+
+
Orchestrator
+
{{ orchestrator_url }}
+
+
+
+
+
+{% endblock %}
From f47facaafb97abe1315b81853abc7aa7441b7d4c Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 2 Apr 2019 09:32:17 +0000
Subject: [PATCH 04/13] Fixing header
---
app/templates/deployments.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/templates/deployments.html b/app/templates/deployments.html
index a8c581ce8..a6e81e1aa 100644
--- a/app/templates/deployments.html
+++ b/app/templates/deployments.html
@@ -42,7 +42,7 @@
{% endif %}
{% endwith %}
-
My deployments ({{ current_page|int +1 }}/{{tot_pages}}):
+ My deployments:
Refresh
From b9c8e842a782a69dc06f5552efa27382bcc47287 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 2 Apr 2019 09:56:48 +0000
Subject: [PATCH 05/13] Fixing select option
---
app/templates/createdep.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/templates/createdep.html b/app/templates/createdep.html
index 325f820b0..d2c2c403c 100644
--- a/app/templates/createdep.html
+++ b/app/templates/createdep.html
@@ -22,7 +22,7 @@
{% for tosca in templates %}
-
+
{% endfor %}
From 54574f46cb0b8e16ab69c82dd4ea3cf38ccd5af0 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Wed, 3 Apr 2019 11:09:33 +0000
Subject: [PATCH 06/13] Added SLAs page
---
app/config-sample.json | 1 +
app/routes.py | 37 +++++++++++++++++++++++++++++----
app/templates/base.html | 2 +-
app/templates/sla.html | 45 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 80 insertions(+), 5 deletions(-)
create mode 100644 app/templates/sla.html
diff --git a/app/config-sample.json b/app/config-sample.json
index 85ee47ec8..0e72986dc 100644
--- a/app/config-sample.json
+++ b/app/config-sample.json
@@ -3,5 +3,6 @@
"IAM_CLIENT_SECRET": "my_client_secret",
"IAM_BASE_URL": "https://iam-test.indigo-datacloud.eu",
"ORCHESTRATOR_URL": "https://indigo-paas.cloud.ba.infn.it/orchestrator",
+ "SLAM_URL": "https://indigo-slam.cloud.ba.infn.it:8443",
"TOSCA_TEMPLATES_DIR": "/opt/tosca-templates"
}
diff --git a/app/routes.py b/app/routes.py
index 9dfcc08cc..4970ee66f 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -29,6 +29,7 @@ def avatar(email, size):
toscaTemplates.append( os.path.relpath(os.path.join(path, name), toscaDir ))
orchestratorUrl = app.config.get('ORCHESTRATOR_URL')
+slamUrl = app.config.get('SLAM_URL')
@app.route('/settings')
def show_settings():
@@ -41,20 +42,46 @@ def login():
session.clear()
return render_template('home.html')
+
+@app.route('/slas')
+def getslas():
+
+ if not iam_blueprint.session.authorized:
+ return redirect(url_for('login'))
+
+ slas={}
+
+ try:
+ access_token = iam_blueprint.token['access_token']
+ headers = {'Authorization': 'bearer %s' % (access_token)}
+
+ url = slamUrl + "/rest/slam/preferences/" + session['organisation_name']
+ response = requests.get(url, headers=headers, timeout=20)
+ app.logger.info("SLA response status: " + str(response.status_code))
+
+ response.raise_for_status()
+
+ slas = response.json()['sla']
+ except Exception as e:
+ flash("Error retrieving SLAs list: \n" + str(e), 'warning')
+
+ return render_template('sla.html', slas=slas)
+
@app.route('/dashboard/')
@app.route('/')
@app.route('/')
def home(page=0):
- if not iam_blueprint.session.authorized:
- return redirect(url_for('login'))
-
+ if not iam_blueprint.session.authorized:
+ return redirect(url_for('login'))
+ try:
account_info=iam_blueprint.session.get("/userinfo")
if account_info.ok:
account_info_json = account_info.json()
session['username'] = account_info_json['name']
session['gravatar'] = avatar(account_info_json['email'], 26)
+ session['organisation_name']=account_info_json['organisation_name']
access_token = iam_blueprint.token['access_token']
headers = {'Authorization': 'bearer %s' % (access_token)}
@@ -70,7 +97,9 @@ def home(page=0):
pages=response.json()['page']['totalPages']
app.logger.debug(pages)
return render_template('deployments.html', deployments=deployments, tot_pages=pages, current_page=page)
-
+ except Exception:
+ app.logger.info("error")
+ return redirect(url_for('logout'))
@app.route('/template/')
diff --git a/app/templates/base.html b/app/templates/base.html
index 4cf64acb5..d36c5dae8 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -26,13 +26,13 @@
{% if session['username'] %}
-
{{ session['username'] }}
diff --git a/app/templates/sla.html b/app/templates/sla.html
new file mode 100644
index 000000000..23bb0dfa7
--- /dev/null
+++ b/app/templates/sla.html
@@ -0,0 +1,45 @@
+{% extends "base.html" %}
+{% block content %}
+
+
+
+{% with messages = get_flashed_messages() %}
+{% if messages %}
+{% for message in messages %}
+
+ Warning! {{ message }}
+
+
+{% endfor %}
+{% endif %}
+{% endwith %}
+
+
Service Level Agreements:
+
+
+
+
+
+
+ id |
+ Provider |
+ Start date |
+ End date |
+
+
+
+ {% for sla in slas %}
+
+ {{sla.id}} |
+ {{sla.provider}} |
+ {{sla.start_date}} |
+ {{sla.end_date}} |
+
+ {% endfor %}
+
+
+
+
+
+{% endblock %}
+
From 6e6d756335df04ce254fcbc5d4293f3bba046e58 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Fri, 5 Apr 2019 09:42:42 +0000
Subject: [PATCH 07/13] Improved SLAs view; Implemented provider selection for
deployment
---
README.md | 4 +-
app/config-sample.json | 1 +
app/routes.py | 79 +++++++++++++++++++++++++++-------
app/templates/createdep.html | 13 ++++++
app/templates/deployments.html | 6 +--
app/templates/sla.html | 10 +++--
6 files changed, 90 insertions(+), 23 deletions(-)
diff --git a/README.md b/README.md
index 4babbcac6..1730c6b43 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,9 @@ Create the `config.json` file (see the [example](app/config-sample.json)):
"IAM_CLIENT_SECRET": "*****",
"IAM_BASE_URL": "https://iam-test.indigo-datacloud.eu",
"ORCHESTRATOR_URL": "https://indigo-paas.cloud.ba.infn.it/orchestrator",
- "TOSCA_TEMPLATES_DIR": "/opt/tosca-templates"
+ "TOSCA_TEMPLATES_DIR": "/opt/tosca-templates",
+ "SLAM_URL": "https://indigo-slam.cloud.ba.infn.it:8443",
+ "CMDB_URL": "https://indigo-paas.cloud.ba.infn.it/cmdb"
}
````
Clone the tosca-templates repository to get a set of tosca templates that the dashboard will load, e.g.:
diff --git a/app/config-sample.json b/app/config-sample.json
index 0e72986dc..8d294c3b5 100644
--- a/app/config-sample.json
+++ b/app/config-sample.json
@@ -4,5 +4,6 @@
"IAM_BASE_URL": "https://iam-test.indigo-datacloud.eu",
"ORCHESTRATOR_URL": "https://indigo-paas.cloud.ba.infn.it/orchestrator",
"SLAM_URL": "https://indigo-slam.cloud.ba.infn.it:8443",
+ "CMDB_URL": "https://indigo-paas.cloud.ba.infn.it/cmdb",
"TOSCA_TEMPLATES_DIR": "/opt/tosca-templates"
}
diff --git a/app/routes.py b/app/routes.py
index 4970ee66f..976280c31 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -30,6 +30,7 @@ def avatar(email, size):
orchestratorUrl = app.config.get('ORCHESTRATOR_URL')
slamUrl = app.config.get('SLAM_URL')
+cmdbUrl = app.config.get('CMDB_URL')
@app.route('/settings')
def show_settings():
@@ -43,16 +44,23 @@ def login():
return render_template('home.html')
-@app.route('/slas')
-def getslas():
+def get_service_type(access_token, service_id):
+ headers = {'Authorization': 'bearer %s' % (access_token)}
+ url = cmdbUrl + "/service/id/" + service_id
+ response = requests.get(url, headers=headers, timeout=20)
+ response.raise_for_status()
+ app.logger.info(json.dumps(response.json()['data']['service_type']))
- if not iam_blueprint.session.authorized:
- return redirect(url_for('login'))
+ service_type=response.json()['data']['service_type']
- slas={}
+ if 'properties' in response.json()['data']:
+ if 'gpu_support' in response.json()['data']['properties']:
+ service_type = service_type + " (gpu_support: " + str(response.json()['data']['properties']['gpu_support']) + ")"
+
+ return service_type
+
+def get_slas(access_token):
- try:
- access_token = iam_blueprint.token['access_token']
headers = {'Authorization': 'bearer %s' % (access_token)}
url = slamUrl + "/rest/slam/preferences/" + session['organisation_name']
@@ -60,13 +68,34 @@ def getslas():
app.logger.info("SLA response status: " + str(response.status_code))
response.raise_for_status()
-
+ app.logger.info("SLA response: " + json.dumps(response.json()))
slas = response.json()['sla']
+
+ for i in range(len(slas)):
+ service_type=get_service_type(access_token,slas[i]['services'][0]['service_id'])
+ slas[i]['service_type']=service_type
+
+ return slas
+
+@app.route('/slas')
+def getslas():
+
+ if not iam_blueprint.session.authorized:
+ return redirect(url_for('login'))
+
+ slas={}
+
+ try:
+ access_token = iam_blueprint.token['access_token']
+ slas = get_slas(access_token)
+
except Exception as e:
flash("Error retrieving SLAs list: \n" + str(e), 'warning')
+ return redirect(url_for('home'))
return render_template('sla.html', slas=slas)
+
@app.route('/dashboard/')
@app.route('/')
@app.route('/')
@@ -162,7 +191,22 @@ def depcreate():
description = "N/A"
if 'description' in template:
description = template['description']
- return render_template('createdep.html', templates=toscaTemplates, selectedTemplate=selected_tosca, description=description, inputs=inputs)
+
+ slas = get_slas(access_token)
+ return render_template('createdep.html', templates=toscaTemplates, selectedTemplate=selected_tosca, description=description, inputs=inputs, slas=slas)
+
+def add_sla_to_template(template, sla_id):
+ # Add the placement policy
+
+ nodes=template['topology_template']['node_templates']
+ compute_nodes = []
+ for key, dict in nodes.items():
+ node_type=dict["type"]
+ if node_type == "tosca.nodes.indigo.Compute" or node_type == "tosca.nodes.indigo.Container.Application.Docker.Chronos" :
+ compute_nodes.append(key)
+ template['topology_template']['policies']=[{ "deploy_on_specific_site": { "type": "tosca.policies.Placement", "properties": { "sla_id": sla_id }, "targets": compute_nodes } }]
+ app.logger.info(yaml.dump(template,default_flow_style=False))
+ return template
#
#
@app.route('/submit', methods=['POST'])
@@ -173,11 +217,14 @@ def createdep():
access_token = iam_blueprint.session.token['access_token']
-
try:
- with io.open( toscaDir + request.args.get('template')) as stream:
- payload = { "template" : stream.read(), "parameters": request.form.to_dict() }
-
+ with io.open( toscaDir + request.args.get('template')) as stream:
+ template = yaml.load(stream)
+ if 'selectSla' in request.form.to_dict():
+ template = add_sla_to_template(template, request.form.get('selectedSLA'))
+
+ payload = { "template" : yaml.dump(template,default_flow_style=False), "parameters": request.form.to_dict() }
+
body= json.dumps(payload)
url = orchestratorUrl + "/deployments/"
@@ -186,10 +233,11 @@ def createdep():
if not response.ok:
flash("Error submitting deployment: \n" + response.text)
-
+
return redirect(url_for('home'))
+
except Exception as e:
- app.logger.error("Error submitting deployment:" + str(e))
+ flash("Error submitting deployment:" + str(e) + ". Please retry")
return redirect(url_for('home'))
@@ -200,3 +248,4 @@ def logout():
# del iam_blueprint.session.token
return redirect(url_for('login'))
+
diff --git a/app/templates/createdep.html b/app/templates/createdep.html
index d2c2c403c..8b867f86a 100644
--- a/app/templates/createdep.html
+++ b/app/templates/createdep.html
@@ -52,6 +52,15 @@ Set input values:
{% endfor %}
{% endif %}
+
+
+
+
+
Submit
{% endif %}
@@ -70,5 +79,9 @@ Set input values:
return true;
});
});
+
+$('#checkboxSLA').change(function() {
+ $('#selectSLA').attr('disabled',!this.checked)
+});
{% endblock %}
diff --git a/app/templates/deployments.html b/app/templates/deployments.html
index a6e81e1aa..a9d3c525f 100644
--- a/app/templates/deployments.html
+++ b/app/templates/deployments.html
@@ -84,19 +84,17 @@
{% if tot_pages > 1 %}
-
{% endif %}
{% endblock %}
From fb7e87cf30094e979583525a4aedc306b2483062 Mon Sep 17 00:00:00 2001
From: Marica Antonacci
Date: Tue, 16 Apr 2019 10:27:27 +0000
Subject: [PATCH 13/13] Added SLAM_CERT
---
app/routes.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/app/routes.py b/app/routes.py
index 8aa20f4e9..98710741e 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -31,6 +31,7 @@ def avatar(email, size):
orchestratorUrl = app.config.get('ORCHESTRATOR_URL')
slamUrl = app.config.get('SLAM_URL')
cmdbUrl = app.config.get('CMDB_URL')
+slam_cert = app.config.get('SLAM_CERT')
@app.route('/settings')
def show_settings():
@@ -64,7 +65,10 @@ def get_slas(access_token):
headers = {'Authorization': 'bearer %s' % (access_token)}
url = slamUrl + "/rest/slam/preferences/" + session['organisation_name']
- response = requests.get(url, headers=headers, timeout=20)
+ verify = True
+ if slam_cert:
+ verify = slam_cert
+ response = requests.get(url, headers=headers, timeout=20, verify=verify)
app.logger.info("SLA response status: " + str(response.status_code))
response.raise_for_status()