From a50ad99473699cd28b83bcf627d8e18e52889b52 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 12 Apr 2011 13:24:06 +0200 Subject: [PATCH 1/7] Feature #565: Added template operations in opennebula.js --- src/sunstone/public/js/opennebula.js | 296 +++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index ce40c52746..656758f766 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -1931,5 +1931,301 @@ var OpenNebula = { } }); } + }, + + "Template" : { + "resource" : "TEMPLATE", + + "create" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var data = params.data; + var resource = OpenNebula.Template.resource; + + var request = OpenNebula.Helper.request(resource,"create",data); + + $.ajax({ + url: "/template", + type: "POST", + dataType: "json", + data: JSON.stringify(data), + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + + }, + "addattr" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var name = params.data.name; + var value = params.data.value; + + var method = "update"; + var action = OpenNebula.Helper.action(method, { + "name" : name, + "value" : value + }); + + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,method, [id, name, value]); + + $.ajax({ + url: "/template/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "update" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var name = params.data.name; + var value = params.data.value; + + var method = "update"; + var action = OpenNebula.Helper.action(method, { + "name" : name, + "value" : value + }); + + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,method, [id, name, value]); + + $.ajax({ + url: "/template/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "rmattr" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var name = params.data.name; + var value = params.data.value; + + var method = "rm_attr"; + var action = OpenNebula.Helper.action(method, { + "name" : name + }); + + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,method, [id, name]); + + $.ajax({ + url: "/template/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "publish" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + + var method = "publish"; + var action = OpenNebula.Helper.action(method); + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,method, id); + + $.ajax({ + url: "/template/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function() + { + if (callback) + { + callback(request); + } + }, + error: function(response) + { + if(callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "unpublish" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + + var method = "unpublish"; + var action = OpenNebula.Helper.action(method); + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,method, id); + + $.ajax({ + url: "/template/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function() + { + if (callback) + { + callback(request); + } + }, + error: function(response) + { + if(callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "list" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var timeout = params.timeout || false; + + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,"list"); + + $.ajax({ + url: "/template", + type: "GET", + dataType: "json", + data: {timeout: timeout}, + success: function(response) + { + if (callback) + { + var template_pool = OpenNebula.Helper.pool(resource,response); + callback(request, template_pool); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "show" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + + var resource = OpenNebula.Template.resource; + var request = OpenNebula.Helper.request(resource,"show", id); + + $.ajax({ + url: "/template/" + id, + type: "GET", + dataType: "json", + success: function(response) + { + if (callback) + { + callback(request, response); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + "delete" : function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var resource = OpenNebula.Template.resource; + + var request = OpenNebula.Helper.request(resource,"delete", id); + + $.ajax({ + url: "/template/" + id, + type: "DELETE", + success: function() + { + if (callback) + { + callback(request); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + } } } From 9b63d5c3acd70dc7e0106e2b419f27ad0ce6b468 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 12 Apr 2011 13:41:37 +0200 Subject: [PATCH 2/7] Feature #565: Added template server support. It is untested... --- src/sunstone/models/OpenNebulaJSON.rb | 1 + .../models/OpenNebulaJSON/PoolJSON.rb | 1 + .../models/OpenNebulaJSON/TemplateJSON.rb | 65 +++++++++++++++++++ src/sunstone/models/SunstoneServer.rb | 39 ++++++----- 4 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb diff --git a/src/sunstone/models/OpenNebulaJSON.rb b/src/sunstone/models/OpenNebulaJSON.rb index 9fb45fac7d..cfdb0d162e 100644 --- a/src/sunstone/models/OpenNebulaJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON.rb @@ -20,6 +20,7 @@ include OpenNebula require 'OpenNebulaJSON/ClusterJSON' require 'OpenNebulaJSON/HostJSON' require 'OpenNebulaJSON/ImageJSON' +require 'OpenNebulaJSON/TemplateJSON' require 'OpenNebulaJSON/JSONUtils' require 'OpenNebulaJSON/PoolJSON' require 'OpenNebulaJSON/UserJSON' diff --git a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb index d32241c5d7..578082bdbf 100644 --- a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb @@ -21,6 +21,7 @@ module OpenNebulaJSON class VirtualMachinePoolJSON < OpenNebula::VirtualMachinePool; include JSONUtils; end class VirtualNetworkPoolJSON < OpenNebula::VirtualNetworkPool; include JSONUtils; end class ImagePoolJSON < OpenNebula::ImagePool; include JSONUtils; end + class TemplatePoolJSON < OpenNebula::ImagePool; include JSONUtils; end class ClusterPoolJSON < OpenNebula::ClusterPool; include JSONUtils; end class UserPoolJSON < OpenNebula::UserPool; include JSONUtils; end end diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb new file mode 100644 index 0000000000..9680ad2a8b --- /dev/null +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -0,0 +1,65 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'OpenNebulaJSON/JSONUtils' + +module OpenNebulaJSON + class TemplateJSON < OpenNebula::VirtualMachine + include JSONUtils + + def create(template_json) + template_hash = parse_json(template_json, 'template') + if OpenNebula.is_error?(template_hash) + return template_hash + end + + if template_hash['template_raw'] + template = vm_hash['template_raw'] + else + template = template_to_str(template_hash) + end + + self.allocate(template) + end + + def perform_action(template_json) + action_hash = parse_json(template_json, 'action') + if OpenNebula.is_error?(action_hash) + return action_hash + end + + rc = case action_hash['perform'] + when "publish" then self.publish + when "rm_attr" then self.remove_attr(action_hash['params']) + when "unpublish" then self.unpublish + when "update" then self.update(action_hash['params']) + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + + end + + def update(params=Hash.new) + super(params['name'], params['value']) + end + + def remove_attr(params=Hash.new) + super(params['name']) + end + end +end diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index ea690c33a9..c79854694d 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -68,12 +68,13 @@ class SunstoneServer def get_pool(kind) user_flag = -2 pool = case kind - when "cluster" then ClusterPoolJSON.new(@client) - when "host" then HostPoolJSON.new(@client) - when "image" then ImagePoolJSON.new(@client, user_flag) - when "vm" then VirtualMachinePoolJSON.new(@client, user_flag) - when "vnet" then VirtualNetworkPoolJSON.new(@client, user_flag) - when "user" then UserPoolJSON.new(@client) + when "cluster" then ClusterPoolJSON.new(@client) + when "host" then HostPoolJSON.new(@client) + when "image" then ImagePoolJSON.new(@client, user_flag) + when "template" then TemplatePoolJSON.new(@client, user_flag) + when "vm" then VirtualMachinePoolJSON.new(@client, user_flag) + when "vnet" then VirtualNetworkPoolJSON.new(@client, user_flag) + when "user" then UserPoolJSON.new(@client) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -104,12 +105,13 @@ class SunstoneServer ############################################################################ def create_resource(kind, template) resource = case kind - when "cluster" then ClusterJSON.new(Cluster.build_xml, @client) - when "host" then HostJSON.new(Host.build_xml, @client) - when "image" then ImageJSON.new(Image.build_xml, @client) - when "vm" then VirtualMachineJSON.new(VirtualMachine.build_xml,@client) - when "vnet" then VirtualNetworkJSON.new(VirtualNetwork.build_xml, @client) - when "user" then UserJSON.new(User.build_xml, @client) + when "cluster" then ClusterJSON.new(Cluster.build_xml, @client) + when "host" then HostJSON.new(Host.build_xml, @client) + when "image" then ImageJSON.new(Image.build_xml, @client) + when "template" then TemplateJSON.new(Template.build_xml, @client) + when "vm" then VirtualMachineJSON.new(VirtualMachine.build_xml,@client) + when "vnet" then VirtualNetworkJSON.new(VirtualNetwork.build_xml, @client) + when "user" then UserJSON.new(User.build_xml, @client) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -217,12 +219,13 @@ class SunstoneServer def retrieve_resource(kind, id) resource = case kind - when "cluster" then ClusterJSON.new_with_id(id, @client) - when "host" then HostJSON.new_with_id(id, @client) - when "image" then ImageJSON.new_with_id(id, @client) - when "vm" then VirtualMachineJSON.new_with_id(id, @client) - when "vnet" then VirtualNetworkJSON.new_with_id(id, @client) - when "user" then UserJSON.new_with_id(id, @client) + when "cluster" then ClusterJSON.new_with_id(id, @client) + when "host" then HostJSON.new_with_id(id, @client) + when "image" then ImageJSON.new_with_id(id, @client) + when "template" then TemplateJSON.new_with_id(id, @client) + when "vm" then VirtualMachineJSON.new_with_id(id, @client) + when "vnet" then VirtualNetworkJSON.new_with_id(id, @client) + when "user" then UserJSON.new_with_id(id, @client) else error = Error.new("Error: #{kind} resource not supported") return error From fbbb83fbb53a84539024ae5c95552d5bca4d68a7 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 12 Apr 2011 15:32:15 +0200 Subject: [PATCH 3/7] Feature #565: Fix bugs in the template support. --- src/sunstone/models/OpenNebulaJSON/PoolJSON.rb | 2 +- src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb | 2 +- src/sunstone/public/js/opennebula.js | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb index 578082bdbf..4ed254cbe6 100644 --- a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb @@ -21,7 +21,7 @@ module OpenNebulaJSON class VirtualMachinePoolJSON < OpenNebula::VirtualMachinePool; include JSONUtils; end class VirtualNetworkPoolJSON < OpenNebula::VirtualNetworkPool; include JSONUtils; end class ImagePoolJSON < OpenNebula::ImagePool; include JSONUtils; end - class TemplatePoolJSON < OpenNebula::ImagePool; include JSONUtils; end + class TemplatePoolJSON < OpenNebula::TemplatePool; include JSONUtils; end class ClusterPoolJSON < OpenNebula::ClusterPool; include JSONUtils; end class UserPoolJSON < OpenNebula::UserPool; include JSONUtils; end end diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb index 9680ad2a8b..23801b915b 100644 --- a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -17,7 +17,7 @@ require 'OpenNebulaJSON/JSONUtils' module OpenNebulaJSON - class TemplateJSON < OpenNebula::VirtualMachine + class TemplateJSON < OpenNebula::Template include JSONUtils def create(template_json) diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 656758f766..9895b8df32 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -142,7 +142,14 @@ var OpenNebula = { { return Error('Incorrect Pool'); } - + + + //HACK!!! + if (pool_name == "TEMPLATE_POOL") + { + type = "VMTEMPLATE"; + } + var p_pool = []; if (response[pool_name]) { @@ -1934,7 +1941,7 @@ var OpenNebula = { }, "Template" : { - "resource" : "TEMPLATE", + "resource" : "VMTEMPLATE", "create" : function(params) { @@ -2157,7 +2164,7 @@ var OpenNebula = { { if (callback) { - var template_pool = OpenNebula.Helper.pool(resource,response); + var template_pool = OpenNebula.Helper.pool("TEMPLATE",response); callback(request, template_pool); } }, From 49c78d7bd108e04cf084b11ad332999b799de95c Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 12 Apr 2011 15:33:38 +0200 Subject: [PATCH 4/7] Feature #565: Added templates tab Added the plugin for the templates tab. It is not finished. Handling the creation of templates is still misssing. Added it to the index so it is loaded. --- .../public/js/plugins/templates-tab.js | 499 ++++++++++++++++++ src/sunstone/templates/index.html | 1 + 2 files changed, 500 insertions(+) create mode 100644 src/sunstone/public/js/plugins/templates-tab.js diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js new file mode 100644 index 0000000000..d666c3f95e --- /dev/null +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -0,0 +1,499 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +/*Templates tab plugin*/ + +var templates_tab_content = +'
\ +
\ +
\ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
AllIDUserNameRegistration timePublic
\ +
'; + +var create_template_tmpl = ""; + +var templates_select = ""; +var template_list_json = {}; +var dataTable_templates; + +var template_actions = { + + "Template.create" : { + type: "create", + call: OpenNebula.Template.create, + callback: addTemplateElement, + error: onError, + notify:true + }, + + "Template.create_dialog" : { + type: "custom", + call: popUpCreateTemplateDialog + }, + + "Template.list" : { + type: "list", + call: OpenNebula.Template.list, + callback: updateTemplatesView, + error: onError + }, + + "Template.show" : { + type : "single", + call: OpenNebula.Template.show, + callback: updateTemplateElement, + error: onError + }, + + "Template.showinfo" : { + type: "single", + call: OpenNebula.Template.show, + callback: updateTemplateInfo, + error: onError + }, + + "Template.refresh" : { + type: "custom", + call: function () { + waitingNodes(dataTable_templates); + Sunstone.runAction("Template.list"); + }, + }, + + "Template.autorefresh" : { + type: "custom", + call: function() { + OpenNebula.Template.list({timeout: true, success: updateTemplatesView, error: onError}); + } + }, + + "Template.addattr" : { + type: "multiple", + call: function(obj){ + var id_attr = obj.data.id; + var name = $('#template_attr_name').val(); + var value = $('#template_attr_value').val(); + OpenNebula.Template.addattr( + {data: { + id: id_attr, + name: name, + value: value + }, + success: obj.success, + error: obj.error + }); + }, + callback : function (req) { + Sunstone.runAction("Template.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_templates); }, + error: onError, + notify: true + }, + + "Template.addattr_dialog" : { + type: "custom", + call: popUpTemplateAddattrDialog + }, + + "Template.updateattr_dialog" : { + type: "custom", + call: popUpTemplateAddattrDialog + }, + + "Template.rmattr" : { + type: "multiple", + call: function(obj){ + var id_attr = obj.data.id; + var name = $('#template_attr_name').val(); + OpenNebula.Template.rmattr( + {data: { + id: id_attr, + name: name + }, + success: obj.success, + error: obj.error + }); + }, + callback: function (req) { + Sunstone.runAction("Template.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_templates); }, + error: onError, + notify: true + }, + + "Template.rmattr_dialog" : { + type: "custom", + call: popUpTemplateRmattrDialog, + }, + + "Template.publish" : { + type: "multiple", + call: OpenNebula.Template.publish, + callback: function (req) { + Sunstone.runAction("Template.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_templates); }, + error: onError, + notify: true + }, + + "Template.unpublish" : { + type: "multiple", + call: OpenNebula.Template.unpublish, + callback: function (req) { + Sunstone.runAction("Template.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_templates); }, + error: onError, + notify: true + }, + + "Template.delete" : { + type: "multiple", + call: OpenNebula.Template.delete, + callback: deleteTemplateElement, + elements: function() { return getSelectedNodes(dataTable_templates); }, + error: onError, + notify: true + } +} + + +var template_buttons = { + "Template.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + "Template.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition: True + }, + "Template.addattr_dialog" : { + type: "action", + text: "Add attribute", + condition: True + }, + "Template.updateattr_dialog" : { + type: "action", + text: "Update attribute", + condition: True + }, + "Template.rmattr_dialog" : { + type: "action", + text: "Remove attribute", + condition: True + }, + "action_list" : { + type: "select", + condition: True, + actions: { + "Template.publish" : { + type: "action", + text: "Publish", + condition: True + }, + "Template.unpublish" : { + type: "action", + text: "Unpublish", + condition: True + }, + } + }, + "Template.delete" : { + type: "action", + text: "Delete", + condition: True + } +} + +var template_info_panel = { + "template_info_tab" : { + title: "Template information", + content: "" + } +} + +var templates_tab = { + title: "Templates", + content: templates_tab_content, + buttons: template_buttons, + condition: True +} + +Sunstone.addActions(template_actions); +Sunstone.addMainTab('templates_tab',templates_tab); +Sunstone.addInfoPanel('template_info_panel',template_info_panel); + +// Returns an array containing the values of the template_json and ready +// to be inserted in the dataTable +function templateElementArray(template_json){ + var template = template_json.VMTEMPLATE; + return [ + '', + template.ID, + template.USERNAME ? template.USERNAME : getUserName(template.UID), + template.NAME, + pretty_time(template.REGTIME), + parseInt(template.PUBLIC) ? "yes" : "no" + ]; +} + +// Set up the listener on the table TDs to show the info panel +function templateInfoListener(){ + + $('#tbodytemplates tr').live("click",function(e){ + if ($(e.target).is('input')) {return true;} + popDialogLoading(); + var aData = dataTable_templates.fnGetData(this); + var id = $(aData[0]).val(); + Sunstone.runAction("Template.showinfo",id); + return false; + }); +} + +//Updates the select input field with an option for each template +function updateTemplateSelect(){ + templates_select = makeSelectOptions(dataTable_templates,1,3,5,"No"); + + //update static selectors: + +} + +// Callback to update an element in the dataTable +function updateTemplateElement(request, template_json){ + var id = template_json.VMTEMPLATE.ID; + var element = templateElementArray(template_json); + updateSingleElement(element,dataTable_templates,'#template_'+id); + updateTemplateSelect(); +} + +// Callback to remove an element from the dataTable +function deleteTemplateElement(req){ + deleteElement(dataTable_templates,'#template_'+req.request.data); + updateTemplateSelect(); +} + +// Callback to add a template element +function addTemplateElement(request, template_json){ + var element = templateElementArray(template_json); + addElement(element,dataTable_templates); + //NOTE that the select is not updated because newly added templates + //are not public +} + +// Callback to refresh the list of templates +function updateTemplatesView(request, templates_list){ + template_list_json = templates_list; + var template_list_array = []; + $.each(template_list_json,function(){ + template_list_array.push(templateElementArray(this)); + }); + + updateView(template_list_array,dataTable_templates); + updateTemplateSelect(); + updateDashboard("templates",template_list_json); + +} + +// Prepare the dialog to add/remove/update template attributes +function setupTemplateAttributesDialogs(){ + + //Append to DOM + $('div#dialogs').append('
'); + + //Put HTML in place + $('#template_attributes_dialog').html( + '
\ +
\ +
\ +
\ +
\ + \ + \ +
\ +
\ + \ + \ +
\ +
\ + \ + \ +
\ +
\ +
'); + + $('#template_attributes_dialog').dialog({ + autoOpen:false, + width:400, + modal:true, + height:220, + resizable:false, + }); + + $('#template_attributes_dialog button').button(); + + //Upcase variable names + $('#template_attr_name').keyup(function(){ + $(this).val($(this).val().toUpperCase()); + }); + + $('#template_attributes_dialog #template_attr_proceed').click(function(){ + $('#template_attributes_dialog').dialog('close'); + }); + + $('#template_attributes_dialog #template_attr_cancel').click(function(){ + $('#template_attributes_dialog').dialog('close'); + return false; + }); + +} + +// Popup a dialog to add/update an attribute +function popUpTemplateAddattrDialog(){ + + //Show value field and label + $('#template_attr_value').show(); + $('#template_attr_value').prev().show(); + var desc = "Please write the name and value of the attribute. It will be added or updated in all selected templates:"; + $('#template_attr_proceed').val("Template.addattr"); + $('#template_attr_action_desc').html(desc); + $('#template_attributes_dialog').dialog('open'); + return false; +} + +// Popup a dialog to remove an attribute +function popUpTemplateRmattrDialog(){ + + //Hide value field and label + $('#template_attr_value').hide(); + $('#template_attr_value').prev().hide(); + var desc = "Please type the attribute you want to remove:"; + $('#template_attr_proceed').val("Template.rmattr"); + $('#template_attr_action_desc').html(desc); + $('#template_attributes_dialog').dialog('open'); + return false; +} + +// Callback to update the information panel tabs and pop it up +function updateTemplateInfo(request,template){ + var template_info = template.VMTEMPLATE; + var info_tab = { + title: "Template information", + content: + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
Template "'+template_info.NAME+'" information
ID'+template_info.ID+'
Name'+template_info.NAME+'
Register time'+pretty_time(template_info.REGTIME)+'
Public'+(parseInt(template_info.PUBLIC) ? "yes" : "no")+'
\ + \ + '+ + prettyPrintJSON(template_info.TEMPLATE)+ + '
Template
' + } + + + Sunstone.updateInfoPanelTab("template_info_panel","template_info_tab",info_tab); + + Sunstone.popUpInfoPanel("template_info_panel"); + +} + +// Prepare the template creation dialog +function setupCreateTemplateDialog(){ + + +} + +function popUpCreateTemplateDialog(){ + $('#create_template_dialog').dialog('open'); +} + +// Set the autorefresh interval for the datatable +function setTemplateAutorefresh() { + setInterval(function(){ + var checked = $('input:checked',dataTable_templates.fnGetNodes()); + var filter = $("#datatable_templates_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("Template.autorefresh"); + } + },INTERVAL+someTime()); +} + +//The DOM is ready at this point +$(document).ready(function(){ + + dataTable_templates = $("#datatable_templates").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,3] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2,3] } + ] + }); + + dataTable_templates.fnClearTable(); + addElement([ + spinner, + '','','','',''],dataTable_templates); + Sunstone.runAction("Template.list"); + + setupCreateTemplateDialog(); + setupTemplateAttributesDialogs(); + setTemplateAutorefresh(); + + initCheckAllBoxes(dataTable_templates); + tableCheckboxesListener(dataTable_templates); + templateInfoListener(); + +}) diff --git a/src/sunstone/templates/index.html b/src/sunstone/templates/index.html index aa451a553f..ca0864e08f 100644 --- a/src/sunstone/templates/index.html +++ b/src/sunstone/templates/index.html @@ -28,6 +28,7 @@ + From 7bbf3ae933934406ae5bf7b2928e2bef538ccfab Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Tue, 12 Apr 2011 17:23:29 +0200 Subject: [PATCH 5/7] Feature #565: VM creation - template creation Finished converting VM creation into template creation. Added a dialog to create a VM given a name and a template. Modified the server to support this. --- .../models/OpenNebulaJSON/TemplateJSON.rb | 4 +- .../OpenNebulaJSON/VirtualMachineJSON.rb | 8 +- .../public/js/plugins/templates-tab.js | 1221 +++++++++++++++- src/sunstone/public/js/plugins/vms-tab.js | 1238 +---------------- src/sunstone/public/js/sunstone-util.js | 2 + src/sunstone/public/js/sunstone.js | 4 + src/sunstone/templates/index.html | 2 +- 7 files changed, 1267 insertions(+), 1212 deletions(-) diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb index 23801b915b..7ce484f82d 100644 --- a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -21,13 +21,13 @@ module OpenNebulaJSON include JSONUtils def create(template_json) - template_hash = parse_json(template_json, 'template') + template_hash = parse_json(template_json, 'vmtemplate') if OpenNebula.is_error?(template_hash) return template_hash end if template_hash['template_raw'] - template = vm_hash['template_raw'] + template = template_hash['template_raw'] else template = template_to_str(template_hash) end diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index 55f6cada51..7b04a7b923 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -28,6 +28,12 @@ module OpenNebulaJSON if vm_hash['vm_raw'] template = vm_hash['vm_raw'] + elsif vm_hash['template_id'] + template_id = vm_hash['template_id'] + + template = "TEMPLATE_ID = #{template_id}" + template << "\nNAME = #{vm_hash[:vm_name]}" if vm_hash[:vm_name] + else template = template_to_str(vm_hash) end @@ -55,7 +61,7 @@ module OpenNebulaJSON when "restart" then self.restart when "saveas" then self.save_as(action_hash['params']) when "shutdown" then self.shutdown - when "resubmit" then self.resubmit + when "resubmit" then self.resubmit else error_msg = "#{action_hash['perform']} action not " << " available for this resource" diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index d666c3f95e..cb558aa5c7 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -36,7 +36,459 @@ var templates_tab_content = \ '; -var create_template_tmpl = ""; +var create_template_tmpl = '
\ + \ +
\ +
\ +
\ + \ +

Fields marked with are mandatory
\ + Fold / Unfold all sections

\ +
\ +\ + \ +
\ +
\ +

Capacity options

\ +
\ +
Capacity\ +
\ + \ + \ +
Name that the VM will get for description purposes. If NAME is not supplied a name generated by one will be in the form of one-<VID>.
\ +
\ +
\ + \ + \ +
Amount of RAM required for the VM, in Megabytes.
\ +
\ +
\ + \ + \ +
Percentage of CPU divided by 100 required for the Virtual Machine. Half a processor is written 0.5.
\ +
\ +
\ + \ + \ +
Number of virtual cpus. This value is optional, the default hypervisor behavior is used, usually one virtual CPU.
\ +
\ +
\ +
\ + \ +
\ +
\ +

Boot/OS options

\ +
\ +
OS and Boot options\ +
\ + \ + \ +
CPU architecture to virtualization
\ +
\ + \ +
\ + \ + \ +
Select boot method
\ +
\ +
\ + \ + \ +
Path to the OS kernel to boot the image
\ +
\ +
\ + \ + \ +
Path to the initrd image
\ +
\ +
\ + \ + \ +
Device to be mounted as root
\ +
\ +
\ + \ + \ +
Arguments for the booting kernel
\ +
\ +
\ + \ + \ +
Path to the bootloader executable
\ +
\ +
\ + \ + \ +
Boot device type
\ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add disks/images

\ +
\ +
Disks\ +
\ + \ + Disk\ + \ + Image\ + \ +
\ +
\ +
\ + \ + \ +
Name of the image to use
\ +
\ +
\ + \ + \ +
Type of disk device to emulate: ide, scsi
\ +
\ +
\ + \ + \ +
Device to map image disk. If set, it will overwrite the default device mapping
\ +
\ +
\ + \ + \ +
Specific image mapping driver. KVM: raw, qcow2. Xen:tap:aio:, file:. VMware unsupported
\ +
\ +
\ + \ + \ +
Disk type
\ +
\ +
\ + \ + \ +
Disk file location path or URL
\ +
\ +
\ + \ + \ + \ +
Disk file location path or URL. Mandatory for swap, fs and block images
\ +
\ +
\ + \ + \ + \ +
Filesystem type for the fs images
\ +
\ +
\ + \ + \ +
Clone this image
\ +
\ +
\ + \ + \ +
Save this image after shutting down the VM
\ +
\ +
\ + \ + \ +
Mount image as read-only
\ +
\ +
\ + \ + \ +
\ + \ + \ +
\ +
\ +
\ +
\ +\ + \ +
\ +
\ +

Setup Networks

\ +
\ +
Network\ +
\ + \ + Predefined\ + \ + Manual\ + \ + \ +
\ +
\ +
\ + \ + \ +
Name of the network to attach this device
\ +
\ +
\ + \ + \ +
Request an specific IP from the Network
\ +
\ +
\ + \ + \ +
HW address associated with the network interface
\ +
\ +
\ + \ + \ +
Name of the bridge the network device is going to be attached to
\ +
\ +
\ + \ + \ +
Name for the tun device created for the VM
\ +
\ +
\ + \ + \ +
Name of a shell script to be executed after creating the tun device for the VM
\ +
\ +
\ + \ + \ +
Hardware that will emulate this network interface. With Xen this is the type attribute of the vif.
\ +
\ +
\ + \ + \ +
\ + \ + \ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add inputs

\ +
\ +
Inputs\ +
\ + \ + \ +
\ +
\ +
\ + \ + \ +
\ +
\ +
\ + \ + \ +
\ + \ + \ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add Graphics

\ +
\ +
Graphics\ +
\ + \ + \ +
\ +
\ +
\ + \ + \ +
IP to listen on
\ +
\ +
\ + \ + \ +
Port for the VNC server
\ +
\ +
\ + \ + \ +
Password for the VNC server
\ +
\ +
\ + \ + \ +
Keyboard configuration locale to use in the VNC display
\ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add context variables

\ +
\ +
Context\ +
\ + \ + \ +
Name for the context variable
\ +
\ +
\ + \ + \ +
Value of the context variable
\ +
\ +
\ + \ + \ +
\ + \ + \ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add placement options

\ +
\ +
Placement\ +
\ + \ + \ +
Boolean expression that rules out provisioning hosts from list of machines suitable to run this VM
\ +
\ +
\ + \ + \ +
This field sets which attribute will be used to sort the suitable hosts for this VM. Basically, it defines which hosts are more suitable than others
\ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ +

Add Hypervisor raw options

\ +
\ +
Raw\ + \ +
\ + \ + \ + \ +
Raw data to be passed directly to the hypervisor
\ +
\ +
\ +
\ +\ +\ + \ +
\ +
\ + \ + \ +
\ +
\ +
\ +
\ +
\ +
\ +

Write the Virtual Machine template here

\ +
\ + \ +
\ +
\ +
\ +
\ + \ + \ +
\ +
\ +
\ +
\ +
'; var templates_select = ""; var template_list_json = {}; @@ -287,7 +739,7 @@ function updateTemplateSelect(){ templates_select = makeSelectOptions(dataTable_templates,1,3,5,"No"); //update static selectors: - + $('#create_vm_dialog #template_id').html(templates_select); } // Callback to update an element in the dataTable @@ -447,7 +899,770 @@ function updateTemplateInfo(request,template){ // Prepare the template creation dialog function setupCreateTemplateDialog(){ - + //Helper functions for the dialog operations + + // Called when changing tabs. Since we use the same form for both + // KVM, XEN and others we need to do some operation to update it + var vmTabChange = function(event,ui){ + // ui.tab // anchor element of the selected (clicked) tab + // ui.panel // element, that contains the selected/clicked tab contents + // ui.index // zero-based index of the selected (clicked) tab + switch(ui.index){ + case 0: + enable_kvm(); + break; + case 1: + enable_xen(); + break; + case 2: + break; + case 3: + break; + } + } + + //Using kvm wizard. Updates mandatory tag, optional tags, disable + //XEN-only (and others) items, enables KVM items + var enable_kvm = function(){ + man_class="kvm"; + opt_class="kvm_opt"; + $(xen_items).attr("disabled","disabled"); + $(kvm_items).removeAttr("disabled"); + //$(items+':disabled').hide(); + + + //KVM particularities: + // * Add no_type option for disks + // * Add driver default option for boot and select it - hide some fields + // * Set the raw type to kvm + // * Show the inputs section + $('div#disks select#TYPE option:selected').removeAttr("selected"); + $('div#disks select#TYPE').prepend( + ''); + $('div#disks select#TYPE option#no_type').attr("selected","selected"); + + $('select#boot_method option').removeAttr("selected"); + $('select#boot_method option#no_boot').html("Driver default"); + $('select#boot_method option').removeAttr("selected"); + $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); + + $('div#disks select#BUS').append( + ''); + + + + $('input#TYPE', section_raw).val("kvm"); + + $(section_inputs).show(); + }; + + // Using XEN wizard. Update mandatory and optional classes, disable + // KVM-only (and other) items, enable XEN fields... + enable_xen = function(){ + man_class="xen"; + opt_class="xen_opt"; + $(kvm_items).attr("disabled","disabled"); + $(kvm_items).css("background",""); + $(xen_items).removeAttr("disabled"); + //$(items+':disabled').hide(); + + + // XEN particularities: + // * Remove no_type option from disks + // * Remove driver default boot method + // * Set the raw section to XEN + // * Hide the inputs section + $('div#disks select#TYPE option#no_type').remove(); + + $('select#boot_method option:selected').removeAttr("selected"); + $('select#boot_method option#no_boot').html("Please choose"); + $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); + + $('div#disks select#BUS option#virtio').remove(); + + $('input#TYPE', section_raw).val("xen"); + $(section_inputs).hide(); //not present for xen + }; + + //This function checks that all mandatory items within a section + //have some value. Returns true if so, false if not. + var mandatory_filter = function(context){ + var man_items = "."+man_class; + + //find enabled mandatory items in this context + man_items = $(man_items+' input:visible, '+man_items+' select:visible',context); + var r = true; + + //we fail it the item is enabled and has no value + $.each(man_items,function(){ + if ($(this).parents(".vm_param").attr("disabled") || + !($(this).val().length)) { + r = false; + return false; + }; + }); + return r; + + }; + + //Adds an option element to a multiple select box. Before doing so, + //it checks that the desired filter is passed + var box_add_element = function(context,box_tag,filter){ + var value=""; + var params= $('.vm_param',context); + var inputs= $('input:enabled',params); + var selects = $('select:enabled',params); + var fields = $.merge(inputs,selects); + + //are fields passing the filter? + var result = filter(); + if (!result) { + notifyError("There are mandatory parameters missing in this section"); + return false; + } + + value={}; + + //With each enabled field we form a JSON object + var id = null; + $.each(fields,function(){ + if (!($(this).parents(".vm_param").attr("disabled")) && + $(this).val().length){ + //Pick up parent's ID if we do not have one + id = $(this).attr('id').length ? $(this).attr('id') : $(this).parent().attr('id'); + value[id] = $(this).val(); + } + }); + var value_string = JSON.stringify(value); + var option= ''; + $('select'+box_tag,context).append(option); + return false; + }; + + //Removes selected elements from a multiple select box + var box_remove_element = function(section_tag,box_tag){ + var context = $(section_tag); + $('select'+box_tag+' :selected',context).remove(); + return false; + }; + + //Given the JSON of a VM template (or of a section of it), it crawls + //the fields of certain section (context) and add their name and + //values to the template JSON. + var addSectionJSON = function(template_json,context){ + var params= $('.vm_param',context); + var inputs= $('input:enabled',params); + var selects = $('select:enabled',params); + var fields = $.merge(inputs,selects); + + fields.each(function(){ + if (!($(this).parents(".vm_param").attr("disabled"))){ //if ! disabled + if ($(this).val().length){ //if has a length + template_json[$(this).attr('id')]=$(this).val(); + } + } + }); + } + + // Given an array (usually empty), a section (context) and a tag for + // a multiple select in that section, it adds the contents of the + // box as objects in the array. + // TODO: Make it return a new array? + var addBoxJSON = function(array,context,box_tag){ + $('select'+box_tag+' option',context).each(function(){ + array.push( JSON.parse($(this).val()) ); + }); + } + + //Given an object, removes those elements which are empty + //Used to clean up a template JSON before submitting + //it to opennebula.js + var removeEmptyObjects = function(obj){ + for (elem in obj){ + var remove = false; + var value = obj[elem]; + if (value instanceof Array) + { + 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; + } + + //Toggles the icon when a section is folded/unfolded + var iconToggle = function(){ + $('.icon_right').toggle( + function(e){ + $('span',e.currentTarget).removeClass("ui-icon-plusthick"); + $('span',e.currentTarget).addClass("ui-icon-minusthick"); + },function(e){ + $('span',e.currentTarget).removeClass("ui-icon-minusthick"); + $('span',e.currentTarget).addClass("ui-icon-plusthick"); + }); + } + + // Set ups the capacity section + var capacity_setup = function(){ + //Actually there is nothing to set up, but it used to be + //possible to hide it like others + /* + $('fieldset',section_capacity).hide(); + $('#add_capacity',section_capacity).click(function(){ + $('fieldset',section_capacity).toggle(); + return false; + }); + */ + + } + + //Sets up the OS_BOOT section + var os_boot_setup = function(){ + $('fieldset',section_os_boot).hide(); + $('.bootloader, .kernel',section_os_boot).hide(); + + $('#add_os_boot_opts',section_os_boot).click(function(){ + $('fieldset',section_os_boot).toggle(); + return false; + }); + + + //Chrome workaround + $('#boot_method').change(function(){ + $(this).trigger("click"); + }); + + //Depending on the boot method we enable/disable some options + $('#boot_method',section_os_boot).click(function(){ + select = $(this).val(); + switch (select) + { + case "kernel": + $('.bootloader',section_os_boot).hide(); + $('.bootloader',section_os_boot).attr("disabled","disabled"); + $('.kernel',section_os_boot).show(); + $('.kernel',section_os_boot).removeAttr("disabled"); + break; + case "bootloader": + $('.kernel',section_os_boot).hide(); + $('.kernel',section_os_boot).attr("disabled","disabled"); + $('.bootloader',section_os_boot).show(); + $('.bootloader',section_os_boot).removeAttr("disabled"); + break; + default: + $('.kernel, .bootloader',section_os_boot).hide(); + $('.kernel, .bootloader',section_os_boot).attr("disabled","disabled"); + $('.kernel input, .bootloader input',section_os_boot).val(""); + }; + }); + }; + + // Sets up the disk section + var disks_setup = function(){ + + $('fieldset',section_disks).hide(); + $('.vm_param', section_disks).hide(); + //$('#image_vs_disk',section_disks).show(); + + $('#add_disks', section_disks).click(function(){ + $('fieldset',section_disks).toggle(); + return false; + }); + + //Depending on adding a disk or a image we need to show/hide + //different options and make then mandatory or not + $('#image_vs_disk input',section_disks).click(function(){ + //$('fieldset',section_disks).show(); + $('.vm_param', section_disks).show(); + var select = $('#image_vs_disk :checked',section_disks).val(); + switch (select) + { + case "disk": + $('.add_image',section_disks).hide(); + $('.add_image',section_disks).attr("disabled","disabled"); + $('.add_disk',section_disks).show(); + $('.add_disk',section_disks).removeAttr("disabled"); + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + break; + case "image": + $('.add_disk',section_disks).hide(); + $('.add_disk',section_disks).attr("disabled","disabled"); + $('.add_image',section_disks).show(); + $('.add_image',section_disks).removeAttr("disabled"); + $('#TARGET',section_disks).parent().removeClass(man_class); + $('#TARGET',section_disks).parent().addClass(opt_class); + break; + } + $('#SIZE',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + $('#FORMAT',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + $('#TYPE :selected',section_disks).removeAttr("selected"); + }); + + //Chrome workaround + $('select#TYPE',section_disks).change(function(){ + $(this).trigger('click'); + }); + + //Depending on the type of disk we need to show/hide + //different options and make then mandatory or not + $('select#TYPE',section_disks).click(function(){ + var select = $(this).val(); + switch (select) { + //size,format,target + case "swap": + //size mandatory + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(opt_class); + $('#SIZE',section_disks).parent().addClass(man_class); + + //target optional + $('#TARGET',section_disks).parent().removeClass(man_class); + $('#TARGET',section_disks).parent().addClass(opt_class); + + //format hidden + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + break; + case "fs": + //size mandatory + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(opt_class); + $('#SIZE',section_disks).parent().addClass(man_class); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format mandatory + $('#FORMAT',section_disks).parent().show(); + $('#FORMAT',section_disks).parent().removeAttr("disabled"); + $('#FORMAT',section_disks).parent().removeClass(opt_class); + $('#FORMAT',section_disks).parent().addClass(man_class); + + break; + case "block": + //size shown and optional + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(man_class); + $('#SIZE',section_disks).parent().addClass(opt_class); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format hidden + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + break; + case "floppy": + case "disk": + case "cdrom": + default: + //size hidden + $('#SIZE',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format optional + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + } + }); + + //Our filter for the disks section fields is the mandatory + //filter for this section + var diskFilter = function(){ + return mandatory_filter(section_disks); + }; + + $('#add_disk_button',section_disks).click(function(){ + box_add_element(section_disks,'#disks_box',diskFilter); + return false; + }); + $('#remove_disk_button',section_disks).click(function(){ + box_remove_element(section_disks,'#disks_box'); + return false; + }); + }; + + // Sets up the network section + var networks_setup = function(){ + + $('.vm_param',section_networks).hide(); + $('fieldset',section_networks).hide(); + + $('#add_networks',section_networks).click(function(){ + $('fieldset',section_networks).toggle(); + return false; + }); + + //Depending on adding predefined network or not we show/hide + //some fields + $('#network_vs_niccfg input',section_networks).click(function(){ + + select = $('#network_vs_niccfg :checked',section_networks).val(); + switch (select) { + case "network": + $('.niccfg',section_networks).hide(); + $('.niccfg',section_networks).attr("disabled","disabled"); + $('.network',section_networks).show(); + $('.network',section_networks).removeAttr("disabled"); + break; + case "niccfg": + $('.network',section_networks).hide(); + $('.network',section_networks).attr("disabled","disabled"); + $('.niccfg',section_networks).show(); + $('.niccfg',section_networks).removeAttr("disabled"); + break; + } + }); + + //The filter to add a new network checks that we have selected a + //network, or that the ip or mac are set + //TODO: Improve this check + var nicFilter = function(){ + return mandatory_filter(section_networks); + }; + + $('#add_nic_button',section_networks).click(function(){ + box_add_element(section_networks,'#nics_box',nicFilter); + return false; + }); + $('#remove_nic_button',section_networks).click(function(){ + box_remove_element(section_networks,'#nics_box'); + return false; + }); + + }; + + //Sets up the input section - basicly enabling adding and removing from box + var inputs_setup = function() { + $('fieldset',section_inputs).hide(); + + $('#add_inputs',section_inputs).click(function(){ + $('fieldset',section_inputs).toggle(); + return false; + }); + + $('#add_input_button',section_inputs).click(function(){ + //no filter + box_add_element(section_inputs,'#inputs_box',True); + return false; + }); + $('#remove_input_button',section_inputs).click(function(){ + box_remove_element(section_inputs,'#inputs_box'); + return false; + }); + }; + + //Set up the graphics section + var graphics_setup = function(){ + $('fieldset',section_graphics).hide(); + $('.vm_param',section_graphics).hide(); + $('select#TYPE',section_graphics).parent().show(); + + $('#add_graphics',section_graphics).click(function(){ + $('fieldset',section_graphics).toggle(); + return false; + }); + + //Chrome workaround + $('select#TYPE',section_graphics).change(function(){ + $(this).trigger("click"); + }); + $('select#TYPE',section_graphics).click(function(){ + g_type = $(this).val(); + switch (g_type) { + case "vnc": + $('#LISTEN',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().show(); + $('#PASSWD',section_graphics).parent().show(); + $('#KEYMAP',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().removeAttr("disabled"); + $('#PASSWD',section_graphics).parent().removeAttr("disabled"); + $('#KEYMAP',section_graphics).parent().removeAttr("disabled"); + break; + case "sdl": + $('#LISTEN',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().hide(); + $('#PASSWD',section_graphics).parent().hide(); + $('#KEYMAP',section_graphics).parent().hide(); + $('#PORT',section_graphics).parent().attr("disabled","disabled"); + $('#PASSWD',section_graphics).parent().attr("disabled","disabled"); + $('#KEYMAP',section_graphics).parent().attr("disabled","disabled"); + break; + default: + $('#LISTEN',section_graphics).parent().hide(); + $('#PORT',section_graphics).parent().hide(); + $('#PASSWD',section_graphics).parent().hide(); + $('#KEYMAP',section_graphics).parent().hide(); + + } + }); + + } + + //Set up the context section - TODO: Apply improvements here... + var context_setup = function(){ + $('fieldset',section_context).hide(); + + $('#add_context',section_context).click(function(){ + $('fieldset',section_context).toggle(); + return false; + }); + + $('#add_context_button', section_context).click(function(){ + var name = $('#var_name',section_context).val(); + var value = $('#var_value',section_context).val(); + if (!name.length || !value.length) { + notifyError("Context variable name and value must be filled in"); + return false; + } + option= ''; + $('select#context_box',section_context).append(option); + return false; + }); + + $('#remove_context_button', section_context).click(function(){ + box_remove_element(section_context,'#context_box'); + return false; + }); + + + }; + + // Set up the placement section + var placement_setup = function(){ + $('fieldset',section_placement).hide(); + + $('#add_placement',section_placement).click(function(){ + $('fieldset',section_placement).toggle(); + return false; + }); + + }; + + // Set up the raw section + var raw_setup = function(){ + $('fieldset',section_raw).hide(); + + $('#add_raw',section_raw).click(function(){ + $('fieldset',section_raw).toggle(); + return false; + }); + }; + + //***CREATE VM DIALOG MAIN BODY*** + + $('div#dialogs').append('
'); + //Insert HTML in place + $('#create_template_dialog').html(create_template_tmpl); + //Enable tabs + $('#template_create_tabs').tabs({ + select:vmTabChange + }); + + //Prepare jquery dialog + var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window + $('#create_template_dialog').dialog({ + autoOpen: false, + modal: true, + width: 700, + height: height + }); + + // Enhace buttons + $('#create_template_dialog button').button(); + // Setup tips200 + setupTips($('#create_template_dialog')); + + //Enable different icon for folded/unfolded categories + iconToggle(); //toogle +/- buttons + + //Sections, used to stay within their scope + var section_capacity = $('#capacity'); + var section_os_boot = $('#os_boot_opts'); + var section_disks = $('#disks'); + var section_networks = $('#networks'); + var section_inputs = $('#inputs'); + var section_graphics = $('#graphics'); + var section_context = $('#context'); + var section_placement = $('#placement'); + var section_raw = $('#raw'); + + //Different selector for items of kvm and xen (mandatory and optional) + var items = '.vm_section input,.vm_section select'; + var kvm_man_items = '.kvm input,.kvm select'; + var kvm_opt_items = '.kvm_opt input, .kvm_opt select'; + var kvm_items = kvm_man_items +','+kvm_opt_items; + var xen_man_items = '.xen input,.xen select'; + var xen_opt_items = '.xen_opt input, .xen_opt select'; + var xen_items = xen_man_items +','+ xen_opt_items; + + //Starting template type, optional items class and mandatory items class + var templ_type = "kvm"; + var opt_class=".kvm_opt"; + var man_class=".kvm"; + + enable_kvm(); //enable all kvm options + + //Fold/unfold all sections button + $('#fold_unfold_vm_params').toggle( + function(){ + $('.vm_section fieldset').show(); + return false; + }, + function(){ + $('.vm_section fieldset').hide(); + $('.vm_section fieldset').first().show(); //Show capacity opts + return false; + }); + + //initialise all sections + capacity_setup(); + os_boot_setup(); + disks_setup(); + networks_setup(); + inputs_setup(); + graphics_setup(); + context_setup(); + placement_setup(); + raw_setup(); + + //Process form + $('button#create_template_form_easy').click(function(){ + //validate form + + var vm_json = {}; + + //process capacity options + var scope = section_capacity; + + if (!mandatory_filter(scope)){ + notifyError("There are mandatory fields missing in the capacity section"); + return false; + }; + addSectionJSON(vm_json,scope); + + //process os_boot_opts + scope= section_os_boot; + switch (templ_type){ + case "xen": + boot_method = $('#boot_method option:selected',scope).val(); + if (!boot_method.length){ + notifyError("Xen templates must specify a boot method"); + return false;} + }; + + if (!mandatory_filter(scope)){ + notifyError("There are mandatory fields missing in the OS Boot options section"); + return false; + }; + vm_json["OS"] = {}; + addSectionJSON(vm_json["OS"],scope); + + //process disks -> fetch from box + scope = section_disks; + vm_json["DISK"] = []; + addBoxJSON(vm_json["DISK"],scope,'#disks_box'); + + //process nics -> fetch from box + scope = section_networks; + vm_json["NIC"] = []; + addBoxJSON(vm_json["NIC"],scope,'#nics_box'); + + //process inputs -> fetch from box + scope = section_inputs; + vm_json["INPUT"] = []; + addBoxJSON(vm_json["INPUT"],scope,'#inputs_box'); + + //process graphics -> fetch fields with value + scope = section_graphics; + vm_json["GRAPHICS"] = {}; + addSectionJSON(vm_json["GRAPHICS"],scope); + + //context + scope = section_context; + var context = $('#CONTEXT',scope).val(); + vm_json["CONTEXT"] = {}; + $('#context_box option',scope).each(function(){ + name = $(this).attr("name"); + value = $(this).val(); + vm_json["CONTEXT"][name]=value; + }); + + //placement -> fetch with value + scope = section_placement; + addSectionJSON(vm_json,scope); + + //raw -> if value set type to driver and fetch + scope = section_raw; + vm_json["RAW"] = {}; + addSectionJSON(vm_json["RAW"],scope); + + // remove empty elements + vm_json = removeEmptyObjects(vm_json); + + //wrap it in the "vmtemplate" object + vm_json = {vmtemplate: vm_json}; + + + Sunstone.runAction("Template.create",vm_json); + + $('#create_template_dialog').dialog('close'); + return false; + }); + + //Handle manual forms + $('button#create_template_form_manual').click(function(){ + var template = $('#textarea_vm_template').val(); + + //wrap it in the "vm" object + template = {"vmtemplate": {"template_raw": template}}; + + Sunstone.runAction("Template.create",template); + $('#create_template_dialog').dialog('close'); + return false; + }); + + //Reset form - empty boxes + $('button#reset_vm_form').click(function(){ + $('select#disks_box option',section_disks).remove(); + $('select#nics_box option',section_networks).remove(); + $('select#inputs_box option',section_inputs).remove(); + return true; + }); + + } diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js index 9fbbb65bc5..d42e254b12 100644 --- a/src/sunstone/public/js/plugins/vms-tab.js +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -39,460 +39,23 @@ var vms_tab_content = \ '; -var create_vm_tmpl = -'
\ - \ -
\ -
\ -
\ - \ -

Fields marked with are mandatory
\ - Fold / Unfold all sections

\ -
\ -\ - \ -
\ -
\ -

Capacity options

\ -
\ -
Capacity\ -
\ - \ - \ -
Name that the VM will get for description purposes. If NAME is not supplied a name generated by one will be in the form of one-<VID>.
\ -
\ -
\ - \ - \ -
Amount of RAM required for the VM, in Megabytes.
\ -
\ -
\ - \ - \ -
Percentage of CPU divided by 100 required for the Virtual Machine. Half a processor is written 0.5.
\ -
\ -
\ - \ - \ -
Number of virtual cpus. This value is optional, the default hypervisor behavior is used, usually one virtual CPU.
\ -
\ -
\ -
\ - \ -
\ -
\ -

Boot/OS options

\ -
\ -
OS and Boot options\ -
\ - \ - \ -
CPU architecture to virtualization
\ -
\ - \ -
\ - \ - \ -
Select boot method
\ -
\ -
\ - \ - \ -
Path to the OS kernel to boot the image
\ -
\ -
\ - \ - \ -
Path to the initrd image
\ -
\ -
\ - \ - \ -
Device to be mounted as root
\ -
\ -
\ - \ - \ -
Arguments for the booting kernel
\ -
\ -
\ - \ - \ -
Path to the bootloader executable
\ -
\ -
\ - \ - \ -
Boot device type
\ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add disks/images

\ -
\ -
Disks\ -
\ - \ - Disk\ - \ - Image\ - \ -
\ -
\ -
\ - \ - \ -
Name of the image to use
\ -
\ -
\ - \ - \ -
Type of disk device to emulate: ide, scsi
\ -
\ -
\ - \ - \ -
Device to map image disk. If set, it will overwrite the default device mapping
\ -
\ -
\ - \ - \ -
Specific image mapping driver. KVM: raw, qcow2. Xen:tap:aio:, file:. VMware unsupported
\ -
\ -
\ - \ - \ -
Disk type
\ -
\ -
\ - \ - \ -
Disk file location path or URL
\ -
\ -
\ - \ - \ - \ -
Disk file location path or URL. Mandatory for swap, fs and block images
\ -
\ -
\ - \ - \ - \ -
Filesystem type for the fs images
\ -
\ -
\ - \ - \ -
Clone this image
\ -
\ -
\ - \ - \ -
Save this image after shutting down the VM
\ -
\ -
\ - \ - \ -
Mount image as read-only
\ -
\ -
\ - \ - \ -
\ - \ - \ -
\ -
\ -
\ -
\ -\ - \ -
\ -
\ -

Setup Networks

\ -
\ -
Network\ -
\ - \ - Predefined\ - \ - Manual\ - \ - \ -
\ -
\ -
\ - \ - \ -
Name of the network to attach this device
\ -
\ -
\ - \ - \ -
Request an specific IP from the Network
\ -
\ -
\ - \ - \ -
HW address associated with the network interface
\ -
\ -
\ - \ - \ -
Name of the bridge the network device is going to be attached to
\ -
\ -
\ - \ - \ -
Name for the tun device created for the VM
\ -
\ -
\ - \ - \ -
Name of a shell script to be executed after creating the tun device for the VM
\ -
\ -
\ - \ - \ -
Hardware that will emulate this network interface. With Xen this is the type attribute of the vif.
\ -
\ -
\ - \ - \ -
\ - \ - \ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add inputs

\ -
\ -
Inputs\ -
\ - \ - \ -
\ -
\ -
\ - \ - \ -
\ -
\ -
\ - \ - \ -
\ - \ - \ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add Graphics

\ -
\ -
Graphics\ -
\ - \ - \ -
\ -
\ -
\ - \ - \ -
IP to listen on
\ -
\ -
\ - \ - \ -
Port for the VNC server
\ -
\ -
\ - \ - \ -
Password for the VNC server
\ -
\ -
\ - \ - \ -
Keyboard configuration locale to use in the VNC display
\ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add context variables

\ -
\ -
Context\ -
\ - \ - \ -
Name for the context variable
\ -
\ -
\ - \ - \ -
Value of the context variable
\ -
\ -
\ - \ - \ -
\ - \ - \ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add placement options

\ -
\ -
Placement\ -
\ - \ - \ -
Boolean expression that rules out provisioning hosts from list of machines suitable to run this VM
\ -
\ -
\ - \ - \ -
This field sets which attribute will be used to sort the suitable hosts for this VM. Basically, it defines which hosts are more suitable than others
\ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ -

Add Hypervisor raw options

\ -
\ -
Raw\ - \ -
\ - \ - \ - \ -
Raw data to be passed directly to the hypervisor
\ -
\ -
\ -
\ -\ -\ - \ -
\ -
\ - \ - \ -
\ -
\ -
\ -
\ -
\ -
\ -

Write the Virtual Machine template here

\ -
\ - \ -
\ -
\ -
\ -
\ - \ - \ -
\ -
\ -
\ +var create_vm_tmpl ='
\ +
\ +
\ + \ +
\ + \ + \
\ -
'; + \ +
\ +
\ + \ + \ +
\ +
\ +'; var vmachine_list_json = {}; var dataTable_vMachines; @@ -751,9 +314,11 @@ var vm_buttons = { }, "VM.create_dialog" : { - type: "create_dialog", + type: "action", text: "+ New", - condition: True + condition: True, + alwaysActive: true, + }, "VM.shutdown" : { @@ -1047,772 +612,36 @@ function updateVMInfo(request,vm){ } -// Sets up the create-VM dialog and all the processing associated to it, +// Sets up the create-template dialog and all the processing associated to it, // which is a lot. function setupCreateVMDialog(){ - //Helper functions for the dialog operations - - // Called when changing tabs. Since we use the same form for both - // KVM, XEN and others we need to do some operation to update it - var vmTabChange = function(event,ui){ - // ui.tab // anchor element of the selected (clicked) tab - // ui.panel // element, that contains the selected/clicked tab contents - // ui.index // zero-based index of the selected (clicked) tab - switch(ui.index){ - case 0: - enable_kvm(); - break; - case 1: - enable_xen(); - break; - case 2: - break; - case 3: - break; - } - } - - //Using kvm wizard. Updates mandatory tag, optional tags, disable - //XEN-only (and others) items, enables KVM items - var enable_kvm = function(){ - man_class="kvm"; - opt_class="kvm_opt"; - $(xen_items).attr("disabled","disabled"); - $(kvm_items).removeAttr("disabled"); - //$(items+':disabled').hide(); - - - //KVM particularities: - // * Add no_type option for disks - // * Add driver default option for boot and select it - hide some fields - // * Set the raw type to kvm - // * Show the inputs section - $('div#disks select#TYPE option:selected').removeAttr("selected"); - $('div#disks select#TYPE').prepend( - ''); - $('div#disks select#TYPE option#no_type').attr("selected","selected"); - - $('select#boot_method option').removeAttr("selected"); - $('select#boot_method option#no_boot').html("Driver default"); - $('select#boot_method option').removeAttr("selected"); - $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); - - $('div#disks select#BUS').append( - ''); - - - - $('input#TYPE', section_raw).val("kvm"); - - $(section_inputs).show(); - }; - - // Using XEN wizard. Update mandatory and optional classes, disable - // KVM-only (and other) items, enable XEN fields... - enable_xen = function(){ - man_class="xen"; - opt_class="xen_opt"; - $(kvm_items).attr("disabled","disabled"); - $(kvm_items).css("background",""); - $(xen_items).removeAttr("disabled"); - //$(items+':disabled').hide(); - - - // XEN particularities: - // * Remove no_type option from disks - // * Remove driver default boot method - // * Set the raw section to XEN - // * Hide the inputs section - $('div#disks select#TYPE option#no_type').remove(); - - $('select#boot_method option:selected').removeAttr("selected"); - $('select#boot_method option#no_boot').html("Please choose"); - $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); - - $('div#disks select#BUS option#virtio').remove(); - - $('input#TYPE', section_raw).val("xen"); - $(section_inputs).hide(); //not present for xen - }; - - //This function checks that all mandatory items within a section - //have some value. Returns true if so, false if not. - var mandatory_filter = function(context){ - var man_items = "."+man_class; - - //find enabled mandatory items in this context - man_items = $(man_items+' input:visible, '+man_items+' select:visible',context); - var r = true; - - //we fail it the item is enabled and has no value - $.each(man_items,function(){ - if ($(this).parents(".vm_param").attr("disabled") || - !($(this).val().length)) { - r = false; - return false; - }; - }); - return r; - - }; - - //Adds an option element to a multiple select box. Before doing so, - //it checks that the desired filter is passed - var box_add_element = function(context,box_tag,filter){ - var value=""; - var params= $('.vm_param',context); - var inputs= $('input:enabled',params); - var selects = $('select:enabled',params); - var fields = $.merge(inputs,selects); - - //are fields passing the filter? - var result = filter(); - if (!result) { - notifyError("There are mandatory parameters missing in this section"); - return false; - } - - value={}; - - //With each enabled field we form a JSON object - var id = null; - $.each(fields,function(){ - if (!($(this).parents(".vm_param").attr("disabled")) && - $(this).val().length){ - //Pick up parent's ID if we do not have one - id = $(this).attr('id').length ? $(this).attr('id') : $(this).parent().attr('id'); - value[id] = $(this).val(); - } - }); - var value_string = JSON.stringify(value); - var option= ''; - $('select'+box_tag,context).append(option); - return false; - }; - - //Removes selected elements from a multiple select box - var box_remove_element = function(section_tag,box_tag){ - var context = $(section_tag); - $('select'+box_tag+' :selected',context).remove(); - return false; - }; - - //Given the JSON of a VM template (or of a section of it), it crawls - //the fields of certain section (context) and add their name and - //values to the template JSON. - var addSectionJSON = function(template_json,context){ - var params= $('.vm_param',context); - var inputs= $('input:enabled',params); - var selects = $('select:enabled',params); - var fields = $.merge(inputs,selects); - - fields.each(function(){ - if (!($(this).parents(".vm_param").attr("disabled"))){ //if ! disabled - if ($(this).val().length){ //if has a length - template_json[$(this).attr('id')]=$(this).val(); - } - } - }); - } - - // Given an array (usually empty), a section (context) and a tag for - // a multiple select in that section, it adds the contents of the - // box as objects in the array. - // TODO: Make it return a new array? - var addBoxJSON = function(array,context,box_tag){ - $('select'+box_tag+' option',context).each(function(){ - array.push( JSON.parse($(this).val()) ); - }); - } - - //Given an object, removes those elements which are empty - //Used to clean up a template JSON before submitting - //it to opennebula.js - var removeEmptyObjects = function(obj){ - for (elem in obj){ - var remove = false; - var value = obj[elem]; - if (value instanceof Array) - { - 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; - } - - //Toggles the icon when a section is folded/unfolded - var iconToggle = function(){ - $('.icon_right').toggle( - function(e){ - $('span',e.currentTarget).removeClass("ui-icon-plusthick"); - $('span',e.currentTarget).addClass("ui-icon-minusthick"); - },function(e){ - $('span',e.currentTarget).removeClass("ui-icon-minusthick"); - $('span',e.currentTarget).addClass("ui-icon-plusthick"); - }); - } - - // Set ups the capacity section - var capacity_setup = function(){ - //Actually there is nothing to set up, but it used to be - //possible to hide it like others - /* - $('fieldset',section_capacity).hide(); - $('#add_capacity',section_capacity).click(function(){ - $('fieldset',section_capacity).toggle(); - return false; - }); - */ - - } - - //Sets up the OS_BOOT section - var os_boot_setup = function(){ - $('fieldset',section_os_boot).hide(); - $('.bootloader, .kernel',section_os_boot).hide(); - - $('#add_os_boot_opts',section_os_boot).click(function(){ - $('fieldset',section_os_boot).toggle(); - return false; - }); - - - //Chrome workaround - $('#boot_method').change(function(){ - $(this).trigger("click"); - }); - - //Depending on the boot method we enable/disable some options - $('#boot_method',section_os_boot).click(function(){ - select = $(this).val(); - switch (select) - { - case "kernel": - $('.bootloader',section_os_boot).hide(); - $('.bootloader',section_os_boot).attr("disabled","disabled"); - $('.kernel',section_os_boot).show(); - $('.kernel',section_os_boot).removeAttr("disabled"); - break; - case "bootloader": - $('.kernel',section_os_boot).hide(); - $('.kernel',section_os_boot).attr("disabled","disabled"); - $('.bootloader',section_os_boot).show(); - $('.bootloader',section_os_boot).removeAttr("disabled"); - break; - default: - $('.kernel, .bootloader',section_os_boot).hide(); - $('.kernel, .bootloader',section_os_boot).attr("disabled","disabled"); - $('.kernel input, .bootloader input',section_os_boot).val(""); - }; - }); - }; - - // Sets up the disk section - var disks_setup = function(){ - - $('fieldset',section_disks).hide(); - $('.vm_param', section_disks).hide(); - //$('#image_vs_disk',section_disks).show(); - - $('#add_disks', section_disks).click(function(){ - $('fieldset',section_disks).toggle(); - return false; - }); - - //Depending on adding a disk or a image we need to show/hide - //different options and make then mandatory or not - $('#image_vs_disk input',section_disks).click(function(){ - //$('fieldset',section_disks).show(); - $('.vm_param', section_disks).show(); - var select = $('#image_vs_disk :checked',section_disks).val(); - switch (select) - { - case "disk": - $('.add_image',section_disks).hide(); - $('.add_image',section_disks).attr("disabled","disabled"); - $('.add_disk',section_disks).show(); - $('.add_disk',section_disks).removeAttr("disabled"); - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - break; - case "image": - $('.add_disk',section_disks).hide(); - $('.add_disk',section_disks).attr("disabled","disabled"); - $('.add_image',section_disks).show(); - $('.add_image',section_disks).removeAttr("disabled"); - $('#TARGET',section_disks).parent().removeClass(man_class); - $('#TARGET',section_disks).parent().addClass(opt_class); - break; - } - $('#SIZE',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - $('#FORMAT',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - $('#TYPE :selected',section_disks).removeAttr("selected"); - }); - - //Chrome workaround - $('select#TYPE',section_disks).change(function(){ - $(this).trigger('click'); - }); - - //Depending on the type of disk we need to show/hide - //different options and make then mandatory or not - $('select#TYPE',section_disks).click(function(){ - var select = $(this).val(); - switch (select) { - //size,format,target - case "swap": - //size mandatory - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(opt_class); - $('#SIZE',section_disks).parent().addClass(man_class); - - //target optional - $('#TARGET',section_disks).parent().removeClass(man_class); - $('#TARGET',section_disks).parent().addClass(opt_class); - - //format hidden - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - break; - case "fs": - //size mandatory - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(opt_class); - $('#SIZE',section_disks).parent().addClass(man_class); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format mandatory - $('#FORMAT',section_disks).parent().show(); - $('#FORMAT',section_disks).parent().removeAttr("disabled"); - $('#FORMAT',section_disks).parent().removeClass(opt_class); - $('#FORMAT',section_disks).parent().addClass(man_class); - - break; - case "block": - //size shown and optional - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(man_class); - $('#SIZE',section_disks).parent().addClass(opt_class); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format hidden - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - break; - case "floppy": - case "disk": - case "cdrom": - default: - //size hidden - $('#SIZE',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format optional - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - } - }); - - //Our filter for the disks section fields is the mandatory - //filter for this section - var diskFilter = function(){ - return mandatory_filter(section_disks); - }; - - $('#add_disk_button',section_disks).click(function(){ - box_add_element(section_disks,'#disks_box',diskFilter); - return false; - }); - $('#remove_disk_button',section_disks).click(function(){ - box_remove_element(section_disks,'#disks_box'); - return false; - }); - }; - - // Sets up the network section - var networks_setup = function(){ - - $('.vm_param',section_networks).hide(); - $('fieldset',section_networks).hide(); - - $('#add_networks',section_networks).click(function(){ - $('fieldset',section_networks).toggle(); - return false; - }); - - //Depending on adding predefined network or not we show/hide - //some fields - $('#network_vs_niccfg input',section_networks).click(function(){ - - select = $('#network_vs_niccfg :checked',section_networks).val(); - switch (select) { - case "network": - $('.niccfg',section_networks).hide(); - $('.niccfg',section_networks).attr("disabled","disabled"); - $('.network',section_networks).show(); - $('.network',section_networks).removeAttr("disabled"); - break; - case "niccfg": - $('.network',section_networks).hide(); - $('.network',section_networks).attr("disabled","disabled"); - $('.niccfg',section_networks).show(); - $('.niccfg',section_networks).removeAttr("disabled"); - break; - } - }); - - //The filter to add a new network checks that we have selected a - //network, or that the ip or mac are set - //TODO: Improve this check - var nicFilter = function(){ - return mandatory_filter(section_networks); - }; - - $('#add_nic_button',section_networks).click(function(){ - box_add_element(section_networks,'#nics_box',nicFilter); - return false; - }); - $('#remove_nic_button',section_networks).click(function(){ - box_remove_element(section_networks,'#nics_box'); - return false; - }); - - }; - - //Sets up the input section - basicly enabling adding and removing from box - var inputs_setup = function() { - $('fieldset',section_inputs).hide(); - - $('#add_inputs',section_inputs).click(function(){ - $('fieldset',section_inputs).toggle(); - return false; - }); - - $('#add_input_button',section_inputs).click(function(){ - //no filter - box_add_element(section_inputs,'#inputs_box',True); - return false; - }); - $('#remove_input_button',section_inputs).click(function(){ - box_remove_element(section_inputs,'#inputs_box'); - return false; - }); - }; - - //Set up the graphics section - var graphics_setup = function(){ - $('fieldset',section_graphics).hide(); - $('.vm_param',section_graphics).hide(); - $('select#TYPE',section_graphics).parent().show(); - - $('#add_graphics',section_graphics).click(function(){ - $('fieldset',section_graphics).toggle(); - return false; - }); - - //Chrome workaround - $('select#TYPE',section_graphics).change(function(){ - $(this).trigger("click"); - }); - $('select#TYPE',section_graphics).click(function(){ - g_type = $(this).val(); - switch (g_type) { - case "vnc": - $('#LISTEN',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().show(); - $('#PASSWD',section_graphics).parent().show(); - $('#KEYMAP',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().removeAttr("disabled"); - $('#PASSWD',section_graphics).parent().removeAttr("disabled"); - $('#KEYMAP',section_graphics).parent().removeAttr("disabled"); - break; - case "sdl": - $('#LISTEN',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().hide(); - $('#PASSWD',section_graphics).parent().hide(); - $('#KEYMAP',section_graphics).parent().hide(); - $('#PORT',section_graphics).parent().attr("disabled","disabled"); - $('#PASSWD',section_graphics).parent().attr("disabled","disabled"); - $('#KEYMAP',section_graphics).parent().attr("disabled","disabled"); - break; - default: - $('#LISTEN',section_graphics).parent().hide(); - $('#PORT',section_graphics).parent().hide(); - $('#PASSWD',section_graphics).parent().hide(); - $('#KEYMAP',section_graphics).parent().hide(); - - } - }); - - } - - //Set up the context section - TODO: Apply improvements here... - var context_setup = function(){ - $('fieldset',section_context).hide(); - - $('#add_context',section_context).click(function(){ - $('fieldset',section_context).toggle(); - return false; - }); - - $('#add_context_button', section_context).click(function(){ - var name = $('#var_name',section_context).val(); - var value = $('#var_value',section_context).val(); - if (!name.length || !value.length) { - notifyError("Context variable name and value must be filled in"); - return false; - } - option= ''; - $('select#context_box',section_context).append(option); - return false; - }); - - $('#remove_context_button', section_context).click(function(){ - box_remove_element(section_context,'#context_box'); - return false; - }); - - - }; - - // Set up the placement section - var placement_setup = function(){ - $('fieldset',section_placement).hide(); - - $('#add_placement',section_placement).click(function(){ - $('fieldset',section_placement).toggle(); - return false; - }); - - }; - - // Set up the raw section - var raw_setup = function(){ - $('fieldset',section_raw).hide(); - - $('#add_raw',section_raw).click(function(){ - $('fieldset',section_raw).toggle(); - return false; - }); - }; - - //***CREATE VM DIALOG MAIN BODY*** - - $('div#dialogs').append('
'); + $('div#dialogs').append('
'); //Insert HTML in place $('#create_vm_dialog').html(create_vm_tmpl); - //Enable tabs - $('#vm_create_tabs').tabs({ - select:vmTabChange - }); //Prepare jquery dialog - var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window $('#create_vm_dialog').dialog({ autoOpen: false, modal: true, - width: 700, - height: height + width: 400 }); - // Enhace buttons $('#create_vm_dialog button').button(); - //Enable different icon for folded/unfolded categories - iconToggle(); //toogle +/- buttons - - //Sections, used to stay within their scope - var section_capacity = $('#capacity'); - var section_os_boot = $('#os_boot_opts'); - var section_disks = $('#disks'); - var section_networks = $('#networks'); - var section_inputs = $('#inputs'); - var section_graphics = $('#graphics'); - var section_context = $('#context'); - var section_placement = $('#placement'); - var section_raw = $('#raw'); - - //Different selector for items of kvm and xen (mandatory and optional) - var items = '.vm_section input,.vm_section select'; - var kvm_man_items = '.kvm input,.kvm select'; - var kvm_opt_items = '.kvm_opt input, .kvm_opt select'; - var kvm_items = kvm_man_items +','+kvm_opt_items; - var xen_man_items = '.xen input,.xen select'; - var xen_opt_items = '.xen_opt input, .xen_opt select'; - var xen_items = xen_man_items +','+ xen_opt_items; - - //Starting template type, optional items class and mandatory items class - var templ_type = "kvm"; - var opt_class=".kvm_opt"; - var man_class=".kvm"; - - enable_kvm(); //enable all kvm options - - //Fold/unfold all sections button - $('#fold_unfold_vm_params').toggle( - function(){ - $('.vm_section fieldset').show(); - return false; - }, - function(){ - $('.vm_section fieldset').hide(); - $('.vm_section fieldset').first().show(); //Show capacity opts - return false; - }); - - //initialise all sections - capacity_setup(); - os_boot_setup(); - disks_setup(); - networks_setup(); - inputs_setup(); - graphics_setup(); - context_setup(); - placement_setup(); - raw_setup(); - - //Process form - $('button#create_vm_form_easy').click(function(){ - //validate form - - var vm_json = {}; - - //process capacity options - var scope = section_capacity; - - if (!mandatory_filter(scope)){ - notifyError("There are mandatory fields missing in the capacity section"); - return false; - }; - addSectionJSON(vm_json,scope); - - //process os_boot_opts - scope= section_os_boot; - switch (templ_type){ - case "xen": - boot_method = $('#boot_method option:selected',scope).val(); - if (!boot_method.length){ - notifyError("Xen templates must specify a boot method"); - return false;} - }; - - if (!mandatory_filter(scope)){ - notifyError("There are mandatory fields missing in the OS Boot options section"); - return false; - }; - vm_json["OS"] = {}; - addSectionJSON(vm_json["OS"],scope); - - //process disks -> fetch from box - scope = section_disks; - vm_json["DISK"] = []; - addBoxJSON(vm_json["DISK"],scope,'#disks_box'); - - //process nics -> fetch from box - scope = section_networks; - vm_json["NIC"] = []; - addBoxJSON(vm_json["NIC"],scope,'#nics_box'); - - //process inputs -> fetch from box - scope = section_inputs; - vm_json["INPUT"] = []; - addBoxJSON(vm_json["INPUT"],scope,'#inputs_box'); - - //process graphics -> fetch fields with value - scope = section_graphics; - vm_json["GRAPHICS"] = {}; - addSectionJSON(vm_json["GRAPHICS"],scope); - - //context - scope = section_context; - var context = $('#CONTEXT',scope).val(); - vm_json["CONTEXT"] = {}; - $('#context_box option',scope).each(function(){ - name = $(this).attr("name"); - value = $(this).val(); - vm_json["CONTEXT"][name]=value; - }); - - //placement -> fetch with value - scope = section_placement; - addSectionJSON(vm_json,scope); - - //raw -> if value set type to driver and fetch - scope = section_raw; - vm_json["RAW"] = {}; - addSectionJSON(vm_json["RAW"],scope); - - // remove empty elements - vm_json = removeEmptyObjects(vm_json); - - //wrap it in the "vm" object - vm_json = {vm: vm_json}; - + $('#create_vm_dialog #create_vm_proceed').click(function(){ + var vm_name = $('#create_vm_form #vm_name').val(); + var template_id = $('#create_vm_form #template_id').val(); + var vm_json = { vm: { vm_name: vm_name, template_id : template_id }}; Sunstone.runAction("VM.create",vm_json); - $('#create_vm_dialog').dialog('close'); - return false; - }); - - //Handle manual forms - $('button#create_vm_form_manual').click(function(){ - var template = $('#textarea_vm_template').val(); - - //wrap it in the "vm" object - template = {"vm": {"vm_raw": template}}; - - Sunstone.runAction("VM.create",template); - $('#create_vm_dialog').dialog('close'); - return false; - }); - - //Reset form - empty boxes - $('button#reset_vm_form').click(function(){ - $('select#disks_box option',section_disks).remove(); - $('select#nics_box option',section_networks).remove(); - $('select#inputs_box option',section_inputs).remove(); - return true; - }); - - + return false; + }); + + $('#create_vm_dialog #create_vm_cancel').click(function(){ + + }); } // Open creation dialog @@ -1965,5 +794,4 @@ $(document).ready(function(){ initCheckAllBoxes(dataTable_vMachines); tableCheckboxesListener(dataTable_vMachines); vMachineInfoListener(); - setupTips($('#create_vm_dialog')); }) diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index 59a2c54434..359f203aec 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -93,6 +93,7 @@ function tableCheckboxesListener(dataTable){ last_action_b.button("disable"); }; $('.create_dialog_button',context).button("enable"); + $('.alwaysActive',context).button("enable"); //listen to changes in the visible inputs $('tbody input',dataTable).live("change",function(){ @@ -127,6 +128,7 @@ function tableCheckboxesListener(dataTable){ //any case the create dialog buttons should always be enabled. $('.create_dialog_button',context).button("enable"); + $('.alwaysActive',context).button("enable"); }); } diff --git a/src/sunstone/public/js/sunstone.js b/src/sunstone/public/js/sunstone.js index dad3ae4cb6..4492c40038 100644 --- a/src/sunstone/public/js/sunstone.js +++ b/src/sunstone/public/js/sunstone.js @@ -448,6 +448,10 @@ function insertButtonsInTab(tab_name){ } + if (button.alwaysActive) { + button_code = $(button_code).addClass("alwaysActive"); + } + $('div#'+tab_name+' .action_blocks').append(button_code); }//for each button in tab diff --git a/src/sunstone/templates/index.html b/src/sunstone/templates/index.html index ca0864e08f..e07d76051f 100644 --- a/src/sunstone/templates/index.html +++ b/src/sunstone/templates/index.html @@ -25,10 +25,10 @@ + - From 4a6f711afa8f637d62767e1e1502483cb033d136 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 13 Apr 2011 13:00:30 +0200 Subject: [PATCH 6/7] Feature #565: Removed hack after xml fix in the onetemplate branch. --- src/sunstone/public/js/opennebula.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 9895b8df32..68d364783d 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -143,13 +143,6 @@ var OpenNebula = { return Error('Incorrect Pool'); } - - //HACK!!! - if (pool_name == "TEMPLATE_POOL") - { - type = "VMTEMPLATE"; - } - var p_pool = []; if (response[pool_name]) { From f9cc3bdb91b08880ff9b5d16bf4b3de6e740ecb3 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 13 Apr 2011 16:25:31 +0200 Subject: [PATCH 7/7] Feature #565: Fixed opennebula.js list vmtemplate resource --- src/sunstone/public/js/opennebula.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 68d364783d..904492f964 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -2157,7 +2157,7 @@ var OpenNebula = { { if (callback) { - var template_pool = OpenNebula.Helper.pool("TEMPLATE",response); + var template_pool = OpenNebula.Helper.pool(resource,response); callback(request, template_pool); } },