diff --git a/share/doc/xsd/oned.conf b/share/doc/xsd/oned.conf index e251b157f42..0d9318825c3 100644 --- a/share/doc/xsd/oned.conf +++ b/share/doc/xsd/oned.conf @@ -371,7 +371,7 @@ IM_MAD = [ NAME="dummy", SUNSTONE_NAME="Testing", EXECUTABLE="one_im_dummy"] # # type : driver type, supported drivers: xen, kvm, xml # -# keep_snapshots: do not remove snapshots on power on/off cycles and live +# keep_snapshots: do not remove snapshots on power on/off cycles and live # migrations if the hypervisor supports that. # # imported_vms_actions : comma-separated list of actions supported @@ -770,6 +770,7 @@ VM_RESTRICTED_ATTR = "MEMORY_COST" VM_RESTRICTED_ATTR = "DISK_COST" VM_RESTRICTED_ATTR = "PCI" VM_RESTRICTED_ATTR = "USER_INPUTS" +VM_RESTRICTED_ATTR = "DEPLOY_FOLDER" #VM_RESTRICTED_ATTR = "RANK" #VM_RESTRICTED_ATTR = "SCHED_RANK" diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 9f65a101ae8..95b1e9fc8a4 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -824,6 +824,7 @@ VM_RESTRICTED_ATTR = "EMULATOR" VM_RESTRICTED_ATTR = "USER_INPUTS/CPU" VM_RESTRICTED_ATTR = "USER_INPUTS/MEMORY" VM_RESTRICTED_ATTR = "USER_INPUTS/VCPU" +VM_RESTRICTED_ATTR = "DEPLOY_FOLDER" #VM_RESTRICTED_ATTR = "RANK" #VM_RESTRICTED_ATTR = "SCHED_RANK" diff --git a/src/cli/one_helper.rb b/src/cli/one_helper.rb index 0abd683bf21..86d60f897fb 100644 --- a/src/cli/one_helper.rb +++ b/src/cli/one_helper.rb @@ -352,6 +352,13 @@ module OpenNebulaHelper :name => 'report_ready', :large => '--report_ready', :description => 'Sends READY=YES to OneGate, useful for OneFlow' + }, + { + :name => 'deploy_folder', + :large => '--deploy_folder path', + :format => String, + :description => "In a vCenter environment sets the the VMs and Template folder where the VM will be placed in." \ + " The path uses slashes to separate folders. For example: --deploy_folder \"/Management/VMs\"" } ] @@ -1126,6 +1133,8 @@ def self.create_template(options, template_obj=nil) template<<' ]' << "\n" end + template<<"DEPLOY_FOLDER=#{options[:deploy_folder]}\n" if options[:deploy_folder] + context=create_context(options) template< 0) { @@ -275,6 +278,17 @@ define(function(require) { delete templateJSON["KEEP_DISKS_ON_DONE"]; + if (Config.isFeatureEnabled("vcenter_deploy_folder")) { + if (templateJSON["HYPERVISOR"] == 'vcenter' && + templateJSON["DEPLOY_FOLDER"]) { + WizardFields.fillInput($("#vcenter_deploy_folder", context), templateJSON["DEPLOY_FOLDER"]); + } + } else { + $(".vcenter_deploy_folder_input", context).remove(); + } + + delete templateJSON["DEPLOY_FOLDER"]; + if (templateJSON["HYPERVISOR"] == 'vcenter') { var publicClouds = templateJSON["PUBLIC_CLOUD"]; diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs index 26e33213c58..02414628ef1 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs @@ -120,6 +120,15 @@ +
+
+ + +
+
{{{capacityCreateHTML}}}
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js index d3ecbcc1fd6..a7e81d804af 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js @@ -31,6 +31,7 @@ define(function(require) { var WizardFields = require('utils/wizard-fields'); var DisksResize = require('utils/disks-resize'); var NicsSection = require('utils/nics-section'); + var DeployFolder = require('utils/deploy-folder'); var CapacityInputs = require('tabs/templates-tab/form-panels/create/wizard-tabs/general/capacity-inputs'); var Config = require('sunstone-config'); @@ -206,6 +207,13 @@ define(function(require) { tmp_json.PCI = pcis; } + if (Config.isFeatureEnabled("vcenter_deploy_folder")){ + if(!$.isEmptyObject(original_tmpl.TEMPLATE.PUBLIC_CLOUD.TYPE) && + original_tmpl.TEMPLATE.PUBLIC_CLOUD.TYPE === 'vcenter'){ + $.extend(tmp_json, DeployFolder.retrieveChanges($(".deployFolderContext" + template_id))); + } + } + capacityContext = $(".capacityContext" + template_id, context); $.extend(tmp_json, CapacityInputs.retrieveChanges(capacityContext)); @@ -262,6 +270,10 @@ define(function(require) { 'securityGroups': Config.isFeatureEnabled("secgroups") }); + deployFolderContext = $(".deployFolderContext" + template_json.VMTEMPLATE.ID, context); + DeployFolder.setup(deployFolderContext); + DeployFolder.fill(deployFolderContext, template_json.VMTEMPLATE); + var inputs_div = $(".template_user_inputs" + template_json.VMTEMPLATE.ID, context); UserInputs.vmTemplateInsert( diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs index 1b6cdab2c68..d95c3fedd2f 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs @@ -51,4 +51,10 @@
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/sunstone/public/app/utils/deploy-folder.js b/src/sunstone/public/app/utils/deploy-folder.js new file mode 100644 index 00000000000..f021fc2d19c --- /dev/null +++ b/src/sunstone/public/app/utils/deploy-folder.js @@ -0,0 +1,74 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + var Locale = require('utils/locale'); + var Config = require('sunstone-config'); + var OpenNebula = require('opennebula'); + var OpenNebulaImage = require('opennebula/image'); + var UserInputs = require('utils/user-inputs'); + var WizardFields = require('utils/wizard-fields'); + var DeployFolderTemplate = require('hbs!./deploy-folder/html'); + + return { + 'setup': _setup, + 'fill': _fill, + 'retrieveChanges': _retrieveChanges + }; + + function _setup(context) { + if (!Config.isFeatureEnabled("vcenter_deploy_folder")){ + $(context).remove(); + } + } + + function _fill(context, element) { + + if (Config.isFeatureEnabled("vcenter_deploy_folder")){ + var deployFolderContext = context; + var template_public_cloud_type = element.TEMPLATE.PUBLIC_CLOUD.TYPE + + if ($.isEmptyObject(template_public_cloud_type)) { + deployFolderContext.html(""); + } else { + if (template_public_cloud_type === 'vcenter') { + var deploy_folder = element.TEMPLATE.DEPLOY_FOLDER + deployFolderContext.html(DeployFolderTemplate()); + $("#deploy_folder_input", deployFolderContext).val(deploy_folder); + $("#deploy_folder_input", deployFolderContext).data("original_value",deploy_folder); + } else { + deployFolderContext.html(""); + } + } + } + } + + + function _retrieveChanges(context) { + + var templateJSON = WizardFields.retrieve(context); + var fields = $('[wizard_field]', context); + + fields.each(function() { + var field_name = $(this).attr('wizard_field'); + if (templateJSON[field_name] == $(this).data("original_value")){ + delete templateJSON[field_name]; + } + }); + + return templateJSON; + } +}); \ No newline at end of file diff --git a/src/sunstone/public/app/utils/deploy-folder/html.hbs b/src/sunstone/public/app/utils/deploy-folder/html.hbs new file mode 100644 index 00000000000..9bb686bb7e5 --- /dev/null +++ b/src/sunstone/public/app/utils/deploy-folder/html.hbs @@ -0,0 +1,29 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2016, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! Licensed under the Apache License, Version 2.0 (the "License"); you may }} +{{! not use this file except in compliance with the License. You may obtain }} +{{! a copy of the License at }} +{{! }} +{{! http://www.apache.org/licenses/LICENSE-2.0 }} +{{! }} +{{! Unless required by applicable law or agreed to in writing, software }} +{{! distributed under the License is distributed on an "AS IS" BASIS, }} +{{! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }} +{{! See the License for the specific language governing permissions and }} +{{! limitations under the License. }} +{{! -------------------------------------------------------------------------- }} + +
+ + {{tr "vCenter Deployment"}} + +
+ + +
+
+ diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index cc52895b156..bf748677dcc 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -2490,6 +2490,21 @@ def self.clone_vm(xml_text, hostname, datastore, ops = {}) connection = VIClient.new(hid) vc_template = connection.find_vm_fast(uuid, ops[:ref], ops[:name]) + deploy_folder = nil + deploy_folder_name = xml.root.elements["/VM/USER_TEMPLATE/DEPLOY_FOLDER"] + + if !deploy_folder_name.nil? + deploy_folder_name = deploy_folder_name.text + if !deploy_folder_name.empty? + # Look for folder object + deploy_folder = connection.dc.find_folder(deploy_folder_name) + end + end + + if deploy_folder.nil? + deploy_folder = vc_template.parent + end + # Find out requested and available resource pool req_rp = nil @@ -2598,7 +2613,7 @@ def self.clone_vm(xml_text, hostname, datastore, ops = {}) storage_spec = RbVmomi::VIM.StoragePlacementSpec( type: 'clone', cloneName: vcenter_name, - folder: vc_template.parent, + folder: deploy_folder, podSelectionSpec: pod_spec, vm: vc_template, cloneSpec: clone_spec @@ -2624,7 +2639,7 @@ def self.clone_vm(xml_text, hostname, datastore, ops = {}) begin vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, + :folder => deploy_folder, :name => vcenter_name, :spec => clone_spec).wait_for_completion rescue Exception => e @@ -2639,7 +2654,7 @@ def self.clone_vm(xml_text, hostname, datastore, ops = {}) vm.Destroy_Task.wait_for_completion vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, + :folder => deploy_folder, :name => vcenter_name, :spec => clone_spec).wait_for_completion end