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..4ed254cbe6 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::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 new file mode 100644 index 0000000000..7ce484f82d --- /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::Template + include JSONUtils + + def create(template_json) + template_hash = parse_json(template_json, 'vmtemplate') + if OpenNebula.is_error?(template_hash) + return template_hash + end + + if template_hash['template_raw'] + template = template_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/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/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 diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index ce40c52746..904492f964 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -142,7 +142,7 @@ var OpenNebula = { { return Error('Incorrect Pool'); } - + var p_pool = []; if (response[pool_name]) { @@ -1931,5 +1931,301 @@ var OpenNebula = { } }); } + }, + + "Template" : { + "resource" : "VMTEMPLATE", + + "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)); + } + } + }); + } } } 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..cb558aa5c7 --- /dev/null +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -0,0 +1,1714 @@ +/* -------------------------------------------------------------------------- */ +/* 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 = '
\ + \ +
\ +
\ +
\ + \ +

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 = {}; +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: + $('#create_vm_dialog #template_id').html(templates_select); +} + +// 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(){ + //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; + }); + + + +} + +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/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 aa451a553f..e07d76051f 100644 --- a/src/sunstone/templates/index.html +++ b/src/sunstone/templates/index.html @@ -25,6 +25,7 @@ +