From e2d38abe064dc25244102ec436feb8fae2641acd Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Wed, 22 Mar 2017 11:32:47 +0100 Subject: [PATCH 01/80] F #5001 Added trash icon in VM.TerminateHARD (#227) --- src/sunstone/public/app/tabs/vms-tab/buttons.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sunstone/public/app/tabs/vms-tab/buttons.js b/src/sunstone/public/app/tabs/vms-tab/buttons.js index 0a210276d2..7512bb6d81 100644 --- a/src/sunstone/public/app/tabs/vms-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vms-tab/buttons.js @@ -141,9 +141,11 @@ define(function(require) { custom_classes : "state-dependent" }, "VM.terminate_hard" : { - type: text, - text: Locale.tr("Terminate") + ' ' + Locale.tr("hard") + '', + type: "confirm", + icon: "", + text: Locale.tr(" Terminate") + ' ' + Locale.tr("hard") + '', layout: "vmsdelete_buttons", + tip: Locale.tr("This will remove information from non-persistent hard disks"), custom_classes : "state-dependent" }, "VM.resched" : { From dec4ac7b5711885fd50cc187e89d190937bd7933 Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Wed, 22 Mar 2017 13:31:09 +0100 Subject: [PATCH 02/80] Added dialog in Revert Snapshots (#228) --- src/sunstone/public/app/tabs/vms-tab.js | 1 + .../public/app/tabs/vms-tab/dialogs/revert.js | 92 +++++++++++++++++++ .../tabs/vms-tab/dialogs/revert/dialogId.js | 19 ++++ .../app/tabs/vms-tab/dialogs/revert/html.hbs | 40 ++++++++ .../app/tabs/vms-tab/panels/snapshots.js | 6 +- 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/sunstone/public/app/tabs/vms-tab/dialogs/revert.js create mode 100644 src/sunstone/public/app/tabs/vms-tab/dialogs/revert/dialogId.js create mode 100644 src/sunstone/public/app/tabs/vms-tab/dialogs/revert/html.hbs diff --git a/src/sunstone/public/app/tabs/vms-tab.js b/src/sunstone/public/app/tabs/vms-tab.js index f8c62025f0..2264fbce52 100644 --- a/src/sunstone/public/app/tabs/vms-tab.js +++ b/src/sunstone/public/app/tabs/vms-tab.js @@ -33,6 +33,7 @@ define(function(require) { require('./vms-tab/dialogs/disk-resize'), require('./vms-tab/dialogs/attach-nic'), require('./vms-tab/dialogs/snapshot'), + require('./vms-tab/dialogs/revert'), require('./vms-tab/dialogs/vnc'), require('./vms-tab/dialogs/spice'), require('./vms-tab/dialogs/saveas-template') diff --git a/src/sunstone/public/app/tabs/vms-tab/dialogs/revert.js b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert.js new file mode 100644 index 0000000000..19805bcb63 --- /dev/null +++ b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert.js @@ -0,0 +1,92 @@ +/* -------------------------------------------------------------------------- */ +/* 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) { + /* + DEPENDENCIES + */ + + var BaseDialog = require('utils/dialogs/dialog'); + var TemplateHTML = require('hbs!./revert/html'); + var Sunstone = require('sunstone'); + var Tips = require('utils/tips'); + + /* + CONSTANTS + */ + + var DIALOG_ID = require('./revert/dialogId'); + var TAB_ID = require('../tabId') + + /* + CONSTRUCTOR + */ + + function Dialog() { + this.dialogId = DIALOG_ID; + + BaseDialog.call(this); + }; + + Dialog.DIALOG_ID = DIALOG_ID; + Dialog.prototype = Object.create(BaseDialog.prototype); + Dialog.prototype.constructor = Dialog; + Dialog.prototype.html = _html; + Dialog.prototype.onShow = _onShow; + Dialog.prototype.setup = _setup; + Dialog.prototype.setElement = _setElement; + + return Dialog; + + /* + FUNCTION DEFINITIONS + */ + + function _html() { + return TemplateHTML({ + 'dialogId': this.dialogId + }); + } + + function _setup(context) { + + var that = this; + + Tips.setup(context); + + $('#' + DIALOG_ID + 'Form', context).submit(function() { + + var snapshot_id = $(this).parents('tr').attr('snapshot_id'); + Sunstone.runAction('VM.snapshot_revert', that.element.ID, {"snapshot_id": snapshot_id}); + + Sunstone.getDialog(DIALOG_ID).hide(); + Sunstone.getDialog(DIALOG_ID).reset(); + return false; + }); + + return false; + } + + function _onShow(context) { + this.setNames( {tabId: TAB_ID} ); + return false; + } + + function _setElement(element) { + this.element = element + } + +}); diff --git a/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/dialogId.js b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/dialogId.js new file mode 100644 index 0000000000..14a82c35cd --- /dev/null +++ b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/dialogId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* 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) { + return 'revertVMDialog'; +}); diff --git a/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/html.hbs b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/html.hbs new file mode 100644 index 0000000000..1aa1649b9c --- /dev/null +++ b/src/sunstone/public/app/tabs/vms-tab/dialogs/revert/html.hbs @@ -0,0 +1,40 @@ +{{! -------------------------------------------------------------------------- }} +{{! 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 "Revert"}} +

+
+
+
+
+
+
{{tr "You have to confirm this action."}}
+
+
{{tr "Do you want to proceed?"}}
+
+
+
+ +
+ +
+
+
diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/snapshots.js b/src/sunstone/public/app/tabs/vms-tab/panels/snapshots.js index 369dea7c9f..ba6d083e11 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/snapshots.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/snapshots.js @@ -34,6 +34,7 @@ define(function(require) { var TAB_ID = require('../tabId'); var PANEL_ID = require('./snapshots/panelId'); var SNAPSHOT_DIALOG_ID = require('../dialogs/snapshot/dialogId'); + var REVERT_DIALOG_ID = require('../dialogs/revert/dialogId'); var RESOURCE = "VM" var XML_ROOT = "VM" @@ -165,8 +166,9 @@ define(function(require) { if (Config.isTabActionEnabled("vms-tab", "VM.snapshot_revert")) { context.off('click', '.snapshot_revert'); context.on('click', '.snapshot_revert', function() { - var snapshot_id = $(this).parents('tr').attr('snapshot_id'); - Sunstone.runAction('VM.snapshot_revert', that.element.ID, {"snapshot_id": snapshot_id}); + var dialog = Sunstone.getDialog(REVERT_DIALOG_ID); + dialog.setElement(that.element); + dialog.show(); return false; }); } From 11b636133ab9bc324e1b7b738166333b2c78e6ef Mon Sep 17 00:00:00 2001 From: Javi Fontan Date: Wed, 22 Mar 2017 19:11:38 +0100 Subject: [PATCH 03/80] Add usage comment to patch ip4_6_static.rb --- src/onedb/patches/ip4_ip6_static.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/onedb/patches/ip4_ip6_static.rb b/src/onedb/patches/ip4_ip6_static.rb index 5effc77b25..739e448df9 100644 --- a/src/onedb/patches/ip4_ip6_static.rb +++ b/src/onedb/patches/ip4_ip6_static.rb @@ -14,6 +14,18 @@ # limitations under the License. # #--------------------------------------------------------------------------- # +# This patch changes the type of an AR to IP4_6_STATIC and also lets +# us add or change parameters. The AR must be specified in the extra +# option. For example, to change network 2, ar 1 and add ip6 and +# prefix_length you can use: +# +# onedb patch -s one.db ip4_6_static.rb \ +# --extra vn=2;ar=1;ip6=2001::1;prefix_length=48 +# +# You can also specify several ARs separated by ,: +# +# vn=3;ar=0;ip6=2001::1;prefix_length=48,vn=3;ar=1;ip6=2001::2;prefix_length=64 + if !ONE_LOCATION LOG_LOCATION = "/var/log/one" else From 5e9dbba51577e04aac9a48e66c798c6c021a70fe Mon Sep 17 00:00:00 2001 From: abelCoronado93 Date: Thu, 23 Mar 2017 10:39:17 +0100 Subject: [PATCH 04/80] Solves bugs: * issue with DISK_COST attribute for regaular users (cherry picked from commit 8353763bc776992f809b0a8cdcc909ae6f24c9ac) * IPv6 remove attribute from AR (cherry picked from commit 54ecd1e2ab0c88266aefce520aeec39211661fcc) --- .../templates-tab/form-panels/create/wizard-tabs/general.js | 2 +- .../form-panels/create/wizard-tabs/network/nic-tab/html.hbs | 2 +- src/sunstone/public/app/tabs/vnets-tab/utils/ar-tab/html.hbs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js index 4945e55170..1800b5784b 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js @@ -182,7 +182,7 @@ define(function(require) { templateJSON["DISK_COST"] = templateJSON["DISK_COST"] * 1024; } else{ - templateJSON["DISK_COST"] = "0"; + delete templateJSON["MEMORY_UNIT_COST"]; } if(templateJSON["MEMORY_UNIT_COST"] == "GB") templateJSON["MEMORY_COST"] = templateJSON["MEMORY_COST"] * 1024; diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs index b50bdf0ac8..1f7e6af1ff 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs @@ -106,7 +106,7 @@
diff --git a/src/sunstone/public/app/tabs/vnets-tab/utils/ar-tab/html.hbs b/src/sunstone/public/app/tabs/vnets-tab/utils/ar-tab/html.hbs index fda4190888..df52e55a05 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/utils/ar-tab/html.hbs +++ b/src/sunstone/public/app/tabs/vnets-tab/utils/ar-tab/html.hbs @@ -44,7 +44,7 @@
- +
From 57bc086cb89297a3295b549d3d1b19b0099c2fd0 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 24 Mar 2017 13:02:05 +0100 Subject: [PATCH 05/80] B #5077: Destroy VM if reconfigure or poweron actions fail in clone_vm --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 3d3e741cac..686c28cbfe 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -2677,20 +2677,31 @@ private end + begin + # Reconfigure the VM + reconfigure_vm(vm, xml, true, hostname) + rescue Exception => e + vm.Destroy_Task.wait_for_completion + raise "Could not reconfigure the VM after a clone has been created: #{e.message}" + end + begin + # Power on the VM + vm.PowerOnVM_Task.wait_for_completion + rescue Exception => e + vm.Destroy_Task.wait_for_completion + raise "Could not power on the VM: #{e.message}" + end - reconfigure_vm(vm, xml, true, hostname) - - # Power on the VM - vm.PowerOnVM_Task.wait_for_completion - - # Set to yes the running flag - - config_array = [{:key=>"opennebula.vm.running",:value=>"yes"}] - spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig =>config_array}) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion + begin + # Set the running flag to yes + config_array = [{:key=>"opennebula.vm.running",:value=>"yes"}] + spec = RbVmomi::VIM.VirtualMachineConfigSpec({:extraConfig =>config_array}) + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + rescue Exception => e + vm.Destroy_Task.wait_for_completion + raise "Could not set opennebula.vm.running: #{e.message}" + end return vm.config.uuid end From 80b0991cc9adf861d8d65cc2df8f28d86a721206 Mon Sep 17 00:00:00 2001 From: juanmont Date: Mon, 27 Mar 2017 12:32:10 +0200 Subject: [PATCH 06/80] Feature #5027 (PR #229): Sunstone IPv6 interface * changed ar-datatable with ranges * Feature vnet Added IPV6 support to virtual routers --- .../create/wizard-tabs/network/nic-tab/html.hbs | 4 ++-- .../form-panels/instantiate.js | 1 + .../app/tabs/vrouters-tab/dialogs/attach-nic.js | 1 + src/sunstone/public/app/utils/nics-section.js | 9 +++++++++ .../public/app/utils/nics-section/dd.hbs | 17 +++++++++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs index 1f7e6af1ff..701b179b93 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs @@ -105,10 +105,10 @@ {{tr "Override Network Values IPv6"}}
-
{{/if}}
+
+ {{#if options.forceIPv6}} +
+ +
+ {{/if}} +
{{#if options.securityGroups}}
From 0d6259e009ee958843bbb34c48bf3352a494a14a Mon Sep 17 00:00:00 2001 From: juanmont Date: Mon, 27 Mar 2017 18:51:20 +0200 Subject: [PATCH 07/80] B #5079 Displayed advanced parameters per Role (#234) --- .../public/app/tabs/oneflow-templates-tab/form-panels/create.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sunstone/public/app/tabs/oneflow-templates-tab/form-panels/create.js b/src/sunstone/public/app/tabs/oneflow-templates-tab/form-panels/create.js index 84c27b6c69..9bb19dd135 100644 --- a/src/sunstone/public/app/tabs/oneflow-templates-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/oneflow-templates-tab/form-panels/create.js @@ -399,7 +399,6 @@ define(function(require) { $(".networks_role", role_section).show(); } - $(".vm_template_contents", role_section).val(""); $.each(selected_networks, function(){ $(".service_network_checkbox[value='"+this+"']", role_section).attr('checked', true).change(); From 940ce3b38d47df4c7ff4d58d357de3c57461b37c Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Wed, 29 Mar 2017 14:21:59 +0200 Subject: [PATCH 08/80] Feature #4913: Attach disk (PR #233) * Attach disk | SWAP removed for vCenter templates * Attach disk | qcow2 removed for vCenter templates * Attach disk | SWAP & cowq2 removed for vCenter vms * VM attach disk | Changed 'Advanced options' for vCenter disks * Restyled import image * Update html.hbs Add missing ; --- .../images-tab/form-panels/import/html.hbs | 16 +++++----- .../wizard-tabs/storage/disk-tab/html.hbs | 10 +++++-- .../wizard-tabs/storage/disk-tab/options.hbs | 30 +++++++++++++++++-- .../public/app/tabs/vms-tab/panels/storage.js | 7 +++-- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/sunstone/public/app/tabs/images-tab/form-panels/import/html.hbs b/src/sunstone/public/app/tabs/images-tab/form-panels/import/html.hbs index ab8ee9d356..b843babfce 100644 --- a/src/sunstone/public/app/tabs/images-tab/form-panels/import/html.hbs +++ b/src/sunstone/public/app/tabs/images-tab/form-panels/import/html.hbs @@ -31,19 +31,21 @@
-
+
-
- - +
+
+
+ +
{{{vCenterImagesHTML}}}
-
\ No newline at end of file +
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/html.hbs index 479a92e087..8edbec819d 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/html.hbs @@ -74,19 +74,25 @@ - +
- +

diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/options.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/options.hbs index db9f134fee..f4ea7f4fc0 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/options.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/storage/disk-tab/options.hbs @@ -1,5 +1,5 @@
-
+
-
+
-
+
@@ -45,6 +45,30 @@
+
+ + +
+
+ + +
diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js index 1eb072c0a9..eee04502bd 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js @@ -436,6 +436,10 @@ define(function(require) { context.on('click', '#attach_disk', function() { var dialog = Sunstone.getDialog(ATTACH_DISK_DIALOG_ID); dialog.setElement(that.element); + if(that.element.USER_TEMPLATE.HYPERVISOR && that.element.USER_TEMPLATE.HYPERVISOR == 'venter'){ + $('.hypervisor.only_kvm').hide(); + $('.hypervisor.only_vcenter').show(); + } dialog.show(); return false; }); @@ -445,7 +449,6 @@ define(function(require) { context.off('click', '.detachdisk'); context.on('click', '.detachdisk', function() { var disk_id = $(this).parents('tr').attr('disk_id'); - Sunstone.getDialog(CONFIRM_DIALOG_ID).setParams({ //header : headerTabId: TAB_ID, @@ -596,7 +599,7 @@ define(function(require) { return false; }); } - + Tree.setup(context); } From 61b549b1f14ac195a54b6d320b3e718558709c02 Mon Sep 17 00:00:00 2001 From: juanmont Date: Wed, 29 Mar 2017 14:23:21 +0200 Subject: [PATCH 09/80] F #4913 Disabled datastore creation (#235) --- src/sunstone/etc/sunstone-views/admin_vcenter.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml index 75ef5ef014..f0f4250354 100644 --- a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml +++ b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml @@ -544,7 +544,7 @@ tabs: #- 13 # Search data actions: Datastore.refresh: true - Datastore.create_dialog: true + Datastore.create_dialog: false Datastore.import_dialog: true Datastore.addtocluster: true Datastore.rename: true From 9f1f5926da272382970c3baa4be28982c6d9fb5a Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Wed, 29 Mar 2017 14:25:20 +0200 Subject: [PATCH 10/80] F #4913 Virtual Network vCenter (PR #236) --- .../app/tabs/vnets-tab/form-panels/create.js | 13 +++++- .../vnets-tab/form-panels/create/wizard.hbs | 42 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/sunstone/public/app/tabs/vnets-tab/form-panels/create.js b/src/sunstone/public/app/tabs/vnets-tab/form-panels/create.js index 797ea28a27..a97eafdaee 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/vnets-tab/form-panels/create.js @@ -126,7 +126,8 @@ define(function(require) { $("div.mode_param [wizard_field]", context).prop('wizard_field_disabled', true); $('input#vn_mad', context).removeAttr('required'); - + $('input#vn_mad', context).removeAttr('value'); + $('#vcenter_switch_name', context).removeAttr('required'); switch ($(this).val()) { case "dummy": $("div.mode_param.dummy", context).show(); @@ -164,6 +165,16 @@ define(function(require) { $('input#bridge', context).attr('required', ''); break; + case "vcenter": + $("div.mode_param.vcenter", context).show(); + $("div.mode_param.vcenter [wizard_field]", context).prop('wizard_field_disabled', false); + $('input#bridge', context).attr('value', $('#name', context).val()); + $('#vcenter_switch_name', context).attr('required', ''); + $('input#vn_mad', context).attr('required', ''); + $('input#vn_mad', context).attr('value', 'vcenter'); + + $('#div_vn_mad', context).hide(); + break; case "custom": $("div.mode_param.custom", context).show(); $("div.mode_param.custom [wizard_field]", context).prop('wizard_field_disabled', false); diff --git a/src/sunstone/public/app/tabs/vnets-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/vnets-tab/form-panels/create/wizard.hbs index a4a35bcfd8..5094d2c652 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/form-panels/create/wizard.hbs +++ b/src/sunstone/public/app/tabs/vnets-tab/form-panels/create/wizard.hbs @@ -87,10 +87,11 @@ +
-
+
@@ -115,6 +116,9 @@
{{tr "Open vSwitch, restrict network access with Open vSwitch Virtual Switch. Security Groups are not applied."}}
+
+ {{tr "vSphere standard switches or distributed switches with port groups. Security Groups are not applied."}} +
{{tr "Custom, use a custom virtual network driver."}}
@@ -139,7 +143,7 @@
-
+
-
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ +
+
From e6c85f55f3b05769e06b79ee8a7586e4b65234b4 Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Wed, 29 Mar 2017 14:26:07 +0200 Subject: [PATCH 11/80] F #4913 Solved bug OPENNEBULA_MANAGED in Template wizard (#237) * Solved bug OPENNEBULA_MANAGED in Template wizard * F #4913 Solved bug OPENNEBULA_MANAGED in Template wizard --- .../create/wizard-tabs/network/nic-tab/html.hbs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs index b50bdf0ac8..8c3503eaf5 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs @@ -47,6 +47,14 @@
+
{{tr "Override Network Values IPv4"}} From 6a12c25ed196cebac65064d3a7b124b7485cdb55 Mon Sep 17 00:00:00 2001 From: Abel Coronado Date: Thu, 30 Mar 2017 09:36:27 +0200 Subject: [PATCH 12/80] F #4913 Solved bug attach disk in vCenter VM (#238) --- src/sunstone/public/app/tabs/vms-tab/panels/storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js index eee04502bd..e7607f0ccd 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/storage.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/storage.js @@ -436,7 +436,7 @@ define(function(require) { context.on('click', '#attach_disk', function() { var dialog = Sunstone.getDialog(ATTACH_DISK_DIALOG_ID); dialog.setElement(that.element); - if(that.element.USER_TEMPLATE.HYPERVISOR && that.element.USER_TEMPLATE.HYPERVISOR == 'venter'){ + if(that.element.USER_TEMPLATE.HYPERVISOR && that.element.USER_TEMPLATE.HYPERVISOR == 'vcenter'){ $('.hypervisor.only_kvm').hide(); $('.hypervisor.only_vcenter').show(); } From 595a74f999d99d1454db9e080c1f3682f6d52458 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:05:41 +0200 Subject: [PATCH 13/80] F #4913: Solved some wrong types declared for Rbvmomi SOAP responses --- share/vendor/ruby/gems/rbvmomi/vmodl.db | Bin 1293677 -> 1522397 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/share/vendor/ruby/gems/rbvmomi/vmodl.db b/share/vendor/ruby/gems/rbvmomi/vmodl.db index c332918483034ee705340a2cace22455fbc68968..15440ef703602396ee96ff8262aa2126c9dc5d64 100644 GIT binary patch delta 180284 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

I-UV+SUS^RHm(lxO)pUa4b^ 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 delta 136112 zcmbS!cYG98_xEpRcV;$iOOj0p32D^O5`@qR2_QWXdMAXQ5Fi1hmqe;a2}W{IX%Xo) zqAn^WsDO${6|Mu@lPmA&$oW=pWpPu7u7o1Z%I|C z*-fznUhn(nuR4^GfA*tAY8l$6)5Ws}Oa2eXmf{mSYH)UhT6Q!}T(N)6iOV8hGyPb< zl=E0H=Rf{54_{{a(Uolhf%!!zd*SWAF9~*GTz>9nD|uOd_^FWwG^3=CYytVzKkdo; zptE`6xcted8DO*g@_o;Y<`1mt`20W4ELYzcO!={2*z(1*FX78E-~4T7Sw)PYO}Er9 zf6eEs@d*zJU$7BT>B<)j6Zpa=_~DmszEYI~f|B3;t0lYv9ho4e;VILPZW+Xpc+!y5 z>Kg_KdK50OVNt$!suY(0$!C64`i9tC{iH#HCWF7#5dR;lr|+NmT}y_`-R6AZUPgY6 z%WMYf3t9Uctdw%u5V(I}X{3;!btr&Z?>5KmFS#;Qpvc#xP+Ggz&qjB%ye#zHO21gj zYNOPqQ#&MO|HB_@3Frur2=~V2zy1@O9hQq>Ve?hCrs@kNb{C9v{duFj|MbtR7#wJk z{cAcNMp`Iom(UBN+SKa8y)ixvv`*3f$rGoJ%765G6-ta3YUK~R$fm#BOu{zfxcoc6 zFXnH~ZrHr&VOP;czb$Ht3QF4p_>zybT`tD!x?;C8QnBUnFnXNS-&#h;;OP1%n`mL6PN326foFH^^ zVlaa(g&9@BTn!AuCiSUDm~V3`-YUh=zGX@nT^J%*>C@*eDn~g=jKVSv%JH($Q^R9D z8{Ll3f~YmnBFHcfP4t|YvwR#j(?L0X0gr1cN5smV*=gpPhfP1-k8v{KjU zUJ*2`rqGOr{bH<4^R7!0#f1t?=4|t)yij3~hD^Lo9BK`w=3zn`*C(tt>Lv&l>KraGrUt;-ulZD_tYpE@g>2zj zF_0!k2tCvqXCs7B>Qhle->T$e7bEja{$RssLesia@TJFb25%Y^#k-wu(GX$`pn1`J zr9u80Td*a(Z2>2Zq59Q?eV9rBm9Ddx=*U!Sl%r8~!N%5#b9)(Dbv&#gh>X?;TO5Hg z!VrOmEwKbTHq;hc3Y-xgUUh{Us$dyhPuR<$yY@+0CW-q!JE4)G_ zL&Rv*1F_9E*duBA`kYAATAM97Jf zK4~PJM=S6l=k~D192C5kp=V(IR)7>h!8K6h@Jyv*1rO#axN9x(Q}F-$LUNM}w9^oX7|T;^TwBisAz_ za(S2#K|dw%1;Si%S_{WjL`_Z-?oixmA<#i>ghXwA*V+m%VBlJIb!rr6uR_t!@&%ve z=Q#STuwART>N_Qvj-@dScM-ZerganwSjh*0w5q9L9KGCGP(?V^>mp3yQ(=;ws&o~Y zPWv;ENeD;nWZ^ZnKlaLmJ5#EvHgU910Y~#?r^P*ld=&Tv@oL9<@;+3J;P|DNaF+D} zOftnxJ^J#+Jr_s~mKesMV1S*L_v0--2xJtAPyTkth5ka2)_cT2O&CyG5Esu3oBsBS z*aQ*TIw^LFOIQ48`yf!Ijjj$7m$>NNtEG5Zlx=VI!W@&eAEepAtfm zgA^mBJY%=f*TaQ%S}7)_%7-s&*(+1ak-|b0fVA}4;td`5AH^jkI@U*JOuWd>sMT?4 zw6K8DSpcm}7mnk*wno2Z2nI$?Oyx3+X9{c8r^=g@NE+0~!1};KF+p&7yzm)+qbl#o z(R68oF6hg^;cutHmx5|i>?C0q>MjVNJClSRcxo9yCns~#1mH>WPL5%7D;WgYm$k^x z?CAcS(16i`REY|wa*Ag>%IXyVV+f>e39^;mnZ{RJFUa}Br;_9HbYUTD2QJl2qHdMw zr5yNQ30%2ysT0cAaoiaqzfQ3RA z4eQXlKQ0ss)S=yJ&@GFF!3+qMU1-h=Tt$~({x%`BYAK&>n-C6Q&QejK!WTJ|C_Ebp zmfpBbSYl%Rbc(k1qQYfDME=H4thDz9VW2wt*ULGvqie2m-(A5u1Fxwog>fzjQuB0G ztl=8yd1;kUsCL4z=Q#0_P+NtWy6iQMM@dW|<-9Cps&yW|%(XuIwwlXSO_2;O;9>$J z{+F%jR!bq1hP|Q#RCL0~#6t{|6B$(cDxW{PbAG4NV?wf~7%?alS{K&}&#Pd$YF%5$ z!9q)B#E@YFmj|$=c5UGL1~ayrVFc34PUms?;-^*}xeO-_lBA9Wj z6Fp-l3)7LEq62%58k0VG%BV@Ss;)7V{-`Edsd&4$5B>7C##}JHnmZLa4c*KgEkK@j zEzM20_yir^Y%7;Ufd1?@vAHIC!gY1u#Y(5P>B3#B5JRai8cg&!(C$yuMsrI7)#mNs zBn2b4+D@ULMz3BrI=)k2OaqZw!C=SdR#r;ht#P`BmY6_C>K+x z1|{SeVQ!`PX(n&%PeLWSD2TPldIEOX7e!p+VP?ZF3rorRtSFVSe2Rwn2T=BYZU_OS zsL7^CDt$*+uwCC0Ca?ui8#A2U3Z*A(r}9nc@Yn#)nw*Whz(Vx0s z(X}@B0JfCq7y|uhBv7>5JCG*)8(^Z+v$`H@c1~bH2Mh~f+d8=pLo?pS=M7(QL0t~k z|F4cVekCkMm*qMtk4LKajb?4qx^Fns&+;qym-C%w(BD1}_xFiD>Rr&*&9Uu*kXwO% zoyFXOU3W>??ZQcn2-ev;{z zy(aMR&wM)Q>8qbBlF6-We1(1pbASr2=XZm>VQ`)H`juLZdC+QZ^r6<5aBWsoeQMe z5Z(V4wtE`!$)@UHzuc)f7_$i+@T&V&K*kebEck~n{(awaU@#PPh@|`favz{9svMOc z3L}}frn>u%JCB85*#ctb&QKIx`OzoHF~=wlVWXquH%VkBzK)%JvQeVDvdG*qd@E2y z7A(_Dl}#p*`67Qts#=W4;Hf9|hO+F=jZ(B>;pw{3t+)|jda zPC9bw~T| z;+xu1pV{tJjY@m+AUj6jt8%@Ect{6+L=qFaC6ahZ-oW9~~Xf&{f%GgIbqO^tr+c9IL*wj&_zZk8u2FJmB z1I77#eExP|kodd`jdQW~3>MWeEgd`sZXGg&6IG$F!#Y%4s!eQXDjyMZ>NkwDBuE2f znos=|dw^;xmfo@1=u(>a1MlAP`Eap?fH(k)H&zVFI+90JH zSb&=rNaHeei4Zl8hvik)EXWj@#l~MWF6WH-?sK9K4eMg|&#(8eiQ~2LB6mmc)#P*D zIFVyOd)t&HF4ViopiSB0V%OW|Num~YIXY1j2yD68HVdZi`o=^KVN6E3Sh~DquSzs- zq*#+mH_JftOR*AjUTCn*4a@J?zfts~Bdl<|82|WMIR^5^K znyv?RsUJZ2W~01tA8#_QbK5ixLtLz_$K8IaP01TX7K8^vTtn2^tnmX|D76LiXi*If zyk8ez#?!6Zbntauy_fg#t#4>1!hhT4nJqeo+>Ezn8z;SswOt@^ehl7)sC{BTFCWGh zO=xA3R}C6gY;H!8i$Q~aZM*^;H+G2cF`5EShneg_j*Gj*BkUczinCYKy_^^jXZn4w z$f9BhnKAk{6p62}db`bz-EWFD+2h+*y41^DnO3Y1YC;X);zW;jNrQagiXIU=QRG3t z=+!qZ68$z(@}co>i;Xo6H>57Nc}Bd$ZJyk^EJ~nz>==*jc3yRe%!PZhOkbt#b?N-O zTqq$taWp@um8Mbv6Bqx_y)VA34feK`cevw>UpW16kS_z;tehxS&u?*xZx`sBrGaF9 zA*i;qC*I6@gqtE|=5;`2qT|J!iS&TnzPGS3vGzmY|L>!GRwzj5>l01u-UBDb9Yd_4 zm6t?&`ubSO_kA&(A{UB5l=H065VLGmk9K^h;ZIvq5Z{H5^p5oXH)?%CtU?jT`RcQg zVe3QK&#qTd*dMV{p~+rJ)lFwki26=|zG2V-!(t2`BK!CgF^9i$ru*>IvTuh^YI=+r zfSGjov$ARpnu{4Sg}wzT<{(;rTFg~<+_DNpBPE{U7EJ(^RK99PiL@$Xr2uO2U9@+cmg3J<;z*`^(5WQk%9cn8t4FU4&t{Cu&wgk5<- z^rPZ)y5X4J$UlsheI*uaRN&NIbLx}NH@wzg)#>;*;*V}B%>Pz5#=(4yFk`qBcVLXD zGCF=^WrG)WyHpkYbuvXwPqm&JO%l ze8};+;5YFcdN~=Z%Ssjw|00%Z{~*4}!EQC`X18;~m7*JYhl= z-ZiPS$#9!*+S7P1LlIxUF5U*V7l)?U4@}ZbaCPm;-`B91m+?XB`)NaRs@!ffRHs2^ zgX)Cw3JWb|s~1{b)fr{}+Q9Ld&G3q5-sA@uG&7`bpkV}xHBvBt2Q#*w-EfVtIT1oL zZ~FLApCGN@GMAkas~%*ULEasb$doT^5jMNexKpD1=FF={Rxn6dE=X?q%F? z9~*U(&3y@b)RN;`j3JXzYeFSTuVWah?hb7Xg&aLK7rxl9FCvDt@g-St#MCvkWfc+A z@VLP~VUp08xiC#o51Uc9>KoPwm1$|LVKH~JsCAs-O%!1ZTxnonuD;NS;nY#>8G~J0 z5ZGk?Wfp79J?DCRxlV~G;D8SV5tmnOjb=dJj+c^Zfs;0g7afK zBg%cNiGf+BsEaMuTWVd7z{kxvA*mq@GPE!-AERuS+(;;DseQ-WIQp&?$1}ocGZPFf z9FO|95)5pGc|3QlXTh6M%Pyh67A z*v_C;^KWl>o+$=s*B`v#PH_GjG$% ze4h@$;2pK>Z^+Q58kFmWq%)nx4YUfC!VV+6Vp3hC78^aBu^mCeF8ZU)dOQelI3o-P~ zaKp#W2K>PhGt$7rL-&21)f^vpux-p(+5sutvpGYrQQ3W{Qo_!sMMWK&Y>X|raAy2Co&pgG@a4>wc&gXzHp zE(#&NbbHV7XriGGi?>KkUGbK3aqgC;M3lzoFpzb;TaT;L(>dg`IiBM z!3gGL8-st%FpOq+2Sm9cVr@$7FSc-eHVZqAOu{(U%rSIeA{oWp8JU%1xQJKmJ8F_0 zPe12!5VUXL&tq;v9ZhZ2V7}oJ+Ja~!7jP|&9Xc@Te5$fg6V9#zE@(C_(#5;0!J)-m z!=V!`D`R*wdUJ`+KCXJU9}OAQWT|00M#MN8w5UAoMMI$qMR^y8=>=)I;dQm_dNqj| z2wkikkn7WpGHqX>aheNCCnXkySiLAN&+rg!u$#KR~rfWrb?8!niCZoL^k8Ztf}|O1zcLAxi4{~pvD~HGPo@7 zzp#eG{hz88zWVfP8MJdPHyz4#wDARPD~O{a@0y{u`dM0vMCsq zMz)}dh5Dj#Y|VJxu$ec~m+ILTv}2PdYbbY^FFe@I91nbM8B}Al`$89z)KF&dR<2J$ zFpMM|wYC{}f+*h8wsV<*r`M+W)-2ee_s&$r-hGB}y1aukB`R=h=f-sGG5onxqXOsJ zJMQc zH3t$;m0ME!egoTQfO~Iy%fJKGcx>>t!NkTw&F=3S5;f0QLrGl+hfOVGXm*kTKs#`N zFM<2Q#P|5px-b0Xea?m`Ow9AGM7akIJ<+$JC0Cg}4r%zHyroEdGaWYUa?SMdVSSBw zVaLrpAS|}hSOB=#Rje75yt7kBwa#1>ygt-r!=Yo`sK9DOeWWcMZxr#jL7{5LbQ9QB zjR`Erh2yGmwz`#0Sa{m~v0)*mQ1+YS=qCoAO9(+#(#IT1CBX<|CcdNC9IZ|oQW(x5 z;J#~a8;d7v2;KS}!P&V+a~At%p__MX5*;{Y=!4R`ttk6zSaQuz^H(I|yms1C)?Wm9)XFb?Av zhUyF^U?cYuOyA948dxw7F{GPDIkB_4tN-R#8k-b6=QV?NHN~7tOJugtyUnX}O-=P=Q5d-gzA>=N)NocQ<28c9*{2)tOU zW4~tXcZLCK?X<-~D`|f}b7dC8ru`SWnSyc4%WKsFg4xOAY$Gol@@eB1V;~(VMQ6Jz z1OAPTO-AZeYS0sm8?~mAQr%H3*O}wi6@%uPI$rw0Kq_XD$lXTs;gB}7YMPO40%FUh z?p3uiOwN*@4Xc@9xw;iMENkS!$b0Y`r&u7n@OPeWi>(sBaP03ktH*5*ysrAAoV8N2 z*Vjfl*ZDjl!!=!XsWrWFgLgH{j|m&iCc4zxaptCBHv_RtA|LhspIpm*)mmqVRVY*U zQmNK$Zqcb_j%V%|s%Yl)oV#3UV>r$x$L|?l(&#Du9|NOtfcfJ;T$!+~o=#F-+P76= z?hDra-oqd*FQU%_!zztD&nG%+KQx4}UXXOeGMbJ);_R%wee&4ALbAtv-_ADj{VmWg zUpu1@azoDu#!pa+&|rhJG5X1ZW6VHgf~-pty=E}7c|BP{#};bDO73gu#w&S1Sa{`zZ5ZU~7{MG!7pz9rsMb>{1L?BO$fUnhf{$tAc;s*7W;2t3<3#ZCXhUr( z2sDn;7GO*pO0XN5BZ1CQV>BfPVPY&Zm;MMcZgX}A^Yz^}ouVV!rcD?z3Wrkc##&T7 z5yE1Fm)VE91#>dRC>(K9LyXVU&H8dM-EU*|r?!=ii(KJBYJ34=5c%m%DJ8+bhdT6O zv#}aI4CTGt_jU9QGg^%(X=MdNMUyp2(52r<%M+4?=O~|9XsMwDj~JVtIkIj3-qL8D z?lRg^Rqw2A<2#>jUB0NWV?{JE0<5L!zUIIsB2V1 zA>|Y3Ab!$NfoH$6;ZgII`o_C>La(kuW{TWs1nICT&bV03z3tz?__Drt28v6(U=DPo zJY&4WtaOO~4IRv3j+}VoNtF-FZeme8;D`-&pdIyUYGhFc7s=w=^k$rYAh^mPsBEJ; zEsV_9aH&l+;vBrZrSWqVz%sO@;()-+k$UKEShA4?0-(8u-L*y2tOTRJ_V`pLT^Deq zw>Gk%1o|ky)m^q4u=G!&kwu_Tjgt5pflghcl<)FU8{=ZN?#-^oR6ISU?!9(8X_fCI zq`h$gT7sgSXHUvkSl>Yh=zo~IF3*tw!JH*~`}7GTlQJ_&NHQ|R#Qp5_MjRaK)78iV zbExWOa^S0`hZ@@Lq9bCl| zWKhK{PhIZ9x|!FT3mr7T2?W=s5f$_?GOGucjjgZIk00C$bad@!TrV(@T41(BQ1hxz zVSu&K6yMkFIaN8r2O4>LwAg`q4AR&7_#op1-YHEqBi=G}u(6-|y7DLN=UyCa?4`aY z4KZr5UcR9+WGG)oRh%O9CwAx*?cH_am~=`)gpKmvN8Ts$Is2-OT@lJW*%C&UahgQb z_y+*ZO5=hCKzpd+2p?h8_6nGicI+N$jO8vhd5t!{&4)p6=#^!#a1HVpJV&4YL4*SK08Kaj<}3 z+cy7B(MXeh!yZI=ea(`(u{mU#k;T}`hfrW>uCkkzfqo6q6s&Vw1oH`Qv;@8hV$ zCVM!g%`&nLfpekdPuRf8A49$88e^#T9HW+3p>8Et?L@QYa#0D;_0u|Y@y-eob!%3bKD~#_m%tI*@S;#)<8_>?j_O`) z>nvK*f<2QW%|=r4A@$r#sah(%SUa79)!xKWs~_wsPC2 ze>=zdt*UXW#rU(f8?}&op`e2JQRE z%S5RkdU;d*{ay-LPE@Q{wA4S4T77KnuA-MaopnAj@*swPJRv!tE=8`fB;}WGQ)t77 zb~8J@gmbDVjqP0LvS{UJR$nSUVU=jn7eQ8f)Dqt(`xo7yH*qcg_8Q3YzH{NdPwPpk>(tTsOxMv-TY zW3lqcp;%zGP~JJCFO{4%W}_j(K7&3t=BXQ4AzyGl2GSreqv*(E-KUz{*&0TjzSNu} zdi_go*znb6lsBy#tv$yrF@)O+*MnF3er4=Xp48fXZCp_P%fxSt^VM-9&l^dVDc3e3 z*W}@OBiqZpU73fmeJ^m!4uX~upXEDauGS5}{Omh!D`Ql4?9y@OqVcS{V@5?+jOpkD zby%i@qu_hvY9DBTa#fil=!Q0K3c=L{N`8VRIMT8*s|YLIaY39rZpY(hw(e+ z45`y}T)$~-!r;X#^QPYY)3^n1V9N1-8AtFZK97!n8|SJh{QGatl&Wh+TOPtWZgGbT z10V-*ji7|P9Nr5lbnUKjx!P*eJ&wP@7LMBw?{jBHd%OM*x3aXifCrq#Fe4|%G_i9b z#qrrgqn8$;F+6rpLR#f%-B!OX<*0*?5F}=kOzXx6Un5G|RN5IN<|9B0mKvl_)wUvX$iMyd?n`CgFPSn+GD80d_z+@? zQVvf}KO{FuQjJk~I_WelSZYkutrE*mebNm<1;$v}J!yi!q&YS+5LucJ|E*{-#g zX?BUlXVA4qmo@SB3#hjY6k1hoxhQpQVbtCrG@*Hk0yF<0;RaWdblV3@musq}rvsqZ z>=23NuXtklaa1)_VxBj!hsd&i0!~vA$HOG%Ggc5aoUB`iOEcLbU{|hxyNYHW0tVy# z5W(6Pp`UTPY!m``MA)%0LYm;r(#27^J$?`lwzit|j#_16b%{wwfbOhJSv91|>bKi9Bqm&(aghBu5Xuh8MAhO1fl2-IqO7ho zWxrypt0N5s*w1A#8a(}O3Seu8r&nrAs>?}%btKIMU0z3Ge2!9~u3kF3uHN=mU5Tw6 zN)e%WhHZbc7$;sI){}<1NSo?QX|A^`nNl_CA1kpV5%+3R;WM0eFvX}kUeWY>1Ia`? z<2a7c5i1R52&jnu5%fy~&K6oH%oul9t#_wrAIe^?B*Jk{rZ_V^nRS2oHpb}IdUUg) zGyva`)@-&%(XhI{j8wtBz+(Vy`_620G>VsMGoSkiC2htTxpgVX&38t*lqQ_#kMw4N-w^=*2q1VedHrL$Y_^AJt-kepvK1e1PcuGuX0ugn zp441=-DBSt3#hHMoo~D&yM@%33GixtsI;XtRehS+N_tLxde}n38I`Jjy)Lv2p!gQ-WCpXk!tAn}_n`a}2f*$JJc7d+Nz+C{_CkYs73M=TX|m9}y$v08vn!xHMd#S%sJ#R>dMbpzw+ z-EPugGyok}?JiA319#I%rlZ}ZZ60CVks@v8qZfsm8I117H20KLm!GUBku!U$rpb2PJcK;O4Lluy}pc~us`yX)SN>5NEuplz;0^?6SKM%M?*4(NMQiK>rMBKHkmFiV*COjXjeUU**qGKlzF&xy{;t2&UmJ=kh5=>emCry) zKl6l|n+HmxJfd)=)gD19wS42LdlQK%D~;_r<`@I3>vkncN<|;;xnZ{zTR4y=)v0uh zx0Omd+xk-6P-!&43!uBha8uCuPF6GhGgKOg-T>|BR4#V$blLgTf0&dGdUYoOU+qgr zhe~xQGEHL9U!dW58t(v49forPbk{7|acQ`;h@HOK>qe|%-8PPtSUhM*T`Irpg^BJ) ze(sZOoJ={RrR^wmI~WZfBkjdlL+Vy+S+yRejg=0g)Exp*dddbh-1+Z->a=koj<)Yk zm%he0*E&_~Dw!T1!=~wX84}xcVjRC$Nn=lD%BkU{sk&PU0VC-|rc@h2G)8k_6nPWz z-y5&_D|C9jziSk>9$)sOs0=RW-H(?&+61lfhi`R?n}>@pa^8}{b(+NjB2}!VdK=W7 ziPCtDAVJGDvZR5oH(LY0F?9V?KNGFn;a7=48lcserHt1%@`;iL@pnCB1j9#-2FPkExnNROv* z@d_m{?m1~3x~t|^30S8}EYt$QoH&I=e~ zdyW*V+c0?DFb{UIX40Tum0T%~zk2GuV6Mc1=CDZ7rJX{nT8-HH8V%HCoNpw9{|jcDa|n~8#Z`mxXi zuvBt2h#xg&b|7AR$bo@0;1I&O13O!+RBs9~Vh|z-%L!fTyfr zrJ>3!D;MjFj-wNH3R$8{z$?)(&(yQMw#|%Biwc}x9o}w5 zdk0f2No}*!y|3#+eHslpOCZBi$ zjBL*hBVOMu-N4hSfsT7yBuOBj&8k$Vx|?;NP=$GjZ3i)+oU#d!p#>}GIf!z%a%cw* zqKE2}c@WLrCjFqHEqo9arg{a^!R=CK?GwQ4yhG}P1G1q2P@?lYq)O-udegR3I)$h4 z10A<^O8g2ZP-T=g0GaPaEP}pUdIQB^3zrDzxmpE#xG+WK!^w)u{=m3LVa_0d_oy$Pkx zfLi6JWrrQWwRTbac>^YQ4p@R|6J7y_d;TxQ+R(;VAdj-%(lt|PEm^k-F_&3yms7#- zNRt2zzK8xLHPq!7Xw=ss4d?U_c?O=VWgpc0bwM%H8He8Om9OBPq#lsku^fajIvs4c z(k} zxPwxEIK=Lf{r3#)6dg<5KR{4+_Dr7`x*6;T{cwoKe=wi4!@53tRlsS;8;7Ny7y$*{ zkMIfM>4PJ>%4||Bv3(?bTlFhK)E^Z~w>U1oKPt7y_wR9?%?Hv^Jb`G!KjiMLJE@pV zdq0$psU1E45yuR=v@EgK=jsZ`aNp|kQE*!EF&@H!D0=D$vB7Zs!^Xo#OiA(A485a6 zaevG^C%6H^E`h5kAQC>7QaHVB_*mMh&STIg(rAwm-TZ{}2!Od_wFJGA2pGHt_>2`f%}?U%T` z?Z)S-k!&WoZ%hqh8gp{tcQNISrdNh|Xv&mF(4dNi8;4K>#sOfvvKCnDulPJ{>ImSL zYk2xk5H`qzA-w1VDZaqw&-^Z6CgQxbMzh#!QQ@~>x}VNVs{u#W71Eh^Hw`N>)cZ_f`>2D2B>q-ddW+b znTgAMnb!o=xhIXrLn~q&R^uB|1jQ*Zzw<)GP)!Pg3B- zHPR4`IgoP`_^Z@N)MzO>f8)(y+8AQ@rn$d!F1%?jXChnOVyw_A2hy?th4CUhp+h0| z`b_Ut=QnfYT$eVW`{yzB##9_)uSpYb@R%)@oB5#--FMxYfiURmv-(x3u0!%>niB-M z7s-bqx1@ouLPTP=AuxaU zj|$zmhh?b$w`9fyMnRM{Aln^i@toCAe{6!PLO%Jol!ck2b*J0X^8n5L;AFldeWBL7 zaYvfvp&q8N_bxYz&>uDd)kwC7%GXlq;XS@303yi?l3fvhY7ibAO#S|mx`9yKtJkmp zkv5>;dhVsy{(q(QD0PSBdN9R8^*9c9xh_1Aeo<%k`9obxruxgO?cf3SY6EF~C@#qT z-5Z8J+yfRq0!c8&1<3ADn7q1y%rbSb36OTJGMNRr1Nt86h9uFqu+UJM>W}b_r#anx zHK}=ae?TCGbn&&&0|tMND6d2Z?xX-ZNRZ{IGPXbDre~*UP$eIP#TRo1fHKPMWvb$+ zE6MAbHGb2rvQ-qh6jRxS7?>AQW+&V?XyS&G_#l%!5JVi1R#9A>P3#n1n>L0aNaO1z zZvy=8R#)vef+7d_G^Jk@1Y<&~*e&#H80;}T;W%JCVmqaSWu}R~PokogIClm)s%;P< z&4tN45S3Hr^M%1TP^CMGdfZRe;-9U}GP9Geb)p_aeFNw#v&;gL=t_-!s=497?^9jC zq$;3{JYN@#z-n3*do-PHWYc1YzBakP3eO}P9}$rKW|Or51E`N}@Zei%1Ds#D?k}@o zITTJxfII=K;#QkbgSCjYFRu=QEPWZApR<#gl`N_1%gVVA67>XBV`rFuNU zjMajj);0`_cY|dXWp%f1$&^w_W_;()hl5SAw+ePUUfc~=o~<1>gfg~(_7IkZCvn!_ zMx`M-z8`KtM1<)O4>SUlUa2haQ?axmRGz3lg@wt?=)$Cv{`3o=onbNy{oysBip;Wv z@bpR*d7AnZ9xk(OIec3k&Itfdw+dkmhDY$#0m2tX=&SQ6LSK`qk@^_c7jea`5+(Qc z#PbE=_PWd@)MARiMd>%S(wm0qF=2h zzXr^>iwi)&WmlJXs6ExKAv5WYK6lrUr+C06A_?JVm}aOcvt2a+Ro=ncTT52=KPkIC z&WpB-k(t2*WNnSnDK@mWj=)v5+0NSVBGelUuBwISMK3)#*gdj zb9%3y%x--Qe)mij@aL zKDk9K^tPQE)D5=NnOKgDx28_Zj*JA!XJj4#rtD|rPf+dk5p)Y)Jk7b{Q;$k^VH5IDJowdRD_I+rRfCpY@QxqZ z6i-_c$#ipv6vgBuqD@+FY(I&KzW=eKoF?)+KuRk&(U)C_9oM9cZv&(0wWcx)2|?2} zX(qqJIrvdCc{@IV8gjnyvD2r`by=0&9=ouKE#%WE4IN40EuGBPl9Lm-3n%CUDCAjR z&2haIW(}Z%Rx-O7kFlb5_^fY~XCuqjcH)H5>0>CRw|6XEOyHa7XsVCRR3~1Kx7NpQ zl_>YstVfVJQW(cl(c?})xAX^-F z+sdD+F%D$ySm@!iGTVa+Aj@Q{iT0f_DpZnW!y&d4ve~h>yp}sn~P{ zl{8I@Jkm2gWZf#q+vuLMo>eg1#{L3h1SY^jCBtoQc-B$UOXf-BSSeTEK7-^KTG5A# zni-?$VIO&Cb@xm=V-%RSErO>L$G1<%NuQ!Pgy1ym00#Z~NLWh)`pHW?NIx8NJiXAn z5)JGJe~0;tfYYr3hwW!OV!><=vAC1IhnUk_r#TnsxI=Wfhrw2kqT7+M1U~yXu(~Rt za#osHoDnRW^N#mu>OWYn%lRrO3h}qK^W_1Q5Ct~^PYAh{A^{S%Ltk6W3s7b$m*sFTDZe4h8)0J zOdKgM_Rwjg(G)vMeoO5yBvWQCuv-yMd86gso(dfk$H?^sbOKu2IhJcL@L$z*nQfA} zgDja2rOPauib-J>nhRbsz}NZ5BADLzaWXsk96;B{$*WZe2lw=4#vBTL#_PuA;8p%w z-VSmv1IT}ZoTG7Y9Xgthr8qo6W}EcDhI0T<6CuAWdA~Zq*(@EbPTBfUA7sl}X!`zW zH~dBuC&`02jSb6ym#}WW9M9j*&d2`@fX>v2Z~evKza2+G>|Rsk%O0_FwyM3BqxExg zIzuYfsCcTZ1uUA5mDLE83gt)B%1YjyFUXB)`Ebg@Ri=HhQU?IBw!6C}tW=$)GO0e>fYH>fx*e(NSUR)^_53xT zD`6DmRLA`PrFviJvqbH$&=&J3d=t$PiEPP81>8^c{nKVSV5a|sdC728ACZQ$+J9yP+9|W zF;>CA{BMjBGjPF|%e2ehqYP6AaJgNchhi8=OlN;tq{bmU4ti#{97LB2xDCVn;T7o= zyhgr@r*-L6yjSjwP0|>$z9JjxLT$j;>POsNHgp!Q13a`t?n|X(Ew+MZ{VkO7s@#eH zfe>wKYPZvGult#Cf|g}fSljhYnK)^Rn##jAd>lhwleY_6o{x=}QuYmOo2RVfD+dH0 zcRsaT&tnDn7CGIIApnxML2D&|_HN(@?}6~Fl_pKDE>BU)Z0v*=%52Am%?iyA70TJ# z8`>N_V9mjIJlQwN?0N}iUbv@>xSG%`8(x7E*5xDYZM#CkE{)9%(G;_8h!$li-L$>s zMRu}n;rTNZo?=KFw+8UPN_ zYeHDW9gvq|D5P|UpQ=Ks4HOodb4N^QFy>vE?bQIK_+K8D$>pxz>R@{BJ^8(G4={nL z{M+^IRVIPr*85y-VzQ$T$}`nz|9Mc45zIIw&%?LCU=rFR9@Ofv+@4Jt{#wmoH`;-9 zPbu-1#>^wKQe>(R(<_V!^jkP6Z7vR73_T5E)dUoXMJFK58@peuTeg`;<-gDY{%t7t z1DzER#UDYVKa^LZ0RO2J@e#K{@U-tEF0(P3i{wF1qp1FI9_T;;gqmgtMSU&TqtdTT z&52IPWwNRgKjz)RtA6ieIn%Y+GryG6wKo9#*&DdvG4fOH9x-ZI9^?o+Cu=u`I4+%p zR{^SUZ`GB2f;<&2t7FrUc7rSKs+Hkv7gy;DZVNmYKBugslI|9WYjY-k2nlePc4|#5sAUCvmZQBK~qL zw4rY!vhLC)E$bgd>5gQXq~}DLJ%(+Y5AtcClLr0~41Ztd6nt1?9IJMwSp6C3h63rk z_Wq$XE?a3tzn$=2&=Q>PQhAwrQ<2vdnVlmDpl531ij(dga0|luD{^o3Xx5G$zxq7&x~Z41k{HC{oxj@?a0b z4TPRt3O1M*jMONeE9pWx{i>t4>Tg^QVCw6CeN9&mVde-^GGY z@Qq7)l>P~i9rCLgCI1CyW!()u*mgs%OMcg^T6#*vO+6%)ds9Bi#0LbYTd4pRz)iO? zFkXvq$uFw}swmiur zc4BM8h~dP=m*lwJdo);K{=|xG1L^ZV6BXba)oWhMx|?&`rrkDf|ZkGl#^#($hI3g2I z29u&`^ARRxF&we+*hR**jdoNhbw~U7T?FW#@-5(!gyNe ztt6{Y551MH>eJ&o*yft;qp%ncGNLZ$@We}Zd#=e8UKd!}H{Dy^Re#{CFnb35uJBWK z0Jrg36>*Ew7sBy3Z7a;mVl1EgJ+JX~?IDh#7Nx67?;GpF#l&B_zJUgAl^mf)7}NXl z6ut|w)~5#7SNbb#x8lGcHOXg0fRc(=*s&Xav_(+P9cZ`W6GrS>nN7@KjB%q0cl9B^ zdJxIGcOjOBQ%6j$!yA}nS26*jyB5i04N|tD+JCl2U(TXkJFKBh5U)c6h>-e~l;_l^ zw<{@g)Tg}`Fa59(YFr6XcraEi%dM=Gv94-|Dm;h_$lMAR`YBX-8x0Y;-yWv09aB7A zIjsazUJW>O9jb6*i^`@wRg`Zae@4)WdLR)kOo8uF4}9(P;s?+%#V-Z2fOF&Qit7&i z7Dgyl_%R_Wt)uiqJ@&sZPww>qwTB{=B0$kNo3h`;-2wxv>B&CGg$$&UYA}H6M{^R+ z%BIh%;U7QQ;5@M-_9I!Qo6$-S^zM#Q0Bv@CxCS^L1dYgUdwaCXSElX;fBx6RO`aIm zLoXP1WqpX?N7WP-Jcsz2`h(X@!qrdewoqIRg?Wk?tgwc{u2+IYOKj+?#R;x7R9FlV zNM08Z;55hZ+G?j&cZ~7YK1N}Co_Ml0vN@AaVLP*&&jKMhT+ah@H_v1oiAC@&=rBvr zWdG?hrjDZCXF_M|C~Tk29qyB9Y+dClS23yely^OF+X!kMi_rDB`pPoYaJSYYC@mIx z?Z5WFfT+2#2%o=y$A*JEpK>`>hEF`gu^|?bkLwL|QRVW3T*!|4-e;7GMHkxB<6Ztf z(2IZPVsQ#^5whIbhBMRjb;|cAnUM&IY^}%cAn8%t z)Q*0Q@au(MGyQNop{LVk=z-xhXNU=TC!GUFdLTSp_aMXpQNO-tji)g)kV2~^@`D7~ zoIS#KvAME~!=U~V-JTXYOIcg$M(L`)eq~Rn-fyWe#DQ{g%p(n^)mQy1GAq+f5p<kbY0C9QQP}H-ZRW9Qd zOFzE7lBu@p@wM+r>ehivT+9K-6mb__2hK-e!>AkB2p!*1c~&C~_p-Gp4s7_#hmbZr zd!yA*MZxVXI`-=iRkRQp>>tf}2CQwgC>17x?;$j(i{1dPXuR&g0oD~sf|^bNfZ?9z zjPYT+oSuUw6Oxr}sDO*w2SLl746>QoA@9DlYmEB0$=+1jL%|7(EDRUj=^=j~o$9 z3TSu58@lff7)@Til?1-n=qSEmjZY(bA|UHJQHJ{U^cjqrLg-gZiDO*?W_R{mvSWNd zh2NNi7VG;fhgDL*?Ay8)<=Ox)C$Kz2J1CyhA`-hPP3XZp2!(Uwe&QfyEJk&2u;xAk z14jSjY76}`T!|-ZU1SAn434pIW?Y?)M|97;z8IJ#P@01r3`GS0zQzr_Wp1ri^n{UO2Fm(&<4dCXf13o@_wG;T+t;I&z}MeD5d zwb68i1q4vAXFAshc#4_9*&a_@XXriGm|3RhO7z}Lg=H3^3cA;ZM9-QbS82B1LBVW= zZREOFbVWmjI^;E5-*9rp`EZE@+uvgAUsfKdueeA;JvFGl_L--vvCrq}n!IBUH~rib zKxvNB4Nc*nCFLrG9t;qaX2vte=Xs^6W8(8l7q$V3kEa%JwTP!?3zfZ?nLCCbL9-e| z8)jPhUi1hmYz#|$*CL*w+G8}`T*Ms>Jf$q=Sj5x6jbUcr5Rh}Z&m0)&ke4X@zrrwk z>@Gc39F3rJFDP$#m<9s=MN7Hsi>H}QFrmnmN-tX1#9oUk`3J)Ws~&7C2sAm53S&Uc zBt#y})6;I3bJ$l;qtBKr8-N}7nP(3wQS_h*%opu&$cbqrtmI}c>SeD~o<%)4NQq7H zw{+|t1&R}KQuZmb0bbJK)%Z87!+G2T0eF2@ajybTpRLl3ig_<9jKgAR_e;tg52!$_ zV|-J1@!WZSLY4AEF!f&c=m{j#1_p8LYK7%2SDRi@RHOF?tCcS?JxuiM9di_}``6Xe z4pLr&{2D>`n}QAoHpi~?)-?(XPr8d60A*{>!E{)D6_$%@v+s#Okt=rCu9-cay0!~4 za}k-;%#OdX`5rDRkJFWl9WpsNX9C%N^JD7SJxf~FDO)`Qme&kefIk#ZS@--UN?6bR zPY<&=zMjVc;n?j(WPqK5?mpXB zp`7iU9_G5BV44`iTH4?mHD>N$3XRb3laYb0Gw9{!IH3quRh|7yJ9!kr9bQ&Xb7b#Q zssQvWH4`@Dhkr} zDJ+v2D;-nB14Hg0O{T6bV5BU+i=*WwJCNI&Gsd@yZmWSRbQ>ET;jPtC2q?^bi z=5%bovPG?@`!wB9dEMlSxJ2c8Z+jGvC>7p$TB)N2jJ6F+K=9Thnz!zBqnJaX`e2#d5eJ~%-4d}j2+gvn2KLmrk!MmU{!k}{r=z;gG36c4gWHaClN^NSimlW+ zp|E6O+)nYy30;LX`&e;+bKFS?CJsUv=Oooon(Kdyj1wl?wZmj+Ho%RIe*(<{S+mFk z@~a%5|7jB+xGK7b+#`N~neSi4eeZ*Rn^iBxf*5;zlAq_nQ^^gpQ}E(-J&xySTrQZ$4)NoG>ka?Vss%vlX;>*coLxkmhc>5Tsw9;adz4R}B&n1%ry# zHs4~;Dhn``YSXD(0!$8f8h7#M%Ev18JfYamf5D|QpzZo4R}<)-A70Vs2ld+R+*7Q( ztLL~ef|Ycg6Y>3;8w%(%_iJS_pZseHnt)aB()y``g#}4an23re}0GKMZr05SjJ zg^41ulx0s$cDtl>IRV6cVJi+mA-XWYbG_6H$}Z2PRa!&c4*MPg^Xa4AI*nw2*%NT) z@0d5+W@2PKz@MLKZbs`n`&7p_kn!?M%3B)Fod;(SHY}SE;E{A(u@DduJHxYSRz+c( zOj!y%W0)WL9u16Dy@i^LA`mGV<87nJ&$$)Jmdlx6=6=ia>_m54mKevKJi$?(Q!qtg zLoq_c@zEMT>*2qrnm-M%AtaNv2Rnt9Z~Q_?JGP0touisd0d(Y7+!iqF7v))M_Ny|v z&Ma(N^_zq6=g1io(#EHc=shEAl-%O~dV|sD;Ah~R_KD)4IdK?&4qbU6pqc~i!Cdg#v_#N8{2^vYj6gUI`|WXm zDl9#cU8hooRz0uuw)qT78k;2)k8gw?7Hcy$22eXb^=rZB)HTUf3ju9y?_vi%_t`jw&b@>z)t-2 z=f}$Ps287wQ{o?LRE6!Odh<=qxPSDRa3a|%n)DsDeKY7y(Uh%r-Ts`JAENU(tE&dn zD?F;Y%V=UJt$@Fu>zJIGHGuArWYW*4pwM}64|8{S%oulj9Z7;5j#W%rI$()n(t`2q z5Q0ZQzBQS&-6q%mg;S3pH05?VL8SiF!`Ix{mEUq?wh*H70P}-sXg%DWs_{HH%jC{)vC;`vh^QE=I2Vw`fwExP|B0Zd%o*MKz5@d>`T_?;-FbsIRKJ+Cpozd zV%H6|6C0RVQUI=HxYoe*uK|ysq&xAPMFJ@K8Iw0HZ-=^O>NMr)qjv3LV{_VN0P{4ur0lh>@#i$r8M+S@mP0HYtsRB z%xQ_HbX0R^Yb28;$+SnUb~?$#Vo&ag@k%@J6W{SYJXMlu_(pFQr^USg^Zk8~+Q9*7 zzL+JcuuE{_w^ul08qxN*>Jc7ybJF;4KG4(-kD${S4cc*AC*rlWLSH5Vc;w~o78$ZP<*wlY_tp&Nv zNTG1#bu|U3`A8RgBQo5jDI5@fg&h7pw-^3I)t_?KTky|=$Zf$C+~-$Z>k4qceb>~8 z`gJ#@LM6Mc29;cm3Ln|+1u3Srm?sQ%ekkx@4~*;A9=k|S0=__O_;{iEU1R34?o?G5~E{Kt*wtOxek%XgZPwe%v#~9INfl zASVnLvWL=ZJ*~PL?XB@|SRd2t=ysN0!61`!Um7b=dw{96s&Ow50!lly2bzj!ig1Zo zmS_EbrbPh3?Y1V1+)|b3+wt(G9R{F1>kzN}JWygZ!>J)bN*C&H9cKKtpQYf)JAhO|y~tLZ#Y`D8pYnNGEbOvpIu1*a`evQheA zuESsioE&WOd}nRy5YG14Bg%akq#Ddn81uVU90BPbr9({xfD1^B%0#}wjZ(pz4hIBu zz&CX8Zz|V+kjK-8nYfDsQgACpKvHIkEH$^~f_6@tsZd3ptJiMBO{`bY1bQudiDdK$ zlWzaI$83uZQ1Se7CjNIjt>$o4&JU;J8h*|Tf&uMQ<@CByrgIn`{&-dgxKPY(=N_1c zTQ+%qP5aD=X;Y~1RSTjy%aG>zV3Ti8Dt_Hug({CVG5K_Lf$K(0;P~o-ia5rNkoI&F zi_^YWl}d_ip>#9d#10j+zi)bS$+7LSH^bBgl^-r3uW=@pGKprnnK<{^`L=l}nz_S1 zwsvAOxnLTWOWiwyX!d5B*r7hWW^{yfZ&hm3UQ@@LHli1Icb22_hK|^&88Sg{yJdoj zC3m90G*R#VdPi)rS@z*t#NAn@{@@080F9s?S*Eu<7B=q$OORjR!Lx&NZkv01nAxO$ z6gY`P{A%Bd=)%p%*H8)&LBFp|=C-FftYW=nDtZgvuy?vSo=&X|GSmBKIEA+gqd%wc zR_-Q|OzS!UmA+GvGo=OS(BS5CCQld8p!DQaQ!?j(|Hs;U$460hapP}7%1+(gbb3OO z79f${LsgJK=p7PzPeSiW9+XZAIMGqbzE zOnlz=^ZV~kx&7R8Pd^8*A_wDV*C5;Dwi%Nr+Q@jy9KPjA#vDAwLICLK$sFI9@vpHg z;Y(X_R%#!R12@tRn_?r?JdP^t%|h6kDI7rY=slHVVDlNSnaVE!ET5aBd+AhFoo*X~ zq0cO3vaWfjr`t+WR0ExnsF=b@F8wLtn!}Kppo2cC1}zOfo(x*?u5Fr5`mst^9lH5X zZgil|izZ)p=%^Bm^jADIXkNtIwjnw}y8IoRNAopi8Jy4VSvGR3)(3$EG>Ael+xC|J z3i#*RY}*L;)7&|>2^bCDJLlT8cnZtr+BDzhD{~DBYW2KA2(9UDU{2g_zRjB`esfwZ zWr1yzHfPTFB$fuAoiS7;jEHsEv5@2QMy9aaCf%mHm|{WrJy$`i<#vFCI>vP$Vj}Sw zwh{OR7e$i?@=(?*(}px4b0FtAIwv@gB_2ooiJ--{HazARTd>$xo`dWm%z|B7%8O1$vjXqpZ*H@P^lf9UH}>d?cs_92ypym2X7Ch4lO`gCGO(jw#J+#k>XPLi*T7%7Otbe79`^md;Gv6U$2O1}Ocyo6Gt>FU=NyWYf{0&mPXk znTuD}?co^a;dFLrPf#FR{Ryszb)VW)HY3j_Yvw*K2eZ3*wvE^bGgOr_m!16BM%odx zdEo24w;+aVv)`7$#YxuxCGSJfc`Or2EHMjG@L|SgjmENq&-i%E00TWQl6%1-&+M?xqjKf=cV)KS0t zlwcp%@FU*MY>{GF>_N_ojGWC9?u#Q?=w-Q>X4bmm5XV?ZLGAOoO*0$b+7>3&{HEqy z@;{$*fWawB_=3x5P=e>G<{F9hG}~Srk7-}pD1n06X{%kD{n{4bh2Vae&uWNC_8hiR z1T%ng#8({Kp|tudl#pBZ>{D9-kot>iwvxP@_E1+`uqkPPGj9af3 zWs8n+WQ?zPB;<}#!Es>e`N#PMp*<#I%w}{kqT%_+VqJQ+0wK;hrU#ovT?*U&gzc_2 z`q-140x~}*_fPWM8Qd$7Zzwx<%9wM_(_FTWbVZYsv?Edn?Q!xs8##NKK{tr=q*##EPaeX(GJcrdnb-TgEl6YZ z)4t_M5}V^rlf=ol=|0{fJ9B{x4~j*Y!Fa?_A&gaxh07RcTpddcSqt*>!ZrO0N1kZd zC8{iha|>G%Q3>ggE(BK6d{+8>MMKpXU^HRG714Dc>(+bwvZxLoBlXl5MQ^ZrfGcRL9GZ%hq)T9(foGdF!*wHj)XWCn#NX+V7=Vj8wf#vsLLb z9|G~^_&I4{kalL=y`Y3mubXcpk4Ur4h-H`aZSPxr9DsCwHVQ2>00zJ~PEa^&qUX`q zZCu5c^@Vqsmg|E@30~O7(LAf25SBObhHbA8F8M$%_ImBeyL@q6)cbFP97W*4Kz93YTWdGzI_eRpM$y5;N1SItY0P7zboVhwsCYO0iGgPB zKCvZfu$TA`C!6r~_kXzZ2c;=bZ4vJ2APr>Ug zT_m_4SWPd%NZf@VuX+h2<<^^=>Mc;5H~pz(5y8W2Z(kA5dP98#BPIe`QGErP09Iy! zuV7H2cwf~|(1*UqPe^dL+}U67pqy{|yZXVooNaTB0Z$bLfp`(L^}gV00q>iMg034o zDhfnZqVHys=a_Cvg27Lq_I%m%shT2qEM&w133(?JfxF6Rogo3bu`D3;6}xLlXzE4R zMz_2FJ%`{COoBOu@%n@@+%u)^MOi|C&{lti(T@HJ82DL$(A>Q&GXg#P2@mpI%0oed z!7O16gMwWK2WaX^uxn}Xv^2!Cl{%pU4^*Sg>*r8cJ+zVY5Gy zOfKdLLLtRH$MQS}Y{A*$f(MJ-qlCZ(=~}11m2fR4no2Jz7!h^w)UXuaN0h!O>&mlcw=uN%q=)2(nM z8&Sr)DoZUV5WR^FD^?!45bxalg^|mU4mc?)aeV6Z2IAASS!~ixWQs~C(=0^(K;WR$NB-}a~iiEzI zICdP%@R#1?e;0IsSkPrDuXco^ZRC(9Q`A8IbLMj28c5UWc6d6}0p~1yj-8v1 z*JDqr3nV#NP?jx;;+wU&BAqlunu!+L>43PRA_XHR(N2eIZ1C#>30Md_4Xws(H3U); z^r)ugmK%P~oBKfG6}Atd?ueKB9tp5&3YYXsb!xNRDc+>RKZE!0g9hziTQC^zqUB)C z&#_p3MRrhXd9P@ZQ=z<QsZsp?on(Xs%#g{vf#jFIy7T;W$sQ2}E6;`T+tKR>KWS_PW4A0;PWmpvz!7bBT zdLp(L?W5jrtsuemV7*=ha8(<;^<`pN$UF`*CEf537xUVNK14>FecgYJ#@! z`{ISy_2&t!K;x$ZX{>X6gI2w?XcCgB1QD>uHNU}%lQ%y@>2V}KpvoZtbu9>pcAiVC&C!w}Ycz?&!)7R@mm*)uie6lZhG~_Z%-0|5vvx8+<|vh(;#w&@xzS&Z zsX{sj%@ZAQ9m3w<<6euNCUn6!T%~v5hqP^)FdHMn0AKV`+dW;-qaKu>VU)65CI1w` z+GRb>2g!kUqzD;k7lEcdV?X2Za4NsFPMbbmHqceYQZ6Q3tRb`c4`_{?vGmuo&os&IMXe&JD1lh6b>-%~-LM zbA{Sq=82@>R6>h{vF%5&hzY(;cyraOc~@dt^MnOx4=3yO`N9yb8`nYq6{a0!f0P`HU|Lm+XEE1+pu6BxgPGDzoI~H4@TctV!tt`9_;^%*?S! z*ou#%OzjRPc7}-qj&v;+n<4bIklXBC!d7<}7=gN)b_StYl_VSgyC3B%^ zwN(OHiDB8ekQ)T$je7ym*TsUxQz41%!4aVJ4^*vnAUvCg}+6Iqg zhGl*p?{|ST`bmnmelU`X^F})GZGsNPr?(g15oR~W-@mi*^12B6_Tw!T@g$pYKxGrt)F`gUO(#=73e;uoJkuj zf2)x9N-c~R?|z5F#38|@i2Md4gfli;GC!i}T|umz+#xK|nj5uKAVWORw1#=C<%&+< zC6F=av@+~aSKu;OBTOO`X7T?3c9}$tNTfShClj#8&m!ci#e|ZGOG9?*;>e z1=sAlTj{Vp!VT2I@cZQPV`jdv!@6OMcP>J$q@F=eHhhmzN3)LF^07dH^vuDu-zUbw z=nx+g$f|wH*BE_){}fIS=K z5>5RZv7U394-h&RXD%FR5o`?s(vt)V*JT#M1NK%wo)L6^%4D*#YGjiF*q*b(m)dG9 z_@)pVBl4V46%Ip$yRc}5T1hAMfT`pg<6&T`C)h)U|FP=nQ9^0U4eq>x!)cAc~PJz5hPmD@sC= zR;+1JB%3Rih*)j29t&g`g|(>OH-KDlOlz{Yp9t@33zZZW=yFlU#B=}QQVNu6J>{|x zb1VHbPjx}`nl^v{X_#u5>(}!3XNeo^1|@nQEPGC6LpeV9Ip=`UIOKg{Z2d>vG;yS| zw3A3o?Tr#HkqHKFW@sMEu5N>?HRpu6MSS=^y$PO86SYh|&sb{j;IOA)nndBlq%w`jZqrNVCyO; zMu(3i9g^L#ZYRki`3MHGwSPc3C@SJiZM>@#QCExys3Mu=5wY@JU)64HG?V_L>wGNv9c@ce1G1jCQMDR9?g4VmK8$MX~e} zB1!&{YpkR=3k4@$Pm5xIlobC#DKCnp^cD?WDf9-V`iO?cYjqUs7cT0SBNxI&T?TS! zx_2N;h!FdtdXZ>$BSIw6VC`r&tqlJK3tdn~90C5#Y>Q6gYI|Lq--5i+J$Z|YH zIZC(7iKL4_X;^vV-OciR1~hQIpZS{SQ>hBt;IXXc$RfXjcv!1=?FceP9j_>o>kGEK zY9(Vr?^hBHy#d}guPl0KBQI7K4P_6$B~}p)g(9B(BSk}@ji+sqBG=Vo-lih~!mG?8 z{)<3`SNkBBr+qO5H^-}rba*hU#??e!QFx%5s4J^6w-DC1x@Z~fnx(aa&NIIxtSKJE zBC$kFlt@Gp26G@vB%@R`+&r42CwdnxQZy~o!Lh_*Vl;V>)MQ6q=LZ5+8`cn$wMGuq z5T|IRw`z)%qrS@zhs6oSHY$Crck3~*^u-x%!I^^HZ{KT{250~&~=2SA%= z8;H}iQon|xuE@RL&~xA4X{7C@_E$t>(Zf*SqsF3#K|+@%qTzIpmhU$)x=e~ON(C_@ z842L)q^5k3I3d3`H3pf|jH5?<4Qeiu+83o=%?%i++d`a%*_)lDSa!dZSW#Q=>Mf1f z4Pa?>ycg2S=+>RPtJ`P;8ZzGyNur0P4tY}~1t?0Z-*inAPf@KsK_AlzVn4JN+vq3+ zKg753Jc;fMH#6Vzd|#@qNL&SGwaisQ(?RUDSW&Yq#3mNayBaIDB8-Lq>a-XCqm{mH zFA`&kcQ1601u@5=I1iC*?+_dX9?(3avq<*{hU%hg@QBqvJrw`BDc$JdA_)%7+l+YR zU7jI@UM;qzlSt7x%wQjyr?^fyt*85mDy1OMC6zC!C9+3|;6ZwcMwkU)=Tp607zIeV zFjSm;)J`foEBO$I2BgdNF5=L0AY4Syd-n>wG!!>tpU~5V@Uc+;zYNhr#!QN_2o3e8 z_Z3Mlic6zIKauRYibR_cw$J*Bx_lVdj~2*I+fNtcZXxzQvVfiF2l)|?mxc&8UGbmU z85-V=-RcLi8X3ult; zY}z1x=>Uw~&LHkHd3vx&VGjaX$01@pPF=N&hfw9SAtK3hOo5kZCwyo=%s{3|zsRmg zEHDu%6rkG=0r2PVrD%cVELeGjcn8g4a1}?2T8^^XRB^Y(2^@|UD!rtA!w^<|nn+=GO!e37=~#$q;u7Ib%44l%jD{7 z*OjRTDNsC3q)0(#u!XSgNl;uYx`LR&To3$WWaQ+^MTTffmc6~9&e~qrX=ky1sul?z zz3!}`1-?#N>+hR)a;E4_*A7yH-+G(hjW`IG>vL~<*pK}89Zv{NndKr8uoKmm`5G5L zo{+S1FpKXg__DA$VpV>O9djU5=^X;c;4@DIJtzSVt*KcfAd0+OW;NCndKs}bTA9?oF46!`e7>Z2xI*VQ*mS&?@LAt^Fsvx8XGNsIaIU=9UU2Oy|$$8}8p*ZMkTz$je@()$(Ec2LwAQ+Hft_aG9th z!UI`4n}kfqfvhzXyIO+oStcIRI(1cYcdvcOST2$whsC54rVThC9e_tphI)S@3mGuptTF>fzH0iKXgJ?wocSVk%!ia z!~>Hj{mZ_

7E!Qi7#si=Xh(92|(-cGP-tp5+89ZQ!B>gpG7X0MfdDF~%eEpAmi- zXcA5}mOUF7T#0&tdvANl_Xu}cfc?NpEa?WkJ=WZnYoQxhyEhpGQSkkZ;wrRmCR&bV zpKTI10^^zO4J`=m%@c3v1R+W zX*kJp1-B1^rotVBq^TQ zVqYM@8EKOG=7?nLil1S2OU!d1OV1VG;9DGSD*~SE197h902>buu1}en>aazd{5o3x zcJM>vB6N$Qf8K2fB#?JN7d-v?kqa$jd5}q(7$9f>FlG|`Tz{XX=5c&RV)a)6G~#3N z0v~wJV3-K}_#sKccOhnkTRcadT8{GUV8Bb_r{Y3wp-%0GJgfJCzz*7@+w|zW&$(m+ z*rxLrB3VwNbaoQ*6jEFnY=+tC15#d|0Ksw9bg3rm`xO@gQ8hh9u4Vy@kzF-aa>q3R z1@`HuP)$4tRh;a~{=jagV^eR$DpN1uT!N2Yr&E+Rzx<;AI4uGIZ6#P=*e9{y5X zrL|_vt~FbCMAY1Kl&{2{`UqWtd5qu4NTSmwvyI*N4Yu;>5itW*0T^qK8q*9pW(cb0 z8>Ot{2B|gmIOkV^U<*7;L2T;RA{nNc-?7o(h_5mEV;jG^oh-3~pAGfer$k*XJMuKIfSLSs+F+@9K)i8hc$@g}-5D-l0El!st4}fS z_*t={=BHJywtzG_6eT3QIK1mRoikd2AFM8Xa_0&>ah?My8hztiLzcw7gKvDxsR?{& zcflnG!7P5g;F6-@+uZLwP{nRh&!bn+|B7cK)(yGNMcpM zMC`i4B}SNMy{lX{gEfx)%_T0uJR0PSWXRR0k{Kv&pXOaG>zeqCV@krHc~RHJ--z(^ z-9ql|uk?p|nPhM1nc79E4=%Jp5OyKdijISit%2djv!BIwnq}~mUqlaQlGkpE-8Gxt z?Kj0}LT`EZZbF!k5t>~|$gGnB-?Rn+pz1Q>Wzcu7tO6mo#nBeG9WnGl{I-j60zttb z*TJIh$)N8+TC=`)#GxKm#Q!89?Q(;D{wiDD)T;-AeL_94&R0%iQZTe4u{T7dn)HFX zAhCxNKA_+E__H%NINO~4Z!0wNf!I@9gIW_|eyS9R?LGQUFA)1`ro5$o6FuCD4*upT zx9j=4OAga@3;XAHvAf$Ad)6N!IT`6@)%BfHF#Ggvh2Nxk-ToAFXd7XzU-2PVJ;bs@ zQziI6JQNS}TjlKE;%@u^2+{KnqC|NIEg>}Xp;$rBTj-IM54Dh$k01e*+`T6pE>WWV zd}zs>P|N_SZAb{K&Un?B`LrcDM{%9B~HaXNz4NQ; zPAcMXtj~f#E(F5Igk?eyyWJgOryoWe5%)N%{o)Hphq4w&$dLN98$T+6UHihf5qnUJ z2PDN>b4^_*k>?`DBJ#(tL}@&SkhYRU!Z29+{4Md}LGjh}H<-Po$`b7#w)tmSB5K!s zn+tvk3TE<$l8qIcf%E`wTl0FVM50%Uk5`7Aqg08+p=hqAU7}URNVeG}{q8U0FiOiE zg>2b0TB-IV)P8i)r0+-ATW+06KZ%)|qwceF;_s5k8{mt!yA z!ccz*OYte<%RUK_!dcyYa4uN%8UzvUFnq;AB(i|W-eQJvb3-JZnN18WWIDDm=}Qa( z)S@y1iftHj5TrnSxMn@@;gq7r5FN!N>xiP!TfC#$yfYAW@rc@`i%FgI)p^k@-I9Ph zRzk8SFcV5jo3-XRL!@Ko|5JsnC{;+U+>K=KR!Wjsh0nSVpoD%EOn;63C=IysSjVr+BtvhcwkQaw2GFtq1G!Qt+7?6WG%L;7<1Ofg%`J#XqFn%32%Wr|vFH~@ym&-d?b`y!z z7uK_6F^zBrN5>e5q)=8gW)!3&JQ5{0QlAkjMHtYFWg6T}(!)SJXeJT+4NN|Yl`p71+jW7edlM2g3>E$l=~=_d^HBU9pZ>vgdNyVE_OP!`j?YST9*669iV z1#fa@8zmAmp)d1eJnug2jd-?z)O;m?J^ztsmfAjz-L?f(Vwcul^4AN(4%|9Q`;LD zvCz;1nQ@YpNCgDN^bXQy4A#`GmG$c=5rr66m7VD(k)Av-fql?P(lzdlJ4<9=fispin_bb&>^qpQTUM&ThqtOOcGsU#cNO}eZ-Qp*;U)7cnm1-bTm zNOT`wZ_0L!1|h|xT*mL>R1JnvrKiMWfm;vdkDh#LX_0JSFOINowr0(GOJs*&4j+$4 z2S+kTAC4LHiK2htwL`mvKz9GJ>d#g&*s%BQE3L-|tcu(0sOd}?4C>b->V8sA_DB&q zCf?Y_Tk(>vKLa+`^cR-Hd2k02qU8S4T&=I@{%{>mZD$B~+#Va8po>#wvMmAhJRcw# zRwH;SDB%cV8wc`R5|7B}MwT>)t>adiyXhW7tfBjfTpflUuMU>pzxX_kk>Dg|EaKg~FEScnDNXQ3s^5jHBHJ<0SGAMNqGP zFmtaqUZQvmuv>it-0jKn5*c9uiY7=)^{q6YbJ9fVsJ3@*N$1{49CR?wnv*$J061N3 z5g5u&OqM8$r5QqqWuudVE9D{K%UC^JPa?c?!=_2|(K<}_qmCPG)|oDmbFdTdF@Hz} zgW31fIc1N>1~VjLKGF3jGbG)%s8NdaF5cnZKD!a3C3pu>oA|}$K!Y)v5*92nP5Or4 zTlW7L_qm&X!1c`U*h(6|w{xbX`~J=bN;}LQe1in>_rjMtR{PHj?_zQY4IG%FbT^?4BxpD zHy%S1W=;XnT+Wr2YZc8*fXB@@2yFzFlD!`%b~uoLAjhRb;A(NQSkjbP_9m2ByHoZ%}Yl3 z`W_j4qp`Dv-hr1|6oKL)fg(P)K{oBUo4%FZzDh3{pt!uBwaFmVfs0T_H=i$&NC1HJ z)?SxNvu8t8BKFOPdng%v8w?Y4dBgIh{Ax7&7x(Zl$r|E;j~9i7&S)=nEot5`8F9di zn;rPgSr<_S1IgsntkD51Vhrx1_-%;#!@0lI-8?8ecJ8Gai_7`tj@iv$E}hrUzB%&z zbOk40@GIIN@)|Ijzp@Z+@6>4!NXu7o*uuXtt9e%_?O!dCXcwghYYZYewTag-%|yS! zTB!ouU|n*&PGg28PGHx%2Q*;^)*4)0!VE-LYrIbC4Jn}6VZL4kxiPpD@W*K9>ssV< zckP_D;2zdw8|;bCdd@asb!M#RG%QBu>OdQ4+6IZNIn263aER#l3~u<>_aqO`o+T);zz1v_k+@{-Z z%1<{qC%WkIDl^RAcpR*kxYt6DJdXOzw`gxe7``-^jf7@ywiX87k%rJ|cyktiQlVY& zs%h5E!PgNz9i~-CSNDx?S9W->^g6qHUr}KYL1(Nwiyn_f{B#`5Qc@xzjHM{}7Gjd! zAGI!1P5b}$IOKgE;pL!gN%WdGQ<{|?A8cm}_i_S#_eY>Jkjj((0vO;i{!{e5ZH2uS z&sT&Io1G^}VDBQpCP}^c2JIXVWdCHpv!y5I4l!u1TIn5Ta?F2wj(wF>nphAAAEtr)$ERpW5=pM5Q zI}RI1B>5}O?3uNTLCl!|NBFCU3})|H^+3@h_~Df!23_0fs6i2ZeN?gvh=}$^9^k`*vfx|L(K`c8v z0d@^sqZ|G=oWTyBk;rbt9OtFo_O8s@`lvK5&)l13Vxl9{0P{d(?#kDWTV&VPzbK58+3>g zj1Gt&#-8{5FDF*;?)(4pJvW^Mi<%r*G4$QP=up*rGVs`)r-9s( zgOpql2V`~eDa({9MR+=n3YMcja7)r1qH6(<23 zVMrE8N>`z>oBYMhPMS*TB7TDUZ~C87CMuvl$zrvVMZ+$UMTN>{>l{4=yIwpBj>!)y zh6b>;O}(nQ*^mBzOXL`a+>TRVzF4I^(wB1Bt$W~2(TkG-H$gTBHoUd5Pp)-u6BD1V@V2O7zcK;tPEPhyv zgsPN!uY$HJF#asQMgO|5V5*_myU77;EQtFTElOsE~n$ZmqFNwik5`4Lbh9ML9W^Muf zVJQ4u(1QU?G?i2D^OHB~)5aXs3ErV>pC}h)r~Ty}sANvyY_rL`w8@PSOLA~?khSE!bbw6A z3YhTUY5n9tnKaU%Z0-ch(FXMko1TCo0KZM)1yinB&18F^e7$y_zkLw_+ zsN7qV*nL`5_J}�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 From c84eb8c78d21d47b9519c9d027edbf1839ae6732 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:11:30 +0200 Subject: [PATCH 14/80] F #4913: Add VNM files for vcenter driver --- src/vnm_mad/remotes/common/dummy.sh | 19 +++ src/vnm_mad/remotes/vcenter/clean | 184 ++++++++++++++++++++++++++++ src/vnm_mad/remotes/vcenter/post | 1 + src/vnm_mad/remotes/vcenter/pre | 1 + 4 files changed, 205 insertions(+) create mode 100755 src/vnm_mad/remotes/common/dummy.sh create mode 100755 src/vnm_mad/remotes/vcenter/clean create mode 120000 src/vnm_mad/remotes/vcenter/post create mode 120000 src/vnm_mad/remotes/vcenter/pre diff --git a/src/vnm_mad/remotes/common/dummy.sh b/src/vnm_mad/remotes/common/dummy.sh new file mode 100755 index 0000000000..3ee910cdd1 --- /dev/null +++ b/src/vnm_mad/remotes/common/dummy.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- # +# 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. # +#--------------------------------------------------------------------------- # + +exit 0 diff --git a/src/vnm_mad/remotes/vcenter/clean b/src/vnm_mad/remotes/vcenter/clean new file mode 100755 index 0000000000..da33f12c88 --- /dev/null +++ b/src/vnm_mad/remotes/vcenter/clean @@ -0,0 +1,184 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2002-2017, 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. # +# ---------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'vcenter_driver' + +drv_action_enc = ARGV[0] +drv_action = OpenNebula::XMLElement.new +drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VM') + +#Get more VM's info from OpenNebula +vm_id = drv_action["ID"] +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id) +vc_cluster_name = one_vm["HISTORY_RECORDS/HISTORY[last()]/HOSTNAME"] + +# Get host information +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + +# Create VM object +vm_ref = drv_action["DEPLOY_ID"] +vi_client = VCenterDriver::VIClient.new_from_host(host_id) +vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) +vm.one_item = one_vm + +# Check if clean operation is due to a hotplug detach nic +hotplug_nic = drv_action.retrieve_xmlelements("TEMPLATE/NIC[ATTACH=\"YES\"]").first rescue nil + +if hotplug_nic # A nic has been hotplug detached + pg_name = hotplug_nic["BRIDGE"] + switch_name = hotplug_nic["VCENTER_SWITCH_NAME"] + vnet_ref = hotplug_nic["VCENTER_NET_REF"] + + if hotplug_nic["VCENTER_PORTGROUP_TYPE"] == "Port Group" + esx_host = VCenterDriver::ESXHost.new_from_ref(vm["runtime.host._ref"], vi_client) + + begin + esx_host.lock # Exclusive lock for ESX host operation + + if esx_host.pg_exists(pg_name) + swname = esx_host.remove_pg(pg_name) + exit if !swname || switch_name != swname + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(hotplug_nic["NETWORK_ID"]) + + exit if !esx_host.vss_exists(switch_name) + swname = esx_host.remove_vss(switch_name) + end + + rescue Exception => e + raise e + ensure + esx_host.unlock # Remove lock + vi_client.close_connection if vi_client + end + end + + if hotplug_nic["VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" + begin + dc = vm.cluster.get_dc # Get datacenter + + dc.lock + + # Explore network folder in search of dpg and dvs + net_folder = dc.network_folder + net_folder.fetch! + + # Get distributed port group if it exists + dpg = dc.dpg_exists(pg_name, net_folder) + dc.remove_dpg(dpg) if dpg + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(hotplug_nic["NETWORK_ID"]) + + # Get distributed virtual switch and try to remove it + dvs = dc.dvs_exists(switch_name, net_folder) + dc.remove_dvs(dvs) if dvs + + rescue Exception => e + #TODO rollback + raise e + ensure + dc.unlock if dc + end + end + +else # VM is being terminated + + # If vm shutdown has been called + if one_vm["/VM/LCM_STATE"] == "12" + + esx_host = VCenterDriver::ESXHost.new_from_ref(vm["runtime.host._ref"], vi_client) + vm.detach_all_nics # Detach all NICs to prevent Resource in use when deleting + + begin + esx_host.lock # Exclusive lock for ESX host operation + nics = one_vm.retrieve_xmlelements("TEMPLATE/NIC[VN_MAD=\"vcenter\"]") + nics.each do |nic| + pg_name = nic["BRIDGE"] + switch_name = nic["VCENTER_SWITCH_NAME"] + vnet_ref = nic["VCENTER_NET_REF"] + + if nic["VCENTER_PORTGROUP_TYPE"] == "Port Group" + begin + next if !esx_host.pg_exists(pg_name) + swname = esx_host.remove_pg(pg_name) + next if !swname || switch_name != swname + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(nic["NETWORK_ID"]) + + next if !esx_host.vss_exists(switch_name) + swname = esx_host.remove_vss(switch_name) + rescue Exception => e + #TODO rollback? + raise e + ensure + esx_host.unlock # Remove lock + end + end + + if nic["VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" + begin + dc = vm.cluster.get_dc # Get datacenter + dc.lock + + # Explore network folder in search of dpg and dvs + net_folder = dc.network_folder + net_folder.fetch! + + # Try to remove distributed port group if it exists + dpg = dc.dpg_exists(pg_name, net_folder) + next if !dpg + dc.remove_dpg(dpg) + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(nic["NETWORK_ID"]) + + # Get distributed virtual switch and try to remove it + dvs = dc.dvs_exists(switch_name, net_folder) + next if !dvs + dc.remove_dvs(dvs) if dvs + + rescue Exception => e + #TODO rollback? + raise e + ensure + dc.unlock if dc + end + end + end + rescue Exception => e + raise e + ensure + vi_client.close_connection if vi_client + end + end +end \ No newline at end of file diff --git a/src/vnm_mad/remotes/vcenter/post b/src/vnm_mad/remotes/vcenter/post new file mode 120000 index 0000000000..300563f2ad --- /dev/null +++ b/src/vnm_mad/remotes/vcenter/post @@ -0,0 +1 @@ +../common/dummy.sh \ No newline at end of file diff --git a/src/vnm_mad/remotes/vcenter/pre b/src/vnm_mad/remotes/vcenter/pre new file mode 120000 index 0000000000..300563f2ad --- /dev/null +++ b/src/vnm_mad/remotes/vcenter/pre @@ -0,0 +1 @@ +../common/dummy.sh \ No newline at end of file From af40b1344305a8e875ebd6a3088b4ae3eb6a522e Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:14:49 +0200 Subject: [PATCH 15/80] F #4913: Modify install.sh to add vcenter VNM driver files --- install.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/install.sh b/install.sh index 0459874171..00b9250cbb 100755 --- a/install.sh +++ b/install.sh @@ -259,6 +259,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/vnm/ebtables \ $VAR_LOCATION/remotes/vnm/fw \ $VAR_LOCATION/remotes/vnm/ovswitch \ + $VAR_LOCATION/remotes/vnm/vcenter \ $VAR_LOCATION/remotes/tm/ \ $VAR_LOCATION/remotes/tm/dummy \ $VAR_LOCATION/remotes/tm/shared \ @@ -415,6 +416,7 @@ INSTALL_FILES=( NETWORK_EBTABLES_FILES:$VAR_LOCATION/remotes/vnm/ebtables NETWORK_FW_FILES:$VAR_LOCATION/remotes/vnm/fw NETWORK_OVSWITCH_FILES:$VAR_LOCATION/remotes/vnm/ovswitch + NETWORK_VCENTER_FILES:$VAR_LOCATION/remotes/vnm/vcenter EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples WEBSOCKIFY_SHARE_FILES:$SHARE_LOCATION/websockify INSTALL_GEMS_SHARE_FILES:$SHARE_LOCATION @@ -857,6 +859,10 @@ NETWORK_OVSWITCH_FILES="src/vnm_mad/remotes/ovswitch/clean \ src/vnm_mad/remotes/ovswitch/update_sg \ src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb" +NETWORK_VCENTER_FILES="src/vnm_mad/remotes/vcenter/pre \ + src/vnm_mad/remotes/vcenter/post \ + src/vnm_mad/remotes/vcenter/clean" + #------------------------------------------------------------------------------- # IPAM drivers to be installed under $REMOTES_LOCATION/ipam #------------------------------------------------------------------------------- From cf116abe939ab4e011e5167eaef60a23b3648ed2 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:18:49 +0200 Subject: [PATCH 16/80] F #4913: Ignore error if file to be deleted does not exist --- .../remotes/lib/vcenter_driver/datastore.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index db51f38f1c..27e71ff2a3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -239,10 +239,17 @@ class Datastore < Storage def delete_virtual_disk(img_name) ds_name = self['name'] - get_vdm.DeleteVirtualDisk_Task( - :name => "[#{ds_name}] #{img_name}", - :datacenter => get_dc.item - ).wait_for_completion + begin + get_vdm.DeleteVirtualDisk_Task( + :name => "[#{ds_name}] #{img_name}", + :datacenter => get_dc.item + ).wait_for_completion + rescue Exception => e + # Ignore if file not found + if !e.message.start_with?('ManagedObjectNotFound') + raise e + end + end end # Copy a VirtualDisk From a54ed786d13aefc09f0346245db3b454b831df31 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:20:13 +0200 Subject: [PATCH 17/80] F #4913: Deprecate Keep Disks on done --- src/vmm_mad/remotes/vcenter/shutdown | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 2779a0fa0f..2c5ccb8844 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -52,10 +52,7 @@ end # Get disk elements from drv_action disks = drv_action.retrieve_xmlelements("VM/TEMPLATE/DISK") -## TODO keep_disks and copy_template -keep_disks = - !drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].nil? && - drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].downcase=="yes" +## TODO copy_template # Manage instantiate to persistent instantiate_to_persistent = @@ -73,12 +70,6 @@ begin # If Terminate action has been called if lcm_state_str == "SHUTDOWN" - # TODO: KEEP_DISKS_ON_DONE deprecation / invisible disks - if keep_disks - # Detach all disks from VM so they are not deleted if VM is destroyed - vm.detach_all_disks - end - # If the VM was instantiated to persistent keep the VM if instantiate_to_persistent vm.mark_as_template #Convert VM to template in vCenter From 8b0322507f9b3948d75b01e195ac741287fc7407 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:21:57 +0200 Subject: [PATCH 18/80] F #4913: Deprecate Keep Disks on done (oca) --- src/oca/ruby/opennebula/virtual_machine.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 714184030a..7d52e4c285 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -744,13 +744,6 @@ module OpenNebula self['DEPLOY_ID'] end - # Returns the deploy_id of the VirtualMachine (numeric value) - def keep_disks? - !self['USER_TEMPLATE/KEEP_DISKS_ON_DONE'].nil? && - self['USER_TEMPLATE/KEEP_DISKS_ON_DONE'].downcase=="yes" - end - - # Clones the VM's source Template, replacing the disks with live snapshots # of the current disks. The VM capacity and NICs are also preserved # From 532b73afa5c7029cc1839ae110c6c7a8913dc756 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:32:04 +0200 Subject: [PATCH 19/80] F #4913: detach_all_disks no longer need (keep_disks deprecation) --- .../lib/vcenter_driver/virtual_machine.rb | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index edb190859b..5c1c588f19 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -91,7 +91,7 @@ class VirtualMachine end # The OpenNebula host - # @return OpenNebula::Host or XMLElement + # @return OpenNebula::Host or XMLElement def host if @host.nil? if one_item.nil? @@ -626,7 +626,7 @@ class VirtualMachine end end - # Returns an array of actions to be included in :deviceChange + # Returns an array of actions to be included in :deviceChange def calculate_add_nic_spec(nic) #TODO include VCENTER_NET_MODEL usage it should be in one_item @@ -755,7 +755,7 @@ class VirtualMachine end - # Detach NIC from VM + # Detach NIC from VM def detach_nic spec_hash = {} nic = nil @@ -895,29 +895,6 @@ class VirtualMachine return ds_ref, img_path end - # Detach all DISKs from VM (terminate action) - def detach_all_disks - spec_hash = {} - spec_hash[:deviceChange] = [] - - @item["config.hardware.device"].each do |disk| - if is_disk_or_cdrom?(disk) - spec_hash[:deviceChange] << { - :operation => :remove, - :device => disk - } - end - end - - return nil if spec_hash[:deviceChange].empty? - - begin - @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion - rescue Exception => e - raise "Cannot detach all DISKs from VM: #{e.message}\n#{e.backtrace}" - end - end - # Get vcenter device representing DISK object (hotplug) def disk_attached_to_vm(disk) img_name = "" From 9c9651646559f5fa588cd14e5c822ce24c7fd7f6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:37:37 +0200 Subject: [PATCH 20/80] F #4913: Fix bug, wrong host id retrieval --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 5c1c588f19..478e4d24b8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -91,7 +91,7 @@ class VirtualMachine end # The OpenNebula host - # @return OpenNebula::Host or XMLElement + # @return OpenNebula::Host or XMLElement def host if @host.nil? if one_item.nil? @@ -99,7 +99,7 @@ class VirtualMachine "access the OpenNebula host." end - host_id = one_item["HISTORY_RECORDS/HISTORY/HID"] + host_id = one_item["HISTORY_RECORDS/HISTORY[last()]/HID"] raise "No valid host_id found." if host_id.nil? @host = VIHelper.one_item(OpenNebula::Host, host_id) From 2ff0a1f4fdd5087fc38b1e42d2761e85313d1253 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:42:20 +0200 Subject: [PATCH 21/80] F #4913: Add DS name reference for unmanaged disks to VM template --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 478e4d24b8..a428a8e684 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -425,6 +425,8 @@ class VirtualMachine if !!non_managed_disks[index] rc = one_item.update("VCENTER_TEMPLATE_DISK_#{non_managed_disks[index]["DISK_ID"]} = \"#{disk[:path]}\"", true) raise "Could not update VCENTER_TEMPLATE_DISK elements" if OpenNebula.is_error?(rc) + rc = one_item.update("VCENTER_TEMPLATE_DS_DISK_#{non_managed_disks[index]["DISK_ID"]} = \"#{disk[:datastore]._ref}\"", true) + raise "Could not update VCENTER_TEMPLATE_DS_DISK elements" if OpenNebula.is_error?(rc) end end one_item.info From 080460e3a1a78ab8731d5953e59e0151347ed164 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:44:44 +0200 Subject: [PATCH 22/80] F #4913: Unmanaged disks can be saved as (tm/cpds) --- src/tm_mad/vcenter/cpds | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index c4bee2e63d..32834f009d 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -75,11 +75,24 @@ begin # Get source and target ds ref disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first - source_ds_ref = disk["VCENTER_DS_REF"] + + source_ds_ref = "" + + # If disk is unmanaged get the reference from template + if disk["OPENNEBULA_MANAGED"] && disk["OPENNEBULA_MANAGED"] == "NO" + image_path = one_vm["USER_TEMPLATE/VCENTER_TEMPLATE_DISK_#{disk["DISK_ID"]}"] + src_path = image_path.sub(/^\[(.*?)\] /, "") + source_ds_ref = one_vm["USER_TEMPLATE/VCENTER_TEMPLATE_DS_DISK_#{disk["DISK_ID"]}"] + else + # Get image source path + src_path = VCenterDriver::FileHelper.get_img_name(disk, vmid, vm['name']) + source_ds_ref = disk["VCENTER_DS_REF"] + end + source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) - # Get image source path - src_path = VCenterDriver::FileHelper.get_img_name(disk, vmid, vm['name']) + + # Get target ds ref target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) From c8ce9fe7bda9c783ec13d8f611ded8737a6dbf72 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:53:42 +0200 Subject: [PATCH 23/80] F #4913: VLAN info (VLAN_TAGGED_ID) is no longer retrieved when vcenter networks are imported --- .../remotes/lib/vcenter_driver/datacenter.rb | 6 --- .../remotes/lib/vcenter_driver/network.rb | 49 ++----------------- 2 files changed, 3 insertions(+), 52 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index be14c09250..378a33e2a3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -327,12 +327,6 @@ class DatacenterFolder network_name = network['name'] network_ref = network['_ref'] - # TODO slow VLAN_ID retrieve for portgroups! set to nil - vlan_id = "" - if network.class == VCenterDriver::DistributedPortGroup - vlan_id = network.vlan_id - end - network.clusters.each do |ccr_ref, ccr_name| one_vnet = VCenterDriver::Network.to_one_template(network_name, network_ref, diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index 047e4d710e..7ae97b092c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -57,21 +57,20 @@ class Network end - def self.to_one_template(network_name, network_ref, network_type, vlan_id, + def self.to_one_template(network_name, network_ref, network_type, ccr_ref, ccr_name, vcenter_uuid) one_tmp = {} one_tmp[:name] = "#{network_name} - #{ccr_name}" one_tmp[:bridge] = network_name one_tmp[:type] = network_type one_tmp[:cluster] = ccr_name - one_tmp[:vlan_id] = vlan_id one_tmp[:vcenter_ccr_ref] = ccr_ref - one_tmp[:one] = to_one(network_name, network_ref, network_type, vlan_id, + one_tmp[:one] = to_one(network_name, network_ref, network_type, ccr_ref, ccr_name, vcenter_uuid) return one_tmp end - def self.to_one(network_name, network_ref, network_type, vlan_id, + def self.to_one(network_name, network_ref, network_type, ccr_ref, ccr_name, vcenter_uuid) template = "NAME=\"#{network_name} - #{ccr_name}\"\n"\ "BRIDGE=\"#{network_name}\"\n"\ @@ -81,8 +80,6 @@ class Network "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"\ "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n" - template << "VLAN_TAGGED_ID=#{vlan_id}\n" if !vlan_id.empty? - return template end @@ -135,24 +132,6 @@ class PortGroup < Network net_clusters end - def vlan_id - id = "" - host_members = self['host'] - host = host_members.first - # This is pretty slow as the host id subsystem has to be queried - cm = host.configManager - nws = cm.networkSystem - nc = nws.networkConfig - pgs = nc.portgroup - pgs.each do |pg| - if pg.spec.name == self["name"] - id << pg.spec.vlanId.to_s if pg.spec.vlanId != 0 - break - end - end - id - end - def network_type "Port Group" end @@ -181,28 +160,6 @@ class DistributedPortGroup < Network net_clusters end - def vlan_id - id = "" - pc = self['config.defaultPortConfig'] - if pc.respond_to?(:vlan) && pc.vlan.respond_to?(:vlanId) - - vlan = pc.vlan.vlanId - - if vlan.is_a? Array - vlan.each do |v| - id << v.start.to_s - id << ".." - id << v.end.to_s - id << "," - end - id.chop! - else - id = vlan.to_s if vlan != 0 - end - end - return id - end - def network_type "Distributed Port Group" end From b7af02a3187e33e0ad6b49b6eb48de347dfe36dd Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 12:57:06 +0200 Subject: [PATCH 24/80] F #4913: Add ESXHost class and standard port group / switches management --- .../remotes/lib/vcenter_driver/host.rb | 384 ++++++++++++++++++ 1 file changed, 384 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 8b072d7bee..92a2a1c148 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -359,4 +359,388 @@ class ClusterComputeResource end end # class ClusterComputeResource +class ESXHost + attr_accessor :item + + include Memoize + + PG_CREATE_TIMEOUT = 240 # We will wait for 4 minutes for the pg creation + + def initialize(item, vi_client=nil) + @net_rollback = [] + @locking = true + @item = item + @vi_client = vi_client + end + + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::HostSystem.new(vi_client.vim, ref), vi_client) + end + + # Locking function. Similar to flock + def lock + hostlockname = @item['name'].downcase.tr(" ", "_") + if @locking + @locking_file = File.open("/tmp/vcenter-#{hostlockname}-lock","w") + @locking_file.flock(File::LOCK_EX) + end + end + + # Unlock driver execution mutex + def unlock + if @locking + @locking_file.close + end + end + + ######################################################################## + # Check if standard switch exists in host + ######################################################################## + + def vss_exists(vswitch_name) + vswitches = @item.configManager.networkSystem.networkInfo.vswitch + return vswitches.select{|vs| vs.name == vswitch_name }.first rescue nil + end + + ######################################################################## + # Create a standard vcenter switch in an ESX host + ######################################################################## + + def create_vss(name, pnics=nil, num_ports=128, mtu=1500, pnics_available=nil) + # Get NetworkSystem + nws = self['configManager.networkSystem'] + vswitchspec = nil + hostbridge = nil + nics = [] + + if pnics + pnics = pnics.split(",") + pnics.each do |pnic| + #Add nics if not in use + nics << pnic if pnics_available.include?(pnic) + end + + if !nics.empty? + hostbridge = RbVmomi::VIM::HostVirtualSwitchBondBridge(:nicDevice => nics) + end + end + + #Create spec + vswitchspec = RbVmomi::VIM::HostVirtualSwitchSpec(:bridge => hostbridge, :mtu => mtu, :numPorts => num_ports) + + #add vSwitch to the host + begin + nws.AddVirtualSwitch(:vswitchName => name, :spec => vswitchspec) + rescue Exception => e + raise "The standard vSwitch #{name} could not be created. AddVirtualSwitch failed Reason: #{e.message}." + end + + @net_rollback << {:action => :delete_sw, :name => name} + + return name + end + + ######################################################################## + # Update a standard vcenter switch in an ESX host + ######################################################################## + def update_vss(switch, name, pnics, num_ports, mtu) + pnics = pnics.split(",") if pnics + + #Backup switch spec for rollback + orig_spec = switch.spec + + #Compare current configuration and return if switch hasn't changed + same_switch = false + same_switch = switch.spec.respond_to?(:mtu) && switch.spec.mtu == mtu && + switch.spec.respond_to?(:numPorts) && switch.spec.mtu == num_ports && + (!pnics || (pnics && switch.spec.respond_to?(:bridge) && + switch.spec.bridge.respond_to?(:nicDevice) && + switch.spec.bridge.nicDevice.uniq.sort == pnics.uniq.sort)) + return if same_switch + + # Let's create a new spec and update the switch + vswitchspec = nil + hostbridge = nil + nws = self['configManager.networkSystem'] + hostbridge = RbVmomi::VIM::HostVirtualSwitchBondBridge(:nicDevice => pnics) if !pnics.empty? + vswitchspec = RbVmomi::VIM::HostVirtualSwitchSpec(:bridge => hostbridge, :mtu => mtu, :numPorts => num_ports) + + begin + nws.UpdateVirtualSwitch(:vswitchName => name, :spec => vswitchspec) + rescue Exception => e + raise "The standard switch with name #{name} could not be updated. Reason: #{e.message}" + end + + @net_rollback << {:action => :update_sw, :name => name, :spec => orig_spec} + end + + ######################################################################## + # Remove a standard vswitch from the host + ######################################################################## + def remove_vss(vswitch_name) + nws = self['configManager.networkSystem'] + + begin + nws.RemoveVirtualSwitch(:vswitchName => vswitch_name) + rescue RbVmomi::VIM::ResourceInUse + STDERR.puts "The standard switch #{vswitch_name} is in use so it cannot be deleted" + return nil + rescue RbVmomi::VIM::NotFound + STDERR.puts "The standard switch #{vswitch_name} was not found in vCenter" + return nil + rescue Exception => e + raise "There was a failure while deleting a vcenter standard switch #{vswitch_name}. Reason: #{e.message}" + end + + return vswitch_name + end + + ######################################################################## + # Get physical nics that are available in a host + ######################################################################## + def get_available_pnics + pnics_in_use = [] + pnics_available = [] + + # Get pnics in use in standard switches + @item.config.network.vswitch.each do |vs| + vs.pnic.each do |pnic| + pnic.slice!("key-vim.host.PhysicalNic-") + pnics_in_use << pnic + end + end + + # Get pnics in host + self['config.network'].pnic.each do |pnic| + pnics_available << pnic.device if !pnics_in_use.include?(pnic.device) + end + + return pnics_available + end + + ######################################################################## + # Check if proxy switch exists in host for distributed virtual switch + ######################################################################## + + def proxy_switch_exists(switch_name) + nws = self['configManager.networkSystem'] + proxy_switches = nws.networkInfo.proxySwitch + return proxy_switches.select{|ps| ps.dvsName == switch_name }.first rescue nil + end + + ######################################################################## + # Assign a host to a a distributed vcenter switch (proxy switch) + ######################################################################## + + def assign_proxy_switch(dvs, switch_name, pnics, pnics_available) + dvs = dvs.item + + # Prepare spec for DVS reconfiguration + configSpec = RbVmomi::VIM::VMwareDVSConfigSpec.new + configSpec.name = switch_name + configSpec.configVersion = dvs['config.configVersion'] + + # Check if host is already assigned to distributed switch + operation = "add" + operation = "edit" if !dvs['config.host'].select { |host| host.config.host._ref == self['_ref'] }.empty? + + # Add host members to the distributed virtual switch + host_member_spec = RbVmomi::VIM::DistributedVirtualSwitchHostMemberConfigSpec.new + host_member_spec.host = @item + host_member_spec.operation = operation + host_member_spec.backing = RbVmomi::VIM::DistributedVirtualSwitchHostMemberPnicBacking.new + host_member_spec.backing.pnicSpec = [] + + # If pnics are needed assign pnics for uplinks + if pnics + pnics = pnics.split(",") + # Get uplink portgroup from dvswitch + uplink_key = dvs['config.uplinkPortgroup'].select{ + |ul| ul.name == "#{switch_name}-uplink-pg"}.first.key rescue nil + + raise "Cannot find the uplink portgroup for #{switch_name}" if !uplink_key + + pnics.each {|pnic| + pnicSpec = RbVmomi::VIM::DistributedVirtualSwitchHostMemberPnicSpec.new + pnicSpec.pnicDevice = pnic + pnicSpec.uplinkPortgroupKey = uplink_key + host_member_spec.backing.pnicSpec << pnicSpec + } + end + + configSpec.host = [host_member_spec] + + # The DVS must be reconfigured + dvs_reconfigure_task = dvs.ReconfigureDvs_Task(:spec => configSpec) + dvs_reconfigure_task.wait_for_completion + if dvs_reconfigure_task.info.state != 'success' + raise "It wasn't possible to assign host #{self["name"]} as a member of #{switch_name}'" + end + + return dvs + end + + ######################################################################## + # Create a standard port group + ######################################################################## + + def create_pg(pgname, vswitch, vlan=0) + spec = RbVmomi::VIM.HostPortGroupSpec( + :name => pgname, + :vlanId => vlan, + :vswitchName => vswitch, + :policy => RbVmomi::VIM.HostNetworkPolicy + ) + + nws = self['configManager.networkSystem'] + + begin + nws.AddPortGroup(:portgrp => spec) + rescue Exception => e + raise "A port group with name #{pgname} could not be created. Reason: #{e.message}" + end + + @net_rollback << {:action => :delete_pg, :name => pgname} + + # wait until the network is ready and we have a reference + networks = @item['network'].select{ |net| net.name == pgname } + (0..PG_CREATE_TIMEOUT).each do + break if !networks.empty? + networks = @item['network'].select{ |net| net.name == pgname } + sleep 1 + end + + raise "Cannot get VCENTER_NET_REF for new port group" if networks.empty? + + return networks.first._ref + end + + ######################################################################## + # Check if standard port group exists in host + ######################################################################## + + def pg_exists(pg_name) + nws = self['configManager.networkSystem'] + portgroups = nws.networkInfo.portgroup + return portgroups.select{|pg| pg.spec.name == pg_name }.first rescue nil + end + + + ######################################################################## + # Is the switch for the pg different? + ######################################################################## + + def pg_changes_sw?(pg, switch_name) + return pg.spec.respond_to?(:vswitchName) && pg.spec.vswitchName != switch_name + end + + ######################################################################## + # Update a standard port group + ######################################################################## + + def update_pg(pg, switch_name, vlan_id) + + if pg.spec.respond_to?(:vlanId) && pg.spec.vlanId != vlan_id + + # Backup original spec + orig_spec = pg.spec + + # Create new spec + pg_name = pg.spec.name + + spec = RbVmomi::VIM.HostPortGroupSpec( + :name => pg, + :vlanId => vlan_id, + :vswitchName => switch_name, + :policy => RbVmomi::VIM.HostNetworkPolicy + ) + + nws = self['configManager.networkSystem'] + + begin + nws.UpdatePortGroup(:pgName => pg_name, :portgrp => spec) + rescue Exception => e + raise "A port group with name #{pg_name} could not be updated. Reason: #{e.message}" + end + + # Set rollback operation + @net_rollback << {:action => :update_pg, :name => pgname, :spec => orig_spec} + end + end + + ######################################################################## + # Remove a standard port group from the host + ######################################################################## + + def remove_pg(pgname) + nws = self['configManager.networkSystem'] + + swname = nil + begin + portgroups = nws.networkConfig.portgroup + portgroups.each {|pg| + if pg.spec.name == pgname + swname = pg.spec.vswitchName + break + end + } + nws.RemovePortGroup(:pgName => pgname) + rescue RbVmomi::VIM::ResourceInUse + STDERR.puts "The standard portgroup #{pgname} is in use so it cannot be deleted" + return nil + rescue RbVmomi::VIM::NotFound + STDERR.puts "The standard portgroup #{pgname} was not found in vCenter" + return nil + rescue Exception => e + raise "There was a failure while deleting a standard portgroup #{pgname} in vCenter. Reason: #{e.message}" + end + + return swname + end + + def network_rollback + nws = self['configManager.networkSystem'] + + @net_rollback.reverse_each do |nr| + + case nr[:action] + when :update_pg + begin + nws.UpdatePortGroup(:pgName => nr[:name], :portgrp => nr[:spec]) + rescue Exception => e + raise "A rollback operation for standard port group #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :update_sw + begin + nws.UpdateVirtualSwitch(:vswitchName => nr[:name], :spec => nr[:spec]) + rescue Exception => e + raise "A rollback operation for standard switch #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :delete_sw + begin + nws.RemoveVirtualSwitch(:vswitchName=> nr[:name]) + rescue RbVmomi::VIM::ResourceInUse + return #Ignore if switch in use + rescue RbVmomi::VIM::NotFound + return #Ignore if switch not found + rescue Exception => e + raise "A rollback operation for standard switch #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :delete_pg + begin + nws.RemovePortGroup(:pgName => nr[:name]) + rescue RbVmomi::VIM::ResourceInUse + return #Ignore if pg in use + rescue RbVmomi::VIM::NotFound + return #Ignore if pg not found + rescue Exception => e + raise "A rollback operation for standard port group #{nr[:name]} could not be performed. Reason: #{e.message}" + end + end + end + end + + +end # class ESXHost + end # module VCenterDriver From 14c3dff7df9f6508fa91209a8d65cb32e6c82fee Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:01:55 +0200 Subject: [PATCH 25/80] F #4913: Distributed virtual switches can now be fetched from network folder --- .../remotes/lib/vcenter_driver/network.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index 7ae97b092c..7561cd8ad2 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -23,6 +23,11 @@ class NetworkFolder item_name = item._ref @items[item_name.to_sym] = DistributedPortGroup.new(item) end + + VIClient.get_entities(@item, "VmwareDistributedVirtualSwitch").each do |item| + item_name = item._ref + @items[item_name.to_sym] = DistributedVirtualSwitch.new(item) + end end ######################################################################## @@ -165,5 +170,18 @@ class DistributedPortGroup < Network end end # class DistributedPortGroup +class DistributedVirtualSwitch < Network + + def initialize(item, vi_client=nil) + if !item.instance_of?(RbVmomi::VIM::VmwareDistributedVirtualSwitch ) + raise "Expecting type 'RbVmomi::VIM::VmwareDistributedVirtualSwitch'. " << + "Got '#{item.class} instead." + end + + @vi_client = vi_client + @item = item + end +end # class DistributedVirtualSwitch + end # module VCenterDriver From 6ab1f325d10faa173dfe26971c8fa3801400ebbc Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:05:09 +0200 Subject: [PATCH 26/80] F #4913: Add distributed port group / switches management to Datacenter --- .../remotes/lib/vcenter_driver/datacenter.rb | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 378a33e2a3..c9f0d478f7 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -349,6 +349,8 @@ end # class DatatacenterFolder class Datacenter attr_accessor :item + DPG_CREATE_TIMEOUT = 240 + def initialize(item, vi_client=nil) if !item.instance_of? RbVmomi::VIM::Datacenter raise "Expecting type 'RbVmomi::VIM::Datacenter'. " << @@ -357,6 +359,8 @@ class Datacenter @vi_client = vi_client @item = item + @net_rollback = [] + @locking = true end def datastore_folder @@ -375,6 +379,319 @@ class Datacenter NetworkFolder.new(@item.networkFolder) end + # Locking function. Similar to flock + def lock + hostlockname = @item['name'].downcase.tr(" ", "_") + if @locking + @locking_file = File.open("/tmp/vcenter-dc-#{hostlockname}-lock","w") + @locking_file.flock(File::LOCK_EX) + end + end + + # Unlock driver execution mutex + def unlock + if @locking + @locking_file.close + end + end + + ######################################################################## + # Check if distributed virtual switch exists in host + ######################################################################## + def dvs_exists(switch_name, net_folder) + + return net_folder.items.values.select{ |dvs| + dvs.instance_of?(VCenterDriver::DistributedVirtualSwitch) && + dvs['name'] == switch_name + }.first rescue nil + end + + ######################################################################## + # Is the distributed switch for the distributed pg different? + ######################################################################## + def pg_changes_sw?(dpg, switch_name) + return dpg['config.distributedVirtualSwitch.name'] != switch_name + end + + ######################################################################## + # Create a distributed vcenter switch in a datacenter + ######################################################################## + def create_dvs(switch_name, pnics, mtu=1500) + # Prepare spec for DVS creation + spec = RbVmomi::VIM::DVSCreateSpec.new + spec.configSpec = RbVmomi::VIM::VMwareDVSConfigSpec.new + spec.configSpec.name = switch_name + + # Specify number of uplinks port for dpg + if pnics + pnics = pnics.split(",") + if !pnics.empty? + spec.configSpec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new + spec.configSpec.uplinkPortPolicy.uplinkPortName = [] + (0..pnics.size-1).each { |index| + spec.configSpec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}" + } + end + end + + #Set maximum MTU + spec.configSpec.maxMtu = mtu + + # The DVS must be created in the networkFolder of the datacenter + begin + dvs_creation_task = @item.networkFolder.CreateDVS_Task(:spec => spec) + dvs_creation_task.wait_for_completion + + # If task finished successfuly we rename the uplink portgroup + dvs = nil + if dvs_creation_task.info.state == 'success' + dvs = dvs_creation_task.info.result + dvs.config.uplinkPortgroup[0].Rename_Task(:newName => "#{switch_name}-uplink-pg").wait_for_completion + else + raise "The Distributed vSwitch #{switch_name} could not be created. " + end + rescue Exception => e + raise e + end + + @net_rollback << {:action => :delete_dvs, :dvs => dvs, :name => switch_name} + + return VCenterDriver::DistributedVirtualSwitch.new(dvs, @vi_client) + end + + ######################################################################## + # Update a distributed vcenter switch + ######################################################################## + def update_dvs(dvs, pnics, mtu) + # Prepare spec for DVS creation + spec = RbVmomi::VIM::VMwareDVSConfigSpec.new + changed = false + + orig_spec = RbVmomi::VIM::VMwareDVSConfigSpec.new + orig_spec.maxMtu = dvs['config.maxMtu'] + orig_spec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new + orig_spec.uplinkPortPolicy.uplinkPortName = [] + (0..dvs['config.uplinkPortgroup'].length-1).each { |index| + orig_spec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}" + } + + # Add more uplinks to default uplink port group according to number of pnics + if pnics + pnics = pnics.split(",") + if !pnics.empty? && dvs['config.uplinkPortgroup'].length != pnics.size + spec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new + spec.uplinkPortPolicy.uplinkPortName = [] + (dvs['config.uplinkPortgroup'].length..num_pnics-1).each { |index| + spec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}" + } + changed = true + end + end + + #Set maximum MTU + if mtu != dvs['config.maxMtu'] + spec.maxMtu = mtu + changed = true + end + + # The DVS must be created in the networkFolder of the datacenter + if changed + spec.configVersion = dvs['config.configVersion'] + + begin + dvs.item.ReconfigureDvs_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "The Distributed switch #{dvs['name']} could not be updated. "\ + "Reason: #{e.message}" + end + + @net_rollback << {:action => :update_dvs, :dvs => dvs.item, :name => dvs['name'], :spec => orig_spec} + end + end + + ######################################################################## + # Remove a distributed vcenter switch in a datacenter + ######################################################################## + def remove_dvs(dvs) + begin + dvs.item.Destroy_Task.wait_for_completion + rescue + #Ignore destroy task exception + end + end + + ######################################################################## + # Check if distributed port group exists in datacenter + ######################################################################## + def dpg_exists(pg_name, net_folder) + + return net_folder.items.values.select{ |dpg| + dpg.instance_of?(VCenterDriver::DistributedPortGroup) && + dpg['name'] == pg_name + }.first rescue nil + end + + ######################################################################## + # Create a distributed vcenter port group + ######################################################################## + def create_dpg(dvs, pg_name, vlan_id, num_ports) + spec = RbVmomi::VIM::DVPortgroupConfigSpec.new + + # OpenNebula use DVS static port binding with autoexpand + if num_ports + spec.autoExpand = true + spec.numPorts = num_ports + end + + # Distributed port group name + spec.name = pg_name + + # Set VLAN information + spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new + spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new + spec.defaultPortConfig.vlan.vlanId = vlan_id + spec.defaultPortConfig.vlan.inherited = false + + # earlyBinding. A free DistributedVirtualPort will be selected and + # assigned to a VirtualMachine when the virtual machine is reconfigured + # to connect to the portgroup. + spec.type = "earlyBinding" + + begin + dvs.item.AddDVPortgroup_Task(spec: [spec]).wait_for_completion + rescue Exception => e + raise "The Distributed port group #{pg_name} could not be created. "\ + "Reason: #{e.message}" + end + + # wait until the network is ready and we have a reference + portgroups = dvs['portgroup'].select{ |dpg| + dpg.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) && + dpg['name'] == pg_name + } + + (0..DPG_CREATE_TIMEOUT).each do + break if !portgroups.empty? + portgroups = dvs['portgroup'].select{ |dpg| + dpg.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) && + dpg['name'] == pg_name + } + sleep 1 + end + + raise "Cannot get VCENTER_NET_REF for new distributed port group" if portgroups.empty? + + @net_rollback << {:action => :delete_dpg, :dpg => portgroups.first, :name => pg_name} + + return portgroups.first._ref + end + + ######################################################################## + # Update a distributed vcenter port group + ######################################################################## + def update_dpg(dpg, vlan_id, num_ports) + spec = RbVmomi::VIM::DVPortgroupConfigSpec.new + + changed = false + + orig_spec = RbVmomi::VIM::DVPortgroupConfigSpec.new + orig_spec.numPorts = dpg['config.numPorts'] + orig_spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new + orig_spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new + orig_spec.defaultPortConfig.vlan.vlanId = dpg['config.defaultPortConfig.vlan.vlanId'] + orig_spec.defaultPortConfig.vlan.inherited = false + + if num_ports && num_ports != orig_spec.numPorts + spec.numPorts = num_ports + changed = true + end + + # earlyBinding. A free DistributedVirtualPort will be selected and + # assigned to a VirtualMachine when the virtual machine is reconfigured + # to connect to the portgroup. + spec.type = "earlyBinding" + + if vlan_id != orig_spec.defaultPortConfig.vlan.vlanId + spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new + spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new + spec.defaultPortConfig.vlan.vlanId = vlan_id + spec.defaultPortConfig.vlan.inherited = false + changed = true + end + + if changed + + spec.configVersion = dpg['config.configVersion'] + + begin + dpg.item.ReconfigureDVPortgroup_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "The Distributed port group #{dpg['name']} could not be created. "\ + "Reason: #{e.message}" + end + + @net_rollback << {:action => :update_dpg, :dpg => dpg.item, :name => dpg['name'], :spec => orig_spec} + end + + end + + ######################################################################## + # Remove distributed port group from datacenter + ######################################################################## + def remove_dpg(dpg) + begin + dpg.item.Destroy_Task.wait_for_completion + rescue RbVmomi::VIM::ResourceInUse => e + STDERR.puts "The distributed portgroup #{dpg["name"]} is in use so it cannot be deleted" + return nil + rescue Exception => e + raise "The Distributed portgroup #{dpg["name"]} could not be deleted. Reason: #{e.message} " + end + end + + ######################################################################## + # Perform vcenter network rollback operations + ######################################################################## + def network_rollback + @net_rollback.reverse_each do |nr| + + case nr[:action] + when :update_dpg + begin + nr[:dpg].ReconfigureDVPortgroupConfigSpec_Task(:spec => nr[:spec]) + rescue Exception => e + raise "A rollback operation for distributed port group #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :update_dvs + begin + nr[:dvs].ReconfigureDvs_Task(:spec => nr[:spec]) + rescue Exception => e + raise "A rollback operation for distributed standard switch #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :delete_dvs + begin + nr[:dvs].Destroy_Task.wait_for_completion + rescue RbVmomi::VIM::ResourceInUse + return #Ignore if switch in use + rescue RbVmomi::VIM::NotFound + return #Ignore if switch not found + rescue Exception => e + raise "A rollback operation for standard switch #{nr[:name]} could not be performed. Reason: #{e.message}" + end + when :delete_dpg + begin + nr[:dpg].Destroy_Task.wait_for_completion + rescue RbVmomi::VIM::ResourceInUse + return #Ignore if pg in use + rescue RbVmomi::VIM::NotFound + return #Ignore if pg not found + rescue Exception => e + raise "A rollback operation for standard port group #{nr[:name]} could not be performed. Reason: #{e.message}" + end + end + end + end + def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref), vi_client) end From 406a517a856545546e4b174df46539d9b655a4ee Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:09:32 +0200 Subject: [PATCH 27/80] F #4913: Add helper to remove VCENTER_NET_REF from vnet --- src/vmm_mad/remotes/lib/vcenter_driver/network.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index 7561cd8ad2..e4246c5bcd 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -107,6 +107,16 @@ class Network return element end + def self.remove_net_ref(network_id) + one_vnet = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualNetwork, network_id) + one_vnet.info + one_vnet.delete_element("TEMPLATE/VCENTER_NET_REF") + one_vnet.delete_element("TEMPLATE/VCENTER_INSTANCE_ID") + tmp_str = one_vnet.template_str + one_vnet.update(tmp_str) + one_vnet.info + end + # This is never cached def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref), vi_client) From 0db55e1c7e845372be949683701082fc5a7fae0f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:17:42 +0200 Subject: [PATCH 28/80] F #4913: Add port group and switch support to VMs (standard & distributed) --- .../lib/vcenter_driver/virtual_machine.rb | 310 ++++++++++++++++-- 1 file changed, 275 insertions(+), 35 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index a428a8e684..b6c4d6c22b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -155,6 +155,10 @@ class VirtualMachine end.first.value rescue nil end + def get_vcenter_instance_uuid + @vi_client.vim.serviceContent.about.instanceUuid + end + ############################################################################ # Getters ############################################################################ @@ -504,6 +508,9 @@ class VirtualMachine def reconfigure extraconfig = [] device_change = [] + networks = {} + + npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) # get vmid extraconfig += extraconfig_vmid @@ -514,25 +521,38 @@ class VirtualMachine # vnc configuration (for config_array hash) extraconfig += extraconfig_vnc + # prepare pg and sw for vcenter nics if any + configure_vcenter_network + # device_change hash (nics) device_change += device_change_nics - # device_change hash (disks) - device_change += device_change_disks + # track pg or dpg in case they must be removed + vcenter_uuid = get_vcenter_instance_uuid + device_change.each do |nic| + if nic[:operation] == :remove - num_cpus = one_item["TEMPLATE/VCPU"] || 1 + vnet_ref = nil - spec_hash = { - :numCPUs => num_cpus.to_i, - :memoryMB => one_item["TEMPLATE/MEMORY"], - :extraConfig => extraconfig - } + if nic[:device].backing.respond_to?(:network) + vnet_ref = nic[:device].backing.network._ref + end - spec_hash[:deviceChange] = device_change if !device_change.empty? + if nic[:device].backing.respond_to?(:port) && + nic[:device].backing.port.respond_to?(:portgroupKey) + vnet_ref = nic[:device].backing.port.portgroupKey + end - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - @item.ReconfigVM_Task(:spec => spec).wait_for_completion + one_network = VCenterDriver::VIHelper.find_by_ref(OpenNebula::VirtualNetworkPool, + "TEMPLATE/VCENTER_NET_REF", + vnet_ref, + vcenter_uuid, + npool) + next if !one_network + if one_network["VN_MAD"] == "vcenter" && !networks.key?(one_network["BRIDGE"]) + networks[one_network["BRIDGE"]] = one_network + end + end end def extraconfig_vmid @@ -628,17 +648,17 @@ class VirtualMachine end end - # Returns an array of actions to be included in :deviceChange + # Returns an array of actions to be included in :deviceChange def calculate_add_nic_spec(nic) #TODO include VCENTER_NET_MODEL usage it should be in one_item mac = nic["MAC"] - bridge = nic["BRIDGE"] - model = nic["VCENTER_NET_MODEL"] + pg_name = nic["BRIDGE"] + model = nic["VCENTER_NET_MODEL"] || VCenterDriver::VIHelper.get_default("VM/TEMPLATE/NIC/MODEL") vnet_ref = nic["VCENTER_NET_REF"] backing = nil - limit_in = nic["INBOUND_PEAK_BW"] + limit_in = nic["INBOUND_PEAK_BW"] || VCenterDriver::VIHelper.get_default("VM/TEMPLATE/NIC/INBOUND_PEAK_BW") limit_out = nic["OUTBOUND_PEAK_BW"] limit = nil @@ -654,15 +674,11 @@ class VirtualMachine rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 end - network = self["runtime.host.network"].select do |n| - n._ref == vnet_ref + network = self["runtime.host"].network.select do |n| + n._ref == vnet_ref || n.name == pg_name end - if network.empty? - raise "Network #{bridge} not found in host #{self['runtime.host.name']}" - else - network = network.first - end + network = network.first card_num = 1 # start in one, we want the next avaliable id @@ -691,7 +707,7 @@ class VirtualMachine if network.class == RbVmomi::VIM::Network backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( - :deviceName => bridge, + :deviceName => pg_name, :network => network) else port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( @@ -707,7 +723,7 @@ class VirtualMachine :key => 0, :deviceInfo => { :label => "net" + card_num.to_s, - :summary => bridge + :summary => pg_name }, :backing => backing, :addressType => mac ? 'manual' : 'generated', @@ -733,6 +749,207 @@ class VirtualMachine } end + def vcenter_standard_network(nic, esx_host, vcenter_uuid) + pg_name = nic["BRIDGE"] + switch_name = nic["VCENTER_SWITCH_NAME"] + pnics = nic["PHYDEV"] || nil + mtu = nic["MTU"] || 1500 + vlan_id = nic["VLAN_ID"] || nic["AUTOMATIC_VLAN_ID"] || 0 + num_ports = nic["VCENTER_SWITCH_NPORTS"] || 128 + + begin + esx_host.lock # Exclusive lock for ESX host operation + + pnics_available = nil + pnics_available = esx_host.get_available_pnics if pnics + + # Get port group if it exists + pg = esx_host.pg_exists(pg_name) + + # Disallow changes of switch name for existing pg + if pg && esx_host.pg_changes_sw?(pg, switch_name) + raise "The port group's switch name can not be modified"\ + " for OpenNebula's virtual network, please revert"\ + " it back in its definition and create a different"\ + " virtual network instead." + end + + if !pg + # Get standard switch if it exists + vs = esx_host.vss_exists(switch_name) + + if !vs + switch_name = esx_host.create_vss(switch_name, pnics, num_ports, mtu, pnics_available) + else + #Update switch + esx_host.update_vss(vs, switch_name, pnics, num_ports, mtu) + end + + vnet_ref = esx_host.create_pg(pg_name, switch_name, vlan_id) + + # We must update XML so the VCENTER_NET_REF is set + one_vnet = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualNetwork, nic["NETWORK_ID"]) + one_vnet.delete_element("TEMPLATE/VCENTER_NET_REF") if one_vnet["TEMPLATE/VCENTER_NET_REF"] + one_vnet.delete_element("TEMPLATE/VCENTER_INSTANCE_ID") if one_vnet["TEMPLATE/VCENTER_INSTANCE_ID"] + rc = one_vnet.update("VCENTER_NET_REF = \"#{vnet_ref}\"\n"\ + "VCENTER_INSTANCE_ID = \"#{vcenter_uuid}\"", true) + if OpenNebula.is_error?(rc) + raise "Could not update VCENTER_NET_REF for virtual network" + end + one_vnet.info + + else + # pg exist, update + esx_host.update_pg(pg, switch_name, vlan_id) + + # update switch if needed + vs = esx_host.vss_exists(switch_name) + esx_host.update_vss(vs, switch_name, pnics, num_ports, mtu) if vs + end + + rescue Exception => e + esx_host.network_rollback + raise e + ensure + esx_host.unlock if esx_host # Remove lock + end + end + + def vcenter_distributed_network(nic, esx_host, vcenter_uuid, dc, net_folder) + pg_name = nic["BRIDGE"] + switch_name = nic["VCENTER_SWITCH_NAME"] + pnics = nic["PHYDEV"] || nil + mtu = nic["MTU"] || 1500 + vlan_id = nic["VLAN_ID"] || nic["AUTOMATIC_VLAN_ID"] || 0 + num_ports = nic["VCENTER_SWITCH_NPORTS"] || 8 + + begin + # Get distributed port group if it exists + dpg = dc.dpg_exists(pg_name, net_folder) + + # Disallow changes of switch name for existing pg + if dpg && dc.pg_changes_sw?(dpg, switch_name) + raise "The port group's switch name can not be modified"\ + " for OpenNebula's virtual network, please revert"\ + " it back in its definition and create a different"\ + " virtual network instead." + end + + if !dpg + # Get distributed virtual switch if it exists + dvs = dc.dvs_exists(switch_name, net_folder) + + if !dvs + dvs = dc.create_dvs(switch_name, pnics, mtu) + else + #Update switch + dc.update_dvs(dvs, pnics, mtu) + end + + vnet_ref = dc.create_dpg(dvs, pg_name, vlan_id, num_ports) + + # We must connect portgroup to current host + begin + esx_host.lock + + pnics_available = nil + pnics_available = esx_host.get_available_pnics if pnics + + proxy_switch = esx_host.proxy_switch_exists(switch_name) + + esx_host.assign_proxy_switch(dvs, switch_name, pnics, pnics_available) + + rescue Exception => e + raise e + ensure + esx_host.unlock if esx_host # Remove lock + end + + # We must update XML so the VCENTER_NET_REF is set + one_vnet = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualNetwork, nic["NETWORK_ID"]) + one_vnet.delete_element("TEMPLATE/VCENTER_NET_REF") if one_vnet["TEMPLATE/VCENTER_NET_REF"] + one_vnet.delete_element("TEMPLATE/VCENTER_INSTANCE_ID") if one_vnet["TEMPLATE/VCENTER_INSTANCE_ID"] + rc = one_vnet.update("VCENTER_NET_REF = \"#{vnet_ref}\"\n"\ + "VCENTER_INSTANCE_ID = \"#{vcenter_uuid}\"", true) + if OpenNebula.is_error?(rc) + raise "Could not update VCENTER_NET_REF for virtual network" + end + one_vnet.info + else + # pg exist, dpg update + dc.update_dpg(dpg, vlan_id, num_ports) + + # update switch if needed + dvs = dc.dvs_exists(switch_name, net_folder) + dc.update_dvs(dvs, pnics, mtu) if dvs + + # We must connect or update portgroup to current host (proxyswitch) + begin + esx_host.lock + + pnics_available = nil + pnics_available = esx_host.get_available_pnics if pnics + + proxy_switch = esx_host.proxy_switch_exists(switch_name) + esx_host.assign_proxy_switch(dvs, switch_name, pnics, pnics_available) + + rescue Exception => e + raise e + ensure + esx_host.unlock if esx_host # Remove lock + end + end + + rescue Exception => e + dc.network_rollback + raise e + end + + end + + def configure_vcenter_network(nic_xml=nil) + nics = [] + if nic_xml + nics << nic_xml + else + nics = one_item.retrieve_xmlelements("TEMPLATE/NIC[VN_MAD=\"vcenter\"]") + end + + return if nics.empty? + + vcenter_uuid = get_vcenter_instance_uuid + esx_host = VCenterDriver::ESXHost.new_from_ref(self['runtime'].host._ref, vi_client) + + nics.each do |nic| + + if nic["VCENTER_INSTANCE_ID"] && nic["VCENTER_INSTANCE_ID"] != vcenter_uuid + raise "The virtual network is not assigned to the right vcenter server, create a different virtual network instead" + end + + if nic["VCENTER_PORTGROUP_TYPE"] == "Port Group" + vcenter_standard_network(nic, esx_host, vcenter_uuid) + end + + if nic["VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" + dc = cluster.get_dc # Get datacenter + begin + dc.lock + + # Explore network folder in search of dpg and dvs + net_folder = dc.network_folder + net_folder.fetch! + + vcenter_distributed_network(nic, esx_host, vcenter_uuid, dc, net_folder) + rescue Exception => e + #TODO rollback + raise e + ensure + dc.unlock if dc + end + end + end + end + # Add NIC to VM def attach_nic spec_hash = {} @@ -741,15 +958,18 @@ class VirtualMachine # Extract nic from driver action nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first - # A new NIC requires a vcenter spec - attach_nic_array = [] - attach_nic_array << calculate_add_nic_spec(nic) - spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? - - # Reconfigure VM - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - begin + # Prepare network for vcenter networks + configure_vcenter_network(nic) if nic["VN_MAD"] == "vcenter" + + # A new NIC requires a vcenter spec + attach_nic_array = [] + attach_nic_array << calculate_add_nic_spec(nic) + spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? + + # Reconfigure VM + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + @item.ReconfigVM_Task(:spec => spec).wait_for_completion rescue Exception => e raise "Cannot attach NIC to VM: #{e.message}\n#{e.backtrace}" @@ -757,7 +977,7 @@ class VirtualMachine end - # Detach NIC from VM + # Detach NIC from VM def detach_nic spec_hash = {} nic = nil @@ -771,7 +991,7 @@ class VirtualMachine is_nic?(device) && (device.macAddress == mac) end rescue nil - raise "Could not find NIC with mac address #{mac}" if nic_device.nil? + return if nic_device.nil? #Silently ignore if nic is not found # Remove NIC from VM in the ReconfigVM_Task spec_hash[:deviceChange] = [ @@ -783,7 +1003,27 @@ class VirtualMachine rescue Exception => e raise "Cannot detach NIC from VM: #{e.message}\n#{e.backtrace}" end + end + # Detach all nics useful when removing pg and sw so they're not in use + def detach_all_nics + spec_hash = {} + device_change = [] + + @item["config.hardware.device"].each do |device| + if is_nic?(device) + device_change << {:operation => :remove, :device => device} + end + end + + # Remove NIC from VM in the ReconfigVM_Task + spec_hash[:deviceChange] = device_change + + begin + @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion + rescue Exception => e + raise "Cannot detach all NICs from VM: #{e.message}\n#{e.backtrace}" + end end # Checks if a RbVmomi::VIM::VirtualDevice is a network interface From bbd7964ef8fdd70071236938323533cf649e30e1 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:19:32 +0200 Subject: [PATCH 29/80] F #4913: Clean vcenter networks when detach nic in poweroff + terminate --- src/tm_mad/vcenter/delete | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index 240df796d0..94405cb21b 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -101,10 +101,104 @@ if path.match(/disk\.\d+$/) else # Remove the VM begin + # All OpenNebula managed disks have been detached. The VM may have still # disks that belong to the template (OPENNEBULA_MANAGED disks). These disks # will be deleted with the destroy operation. If the user wants to # save them to a VM, it can be done using the disk-saveas operation. + + # If we have NICs associated to VN_MAD=vcenter we must check if pgs and + # switches must be deleted + + # track pg or dpg in case they must be removed + vcenter_uuid = vm.get_vcenter_instance_uuid + networks = {} + npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) + + # Check nics in VM + vm.item["config.hardware.device"].each do |dv| + if vm.is_nic?(dv) + if dv.backing.respond_to?(:network) + vnet_ref = dv.backing.network._ref + end + + if dv.backing.respond_to?(:port) && + dv.backing.port.respond_to?(:portgroupKey) + vnet_ref = dv.backing.port.portgroupKey + end + + one_network = VCenterDriver::VIHelper.find_by_ref(OpenNebula::VirtualNetworkPool, + "TEMPLATE/VCENTER_NET_REF", + vnet_ref, + vcenter_uuid, + npool) + next if !one_network + if one_network["VN_MAD"] == "vcenter" && !networks.key?(one_network["BRIDGE"]) + networks[one_network["BRIDGE"]] = one_network + end + end + end + + #Remove pgs and switches if not needed + if !networks.empty? + + esx_host = VCenterDriver::ESXHost.new_from_ref(vm.item.runtime.host._ref, vi_client) + dc = vm.cluster.get_dc # Get datacenter + + networks.each do |pg_name, one| + + if one["TEMPLATE/VCENTER_PORTGROUP_TYPE"] == "Port Group" + begin + esx_host.lock # Exclusive lock for ESX host operation + + next if !esx_host.pg_exists(pg_name) + swname = esx_host.remove_pg(pg_name) + next if !swname + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(one["ID"]) + + next if !esx_host.vss_exists(swname) + swname = esx_host.remove_vss(swname) + + rescue Exception => e + raise e + ensure + esx_host.unlock if esx_host # Remove lock + end + end + + if one["TEMPLATE/VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" + begin + dc.lock + + # Explore network folder in search of dpg and dvs + net_folder = dc.network_folder + net_folder.fetch! + + # Get distributed port group if it exists + dpg = dc.dpg_exists(pg_name, net_folder) + dc.remove_dpg(dpg) if dpg + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(one["ID"]) + + # Get distributed virtual switch and try to remove it + switch_name = one["TEMPLATE/VCENTER_SWITCH_NAME"] + dvs = dc.dvs_exists(switch_name, net_folder) + dc.remove_dvs(dvs) if dvs + + rescue Exception => e + #TODO rollback + raise e + ensure + dc.unlock if dc + end + end + end + + end + vm.destroy rescue Exception => e STDERR.puts "Error unregistering vm #{vmid} (#{vm_ref})."\ From fa6fc9ed2c529371c36a07dc3fc6f9c676e3bdc8 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 13:50:02 +0200 Subject: [PATCH 30/80] F #4913: Fix missing end in vm reconfigure --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b6c4d6c22b..b2c280d9d9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -553,6 +553,7 @@ class VirtualMachine networks[one_network["BRIDGE"]] = one_network end end + end end def extraconfig_vmid From 1e568fe3bfa62adfe4f27e7f7a919593e387d4d1 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 30 Mar 2017 14:36:44 +0200 Subject: [PATCH 31/80] F #4913: Fix vm reconfigure action for enhanced networks --- .../lib/vcenter_driver/virtual_machine.rb | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b2c280d9d9..66bce54155 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -554,8 +554,86 @@ class VirtualMachine end end end + + # device_change hash (disks) + device_change += device_change_disks + + num_cpus = one_item["TEMPLATE/VCPU"] || 1 + + spec_hash = { + :numCPUs => num_cpus.to_i, + :memoryMB => one_item["TEMPLATE/MEMORY"], + :extraConfig => extraconfig + } + + spec_hash[:deviceChange] = device_change if !device_change.empty? + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + @item.ReconfigVM_Task(:spec => spec).wait_for_completion + + #Remove switch and pg if NICs detached in poweroff + if !networks.empty? + + esx_host = VCenterDriver::ESXHost.new_from_ref(@item.runtime.host._ref, vi_client) + dc = cluster.get_dc # Get datacenter + + networks.each do |pg_name, one| + + if one["TEMPLATE/VCENTER_PORTGROUP_TYPE"] == "Port Group" + begin + esx_host.lock # Exclusive lock for ESX host operation + + next if !esx_host.pg_exists(pg_name) + swname = esx_host.remove_pg(pg_name) + next if !swname + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(one["ID"]) + + next if !esx_host.vss_exists(swname) + swname = esx_host.remove_vss(swname) + + rescue Exception => e + raise e + ensure + esx_host.unlock if esx_host # Remove lock + end + end + + if one["TEMPLATE/VCENTER_PORTGROUP_TYPE"] == "Distributed Port Group" + begin + dc.lock + + # Explore network folder in search of dpg and dvs + net_folder = dc.network_folder + net_folder.fetch! + + # Get distributed port group if it exists + dpg = dc.dpg_exists(pg_name, net_folder) + dc.remove_dpg(dpg) if dpg + + # We must update XML so the VCENTER_NET_REF is unset + VCenterDriver::Network.remove_net_ref(one["ID"]) + + # Get distributed virtual switch and try to remove it + switch_name = one["TEMPLATE/VCENTER_SWITCH_NAME"] + dvs = dc.dvs_exists(switch_name, net_folder) + dc.remove_dvs(dvs) if dvs + + rescue Exception => e + dc.network_rollback + raise e + ensure + dc.unlock if dc + end + end + end + + end end + def extraconfig_vmid [ { :key => "opennebula.vm.id", :value => one_item['ID'] } From d90cd64cca544a7b0ea06018ff1c527e507c50e4 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 30 Mar 2017 18:54:58 +0200 Subject: [PATCH 32/80] B #5032: Add datastore capacity usage in quota calculations for storage drivers that clone to SELF (e.g. Ceph) --- include/Quotas.h | 19 +++++ include/VirtualMachine.h | 2 +- include/VirtualMachineDisk.h | 21 ++++- src/dm/DispatchManagerActions.cc | 4 +- src/dm/DispatchManagerStates.cc | 4 +- src/lcm/LifeCycleStates.cc | 11 ++- src/rm/RequestManagerAllocate.cc | 19 ++++- src/rm/RequestManagerVirtualMachine.cc | 47 ++++++---- src/vm/VirtualMachine.cc | 4 +- src/vm/VirtualMachineDisk.cc | 113 +++++++++++++++++-------- 10 files changed, 181 insertions(+), 63 deletions(-) diff --git a/include/Quotas.h b/include/Quotas.h index 030aca1fcc..d2da91e913 100644 --- a/include/Quotas.h +++ b/include/Quotas.h @@ -181,6 +181,25 @@ public: quota_del(DATASTORE, uid, gid, tmpl); } + /** + * Delete Datastore related usage from quota counters. + * for the given user and group + * @param uid of the user + * @param gid of the group + * @param tmpl template for the image, with usage + */ + static void ds_del(int uid, int gid, vector