mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-10 01:17:40 +03:00
* be able to change service elasticity policies * be able to change service min vms * service update view Co-authored-by: Frederick Borges <fborges@opennebula.io>
This commit is contained in:
parent
b28138f411
commit
b9f1abb0de
@ -36,6 +36,7 @@ $LOAD_PATH << RUBY_LIB_LOCATION
|
||||
$LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
|
||||
|
||||
require 'json'
|
||||
require 'tempfile'
|
||||
|
||||
require 'command_parser'
|
||||
require 'opennebula/oneflow_client'
|
||||
@ -348,4 +349,58 @@ CommandParser::CmdParser.new(ARGV) do
|
||||
client.post("#{RESOURCE_PATH}/#{service_id}/action", json)
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
|
||||
update_desc = <<-EOT.unindent
|
||||
Update the template contents. If a path is not provided the editor will
|
||||
be launched to modify the current content.
|
||||
EOT
|
||||
|
||||
command :update, update_desc, :service_id, [:file, nil] do
|
||||
service_id = args[0]
|
||||
client = helper.client(options)
|
||||
|
||||
if args[1]
|
||||
path = args[1]
|
||||
else
|
||||
response = client.get("#{RESOURCE_PATH}/#{service_id}")
|
||||
|
||||
if CloudClient.is_error?(response)
|
||||
exit_with_code response.code.to_i, response.to_s
|
||||
else
|
||||
document = JSON.parse(response.body)['DOCUMENT']
|
||||
template = document['TEMPLATE']['BODY']
|
||||
|
||||
tmp = Tempfile.new(service_id.to_s)
|
||||
path = tmp.path
|
||||
|
||||
tmp.write(JSON.pretty_generate(template))
|
||||
tmp.flush
|
||||
|
||||
if ENV['EDITOR']
|
||||
editor_path = ENV['EDITOR']
|
||||
else
|
||||
editor_path = OpenNebulaHelper::EDITOR_PATH
|
||||
end
|
||||
|
||||
system("#{editor_path} #{path}")
|
||||
|
||||
unless $CHILD_STATUS.exitstatus.zero?
|
||||
STDERR.puts 'Editor not defined'
|
||||
exit(-1)
|
||||
end
|
||||
|
||||
tmp.close
|
||||
end
|
||||
end
|
||||
|
||||
response = client.put("#{RESOURCE_PATH}/#{service_id}", File.read(path))
|
||||
|
||||
if CloudClient.is_error?(response)
|
||||
[response.code.to_i, response.to_s]
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -203,7 +203,7 @@ class EventManager
|
||||
Log.info LOG_COMP, "Waiting #{cooldown_time}s for cooldown for " \
|
||||
"service #{service_id} and role #{role_name}."
|
||||
|
||||
sleep cooldown_time
|
||||
sleep cooldown_time.to_i
|
||||
|
||||
@lcm.trigger_action(:cooldown_cb,
|
||||
service_id,
|
||||
|
@ -440,6 +440,41 @@ class ServiceLCM
|
||||
rc
|
||||
end
|
||||
|
||||
# Update service template
|
||||
#
|
||||
# @param client [OpenNebula::Client] Client executing action
|
||||
# @param service_id [Integer] Service ID
|
||||
# @param new_tempalte [String] New template
|
||||
def service_update(client, service_id, new_template)
|
||||
rc = @srv_pool.get(service_id, client) do |service|
|
||||
unless service.can_update?
|
||||
break OpenNebula::Error.new(
|
||||
"Service cannot be updated in state: #{service.state_str}"
|
||||
)
|
||||
end
|
||||
|
||||
rc = service.check_new_template(new_template)
|
||||
|
||||
unless rc[0]
|
||||
if rc[1] == 'name'
|
||||
break OpenNebula::Error.new(
|
||||
'To change `service/name` use rename operation'
|
||||
)
|
||||
else
|
||||
break OpenNebula::Error.new(
|
||||
"Immutable value: `#{rc[1]}` can not be changed"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
service.update(new_template)
|
||||
end
|
||||
|
||||
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
|
||||
|
||||
rc
|
||||
end
|
||||
|
||||
# Update role elasticity/schedule policies
|
||||
#
|
||||
# @param client [OpenNebula::Client] Client executing action
|
||||
|
@ -120,6 +120,22 @@ module OpenNebula
|
||||
'DOWN' => 1
|
||||
}
|
||||
|
||||
# List of attributes that can't be changed in update operation
|
||||
# cardinality: this is internal information managed by OneFlow server
|
||||
# last_vmname: this is internal information managed by OneFlow server
|
||||
# nodes: this is internal information managed by OneFlow server
|
||||
# parents: this has only sense in deploy operation
|
||||
# state: this is internal information managed by OneFlow server
|
||||
# vm_template: this will affect scale operation
|
||||
IMMUTABLE_ATTRS = %w[
|
||||
cardinality
|
||||
last_vmname
|
||||
nodes
|
||||
parents
|
||||
state
|
||||
vm_template
|
||||
]
|
||||
|
||||
# VM information to save in document
|
||||
VM_INFO = %w[ID UID GID UNAME GNAME NAME]
|
||||
|
||||
@ -675,6 +691,22 @@ module OpenNebula
|
||||
nil
|
||||
end
|
||||
|
||||
# Check that changes values are correct
|
||||
#
|
||||
# @param template_json [String] New template
|
||||
#
|
||||
# @return [Boolean, String] True, nil if everything is correct
|
||||
# False, attr if attr was changed
|
||||
def check_new_template(template)
|
||||
IMMUTABLE_ATTRS.each do |attr|
|
||||
next if template[attr] == @body[attr]
|
||||
|
||||
return [false, "role/#{attr}"]
|
||||
end
|
||||
|
||||
[true, nil]
|
||||
end
|
||||
|
||||
########################################################################
|
||||
# Recover
|
||||
########################################################################
|
||||
|
@ -80,6 +80,29 @@ module OpenNebula
|
||||
SCALING
|
||||
]
|
||||
|
||||
# List of attributes that can't be changed in update operation
|
||||
#
|
||||
# custom_attrs: it only has sense when deploying, not in running
|
||||
# custom_attrs_values: it only has sense when deploying, not in running
|
||||
# deployment: changing this, changes the undeploy operation
|
||||
# log: this is just internal information, no sense to change it
|
||||
# name: this has to be changed using rename operation
|
||||
# networks: it only has sense when deploying, not in running
|
||||
# networks_values: it only has sense when deploying, not in running
|
||||
# ready_status_gate: it only has sense when deploying, not in running
|
||||
# state: this is internal information managed by OneFlow server
|
||||
IMMUTABLE_ATTRS = %w[
|
||||
custom_attrs
|
||||
custom_attrs_values
|
||||
deployment
|
||||
log
|
||||
name
|
||||
networks
|
||||
networks_values
|
||||
ready_status_gate
|
||||
state
|
||||
]
|
||||
|
||||
LOG_COMP = 'SER'
|
||||
|
||||
# Returns the service state
|
||||
@ -123,6 +146,12 @@ module OpenNebula
|
||||
end
|
||||
end
|
||||
|
||||
# Return true if the service can be updated
|
||||
# @return true if the service can be updated, false otherwise
|
||||
def can_update?
|
||||
!transient_state? && !failed_state?
|
||||
end
|
||||
|
||||
def can_recover_deploy?
|
||||
RECOVER_DEPLOY_STATES.include? STATE_STR[state]
|
||||
end
|
||||
@ -471,6 +500,38 @@ module OpenNebula
|
||||
super(template_raw, append)
|
||||
end
|
||||
|
||||
# Check that changes values are correct
|
||||
#
|
||||
# @param template_json [String] New template
|
||||
#
|
||||
# @return [Boolean, String] True, nil if everything is correct
|
||||
# False, attr if attr was changed
|
||||
def check_new_template(template_json)
|
||||
template = JSON.parse(template_json)
|
||||
|
||||
if template['roles'].size != @roles.size
|
||||
return [false, 'service/roles size']
|
||||
end
|
||||
|
||||
IMMUTABLE_ATTRS.each do |attr|
|
||||
next if template[attr] == @body[attr]
|
||||
|
||||
return [false, "service/#{attr}"]
|
||||
end
|
||||
|
||||
template['roles'].each do |role|
|
||||
# Role name can't be changed, if it is changed some problems
|
||||
# may appear, as name is used to reference roles
|
||||
return [false, 'name'] unless @roles[role['name']]
|
||||
|
||||
rc = @roles[role['name']].check_new_template(role)
|
||||
|
||||
return rc unless rc[0]
|
||||
end
|
||||
|
||||
[true, nil]
|
||||
end
|
||||
|
||||
def deploy_networks
|
||||
body = JSON.parse(self['TEMPLATE/BODY'])
|
||||
|
||||
|
@ -279,26 +279,6 @@ post '/service/:id/action' do
|
||||
rc = OpenNebula::Error.new("Action #{action['perform']}: " \
|
||||
'You have to specify a name')
|
||||
end
|
||||
# when 'update'
|
||||
# if opts && opts['append']
|
||||
# if opts['template_json']
|
||||
# begin
|
||||
# service.update(opts['template_json'], true)
|
||||
# status 204
|
||||
# rescue Validator::ParseException, JSON::ParserError => e
|
||||
# OpenNebula::Error.new(e.message)
|
||||
# end
|
||||
# elsif opts['template_raw']
|
||||
# service.update_raw(opts['template_raw'], true)
|
||||
# status 204
|
||||
# else
|
||||
# OpenNebula::Error.new("Action #{action['perform']}: " \
|
||||
# 'You have to provide a template')
|
||||
# end
|
||||
# else
|
||||
# OpenNebula::Error.new("Action #{action['perform']}: " \
|
||||
# 'Only supported for append')
|
||||
# end
|
||||
when *Role::SCHEDULE_ACTIONS
|
||||
# Use defaults only if one of the options is supplied
|
||||
opts['period'] ||= conf[:action_period]
|
||||
@ -323,6 +303,28 @@ post '/service/:id/action' do
|
||||
status 204
|
||||
end
|
||||
|
||||
put '/service/:id' do
|
||||
new_template = request.body.read
|
||||
|
||||
begin
|
||||
# Check that the JSON is valid
|
||||
json_template = JSON.parse(new_template)
|
||||
|
||||
# Check the schema of the new template
|
||||
ServiceTemplate.validate(json_template)
|
||||
rescue Validator::ParseException, JSON::ParserError => e
|
||||
return internal_error(e.message, VALIDATION_EC)
|
||||
end
|
||||
|
||||
rc = lcm.service_update(@client, params[:id], new_template)
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
return internal_error(rc.message, one_error_to_http(rc.errno))
|
||||
end
|
||||
|
||||
status 204
|
||||
end
|
||||
|
||||
# put '/service/:id/role/:name' do
|
||||
# service_pool = nil # OpenNebula::ServicePool.new(@client)
|
||||
#
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
define(function(require) {
|
||||
var OpenNebulaAction = require('./action');
|
||||
var OpenNebulaHelper = require("./helper");
|
||||
var OpenNebulaError = require("./error");
|
||||
var Locale = require('utils/locale');
|
||||
|
||||
var RESOURCE = "DOCUMENT";
|
||||
@ -111,6 +113,35 @@ define(function(require) {
|
||||
|
||||
OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj, PATH);
|
||||
},
|
||||
"update": function(params){
|
||||
params.cache_name = CACHE_NAME;
|
||||
|
||||
var json_aux = JSON.parse(params.data.extra_param);
|
||||
var action_obj = JSON.stringify(json_aux);
|
||||
|
||||
var callback = params.success;
|
||||
var callbackError = params.error;
|
||||
var id = params.data.id;
|
||||
var request = OpenNebulaHelper.request(RESOURCE, "update", [id, action_obj]);
|
||||
|
||||
var reqPath = PATH ? PATH : RESOURCE.toLowerCase();
|
||||
var cache_name = params.cache_name ? params.cache_name : RESOURCE;
|
||||
$.ajax({
|
||||
url: reqPath + "/" + id,
|
||||
type: "PUT",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: action_obj,
|
||||
success: function(response) {
|
||||
//_clearCache(cache_name);
|
||||
|
||||
return callback ? callback(request, response) : null;
|
||||
},
|
||||
error: function(response) {
|
||||
return callbackError ?
|
||||
callbackError(request, OpenNebulaError(response)) : null;
|
||||
}
|
||||
});
|
||||
},
|
||||
"stateStr" : function(stateId) {
|
||||
return STATES_STR[stateId];
|
||||
},
|
||||
@ -129,4 +160,3 @@ define(function(require) {
|
||||
|
||||
return Service;
|
||||
})
|
||||
|
||||
|
@ -40,7 +40,8 @@ define(function(require) {
|
||||
];
|
||||
|
||||
var _formPanels = [
|
||||
require('./oneflow-services-tab/form-panels/create')
|
||||
require('./oneflow-services-tab/form-panels/create'),
|
||||
require('./oneflow-services-tab/form-panels/update')
|
||||
];
|
||||
|
||||
var Tab = {
|
||||
|
@ -30,6 +30,7 @@ define(function(require) {
|
||||
var ROLES_PANEL_ID = require('./panels/roles/panelId');
|
||||
var SCALE_DIALOG_ID = require('./dialogs/scale/dialogId');
|
||||
var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId');
|
||||
var UPDATE_DIALOG_ID = require('./form-panels/update/formPanelId');
|
||||
|
||||
var _commonActions = new CommonActions(OpenNebulaResource, RESOURCE, TAB_ID,
|
||||
XML_ROOT, Locale.tr("Service created"));
|
||||
@ -96,6 +97,9 @@ define(function(require) {
|
||||
"Service.shutdown": _commonActions.multipleAction('shutdown'),
|
||||
"Service.recover": _commonActions.multipleAction('recover'),
|
||||
"Service.recover_delete": _commonActions.multipleAction('recover_delete'),
|
||||
"Service.update" : _commonActions.update(),
|
||||
"Service.update_dialog" : _commonActions.checkAndShowUpdate(),
|
||||
|
||||
"Service.create_dialog" : {
|
||||
type: "custom",
|
||||
call: function() {
|
||||
@ -115,6 +119,21 @@ define(function(require) {
|
||||
}
|
||||
},
|
||||
|
||||
"Service.show_to_update" : {
|
||||
type: "single",
|
||||
call: function(params) {
|
||||
OpenNebulaResource.show(params);
|
||||
},
|
||||
callback: function(request, response) {
|
||||
Sunstone.showFormPanel(TAB_ID, UPDATE_DIALOG_ID, "update",
|
||||
function(formPanelInstance, context) {
|
||||
formPanelInstance.fill(context, response[XML_ROOT]);
|
||||
}
|
||||
);
|
||||
},
|
||||
error: Notifier.onError
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
"Role.scale_dialog" : {
|
||||
|
@ -23,6 +23,11 @@ define(function(require) {
|
||||
layout: "refresh",
|
||||
alwaysActive: true
|
||||
},
|
||||
"Service.update_dialog" : {
|
||||
type: "action",
|
||||
text: Locale.tr("Update"),
|
||||
layout: "main",
|
||||
},
|
||||
"Service.create_dialog" : {
|
||||
type: "action",
|
||||
layout: "create",
|
||||
|
@ -0,0 +1,252 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
||||
/* not use this file except in compliance with the License. You may obtain */
|
||||
/* a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
define(function(require) {
|
||||
/*
|
||||
DEPENDENCIES
|
||||
*/
|
||||
|
||||
var InstantiateTemplateFormPanel = require('tabs/oneflow-services-tab/form-panels/update/update');
|
||||
var Locale = require('utils/locale');
|
||||
var Tips = require('utils/tips');
|
||||
var TemplatesTable = require('tabs/oneflow-templates-tab/datatable');
|
||||
var TemplateUtils = require('utils/template-utils');
|
||||
var RoleTab = require('tabs/oneflow-services-tab/utils/role-tab');
|
||||
|
||||
/*
|
||||
CONSTANTS
|
||||
*/
|
||||
|
||||
var FORM_PANEL_ID = require('./update/formPanelId');
|
||||
var TAB_ID = require('../tabId');
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
|
||||
function FormPanel() {
|
||||
InstantiateTemplateFormPanel.call(this);
|
||||
this.formPanelId = FORM_PANEL_ID;
|
||||
this.tabId = TAB_ID;
|
||||
this.display_vmgroups = true;
|
||||
this.actions = {
|
||||
'update': {
|
||||
'title': Locale.tr("Update Service"),
|
||||
'buttonText': Locale.tr("Update"),
|
||||
'resetButton': true
|
||||
}
|
||||
};
|
||||
this.templatesTable = new TemplatesTable('service_update', {'select': true});
|
||||
}
|
||||
|
||||
FormPanel.FORM_PANEL_ID = FORM_PANEL_ID;
|
||||
FormPanel.prototype = Object.create(InstantiateTemplateFormPanel.prototype);
|
||||
FormPanel.prototype.constructor = FormPanel;
|
||||
FormPanel.prototype.onShow = _onShow;
|
||||
FormPanel.prototype.setup = _setup;
|
||||
FormPanel.prototype.fill = _fill;
|
||||
FormPanel.prototype.addRoleTab = _add_role_tab;
|
||||
|
||||
|
||||
|
||||
return FormPanel;
|
||||
|
||||
/*
|
||||
FUNCTION DEFINITIONS
|
||||
*/
|
||||
function _setup(context) {
|
||||
var that = this;
|
||||
this.roleTabObjects = {};
|
||||
|
||||
InstantiateTemplateFormPanel.prototype.setup.call(this, context);
|
||||
|
||||
$(".selectTemplateTable", context).html(
|
||||
'<br/>' + this.templatesTable.dataTableHTML + '<br/>');
|
||||
|
||||
this.templatesTable.initialize();
|
||||
|
||||
$(".instantiate_wrapper", context).hide();
|
||||
|
||||
this.templatesTable.idInput().off("change").on("change", function(){
|
||||
$(".instantiate_wrapper", context).show();
|
||||
var template_id = $(this).val();
|
||||
that.setTemplateId(context, template_id);
|
||||
});
|
||||
|
||||
that.roles_index = 0;
|
||||
//$("#tf_btn_roles", context).unbind("click");
|
||||
$("#tf_btn_roles", context).bind("click", function(){
|
||||
that.addRoleTab(that.roles_index, context);
|
||||
that.roles_index++;
|
||||
});
|
||||
|
||||
// Fill parents table
|
||||
// Each time a tab is clicked the table is filled with existing tabs (roles)
|
||||
// Selected roles are kept
|
||||
// TODO If the name of a role is changed and is selected, selection will be lost
|
||||
$("#roles_tabs", context).off("click", "a");
|
||||
$("#roles_tabs", context).on("click", "a", function() {
|
||||
var tab_id = "#"+this.id+"Tab";
|
||||
var str = "";
|
||||
|
||||
$(tab_id+" .parent_roles").hide();
|
||||
var parent_role_available = false;
|
||||
|
||||
$("#roles_tabs_content #role_name", context).each(function(){
|
||||
if ($(this).val() && ($(this).val() != $(tab_id+" #role_name", context).val())) {
|
||||
parent_role_available = true;
|
||||
str += "<tr>\
|
||||
<td style='width:20px;text-align:center;'>\
|
||||
<input class='check_item' type='checkbox' value='"+$(this).val()+"' id='"+$(this).val()+"'/>\
|
||||
</td>\
|
||||
<td>"+$(this).val()+"</td>\
|
||||
</tr>";
|
||||
}
|
||||
});
|
||||
|
||||
if (parent_role_available) {
|
||||
$(tab_id+" .parent_roles", context).show();
|
||||
}
|
||||
|
||||
var selected_parents = [];
|
||||
$(tab_id+" .parent_roles_body input:checked", context).each(function(){
|
||||
selected_parents.push($(this).val());
|
||||
});
|
||||
|
||||
$(tab_id+" .parent_roles_body", context).html(str);
|
||||
|
||||
$.each(selected_parents, function(){
|
||||
$(tab_id+" .parent_roles_body #"+this, context).attr('checked', true);
|
||||
});
|
||||
});
|
||||
|
||||
Foundation.reflow(context, 'tabs');
|
||||
|
||||
Tips.setup(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
function _onShow(context) {
|
||||
this.templatesTable.refreshResourceTableSelect();
|
||||
InstantiateTemplateFormPanel.prototype.onShow.call(this, context);
|
||||
}
|
||||
|
||||
function _fill(context, element) {
|
||||
|
||||
var that = this;
|
||||
|
||||
if (this.action != "update") {return;}
|
||||
this.setHeader(element);
|
||||
this.resourceId = element.ID;
|
||||
|
||||
$("#service_name", context).attr("disabled", "disabled");
|
||||
$("#service_name", context).val(element.NAME);
|
||||
|
||||
$("#description", context).val(element.TEMPLATE.BODY.description);
|
||||
|
||||
$('select[name="deployment"]', context).val(element.TEMPLATE.BODY.deployment);
|
||||
$("select[name='shutdown_action_service']", context).val(element.TEMPLATE.BODY.shutdown_action);
|
||||
$("input[name='ready_status_gate']", context).prop("checked",element.TEMPLATE.BODY.ready_status_gate || false);
|
||||
|
||||
// Remove role tabs
|
||||
$("#roles_tabs i.remove-tab", context).trigger("click");
|
||||
|
||||
var roles_names = [];
|
||||
$.each(element.TEMPLATE.BODY.roles, function(index, value){
|
||||
roles_names.push(value.name);
|
||||
|
||||
$("#tf_btn_roles", context).click();
|
||||
|
||||
var role_context = $('.role_content', context).last();
|
||||
var role_id = $(role_context).attr("role_id");
|
||||
|
||||
that.roleTabObjects[role_id].fill(role_context, value, []);
|
||||
});
|
||||
|
||||
$.each(element.TEMPLATE.BODY.roles, function(index, value){
|
||||
var role_context = $('.role_content', context)[index];
|
||||
var str = "";
|
||||
|
||||
$.each(roles_names, function(){
|
||||
if (this != value.name) {
|
||||
str += "<tr>\
|
||||
<td style='width:20px;'>\
|
||||
<input class='check_item' type='checkbox' value='"+this+"' id='"+this+"'/>\
|
||||
</td>\
|
||||
<td>"+this+"</td>\
|
||||
</tr>";
|
||||
}
|
||||
});
|
||||
|
||||
$(".parent_roles_body", role_context).html(str);
|
||||
|
||||
if (value.parents) {
|
||||
$.each(value.parents, function(index, value){
|
||||
$(".parent_roles_body #"+this, role_context).attr('checked', true);
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function _add_role_tab(role_id, dialog) {
|
||||
var that = this;
|
||||
var html_role_id = 'role' + role_id;
|
||||
|
||||
var role_tab = new RoleTab(html_role_id);
|
||||
that.roleTabObjects[role_id] = role_tab;
|
||||
|
||||
// Append the new div containing the tab and add the tab to the list
|
||||
var role_section = $('<div id="'+html_role_id+'Tab" class="tabs-panel role_content wizard_internal_tab" role_id="'+role_id+'">'+
|
||||
role_tab.html() +
|
||||
'</div>').appendTo($("#roles_tabs_content", dialog));
|
||||
|
||||
Tips.setup(role_section);
|
||||
|
||||
var a = $("<li class='tabs-title'>\
|
||||
<a class='text-center' id='"+html_role_id+"' href='#"+html_role_id+"Tab'>\
|
||||
<span>\
|
||||
<i class='off-color fas fa-cube fa-3x'/>\
|
||||
<br>\
|
||||
<span id='role_name_text'>"+Locale.tr("Role ")+role_id+"</span>\
|
||||
</span>\
|
||||
<i class='fas fa-times-circle remove-tab'></i>\
|
||||
</a>\
|
||||
</li>").appendTo($("ul#roles_tabs", dialog));
|
||||
|
||||
Foundation.reInit($("ul#roles_tabs", dialog));
|
||||
$("a", a).trigger("click");
|
||||
|
||||
// close icon: removing the tab on click
|
||||
a.on("click", "i.remove-tab", function() {
|
||||
var target = $(this).parent().attr("href");
|
||||
var li = $(this).closest('li');
|
||||
var ul = $(this).closest('ul');
|
||||
var content = $(target);
|
||||
var role_id = content.attr("role_id");
|
||||
li.remove();
|
||||
content.remove();
|
||||
if (li.hasClass('is-active')) {
|
||||
$('a', ul.children('li').last()).click();
|
||||
}
|
||||
delete that.roleTabObjects[role_id];
|
||||
return false;
|
||||
});
|
||||
role_tab.setup(role_section);
|
||||
role_tab.onShow();
|
||||
}
|
||||
|
||||
});
|
@ -0,0 +1,19 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
||||
/* not use this file except in compliance with the License. You may obtain */
|
||||
/* a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
define(function(require){
|
||||
return 'updateServiceForm';
|
||||
});
|
@ -0,0 +1,126 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<form data-abide novalidate id="{{formPanelId}}Wizard" class="custom creation">
|
||||
<div class="row">
|
||||
<div class="service_template_param st_man medium-6 columns">
|
||||
<label for="service_name">
|
||||
{{tr "Name"}}
|
||||
</label>
|
||||
<input type="text" id="service_name" name="service_name" required/>
|
||||
</div>
|
||||
<div class="service_template_param st_man medium-6 columns">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="service_template_param st_man large-12 columns">
|
||||
<label for="description">
|
||||
{{tr "Description"}}
|
||||
</label>
|
||||
<textarea type="text" id="description" name="description"/>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div id="network_configuration" style="display: none;">
|
||||
{{#advancedSection (tr "Network configuration") }}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<table class="service_networks policies_table dataTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">{{tr "Mandatory"}}</th>
|
||||
<th width="22%">{{tr "Name"}}</th>
|
||||
<th width="23%">{{tr "Description"}}</th>
|
||||
<th width="10%">{{tr "Type"}}</th>
|
||||
<th id="service_network_id_label" width="15%">{{tr "Network"}}</th>
|
||||
<th width="20%">{{tr "Extra"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<a type="button" class="add_service_network button small small-12 secondary radius"><i class="fas fa-lg fa-plus-circle"></i> {{tr "Network"}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
<div id="custom_attr_values" style="display: none;">
|
||||
{{#advancedSection (tr "Custom Attributes Values Configuration") }}
|
||||
{{{userInputsHTML}}}
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
<div id="advanced_service_values" style="display: none;">
|
||||
{{#advancedSection (tr "Advanced service parameters") }}
|
||||
<div class="row">
|
||||
<div class="service_template_param st_man medium-6 columns">
|
||||
<label for="deployment">
|
||||
{{tr "Strategy"}}
|
||||
<span class="tip">{{tr "Straight strategy will instantiate each role in order: parents role will be deployed before their children. None strategy will instantiate the roles regardless of their relationships."}}</span>
|
||||
</label>
|
||||
<select name="deployment">
|
||||
<option value="straight">{{tr "Straight"}}</option>
|
||||
<option value="none">{{tr "None"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="service_template_param st_man medium-6 columns">
|
||||
<label for="shutdown_action_service">
|
||||
{{tr "VM shutdown action"}}
|
||||
</label>
|
||||
<select name="shutdown_action_service">
|
||||
<option value=""></option>
|
||||
<option value="terminate">{{tr "Terminate"}}</option>
|
||||
<option value="terminate-hard">{{tr "Terminate hard"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="service_template_param st_man small-12 columns">
|
||||
<input type="checkbox" name="ready_status_gate" id="ready_status_gate"/>
|
||||
<label for="ready_status_gate">
|
||||
{{tr "Wait for VMs to report that they are READY via OneGate to consider them running"}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h5>
|
||||
{{tr "Roles"}}
|
||||
<a class="button small radius" id="tf_btn_roles" style="vertical-align: text-top; margin-left: 1em; display:none">
|
||||
<i class="fas fa-lg fa-plus-circle"></i>
|
||||
</a>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div id="new_role" class="large-12 columns">
|
||||
<ul class="tabs" id="roles_tabs" data-tabs>
|
||||
</ul>
|
||||
<div class="tabs-content" id="roles_tabs_content" data-tabs-content="roles_tabs">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -0,0 +1,168 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
||||
/* not use this file except in compliance with the License. You may obtain */
|
||||
/* a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
define(function(require) {
|
||||
/*
|
||||
DEPENDENCIES
|
||||
*/
|
||||
|
||||
var BaseFormPanel = require("utils/form-panels/form-panel");
|
||||
var Sunstone = require("sunstone");
|
||||
var Locale = require("utils/locale");
|
||||
var Tips = require("utils/tips");
|
||||
var OpenNebulaAction = require('opennebula/action');
|
||||
var OpenNebula = require('opennebula');
|
||||
var UserInputs = require("utils/user-inputs");
|
||||
var Notifier = require("utils/notifier");
|
||||
/*
|
||||
TEMPLATES
|
||||
*/
|
||||
|
||||
var TemplateHTML = require("hbs!./html");
|
||||
|
||||
/*
|
||||
CONSTANTS
|
||||
*/
|
||||
|
||||
var FORM_PANEL_ID = require("./formPanelId");
|
||||
var TAB_ID = require("../../tabId");
|
||||
var vm_group = "VM_GROUP";
|
||||
var classButton = 'small button leases right radius';
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
|
||||
function FormPanel() {
|
||||
this.formPanelId = FORM_PANEL_ID;
|
||||
this.tabId = TAB_ID;
|
||||
this.display_vmgroups = false;
|
||||
this.actions = {
|
||||
"update": {
|
||||
"title": Locale.tr("Update Service"),
|
||||
"buttonText": Locale.tr("Update"),
|
||||
"resetButton": false
|
||||
}
|
||||
};
|
||||
|
||||
BaseFormPanel.call(this);
|
||||
}
|
||||
|
||||
FormPanel.FORM_PANEL_ID = FORM_PANEL_ID;
|
||||
FormPanel.prototype = Object.create(BaseFormPanel.prototype);
|
||||
FormPanel.prototype.constructor = FormPanel;
|
||||
FormPanel.prototype.setTemplateId = _setTemplateId;
|
||||
FormPanel.prototype.htmlWizard = _html;
|
||||
FormPanel.prototype.submitWizard = _submitWizard;
|
||||
FormPanel.prototype.onShow = _onShow;
|
||||
FormPanel.prototype.setup = _setup;
|
||||
|
||||
return FormPanel;
|
||||
|
||||
/*
|
||||
FUNCTION DEFINITIONS
|
||||
*/
|
||||
|
||||
function _html() {
|
||||
var values_hbs = {
|
||||
'formPanelId': this.formPanelId,
|
||||
'userInputsHTML': UserInputs.html(),
|
||||
};
|
||||
if(config && config.system_config && config.system_config.leases){
|
||||
values_hbs.userInputsCharters = $("<div/>").append(
|
||||
$("<div/>",{style:"display:inline-block;clear:both;width:100%"}).append(
|
||||
$("<button />", {class: classButton, id:"addCharters"}).append(
|
||||
$("<i/>", {class: 'fa fa-clock'})
|
||||
)
|
||||
).add(
|
||||
$("<table/>", {class: "service-charters"})
|
||||
)
|
||||
).prop('outerHTML');
|
||||
}
|
||||
return TemplateHTML(values_hbs);
|
||||
}
|
||||
|
||||
function _setup(context) {
|
||||
Tips.setup(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
function _onShow(context) {
|
||||
//nothing
|
||||
Sunstone.runAction("Service.show", window.ServiceId);
|
||||
}
|
||||
|
||||
function _setTemplateId(context, templateId) {
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
||||
//submit
|
||||
function _submitWizard(context) {
|
||||
if (this.action != "update") return;
|
||||
var that = this;
|
||||
|
||||
var description = $('#description', context).val();
|
||||
var roles = [];
|
||||
|
||||
var json_template = {};
|
||||
var ret = {};
|
||||
|
||||
//
|
||||
OpenNebula.Service.show({
|
||||
data : {
|
||||
id: window.ServiceId
|
||||
},
|
||||
error: Notifier.onError,
|
||||
success: function(request, response){
|
||||
if (
|
||||
response &&
|
||||
response.DOCUMENT &&
|
||||
response.DOCUMENT.TEMPLATE &&
|
||||
response.DOCUMENT.TEMPLATE.BODY
|
||||
) {
|
||||
var body = response.DOCUMENT.TEMPLATE.BODY;
|
||||
|
||||
if (body.roles){
|
||||
$('.role_content', context).each(function() {
|
||||
var role_id = $(this).attr("role_id");
|
||||
|
||||
var role_info = that.roleTabObjects[role_id].retrieve($(this));
|
||||
|
||||
role_info['cardinality'] = parseInt(role_info.cardinality, 10);
|
||||
role_info['cooldown'] = parseInt(role_info.cooldown, 10);
|
||||
role_info['vm_template'] = parseInt(role_info.vm_template, 10);
|
||||
role_info['last_vmname'] = body.roles[role_id].last_vmname;
|
||||
role_info['nodes'] = body.roles[role_id].nodes;
|
||||
role_info['state'] = body.roles[role_id].state;
|
||||
|
||||
roles.push(role_info);
|
||||
});
|
||||
|
||||
json_template = {
|
||||
description: description,
|
||||
roles: roles
|
||||
};
|
||||
}
|
||||
|
||||
Object.assign(ret, body, json_template);
|
||||
Sunstone.runAction("Service.update",that.resourceId, JSON.stringify(ret));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
@ -0,0 +1,552 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
||||
/* not use this file except in compliance with the License. You may obtain */
|
||||
/* a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
define(function(require) {
|
||||
// Dependencies
|
||||
var Locale = require('utils/locale');
|
||||
var Tips = require('utils/tips');
|
||||
var TemplatesTable = require('tabs/templates-tab/datatable');
|
||||
var TemplateUtils = require('utils/template-utils');
|
||||
|
||||
var TemplateHTML = require('hbs!./role-tab/html');
|
||||
var TemplateElasticityRowHTML = require('hbs!./role-tab/elasticity-row');
|
||||
var TemplateScheRowHTML = require('hbs!./role-tab/sche-row');
|
||||
|
||||
function RoleTab(html_role_id) {
|
||||
this.html_role_id = html_role_id;
|
||||
this.global_template = {};
|
||||
this.nics_template = {};
|
||||
this.alias_template = {};
|
||||
this.rest_template = "";
|
||||
this.refresh = _refreshVMTemplate;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
RoleTab.prototype = {
|
||||
'html': _role_tab_content,
|
||||
'setup': _setup_role_tab_content,
|
||||
'onShow': _onShow,
|
||||
'retrieve': _retrieve,
|
||||
'fill': _fill
|
||||
};
|
||||
RoleTab.prototype.constructor = RoleTab;
|
||||
|
||||
return RoleTab;
|
||||
|
||||
function _role_tab_content(){
|
||||
var opts = {
|
||||
info: false,
|
||||
select: true
|
||||
};
|
||||
|
||||
this.templatesTable = new TemplatesTable("roleTabTemplates"+this.html_role_id, opts);
|
||||
|
||||
return TemplateHTML({
|
||||
'templatesTableHTML': this.templatesTable.dataTableHTML
|
||||
});
|
||||
}
|
||||
|
||||
function _setup_role_tab_content(role_section) {
|
||||
this.role_section = role_section;
|
||||
var that = this;
|
||||
|
||||
Tips.setup(role_section);
|
||||
|
||||
this.templatesTable.initialize();
|
||||
this.templatesTable.idInput().attr("required", "");
|
||||
|
||||
$("#role_name", role_section).unbind("keyup");
|
||||
$("#role_name", role_section).bind("keyup", function(){
|
||||
$("#" + that.html_role_id +" #role_name_text").html($(this).val());
|
||||
});
|
||||
|
||||
role_section.on("change", "select#type", function(){
|
||||
var new_tr = $(this).closest('tr');
|
||||
if ($(this).val() == "PERCENTAGE_CHANGE") {
|
||||
$("#min_adjust_step_td", new_tr).html('<input type="text" id="min_adjust_step" name="min_adjust_step"/>');
|
||||
} else {
|
||||
$("#min_adjust_step_td", new_tr).empty();
|
||||
}
|
||||
});
|
||||
|
||||
$("#tf_btn_elas_policies", role_section).bind("click", function(){
|
||||
$( TemplateElasticityRowHTML({}) ).appendTo($("#elasticity_policies_tbody", role_section));
|
||||
});
|
||||
|
||||
role_section.on("click", "#elasticity_policies_table i.remove-tab", function() {
|
||||
var tr = $(this).closest('tr');
|
||||
tr.remove();
|
||||
});
|
||||
|
||||
$("#tf_btn_sche_policies", role_section).bind("click", function(){
|
||||
$( TemplateScheRowHTML({}) ).appendTo($("#scheduled_policies_tbody", role_section));
|
||||
});
|
||||
|
||||
role_section.on("click", "#scheduled_policies_table i.remove-tab", function() {
|
||||
var tr = $(this).closest('tr');
|
||||
tr.remove();
|
||||
});
|
||||
|
||||
$("#tf_btn_elas_policies", role_section).trigger("click");
|
||||
$("#tf_btn_sche_policies", role_section).trigger("click");
|
||||
|
||||
role_section.on("change", ".service_network_checkbox", role_section, function(){
|
||||
// Network values
|
||||
var index = $(this).data("index");
|
||||
var name = $(this).val();
|
||||
|
||||
if (this.checked) {
|
||||
that.nics_template[index] = { "NAME": "NIC"+index, "NETWORK_ID": "$"+name };
|
||||
$("#alias_"+this.id, role_section).prop("disabled", false);
|
||||
$("td.parent_selector select:visible", role_section).each(function() {
|
||||
updateOptionsParents(this, that.nics_template, that.alias_template);
|
||||
});
|
||||
}
|
||||
else {
|
||||
delete that.nics_template[index];
|
||||
delete that.alias_template[index];
|
||||
$("#alias_"+this.id, role_section).prop("disabled", true).prop("checked", false).change();
|
||||
}
|
||||
|
||||
updateOptionsRDP(role_section, $.extend({}, that.nics_template, that.alias_template));
|
||||
updateRemoveTabs(role_section, index);
|
||||
});
|
||||
|
||||
role_section.on("change", ".alias_network_checkbox", role_section, function(){
|
||||
var index = $(this).data("index");
|
||||
var select = $('td.parent_selector select[data-index='+index+']', role_section);
|
||||
toogleNicUsedAsAlias(role_section, select, select.val(), null)
|
||||
select.prop("hidden", !this.checked).prop("required", this.checked);
|
||||
|
||||
if (this.checked && that.nics_template[index]) {
|
||||
that.alias_template[index] = that.nics_template[index];
|
||||
delete that.nics_template[index];
|
||||
}
|
||||
else if (!this.checked && that.alias_template[index]) {
|
||||
that.nics_template[index] = that.alias_template[index];
|
||||
that.nics_template[index] && (delete that.nics_template[index]["PARENT"]);
|
||||
delete that.alias_template[index];
|
||||
}
|
||||
|
||||
$("td.parent_selector select:visible", role_section).each(function() {
|
||||
updateOptionsParents(this, that.nics_template, that.alias_template);
|
||||
});
|
||||
});
|
||||
|
||||
role_section.on('focusin', ".parent_selector select", function(){
|
||||
// save value after change
|
||||
$(this).data('prev', $(this).val());
|
||||
}).on("change", ".parent_selector select", function(){
|
||||
var index = $(this).data('index');
|
||||
var prevIndexParent = $(this).data('prev');
|
||||
var indexParent = $(this).val();
|
||||
|
||||
toogleNicUsedAsAlias(role_section, this, prevIndexParent, indexParent)
|
||||
|
||||
if (that.nics_template[indexParent] && that.alias_template[index]) {
|
||||
that.alias_template[index]["PARENT"] = "NIC"+indexParent;
|
||||
}
|
||||
});
|
||||
|
||||
role_section.on("change", ".networks_role_rdp select#rdp", role_section, function(){
|
||||
var valueSelected = this.value;
|
||||
var allTemplate = $.extend({}, that.nics_template, that.alias_template);
|
||||
|
||||
// remove RDP option in all nics
|
||||
$.each(Object.entries(allTemplate), function(_, network) {
|
||||
var nicIndex = network[0];
|
||||
var nicTemplate = network[1];
|
||||
|
||||
if (nicIndex !== valueSelected && nicTemplate["RDP"]) {
|
||||
(that.nics_template[nicIndex])
|
||||
? delete that.nics_template[nicIndex]["RDP"]
|
||||
: delete that.alias_template[nicIndex]["RDP"];
|
||||
}
|
||||
});
|
||||
|
||||
// then assign if exists
|
||||
if (valueSelected !== "") {
|
||||
if(that.nics_template[valueSelected]) {
|
||||
that.nics_template[valueSelected]["RDP"] = "YES";
|
||||
}
|
||||
else if(that.alias_template[valueSelected]) {
|
||||
that.alias_template[valueSelected]["RDP"] = "YES";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateRemoveTabs(role_section, index) {
|
||||
var form = $(role_section).closest("#createServiceTemplateFormWizard");
|
||||
|
||||
var networkIsUsed = $(".service_network_checkbox[data-index="+index+"]:checked", form);
|
||||
|
||||
(networkIsUsed.length > 0)
|
||||
? $("#network"+index+" i.remove-tab", form)
|
||||
.prop("style", "color:currentColor;cursor:not-allowed;opacity:0.5;")
|
||||
: $("#network"+index+" i.remove-tab", form).prop("style", "");
|
||||
}
|
||||
|
||||
function toogleNicUsedAsAlias(context, currentSelector, prevIndex, index) {
|
||||
var prevNicCb = $(".service_network_checkbox[data-index='"+prevIndex+"']", context);
|
||||
var prevAliasCb = $(".alias_network_checkbox[data-index='"+prevIndex+"']", context);
|
||||
var nicCb = $(".service_network_checkbox[data-index='"+index+"']", context);
|
||||
var aliasCb = $(".alias_network_checkbox[data-index='"+index+"']", context);
|
||||
|
||||
var prevOthers = $(".parent_selector select:visible", context).not(currentSelector)
|
||||
.children("option[value='"+prevIndex+"']:selected");
|
||||
var others = $(".parent_selector select", context).children("option[value='"+index+"']:selected");
|
||||
|
||||
if (prevOthers.length === 0) {
|
||||
prevNicCb.prop("disabled", false);
|
||||
prevAliasCb.prop("disabled", false);
|
||||
}
|
||||
|
||||
if (others.length === 0) {
|
||||
nicCb.prop("disabled", false);
|
||||
aliasCb.prop("disabled", false);
|
||||
}
|
||||
else {
|
||||
aliasCb.prop("disabled", true).prop("checked", false);
|
||||
nicCb.prop("disabled", true).prop("checked", true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateOptionsRDP(context, currentTemplate) {
|
||||
var selectRDP = $(".networks_role_rdp select#rdp", context);
|
||||
// empty all options in select rdp
|
||||
selectRDP.empty();
|
||||
selectRDP.append("<option value=''></option>")
|
||||
|
||||
$(".service_network_checkbox:checked", context).each(function () {
|
||||
var index = $(this).data("index");
|
||||
var name = $(this).val();
|
||||
selectRDP.append("<option value='"+index+"'>"+name+"</option>")
|
||||
});
|
||||
|
||||
// if some nic has RDP, update selector value
|
||||
$.each(Object.entries(currentTemplate), function(_, nic) {
|
||||
var nicIndex = nic[0];
|
||||
var nicTemplate = nic[1];
|
||||
|
||||
if (nicTemplate["RDP"] && String(nicTemplate["RDP"]).toLowerCase() === "yes") {
|
||||
selectRDP.val(nicIndex).change();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateOptionsParents(select, nicsTemplate, aliasTemplate) {
|
||||
select = $(select);
|
||||
var nicIndex = $(select).data('index');
|
||||
// empty all options in select alias parent
|
||||
select.empty();
|
||||
select.append("<option value=''></option>");
|
||||
|
||||
// possible parents
|
||||
var possibleParents = filterByNicIndex(nicsTemplate, nicIndex);
|
||||
$.each(Object.entries(possibleParents), function (_, nic) {
|
||||
select.append("<option value='"+nic[0]+"'>"+nic[1].NETWORK_ID.substring(1)+"</option>")
|
||||
});
|
||||
|
||||
// update selector parent value
|
||||
$.each(Object.entries(aliasTemplate), function(_, nic) {
|
||||
var nicTemplate = nic[1];
|
||||
|
||||
if (nicTemplate["PARENT"]) {
|
||||
var indexParent = nicTemplate["PARENT"].replace("NIC", "");
|
||||
select.val(indexParent).change();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function filterByNicIndex(object, index) {
|
||||
const obj = {};
|
||||
for (const key in object) {
|
||||
if (key !== String(index)) {
|
||||
obj[key] = object[key];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function _onShow(){
|
||||
this.templatesTable.refreshResourceTableSelect();
|
||||
}
|
||||
|
||||
function _retrieve(context){
|
||||
var role = {};
|
||||
role['name'] = $('input[name="name"]', context).val();
|
||||
role['cardinality'] = $('input[name="cardinality"]', context).val();
|
||||
role['vm_template'] = this.templatesTable.retrieveResourceTableSelect();
|
||||
role['shutdown_action'] = $('select[name="shutdown_action_role"]', context).val();
|
||||
role['parents'] = [];
|
||||
role['vm_template_contents'] = TemplateUtils.templateToString({ NIC: Object.values(this.nics_template) });
|
||||
role['vm_template_contents'] += TemplateUtils.templateToString({ NIC_ALIAS: Object.values(this.alias_template) });
|
||||
role['vm_template_contents'] += this.rest_template;
|
||||
|
||||
$('.parent_roles_body input.check_item:checked', context).each(function(){
|
||||
role['parents'].push($(this).val());
|
||||
});
|
||||
|
||||
var shutdown_action = $('select[name="shutdown_action_role"]', context).val();
|
||||
if (shutdown_action) {
|
||||
role['shutdown_action'] = shutdown_action;
|
||||
}
|
||||
|
||||
var min_vms = $('input[name="min_vms"]', context).val();
|
||||
if (min_vms) {
|
||||
role['min_vms'] = min_vms;
|
||||
}
|
||||
|
||||
var max_vms = $('input[name="max_vms"]', context).val();
|
||||
if (max_vms) {
|
||||
role['max_vms'] = max_vms;
|
||||
}
|
||||
|
||||
var cooldown = $('input[name="cooldown"]', context).val();
|
||||
if (cooldown) {
|
||||
role['cooldown'] = cooldown;
|
||||
}
|
||||
|
||||
role = _removeEmptyObjects(role);
|
||||
role['elasticity_policies'] = [];
|
||||
$("#elasticity_policies_tbody tr", context).each(function(){
|
||||
if ($("#type" ,this).val()) {
|
||||
var policy = {};
|
||||
policy['type'] = $("#type" ,this).val();
|
||||
policy['adjust'] = $("#adjust" ,this).val();
|
||||
policy['min_adjust_step'] = $("#min_adjust_step" ,this).val();
|
||||
policy['expression'] = $("#expression" ,this).val();
|
||||
policy['period_number'] = $("#period_number" ,this).val();
|
||||
policy['period'] = $("#period" ,this).val();
|
||||
policy['cooldown'] = $("#cooldown" ,this).val();
|
||||
|
||||
// TODO remove empty policies
|
||||
role['elasticity_policies'].push(_removeEmptyObjects(policy));
|
||||
}
|
||||
});
|
||||
|
||||
role['scheduled_policies'] = [];
|
||||
$("#scheduled_policies_tbody tr", context).each(function(){
|
||||
if ($("#type" ,this).val()) {
|
||||
var policy = {};
|
||||
policy['type'] = $("#type" ,this).val();
|
||||
policy['adjust'] = $("#adjust" ,this).val();
|
||||
policy['min_adjust_step'] = $("#min_adjust_step" ,this).val();
|
||||
|
||||
var time_format = $("#time_format" ,this).val();
|
||||
policy[time_format] = $("#time" ,this).val();
|
||||
|
||||
// TODO remove empty policies
|
||||
role['scheduled_policies'].push(_removeEmptyObjects(policy));
|
||||
}
|
||||
});
|
||||
|
||||
return role;
|
||||
}
|
||||
|
||||
function _fill(context, value, network_names) {
|
||||
var that = this;
|
||||
$("#role_name", context).val(value.name).keyup();
|
||||
$("#role_name", context).attr("disabled", "disabled");
|
||||
|
||||
$("#cardinality", context).val(value.cardinality);
|
||||
$("#cardinality", context).attr("disabled", "disabled");
|
||||
|
||||
this.templatesTable.selectResourceTableSelect({ids : value.vm_template});
|
||||
|
||||
if (value.vm_template_contents){
|
||||
var vmTemplate = TemplateUtils.stringToTemplate(value.vm_template_contents);
|
||||
// map nics with index checkbox
|
||||
var nics = vmTemplate["NIC"];
|
||||
if (nics) {
|
||||
nics = Array.isArray(nics) ? nics : [nics];
|
||||
|
||||
$.each(network_names, function(index, name) {
|
||||
$.each(nics, function(_, nic) {
|
||||
if (nic["NETWORK_ID"] === "$"+name){
|
||||
nic["NAME"] = "NIC"+index;
|
||||
|
||||
$(".service_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
|
||||
that.nics_template[String(index)] = nic;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// map alias with index checkbox
|
||||
var alias = vmTemplate["NIC_ALIAS"];
|
||||
if (alias) {
|
||||
alias = Array.isArray(alias) ? alias : [alias];
|
||||
|
||||
$.each(network_names, function(index, name) {
|
||||
$.each(alias, function(_, nic) {
|
||||
if (nic["NETWORK_ID"] === "$"+name){
|
||||
nic["NAME"] = "NIC"+index;
|
||||
|
||||
$(".service_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
|
||||
$(".alias_network_checkbox[data-index='"+index+"']", context).attr('checked', true).change();
|
||||
that.alias_template[String(index)] = nic;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$.each(that.alias_template, function(index) {
|
||||
$("select[data-index="+index+"]", context).each(function() {
|
||||
updateOptionsParents(this, that.nics_template, that.alias_template);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// copy rest of template
|
||||
delete vmTemplate["NIC"];
|
||||
delete vmTemplate["NIC_ALIAS"];
|
||||
this.rest_template = TemplateUtils.templateToString(vmTemplate);
|
||||
|
||||
// update selector options for RDP
|
||||
updateOptionsRDP(context, $.extend({}, that.nics_template, that.alias_template));
|
||||
}
|
||||
|
||||
$("select[name='shutdown_action_role']", context).val(value.shutdown_action);
|
||||
|
||||
$("#min_vms", context).val(value.min_vms);
|
||||
$("#max_vms", context).val(value.max_vms);
|
||||
$("#cooldown", context).val(value.cooldown);
|
||||
|
||||
if (value['elasticity_policies'].length > 0 ||
|
||||
value['scheduled_policies'].length > 0) {
|
||||
$("div.elasticity_accordion a.accordion_advanced_toggle", context).trigger("click");
|
||||
}
|
||||
|
||||
$("#elasticity_policies_table i.remove-tab", context).trigger("click");
|
||||
$("#scheduled_policies_table i.remove-tab", context).trigger("click");
|
||||
|
||||
if (value['elasticity_policies']) {
|
||||
$.each(value['elasticity_policies'], function(){
|
||||
$("#tf_btn_elas_policies", context).click();
|
||||
var td = $("#elasticity_policies_tbody tr", context).last();
|
||||
$("#type" ,td).val(this['type']);
|
||||
$("#type" ,td).change();
|
||||
$("#adjust" ,td).val(this['adjust'] );
|
||||
$("#min_adjust_step" ,td).val(this['min_adjust_step'] || "");
|
||||
$("#expression" ,td).val(this.expression);
|
||||
$("#period_number" ,td).val(this['period_number'] || "");
|
||||
$("#period" ,td).val(this['period'] || "" );
|
||||
$("#cooldown" ,td).val(this['cooldown'] || "" );
|
||||
});
|
||||
}
|
||||
|
||||
if (value['scheduled_policies']) {
|
||||
$.each(value['scheduled_policies'], function(){
|
||||
$("#tf_btn_sche_policies", context).click();
|
||||
var td = $("#scheduled_policies_tbody tr", context).last();
|
||||
$("#type", td).val(this['type']);
|
||||
$("#type" ,td).change();
|
||||
$("#adjust", td).val(this['adjust'] );
|
||||
$("#min_adjust_step", td).val(this['min_adjust_step'] || "");
|
||||
|
||||
if (this['start_time']) {
|
||||
$("#time_format", td).val('start_time');
|
||||
$("#time", td).val(this['start_time']);
|
||||
} else if (this['recurrence']) {
|
||||
$("#time_format", td).val('recurrence');
|
||||
$("#time", td).val(this['recurrence']);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _refreshVMTemplate(checkedNetworks, nicToDelete) {
|
||||
var that = this;
|
||||
|
||||
if (that.role_section && that.nics_template) {
|
||||
if (nicToDelete) {
|
||||
delete that.nics_template[nicToDelete];
|
||||
delete that.alias_template[nicToDelete];
|
||||
}
|
||||
// update all NAMES and NETWORK IDs
|
||||
$.each(checkedNetworks, function(index, nic) {
|
||||
if (nic && that.nics_template[index]) {
|
||||
if (that.nics_template[index]) {
|
||||
that.nics_template[index]["NAME"] = "NIC"+index;
|
||||
that.nics_template[index]["NETWORK_ID"] = "$"+nic.name;
|
||||
}
|
||||
else if (nic && that.alias_template[index]) {
|
||||
that.alias_template[index]["NAME"] = "NIC"+index;
|
||||
that.alias_template[index]["NETWORK_ID"] = "$"+nic.name;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var allTemplate = $.extend({}, that.nics_template, that.alias_template);
|
||||
updateOptionsRDP(that.role_section, allTemplate);
|
||||
$.each(that.alias_template, function(index) {
|
||||
$("select[data-index="+index+"]", that.role_section).each(function() {
|
||||
updateOptionsParents(this, that.nics_template, that.alias_template);
|
||||
});
|
||||
});
|
||||
// Update remove-tabs state (unabled/disabled)
|
||||
var form = $(that.role_section).closest("#createServiceTemplateFormWizard");
|
||||
$("table.service_networks i.remove-tab", form).each(function() {
|
||||
updateRemoveTabs(that.role_section, $(this).data("index"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
function _removeEmptyObjects(obj){
|
||||
for (var elem in obj){
|
||||
var remove = false;
|
||||
var value = obj[elem];
|
||||
if (value instanceof Array){
|
||||
if (value.length == 0)
|
||||
remove = true;
|
||||
else if (value.length > 0){
|
||||
value = jQuery.grep(value, function (n) {
|
||||
var obj_length = 0;
|
||||
for (e in n)
|
||||
obj_length += 1;
|
||||
|
||||
if (obj_length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (value.length == 0)
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
else if (value instanceof Object){
|
||||
var obj_length = 0;
|
||||
for (e in value)
|
||||
obj_length += 1;
|
||||
if (obj_length == 0)
|
||||
remove = true;
|
||||
}else{
|
||||
value = String(value);
|
||||
if (value.length == 0)
|
||||
remove = true;
|
||||
}
|
||||
|
||||
if (remove)
|
||||
delete obj[elem];
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<select id="type" name="type">
|
||||
<option value=""></option>
|
||||
<option value="CHANGE">{{tr "Change"}}</option>
|
||||
<option value="CARDINALITY">{{tr "Cardinality"}}</option>
|
||||
<option value="PERCENTAGE_CHANGE">{{tr "Percentage"}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="adjust" name="adjust"/>
|
||||
</td>
|
||||
<td id="min_adjust_step_td">
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="expression" name="expression"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="period_number" name="period_number"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="period" name="period"/>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="cooldown" name="cooldown"/>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#"><i class="fas fa-times-circle remove-tab"></i></a>
|
||||
</td>
|
||||
</tr>
|
@ -0,0 +1,50 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<thead style="background:#dfdfdf">
|
||||
<tr>
|
||||
<th colspan="8">
|
||||
{{tr "Elasticity policies"}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="has-tip" title="{{tr "Type of adjustment."}}
|
||||
{{tr "CHANGE: Add/subtract the given number of VMs."}}
|
||||
{{tr "CARDINALITY: Set the cardinality to the given number."}}
|
||||
{{tr "PERCENTAGE_CHANGE: Add/subtract the given percentage to the current cardinality."}}" style="width:14%">{{tr "Type"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Positive or negative adjustment. Its meaning depends on 'type'"}}
|
||||
{{tr "CHANGE: -2, will subtract 2 VMs from the role"}}
|
||||
{{tr "CARDINALITY: 8, will set cardinality to 8"}}
|
||||
{{tr "PERCENTAGE_CHANGE: 20, will increment cardinality by 20%"}}" style="width:12%">{{tr "Adjust"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Optional parameter for PERCENTAGE_CHANGE adjustment type."}}
|
||||
{{tr " If present, the policy will change the cardinality by at least the number of VMs set in this attribute."}}" style="width:9%">{{tr "Min"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Expression to trigger the elasticity"}}
|
||||
{{tr "Example: ATT < 20"}}" style="width:30%">{{tr "Expression"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Number of periods that the expression must be true before the elasticity is triggered"}}" style="width:8%">#
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Duration, in seconds, of each period in '# Periods'"}}" style="width:9%">{{tr "Period"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Cooldown period duration after a scale operation, in seconds"}}" style="width:15%">{{tr "Cooldown"}}
|
||||
</th>
|
||||
<th style="width:3%"></th>
|
||||
</tr>
|
||||
</thead>
|
@ -0,0 +1,162 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<div class="row">
|
||||
<div class="service_param service_role st_man medium-6 columns">
|
||||
<label>
|
||||
{{tr "Role name"}}
|
||||
<input type="text" id="role_name" name="name" aria-describedby="helpText" required pattern="^\w+$"/>
|
||||
<small class="form-error">{{tr "Can only contain alphanumeric and underscore characters"}}</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="service_param service_role medium-4 columns end">
|
||||
<label>
|
||||
{{tr "Number of VMs"}}
|
||||
<input type="number" min="0" id="cardinality" name="cardinality" value="1"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;">
|
||||
<div class="service_param service_role small-12 columns">
|
||||
<label>
|
||||
{{tr "VM template to create this role's VMs"}}
|
||||
</label>
|
||||
<br/>
|
||||
{{{templatesTableHTML}}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;">
|
||||
<div class="service_param service_role large-12 columns">
|
||||
<table class="parent_roles dataTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
{{tr "Parent roles"}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="parent_roles_body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="networks_accordion large-12 columns " style="display: none;">
|
||||
{{#advancedSection (tr "Role network") }}
|
||||
<div class="service_param service_role">
|
||||
<table class="networks_role dataTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="4">
|
||||
<label for="interfaces_role">
|
||||
<i class="fas fa-lg fa-fw fa-globe off-color"/>{{tr "Network Interfaces"}}
|
||||
<span class="tip">{{tr "This network interface will be configured as an ALIAS in the VM without context configuration."}}</span>
|
||||
</label>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="networks_role_body">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-group networks_role_rdp" style="padding:0.6rem;">
|
||||
<label for="rdp">RDP</label>
|
||||
<select class="form-control" id="rdp">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="large-12 columns elasticity_accordion">
|
||||
{{#advancedSection (tr "Role elasticity") }}
|
||||
<div class="row">
|
||||
<div class="medium-4 columns">
|
||||
<label>
|
||||
{{tr "Min VMs"}}
|
||||
<input type="number" min="0" id="min_vms" name="min_vms" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-4 columns">
|
||||
<label>{{tr "Max VMs"}}
|
||||
<input type="number" min="0" id="max_vms" name="max_vms" value="" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="service_param service_role medium-4 columns">
|
||||
<label>
|
||||
{{tr "Cooldown"}}
|
||||
<span class="tip">{{tr "Cooldown time after an elasticity operation (seconds)"}}</span>
|
||||
<input type="number" min="0" id="cooldown" name="cooldown" value="" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<table id="elasticity_policies_table" class="policies_table dataTable">
|
||||
{{> tabs/oneflow-templates-tab/utils/role-tab/elasticity-thead}}
|
||||
<tbody id="elasticity_policies_tbody">
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="8">
|
||||
<a type="button" class="button small radius secondary small-12" id="tf_btn_elas_policies"><i class="fas fa-lg fa-plus-circle"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<table id="scheduled_policies_table" class="policies_table dataTable">
|
||||
{{> tabs/oneflow-templates-tab/utils/role-tab/sched-thead}}
|
||||
<tbody id="scheduled_policies_tbody">
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<a type="button" class="button small radius secondary small-12" id="tf_btn_sche_policies"><i class="fas fa-lg fa-plus-circle"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="large-12 columns advanced_role_accordion">
|
||||
{{#advancedSection (tr "Advanced role parameters") }}
|
||||
<div class="row">
|
||||
<div class="service_param service_role medium-6 columns">
|
||||
<label for="shutdown_action_role">{{tr "VM shutdown action"}}
|
||||
<span class="tip">{{tr "If it is not set, the one set for the Service will be used"}}</span>
|
||||
</label>
|
||||
<select name="shutdown_action_role">
|
||||
<option value=""></option>
|
||||
<option value="terminate">{{tr "Terminate"}}</option>
|
||||
<option value="terminate-hard">{{tr "Terminate hard"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="medium-6 columns">
|
||||
</div>
|
||||
</div>
|
||||
{{/advancedSection}}
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,43 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<select id="type" name="type">
|
||||
<option value=""></option>
|
||||
<option value="CHANGE">{{tr "Change"}}</option>
|
||||
<option value="CARDINALITY">{{tr "Cardinality"}}</option>
|
||||
<option value="PERCENTAGE_CHANGE">{{tr "Percentage"}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="adjust" name="adjust"/>
|
||||
</td>
|
||||
<td id="min_adjust_step_td">
|
||||
</td>
|
||||
<td>
|
||||
<select id="time_format" name="time_format">
|
||||
<option value="start_time">{{tr "Start time"}}</option>
|
||||
<option value="recurrence">{{tr "Recurrence"}}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="time" name="time"/>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#"><i class="fas fa-times-circle remove-tab"></i></a>
|
||||
</td>
|
||||
</tr>
|
@ -0,0 +1,47 @@
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
{{! Copyright 2002-2020, OpenNebula Project, OpenNebula Systems }}
|
||||
{{! }}
|
||||
{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }}
|
||||
{{! not use this file except in compliance with the License. You may obtain }}
|
||||
{{! a copy of the License at }}
|
||||
{{! }}
|
||||
{{! http://www.apache.org/licenses/LICENSE-2.0 }}
|
||||
{{! }}
|
||||
{{! Unless required by applicable law or agreed to in writing, software }}
|
||||
{{! distributed under the License is distributed on an "AS IS" BASIS, }}
|
||||
{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }}
|
||||
{{! See the License for the specific language governing permissions and }}
|
||||
{{! limitations under the License. }}
|
||||
{{! -------------------------------------------------------------------------- }}
|
||||
|
||||
<thead style="background:#dfdfdf">
|
||||
<tr>
|
||||
<th colspan="6">
|
||||
{{tr "Scheduled policies"}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="has-tip" title="{{tr "Type of adjustment."}}
|
||||
{{tr "CHANGE: Add/subtract the given number of VMs."}}
|
||||
{{tr "CARDINALITY: Set the cardinality to the given number."}}
|
||||
{{tr "PERCENTAGE_CHANGE: Add/subtract the given percentage to the current cardinality."}}" style="width:14%">{{tr "Type"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Positive or negative adjustment. Its meaning depends on 'type'"}}
|
||||
{{tr "CHANGE: -2, will subtract 2 VMs from the role"}}
|
||||
{{tr "CARDINALITY: 8, will set cardinality to 8"}}
|
||||
{{tr "PERCENTAGE_CHANGE: 20, will increment cardinality by 20%"}}" style="width:12%">{{tr "Adjust"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Optional parameter for PERCENTAGE_CHANGE adjustment type. If present, the policy will change the cardinality by at least the number of VMs set in this attribute."}}" style="width:9%">{{tr "Min"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Recurrence: Time for recurring adjustments. Time is specified with the Unix cron syntax"}}
|
||||
{{tr "Start time: Exact time for the adjustment"}}" style="width:28%">{{tr "Time format"}}
|
||||
</th>
|
||||
<th class="has-tip" title="{{tr "Time expression depends on the the time format selected"}}
|
||||
{{tr "Recurrence: Time for recurring adjustments. Time is specified with the Unix cron syntax"}}
|
||||
{{tr "Start time: Exact time for the adjustment"}}" style="width:33%">{{tr "Time expression"}}
|
||||
</th>
|
||||
<th style="width:3%"></th>
|
||||
</tr>
|
||||
</thead>
|
@ -221,6 +221,7 @@ define(function(require) {
|
||||
}
|
||||
|
||||
var resourceId = '' + selectedNodes[0];
|
||||
window.ServiceId = resourceId;
|
||||
Sunstone.runAction(that.resourceStr + '.show_to_update', resourceId);
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,14 @@ get '/service/:id' do
|
||||
af_format_response(resp)
|
||||
end
|
||||
|
||||
put '/service/:id' do
|
||||
client = af_build_client
|
||||
|
||||
resp = client.put('/service/' + params[:id], @request_body)
|
||||
|
||||
af_format_response(resp)
|
||||
end
|
||||
|
||||
delete '/service/:id' do
|
||||
client = af_build_client
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user