opennebula 5.12.9 → 6.0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ActionManager.rb +1 -1
  3. data/lib/CommandManager.rb +1 -1
  4. data/lib/DriverExecHelper.rb +44 -28
  5. data/lib/OpenNebulaDriver.rb +8 -4
  6. data/lib/VirtualMachineDriver.rb +9 -2
  7. data/lib/cloud/CloudClient.rb +3 -3
  8. data/lib/datacenter.rb +1257 -0
  9. data/lib/datastore.rb +1025 -0
  10. data/lib/distributed_firewall.rb +280 -0
  11. data/lib/file_helper.rb +370 -0
  12. data/lib/host.rb +1517 -0
  13. data/lib/logical_port.rb +50 -0
  14. data/lib/logical_switch.rb +77 -0
  15. data/lib/memoize.rb +74 -0
  16. data/lib/models.rb +32 -0
  17. data/lib/models/role.rb +1126 -0
  18. data/lib/models/service.rb +709 -0
  19. data/lib/network.rb +699 -0
  20. data/lib/nsx_client.rb +144 -0
  21. data/lib/nsx_component.rb +28 -0
  22. data/lib/nsx_constants.rb +149 -0
  23. data/lib/nsx_driver.rb +78 -0
  24. data/lib/nsx_error.rb +77 -0
  25. data/lib/nsx_rule.rb +193 -0
  26. data/lib/nsxt_client.rb +176 -0
  27. data/lib/nsxt_dfw.rb +196 -0
  28. data/lib/nsxt_logical_port.rb +94 -0
  29. data/lib/nsxt_rule.rb +188 -0
  30. data/lib/nsxt_tz.rb +38 -0
  31. data/lib/nsxv_client.rb +176 -0
  32. data/lib/nsxv_dfw.rb +202 -0
  33. data/lib/nsxv_logical_port.rb +107 -0
  34. data/lib/nsxv_rule.rb +172 -0
  35. data/lib/nsxv_tz.rb +41 -0
  36. data/lib/opaque_network.rb +134 -0
  37. data/lib/opennebula.rb +5 -2
  38. data/lib/opennebula/acl.rb +1 -1
  39. data/lib/opennebula/acl_pool.rb +1 -1
  40. data/lib/opennebula/client.rb +10 -2
  41. data/lib/opennebula/cluster.rb +1 -1
  42. data/lib/opennebula/cluster_pool.rb +1 -1
  43. data/lib/opennebula/datastore.rb +1 -1
  44. data/lib/opennebula/datastore_pool.rb +1 -1
  45. data/lib/opennebula/document.rb +8 -29
  46. data/lib/opennebula/document_json.rb +42 -12
  47. data/lib/opennebula/document_pool.rb +1 -1
  48. data/lib/opennebula/document_pool_json.rb +1 -1
  49. data/lib/opennebula/error.rb +4 -1
  50. data/lib/opennebula/flow.rb +23 -0
  51. data/lib/opennebula/flow/grammar.rb +1195 -0
  52. data/lib/opennebula/flow/service_pool.rb +190 -0
  53. data/lib/opennebula/flow/service_template.rb +608 -0
  54. data/lib/opennebula/flow/service_template_ext.rb +84 -0
  55. data/lib/opennebula/flow/service_template_pool.rb +32 -0
  56. data/lib/opennebula/flow/validator.rb +499 -0
  57. data/lib/opennebula/group.rb +1 -1
  58. data/lib/opennebula/group_pool.rb +1 -1
  59. data/lib/opennebula/hook.rb +5 -12
  60. data/lib/opennebula/hook_log.rb +1 -1
  61. data/lib/opennebula/hook_pool.rb +1 -1
  62. data/lib/opennebula/host.rb +1 -1
  63. data/lib/opennebula/host_pool.rb +1 -1
  64. data/lib/opennebula/image.rb +19 -14
  65. data/lib/opennebula/image_pool.rb +1 -1
  66. data/lib/opennebula/ldap_auth.rb +1 -1
  67. data/lib/opennebula/ldap_auth_spec.rb +1 -1
  68. data/lib/opennebula/lockable_ext.rb +163 -0
  69. data/lib/opennebula/marketplace.rb +1 -1
  70. data/lib/opennebula/marketplace_pool.rb +1 -1
  71. data/lib/opennebula/marketplaceapp.rb +9 -119
  72. data/lib/opennebula/marketplaceapp_ext.rb +586 -0
  73. data/lib/opennebula/marketplaceapp_pool.rb +1 -1
  74. data/lib/opennebula/oneflow_client.rb +4 -3
  75. data/lib/opennebula/pool.rb +6 -3
  76. data/lib/opennebula/pool_element.rb +1 -1
  77. data/lib/opennebula/security_group.rb +1 -1
  78. data/lib/opennebula/security_group_pool.rb +1 -1
  79. data/lib/opennebula/server_cipher_auth.rb +1 -1
  80. data/lib/opennebula/server_x509_auth.rb +1 -1
  81. data/lib/opennebula/ssh_auth.rb +1 -1
  82. data/lib/opennebula/system.rb +1 -1
  83. data/lib/opennebula/template.rb +4 -13
  84. data/lib/opennebula/template_ext.rb +342 -0
  85. data/lib/opennebula/template_pool.rb +1 -1
  86. data/lib/opennebula/user.rb +26 -2
  87. data/lib/opennebula/user_pool.rb +1 -1
  88. data/lib/opennebula/utils.rb +1 -1
  89. data/lib/opennebula/vdc.rb +1 -1
  90. data/lib/opennebula/vdc_pool.rb +1 -1
  91. data/lib/opennebula/virtual_machine.rb +26 -206
  92. data/lib/opennebula/virtual_machine_ext.rb +469 -0
  93. data/lib/opennebula/virtual_machine_pool.rb +1 -1
  94. data/lib/opennebula/virtual_network.rb +4 -10
  95. data/lib/opennebula/virtual_network_pool.rb +1 -1
  96. data/lib/opennebula/virtual_router.rb +4 -12
  97. data/lib/opennebula/virtual_router_pool.rb +1 -1
  98. data/lib/opennebula/vm_group.rb +4 -11
  99. data/lib/opennebula/vm_group_pool.rb +1 -1
  100. data/lib/opennebula/vntemplate.rb +4 -13
  101. data/lib/opennebula/vntemplate_pool.rb +1 -1
  102. data/lib/opennebula/wait_ext.rb +257 -0
  103. data/lib/opennebula/x509_auth.rb +1 -1
  104. data/lib/opennebula/xml_element.rb +1 -1
  105. data/lib/opennebula/xml_pool.rb +1 -1
  106. data/lib/opennebula/xml_utils.rb +1 -1
  107. data/lib/opennebula/zone.rb +1 -1
  108. data/lib/opennebula/zone_pool.rb +1 -1
  109. data/lib/rest_client.rb +201 -0
  110. data/lib/scripts_common.rb +183 -0
  111. data/lib/transport_zone.rb +43 -0
  112. data/lib/vcenter_driver.rb +13 -12
  113. data/lib/vcenter_importer.rb +616 -0
  114. data/lib/vi_client.rb +281 -0
  115. data/lib/vi_helper.rb +313 -0
  116. data/lib/virtual_machine.rb +3477 -0
  117. data/lib/virtual_wire.rb +158 -0
  118. data/lib/vm_device.rb +80 -0
  119. data/lib/vm_disk.rb +202 -0
  120. data/lib/vm_folder.rb +69 -0
  121. data/lib/vm_helper.rb +30 -0
  122. data/lib/vm_monitor.rb +303 -0
  123. data/lib/vm_nic.rb +70 -0
  124. data/lib/vm_template.rb +1963 -0
  125. data/lib/vmm_importer.rb +121 -0
  126. metadata +140 -27
data/lib/host.rb ADDED
@@ -0,0 +1,1517 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2021, OpenNebula Project, OpenNebula Systems #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ ##############################################################################
18
+ # Module VCenterDriver
19
+ ##############################################################################
20
+ module VCenterDriver
21
+
22
+ require 'json'
23
+ require 'nsx_driver'
24
+
25
+ ##########################################################################
26
+ # Class HostFolder
27
+ ##########################################################################
28
+ class HostFolder
29
+
30
+ attr_accessor :item, :items
31
+
32
+ def initialize(item)
33
+ @item = item
34
+ @items = {}
35
+ end
36
+
37
+ def fetch_clusters!
38
+ VIClient
39
+ .get_entities(
40
+ @item,
41
+ 'ClusterComputeResource'
42
+ ).each do |item|
43
+ item_name = item._ref
44
+ @items[item_name.to_sym] = ClusterComputeResource.new(item)
45
+ end
46
+ end
47
+
48
+ def get_cluster(ref)
49
+ if !@items[ref.to_sym]
50
+ rbvmomi_dc =
51
+ RbVmomi::VIM::ClusterComputeResource
52
+ .new(
53
+ @item._connection,
54
+ ref
55
+ )
56
+ @items[ref.to_sym] =
57
+ ClusterComputeResource
58
+ .new(
59
+ rbvmomi_dc
60
+ )
61
+ end
62
+
63
+ @items[ref.to_sym]
64
+ end
65
+
66
+ end
67
+ # class HostFolder
68
+
69
+ ##########################################################################
70
+ # Class ClusterComputeResource
71
+ ##########################################################################
72
+ class ClusterComputeResource
73
+
74
+ attr_accessor :item
75
+ attr_accessor :rp_list
76
+
77
+ include Memoize
78
+
79
+ def initialize(item, vi_client = nil)
80
+ @item = item
81
+ @vi_client = vi_client
82
+ @rp_list # rubocop:disable Lint/Void
83
+ end
84
+
85
+ def fetch_resource_pools(rp, rp_array = [])
86
+ rp_array << rp
87
+
88
+ rp.resourcePool.each do |child_rp|
89
+ fetch_resource_pools(child_rp, rp_array)
90
+ end
91
+
92
+ rp_array
93
+ end
94
+
95
+ def resource_pools
96
+ if @resource_pools.nil?
97
+ @resource_pools = fetch_resource_pools(@item.resourcePool)
98
+ end
99
+
100
+ @resource_pools
101
+ end
102
+
103
+ def get_resource_pool_list(
104
+ rp = @item
105
+ .resourcePool,
106
+ parent_prefix = '',
107
+ rp_array = []
108
+ )
109
+ current_rp = ''
110
+
111
+ if !parent_prefix.empty?
112
+ current_rp << parent_prefix
113
+ current_rp << '/'
114
+ end
115
+
116
+ resource_pool, name = rp.collect('resourcePool', 'name')
117
+ current_rp << name if name != 'Resources'
118
+
119
+ resource_pool.each do |child_rp|
120
+ get_resource_pool_list(child_rp, current_rp, rp_array)
121
+ end
122
+
123
+ rp_info = {}
124
+ rp_info[:name] = current_rp
125
+ rp_info[:ref] = rp._ref
126
+ rp_array << rp_info unless current_rp.empty?
127
+
128
+ rp_array
129
+ end
130
+
131
+ def nsx_get
132
+ nsx_info = ''
133
+ nsx_obj = {}
134
+ # In the future add more than one nsx manager
135
+ extension_list =
136
+ @vi_client
137
+ .vim
138
+ .serviceContent
139
+ .extensionManager
140
+ .extensionList
141
+ extension_list.each do |ext_list|
142
+ case ext_list.key
143
+ when NSXDriver::NSXConstants::NSXV_EXTENSION_LIST
144
+ nsx_obj['type'] = NSXDriver::NSXConstants::NSXV
145
+ url_full = ext_list.client[0].url
146
+ url_split = url_full.split('/')
147
+ # protocol = "https://"
148
+ protocol = url_split[0] + '//'
149
+ # ip_port = ip:port
150
+ ip_port = url_split[2]
151
+ nsx_obj['url'] = protocol + ip_port
152
+ nsx_obj['version'] = ext_list.version
153
+ nsx_obj['label'] = ext_list.description.label
154
+ when NSXDriver::NSXConstants::NSXT_EXTENSION_LIST
155
+ nsx_obj['type'] = NSXDriver::NSXConstants::NSXT
156
+ nsx_obj['url'] = ext_list.server[0].url
157
+ nsx_obj['version'] = ext_list.version
158
+ nsx_obj['label'] = ext_list.description.label
159
+ else
160
+ next
161
+ end
162
+ end
163
+ unless nsx_obj.empty?
164
+ nsx_info << "NSX_MANAGER=\"#{nsx_obj['url']}\"\n"
165
+ nsx_info << "NSX_TYPE=\"#{nsx_obj['type']}\"\n"
166
+ nsx_info << "NSX_VERSION=\"#{nsx_obj['version']}\"\n"
167
+ nsx_info << "NSX_LABEL=\"#{nsx_obj['label']}\"\n"
168
+ end
169
+ nsx_info
170
+ end
171
+
172
+ def nsx_ready?
173
+ @one_item =
174
+ VCenterDriver::VIHelper
175
+ .one_item(
176
+ OpenNebula::Host,
177
+ @vi_client
178
+ .instance_variable_get(
179
+ :@host_id
180
+ ).to_i
181
+ )
182
+
183
+ # Check if NSX_MANAGER is into the host template
184
+ if [nil, ''].include?(@one_item['TEMPLATE/NSX_MANAGER'])
185
+ @nsx_status = "NSX_STATUS = \"Missing NSX_MANAGER\"\n"
186
+ return false
187
+ end
188
+
189
+ # Check if NSX_USER is into the host template
190
+ if [nil, ''].include?(@one_item['TEMPLATE/NSX_USER'])
191
+ @nsx_status = "NSX_STATUS = \"Missing NSX_USER\"\n"
192
+ return false
193
+ end
194
+
195
+ # Check if NSX_PASSWORD is into the host template
196
+ if [nil, ''].include?(@one_item['TEMPLATE/NSX_PASSWORD'])
197
+ @nsx_status = "NSX_STATUS = \"Missing NSX_PASSWORD\"\n"
198
+ return false
199
+ end
200
+
201
+ # Check if NSX_TYPE is into the host template
202
+ if [nil, ''].include?(@one_item['TEMPLATE/NSX_TYPE'])
203
+ @nsx_status = "NSX_STATUS = \"Missing NSX_TYPE\"\n"
204
+ return false
205
+ end
206
+
207
+ # Try a connection as part of NSX_STATUS
208
+ nsx_client = NSXDriver::NSXClient
209
+ .new_from_id(
210
+ @vi_client
211
+ .instance_variable_get(
212
+ :@host_id
213
+ ).to_i
214
+ )
215
+
216
+ if @one_item['TEMPLATE/NSX_TYPE'] == NSXDriver::NSXConstants::NSXV
217
+ # URL to test a connection
218
+ url = '/api/2.0/vdn/scopes'
219
+ begin
220
+ if nsx_client.get(url)
221
+ @nsx_status = "NSX_STATUS = \"OK\"\n"
222
+ return true
223
+ else
224
+ @nsx_status =
225
+ "NSX_STATUS = \"Response code incorrect\"\n"
226
+ return false
227
+ end
228
+ rescue StandardError
229
+ @nsx_status = 'NSX_STATUS = "Error connecting to ' \
230
+ "NSX_MANAGER\"\n"
231
+ return false
232
+ end
233
+ end
234
+
235
+ nxs_type = @one_item['TEMPLATE/NSX_TYPE']
236
+ unless nxs_type == NSXDriver::NSXConstants::NSXT; return; end
237
+
238
+ # URL to test a connection
239
+ url = '/api/v1/transport-zones'
240
+ begin
241
+ if nsx_client.get(url)
242
+ @nsx_status = "NSX_STATUS = \"OK\"\n"
243
+ true
244
+ else
245
+ @nsx_status =
246
+ "NSX_STATUS = \"Response code incorrect\"\n"
247
+ false
248
+ end
249
+ rescue StandardError
250
+ @nsx_status = 'NSX_STATUS = "Error connecting to '\
251
+ "NSX_MANAGER\"\n"
252
+ false
253
+ end
254
+ end
255
+
256
+ def tz_get
257
+ @nsx_status = ''
258
+ if !nsx_ready?
259
+ tz_info = @nsx_status
260
+ else
261
+ tz_info = "NSX_STATUS = OK\n"
262
+ tz_info << 'NSX_TRANSPORT_ZONES = ['
263
+
264
+ nsx_client =
265
+ NSXDriver::NSXClient
266
+ .new_from_id(
267
+ @vi_client
268
+ .instance_variable_get(
269
+ :@host_id
270
+ ).to_i
271
+ )
272
+ tz_object = NSXDriver::TransportZone.new_child(nsx_client)
273
+
274
+ # NSX request to get Transport Zones
275
+ case @one_item['TEMPLATE/NSX_TYPE']
276
+ when NSXDriver::NSXConstants::NSXV
277
+ tzs = tz_object.tzs
278
+ tzs.each do |tz|
279
+ tz_info << tz.xpath('name').text << '="'
280
+ tz_info << tz.xpath('objectId').text << '",'
281
+ end
282
+ tz_info.chomp!(',')
283
+ when NSXDriver::NSXConstants::NSXT
284
+ r = tz_object.tzs
285
+ r['results'].each do |tz|
286
+ tz_info << tz['display_name'] << '="'
287
+ tz_info << tz['id'] << '",'
288
+ end
289
+ tz_info.chomp!(',')
290
+ else
291
+ raise "Unknown Port Group type \
292
+ #{@one_item['TEMPLATE/NSX_TYPE']}"
293
+ end
294
+ tz_info << ']'
295
+ return tz_info
296
+ end
297
+ tz_info
298
+ end
299
+
300
+ def monitor
301
+ total_cpu,
302
+ num_cpu_cores,
303
+ effective_cpu,
304
+ total_memory,
305
+ effective_mem,
306
+ num_hosts,
307
+ num_eff_hosts,
308
+ overall_status,
309
+ drs_enabled,
310
+ ha_enabled= @item.collect('summary.totalCpu',
311
+ 'summary.numCpuCores',
312
+ 'summary.effectiveCpu',
313
+ 'summary.totalMemory',
314
+ 'summary.effectiveMemory',
315
+ 'summary.numHosts',
316
+ 'summary.numEffectiveHosts',
317
+ 'summary.overallStatus',
318
+ 'configuration.drsConfig.enabled',
319
+ 'configuration.dasConfig.enabled')
320
+
321
+ mhz_core = total_cpu.to_f / num_cpu_cores.to_f
322
+ eff_core = effective_cpu.to_f / mhz_core
323
+
324
+ free_cpu = format('%.2f', eff_core * 100).to_f # rubocop:disable Style/FormatStringToken
325
+ total_cpu = num_cpu_cores.to_f * 100
326
+ used_cpu = format('%.2f', total_cpu - free_cpu).to_f # rubocop:disable Style/FormatStringToken
327
+
328
+ total_mem = total_memory.to_i / 1024
329
+ free_mem = effective_mem.to_i * 1024
330
+
331
+ str_info = ''
332
+
333
+ # Get cluster name for informative purposes
334
+ # (replace space with _ if any)
335
+ str_info << 'VCENTER_NAME=' << self['name'].tr(' ', '_') << "\n"
336
+
337
+ # System
338
+ str_info << "HYPERVISOR=vcenter\n"
339
+ str_info << 'TOTALHOST=' << num_hosts.to_s << "\n"
340
+ str_info << 'AVAILHOST=' << num_eff_hosts.to_s << "\n"
341
+ str_info << 'STATUS=' << overall_status << "\n"
342
+
343
+ # CPU
344
+ str_info << 'CPUSPEED=' << mhz_core.to_s << "\n"
345
+ str_info << 'TOTALCPU=' << total_cpu.to_s << "\n"
346
+ str_info << 'USEDCPU=' << used_cpu.to_s << "\n"
347
+ str_info << 'FREECPU=' << free_cpu.to_s << "\n"
348
+
349
+ # Memory
350
+ str_info << 'TOTALMEMORY=' << total_mem.to_s << "\n"
351
+ str_info << 'FREEMEMORY=' << free_mem.to_s << "\n"
352
+ str_info << 'USEDMEMORY=' << (total_mem - free_mem).to_s << "\n"
353
+
354
+ # DRS enabled
355
+ str_info << 'VCENTER_DRS=' << drs_enabled.to_s << "\n"
356
+
357
+ # HA enabled
358
+ str_info << 'VCENTER_HA=' << ha_enabled.to_s << "\n"
359
+
360
+ # NSX info
361
+ str_info << nsx_get
362
+ str_info << tz_get
363
+
364
+ str_info << monitor_resource_pools(mhz_core)
365
+ end
366
+
367
+ def monitor_resource_pools(mhz_core)
368
+ @rp_list = get_resource_pool_list
369
+
370
+ view =
371
+ @vi_client
372
+ .vim
373
+ .serviceContent
374
+ .viewManager
375
+ .CreateContainerView(
376
+ {
377
+ :container => @item, # View for RPs inside this cluster
378
+ :type => ['ResourcePool'],
379
+ :recursive => true
380
+ }
381
+ )
382
+
383
+ pc = @vi_client.vim.serviceContent.propertyCollector
384
+
385
+ monitored_properties = [
386
+ 'config.cpuAllocation.expandableReservation',
387
+ 'config.cpuAllocation.limit',
388
+ 'config.cpuAllocation.reservation',
389
+ 'config.cpuAllocation.shares.level',
390
+ 'config.cpuAllocation.shares.shares',
391
+ 'config.memoryAllocation.expandableReservation',
392
+ 'config.memoryAllocation.limit',
393
+ 'config.memoryAllocation.reservation',
394
+ 'config.memoryAllocation.shares.level',
395
+ 'config.memoryAllocation.shares.shares'
396
+ ]
397
+
398
+ filter_spec = RbVmomi::VIM.PropertyFilterSpec(
399
+ :objectSet => [
400
+ { :obj => view,
401
+ :skip => true,
402
+ :selectSet => [
403
+ RbVmomi::VIM.TraversalSpec(
404
+ :name => 'traverseEntities',
405
+ :type => 'ContainerView',
406
+ :path => 'view',
407
+ :skip => false
408
+ )
409
+ ] }
410
+ ],
411
+ :propSet => [
412
+ {
413
+ :type => 'ResourcePool',
414
+ :pathSet => monitored_properties
415
+ }
416
+ ]
417
+ )
418
+
419
+ result = pc.RetrieveProperties(:specSet => [filter_spec])
420
+
421
+ rps = {}
422
+ result.each do |r|
423
+ hashed_properties = r.to_hash
424
+ if r.obj.is_a?(RbVmomi::VIM::ResourcePool)
425
+ rps[r.obj._ref] = hashed_properties
426
+ end
427
+ end
428
+
429
+ return '' if rps.empty?
430
+
431
+ rp_info = ''
432
+
433
+ rps.each do |ref, info|
434
+ # CPU
435
+ if info['config.cpuAllocation.expandableReservation']
436
+ cpu_expandable = 'YES'
437
+ else
438
+ cpu_expandable = 'NO'
439
+ end
440
+ if info['config.cpuAllocation.limit'] == '-1'
441
+ cpu_limit = 'UNLIMITED'
442
+ else
443
+ cpu_limit = info['config.cpuAllocation.limit']
444
+ end
445
+ cpu_reservation = info['config.cpuAllocation.reservation']
446
+ cpu_num = cpu_reservation.to_f / mhz_core
447
+ cpu_shares_level = info['config.cpuAllocation.shares.level']
448
+ cpu_shares = info['config.cpuAllocation.shares.shares']
449
+
450
+ # MEMORY
451
+ if info['config.memoryAllocation.expandableReservation']
452
+ mem_expandable = 'YES'
453
+ else
454
+ mem_expandable = 'NO'
455
+ end
456
+ if info['config.memoryAllocation.limit'] == '-1'
457
+ mem_limit = 'UNLIMITED'
458
+ else
459
+ mem_limit = info['config.memoryAllocation.limit']
460
+ end
461
+ mem_reservation =
462
+ info['config.memoryAllocation.reservation'].to_f
463
+ mem_shares_level =
464
+ info['config.memoryAllocation.shares.level']
465
+ mem_shares =
466
+ info['config.memoryAllocation.shares.shares']
467
+
468
+ rp_name =
469
+ @rp_list
470
+ .select do |item|
471
+ item[:ref] == ref
472
+ end.first[:name] rescue ''
473
+
474
+ rp_name = 'Resources' if rp_name.empty?
475
+
476
+ rp_info << "\nVCENTER_RESOURCE_POOL_INFO = ["
477
+ rp_info << "NAME=\"#{rp_name}\","
478
+ rp_info << "CPU_EXPANDABLE=#{cpu_expandable},"
479
+ rp_info << "CPU_LIMIT=#{cpu_limit},"
480
+ rp_info << "CPU_RESERVATION=#{cpu_reservation},"
481
+ rp_info << "CPU_RESERVATION_NUM_CORES=#{cpu_num},"
482
+ rp_info << "CPU_SHARES=#{cpu_shares},"
483
+ rp_info << "CPU_SHARES_LEVEL=#{cpu_shares_level},"
484
+ rp_info << "MEM_EXPANDABLE=#{mem_expandable},"
485
+ rp_info << "MEM_LIMIT=#{mem_limit},"
486
+ rp_info << "MEM_RESERVATION=#{mem_reservation},"
487
+ rp_info << "MEM_SHARES=#{mem_shares},"
488
+ rp_info << "MEM_SHARES_LEVEL=#{mem_shares_level}"
489
+ rp_info << ']'
490
+ end
491
+
492
+ view.DestroyView
493
+
494
+ rp_info
495
+ end
496
+
497
+ def hostname_to_moref(hostname)
498
+ result = filter_hosts
499
+
500
+ moref = ''
501
+ result.each do |r|
502
+ if r.obj.name == hostname
503
+ moref = r.obj._ref
504
+ break
505
+ end
506
+ end
507
+ raise "Host #{hostname} was not found" if moref.empty?
508
+
509
+ moref
510
+ end
511
+
512
+ def filter_hosts
513
+ view =
514
+ @vi_client
515
+ .vim
516
+ .serviceContent
517
+ .viewManager
518
+ .CreateContainerView(
519
+ {
520
+ # View for Hosts inside this cluster
521
+ :container => @item,
522
+ :type => ['HostSystem'],
523
+ :recursive => true
524
+ }
525
+ )
526
+
527
+ pc = @vi_client.vim.serviceContent.propertyCollector
528
+
529
+ monitored_properties = [
530
+ 'name',
531
+ 'runtime.connectionState',
532
+ 'summary.hardware.numCpuCores',
533
+ 'summary.hardware.memorySize',
534
+ 'summary.hardware.cpuModel',
535
+ 'summary.hardware.cpuMhz',
536
+ 'summary.quickStats.overallCpuUsage',
537
+ 'summary.quickStats.overallMemoryUsage'
538
+ ]
539
+
540
+ filter_spec = RbVmomi::VIM.PropertyFilterSpec(
541
+ :objectSet => [
542
+ { :obj => view,
543
+ :skip => true,
544
+ :selectSet => [
545
+ RbVmomi::VIM.TraversalSpec(
546
+ :name => 'traverseEntities',
547
+ :type => 'ContainerView',
548
+ :path => 'view',
549
+ :skip => false
550
+ )
551
+ ] }
552
+ ],
553
+ :propSet => [
554
+ { :type => 'HostSystem', :pathSet => monitored_properties }
555
+ ]
556
+ )
557
+
558
+ result = pc.RetrieveProperties(:specSet => [filter_spec])
559
+ view.DestroyView # Destroy the view
560
+ result
561
+ end
562
+
563
+ def monitor_host_systems
564
+ host_info = ''
565
+ result = filter_hosts
566
+ hosts = {}
567
+ result.each do |r|
568
+ hashed_properties = r.to_hash
569
+ if r.obj.is_a?(RbVmomi::VIM::HostSystem)
570
+ hosts[r.obj._ref] = hashed_properties
571
+ end
572
+ end
573
+
574
+ hosts.each do |_ref, info|
575
+ next if info['runtime.connectionState'] != 'connected'
576
+
577
+ total_cpu = info['summary.hardware.numCpuCores'] * 100
578
+ used_cpu =
579
+ (
580
+ info['summary.quickStats.overallCpuUsage']
581
+ .to_f / info['summary.hardware.cpuMhz']
582
+ .to_f
583
+ ) * 100
584
+ # Trim precission
585
+ used_cpu = format('%.2f', used_cpu).to_f # rubocop:disable Style/FormatStringToken
586
+ free_cpu = total_cpu - used_cpu
587
+
588
+ total_memory =
589
+ info['summary.hardware.memorySize']/1024
590
+ used_memory =
591
+ info['summary.quickStats.overallMemoryUsage']*1024
592
+ free_memory = total_memory - used_memory
593
+
594
+ host_info << "\nHOST=["
595
+ host_info << 'STATE=on,'
596
+ host_info << 'HOSTNAME="' <<
597
+ info['name'].to_s << '",'
598
+ host_info <<
599
+ 'MODELNAME="' <<
600
+ info['summary.hardware.cpuModel'].to_s << '",'
601
+ host_info << 'CPUSPEED=' <<
602
+ info['summary.hardware.cpuMhz'].to_s << ','
603
+ host_info << 'MAX_CPU=' << total_cpu.to_s << ','
604
+ host_info << 'USED_CPU=' << used_cpu.to_s << ','
605
+ host_info << 'FREE_CPU=' << free_cpu.to_s << ','
606
+ host_info << 'MAX_MEM=' << total_memory.to_s << ','
607
+ host_info << 'USED_MEM=' << used_memory.to_s << ','
608
+ host_info << 'FREE_MEM=' << free_memory.to_s
609
+ host_info << ']'
610
+ end
611
+
612
+ host_info
613
+ end
614
+
615
+ def monitor_vms(host_id, vm_type)
616
+ vc_uuid = @vi_client.vim.serviceContent.about.instanceUuid
617
+ cluster_name = self['name']
618
+ cluster_ref = self['_ref']
619
+
620
+ # Get info of the host where the VM/template is located
621
+ one_host =
622
+ VCenterDriver::VIHelper
623
+ .one_item(
624
+ OpenNebula::Host,
625
+ host_id
626
+ )
627
+ if !one_host
628
+ STDERR.puts "Failed to retieve host with id #{host.id}"
629
+ if VCenterDriver::CONFIG[:debug_information]
630
+ STDERR.puts "#{message} #{e.backtrace}"
631
+ end
632
+ end
633
+
634
+ esx_hosts = {}
635
+ @item.host.each do |esx_host|
636
+ esx_hosts[esx_host._ref] = {
637
+ :name => esx_host.name,
638
+ :cpu => esx_host.summary.hardware.cpuMhz.to_f
639
+ }
640
+ end
641
+
642
+ monitored_vms = Set.new
643
+ str_info = ''
644
+
645
+ view =
646
+ @vi_client
647
+ .vim
648
+ .serviceContent
649
+ .viewManager
650
+ .CreateContainerView(
651
+ {
652
+ :container => @item, # View for VMs inside this cluster
653
+ :type => ['VirtualMachine'],
654
+ :recursive => true
655
+ }
656
+ )
657
+
658
+ pc = @vi_client.vim.serviceContent.propertyCollector
659
+
660
+ monitored_properties = [
661
+ 'name', # VM name
662
+ 'config.template', # To filter out templates
663
+ 'summary.runtime.powerState', # VM power state
664
+ 'summary.quickStats.hostMemoryUsage', # Memory usage
665
+ 'summary.quickStats.overallCpuUsage', # CPU used by VM
666
+ 'runtime.host', # ESX host
667
+ 'resourcePool', # RP
668
+ 'guest.guestFullName',
669
+ # IP addresses as seen by guest tools,
670
+ 'guest.net',
671
+ 'guest.guestState',
672
+ 'guest.toolsVersion',
673
+ 'guest.toolsRunningStatus',
674
+ # IP addresses as seen by guest tools,
675
+ 'guest.toolsVersionStatus2',
676
+ # VM extraconfig info e.g opennebula.vm.running
677
+ 'config.extraConfig',
678
+ 'config.hardware.numCPU',
679
+ 'config.hardware.memoryMB',
680
+ 'config.annotation',
681
+ 'datastore'
682
+ ]
683
+
684
+ filter_spec = RbVmomi::VIM.PropertyFilterSpec(
685
+ :objectSet => [
686
+ { :obj => view,
687
+ :skip => true,
688
+ :selectSet => [
689
+ RbVmomi::VIM.TraversalSpec(
690
+ :name => 'traverseEntities',
691
+ :type => 'ContainerView',
692
+ :path => 'view',
693
+ :skip => false
694
+ )
695
+ ] }
696
+ ],
697
+ :propSet => [
698
+ {
699
+ :type => 'VirtualMachine',
700
+ :pathSet => monitored_properties
701
+ }
702
+ ]
703
+ )
704
+
705
+ result = pc.RetrieveProperties(:specSet => [filter_spec])
706
+
707
+ vms = {}
708
+ vm_objects = []
709
+ result.each do |r|
710
+ hashed_properties = r.to_hash
711
+ next unless r.obj.is_a?(RbVmomi::VIM::VirtualMachine)
712
+
713
+ # Only take care of VMs, not templates
714
+ if !hashed_properties['config.template']
715
+ vms[r.obj._ref] = hashed_properties
716
+ vm_objects << r.obj
717
+ end
718
+ end
719
+
720
+ pm = @vi_client.vim.serviceContent.perfManager
721
+
722
+ stats = {}
723
+
724
+ max_samples = 9
725
+ refresh_rate = 20 # Real time stats takes samples every 20 seconds
726
+
727
+ last_mon_time = one_host['TEMPLATE/VCENTER_LAST_PERF_POLL']
728
+
729
+ if last_mon_time
730
+ interval = (Time.now.to_i - last_mon_time.to_i)
731
+ interval = 3601 if interval < 0
732
+ samples = (interval / refresh_rate)
733
+ samples = 1 if samples == 0
734
+ interval > 3600 ? max_samples = 9 : max_samples = samples
735
+ end
736
+
737
+ if !vm_objects.empty?
738
+ stats = pm.retrieve_stats(
739
+ vm_objects,
740
+ [
741
+ 'net.transmitted',
742
+ 'net.bytesRx',
743
+ 'net.bytesTx',
744
+ 'net.received',
745
+ 'virtualDisk.numberReadAveraged',
746
+ 'virtualDisk.numberWriteAveraged',
747
+ 'virtualDisk.read',
748
+ 'virtualDisk.write'
749
+ ],
750
+ {
751
+ :max_samples => max_samples
752
+ }
753
+ ) rescue {}
754
+ end
755
+
756
+ if !stats.empty?
757
+ last_mon_time = Time.now.to_i.to_s
758
+ end
759
+
760
+ @rp_list ||= get_resource_pool_list
761
+
762
+ vm_pool =
763
+ VCenterDriver::VIHelper
764
+ .one_pool(
765
+ OpenNebula::VirtualMachinePool
766
+ )
767
+ # We filter to retrieve only those VMs
768
+ # running in the host that we are monitoring
769
+ host_vms =
770
+ vm_pool
771
+ .retrieve_xmlelements(
772
+ "/VM_POOL/VM[HISTORY_RECORDS/HISTORY/HID='#{host_id}']"
773
+ )
774
+
775
+ vms.each do |vm_ref, info|
776
+ vm_info = ''
777
+ begin
778
+ esx_host = esx_hosts[info['runtime.host']._ref]
779
+ info[:esx_host_name] = esx_host[:name]
780
+ info[:esx_host_cpu] = esx_host[:cpu]
781
+ info[:cluster_name] = cluster_name
782
+ info[:cluster_ref] = cluster_ref
783
+ info[:vc_uuid] = vc_uuid
784
+ info[:host_id] = host_id
785
+ info[:rp_list] = @rp_list
786
+
787
+ # Check the running flag
788
+ running_flag = info['config.extraConfig'].select do |val|
789
+ val[:key] == 'opennebula.vm.running'
790
+ end
791
+
792
+ if !running_flag.empty? && running_flag.first
793
+ running_flag = running_flag[0][:value]
794
+ end
795
+
796
+ next if running_flag == 'no'
797
+
798
+ id = -1
799
+ # Find the VM by its deploy_id,
800
+ # which in the vCenter driver is
801
+ # the vCenter managed object reference
802
+ found_vm =
803
+ host_vms
804
+ .select do |vm|
805
+ vm['DEPLOY_ID'].eql? vm_ref
806
+ end.first
807
+ id = found_vm['ID'] if found_vm
808
+
809
+ # skip if it is a wild and
810
+ # we are looking for OpenNebula VMs
811
+ next if (vm_type == 'ones') && (id == -1)
812
+ # skip if it is not a wild and we are looking for wilds
813
+ next if (vm_type == 'wilds') && (id != -1)
814
+ # skip if already monitored
815
+ next if monitored_vms.include? vm_ref
816
+
817
+ monitored_vms << vm_ref
818
+
819
+ vm =
820
+ VCenterDriver::VirtualMachine
821
+ .new(
822
+ @vi_client,
823
+ vm_ref,
824
+ id
825
+ )
826
+ vm.vm_info = info
827
+ vm.monitor(stats)
828
+
829
+ vm_name = "#{info['name']} - #{cluster_name}"
830
+ vm_info << "VM = [ ID=\"#{id}\", "
831
+ vm_info << "VM_NAME=\"#{vm_name}\", "
832
+ vm_info << "DEPLOY_ID=\"#{vm_ref}\", "
833
+
834
+ # if the machine does not exist in
835
+ # opennebula it means that is a wild:
836
+ if vm.one_exist?
837
+ mon_s64 = Base64.strict_encode64(vm.info)
838
+ vm_info << "MONITOR=\"#{mon_s64}\"]\n"
839
+ else
840
+ vm_template64 =
841
+ Base64
842
+ .encode64(
843
+ vm.vm_to_one(vm_name)
844
+ ).gsub("\n", '')
845
+ vm_info << 'VCENTER_TEMPLATE="YES",'
846
+ vm_info << "IMPORT_TEMPLATE=\"#{vm_template64}\"]\n"
847
+ end
848
+ rescue StandardError => e
849
+ vm_info = error_monitoring(e, id, vm_ref, vc_uuid, info)
850
+ end
851
+
852
+ str_info << vm_info
853
+ end
854
+
855
+ view.DestroyView # Destroy the view
856
+
857
+ [str_info, last_mon_time]
858
+ end
859
+
860
+ def error_monitoring(e, id, vm_ref, _vc_uuid, info = {})
861
+ error_info = ''
862
+ vm_name = info['name'] || nil
863
+ tmp_str = e.inspect
864
+ tmp_str << e.backtrace.join("\n")
865
+
866
+ error_info << "VM = [ ID=\"#{id}\", "
867
+ error_info << "VM_NAME=\"#{vm_name}\", "
868
+ error_info << "DEPLOY_ID=\"#{vm_ref}\", "
869
+ error_info <<
870
+ "ERROR=\"#{Base64.encode64(tmp_str).gsub("\n", '')}\"]\n"
871
+ end
872
+
873
+ def monitor_customizations
874
+ customizations =
875
+ self['_connection']
876
+ .serviceContent
877
+ .customizationSpecManager
878
+ .info
879
+
880
+ text = ''
881
+
882
+ customizations.each do |c|
883
+ t = 'CUSTOMIZATION = [ '
884
+ t << %(NAME = "#{c.name}", )
885
+ t << %(TYPE = "#{c.type}" ]\n)
886
+
887
+ text << t
888
+ end
889
+
890
+ text
891
+ end
892
+
893
+ def datacenter # rubocop:disable Naming/AccessorMethodName
894
+ item = @item
895
+
896
+ until item.instance_of? RbVmomi::VIM::Datacenter
897
+ item = item.parent
898
+ if item.nil?
899
+ raise 'Could not find the parent Datacenter'
900
+ end
901
+ end
902
+
903
+ Datacenter.new(item)
904
+ end
905
+
906
+ def self.to_one(cluster, con_ops, rp, one_cluster_id)
907
+ one_host = VCenterDriver::VIHelper.new_one_item(OpenNebula::Host)
908
+
909
+ if OpenNebula.is_error?(one_host)
910
+ raise "Could not create host: #{one_host.message}"
911
+ end
912
+
913
+ one_cluster_id ||= -1
914
+
915
+ rc = one_host
916
+ .allocate(
917
+ cluster[:cluster_name],
918
+ 'vcenter',
919
+ 'vcenter',
920
+ one_cluster_id.to_i
921
+ )
922
+
923
+ if OpenNebula.is_error?(rc)
924
+ raise "Could not allocate host: #{rc.message}"
925
+ end
926
+
927
+ template = "VCENTER_HOST=\"#{con_ops[:host]}\"\n"\
928
+ "VCENTER_PASSWORD=\"#{con_ops[:password]}\"\n"\
929
+ "VCENTER_USER=\"#{con_ops[:user]}\"\n"\
930
+ "VCENTER_CCR_REF=\"#{cluster[:cluster_ref]}\"\n"\
931
+ "VCENTER_INSTANCE_ID=\"#{cluster[:vcenter_uuid]}\"\n"\
932
+ "VCENTER_VERSION=\"#{cluster[:vcenter_version]}\"\n"\
933
+
934
+ template << "VCENTER_RESOURCE_POOL=\"#{rp}\"" if rp
935
+
936
+ template << "VCENTER_PORT=\"#{con_ops[:port]}\"" if con_ops[:port]
937
+
938
+ rc = one_host.update(template, false)
939
+
940
+ if OpenNebula.is_error?(rc)
941
+ update_error = rc.message
942
+ rc = one_host.delete
943
+
944
+ unless OpenNebula.is_error?(rc)
945
+ raise "Could not update host: #{rc.message}"; end
946
+
947
+ raise "Could not update host: #{update_error} "\
948
+ "and could not delete host: #{rc.message}"
949
+ end
950
+
951
+ rc = one_host.offline
952
+
953
+ if OpenNebula.is_error?(rc)
954
+ update_error = rc.message
955
+ rc = one_host.delete
956
+
957
+ unless OpenNebula.is_error?(rc)
958
+ raise "Could not offline host: #{rc.message}"; end
959
+
960
+ raise "Could not offline host: #{update_error} "\
961
+ "and could not delete host: #{rc.message}"
962
+ end
963
+
964
+ rc = one_host.enable
965
+
966
+ if OpenNebula.is_error?(rc)
967
+ update_error = rc.message
968
+ rc = one_host.delete
969
+
970
+ unless OpenNebula.is_error?(rc)
971
+ raise "Could not enable host: #{rc.message}"; end
972
+
973
+ raise "Could not enable host: #{update_error} "\
974
+ "and could not delete host: #{rc.message}"
975
+ end
976
+
977
+ one_host
978
+ end
979
+
980
+ def self.new_from_ref(ref, vi_client)
981
+ new(
982
+ RbVmomi::VIM::ClusterComputeResource
983
+ .new(
984
+ vi_client.vim,
985
+ ref
986
+ ),
987
+ vi_client
988
+ )
989
+ end
990
+
991
+ end
992
+ # class ClusterComputeResource
993
+
994
+ ##########################################################################
995
+ # Class ESXHost
996
+ ##########################################################################
997
+ class ESXHost
998
+
999
+ attr_accessor :item
1000
+
1001
+ include Memoize
1002
+
1003
+ PG_CREATE_TIMEOUT = 240 # We will wait for 4 minutes for the pg creation
1004
+
1005
+ def initialize(item, vi_client = nil)
1006
+ @net_rollback = []
1007
+ @locking = true
1008
+ @item = item
1009
+ @vi_client = vi_client
1010
+ end
1011
+
1012
+ def self.new_from_ref(ref, vi_client)
1013
+ new(RbVmomi::VIM::HostSystem.new(vi_client.vim, ref), vi_client)
1014
+ end
1015
+
1016
+ # Locking function. Similar to flock
1017
+ def lock
1018
+ hostlockname = @item['name'].downcase.tr(' ', '_')
1019
+
1020
+ return unless @locking
1021
+
1022
+ @locking_file =
1023
+ File
1024
+ .open("/tmp/vcenter-#{hostlockname}-lock", 'w')
1025
+ @locking_file.flock(File::LOCK_EX)
1026
+ end
1027
+
1028
+ # Unlock driver execution mutex
1029
+ def unlock
1030
+ return unless @locking
1031
+
1032
+ @locking_file.close
1033
+ end
1034
+
1035
+ ########################################################################
1036
+ # Check if standard switch exists in host
1037
+ ########################################################################
1038
+
1039
+ def vss_exists(vswitch_name)
1040
+ vswitches = @item.configManager.networkSystem.networkInfo.vswitch
1041
+ vswitches.select {|vs| vs.name == vswitch_name }.first rescue nil
1042
+ end
1043
+
1044
+ ########################################################################
1045
+ # Create a standard vcenter switch in an ESX host
1046
+ ########################################################################
1047
+
1048
+ def create_vss(
1049
+ name,
1050
+ num_ports,
1051
+ pnics = nil,
1052
+ mtu = 1500,
1053
+ pnics_available = nil
1054
+ )
1055
+ # Get NetworkSystem
1056
+ nws = self['configManager.networkSystem']
1057
+ hostbridge = nil
1058
+ nics = []
1059
+
1060
+ num_ports = 128 if num_ports.nil?
1061
+
1062
+ if pnics
1063
+ pnics = pnics.split(',')
1064
+ pnics.each do |pnic|
1065
+ # Add nics if not in use
1066
+ nics << pnic if pnics_available.include?(pnic)
1067
+ end
1068
+
1069
+ if !nics.empty?
1070
+ hostbridge =
1071
+ RbVmomi::VIM::HostVirtualSwitchBondBridge(
1072
+ :nicDevice => nics
1073
+ )
1074
+ end
1075
+ end
1076
+
1077
+ # Create spec
1078
+ vswitchspec =
1079
+ RbVmomi::VIM::HostVirtualSwitchSpec(
1080
+ :bridge => hostbridge,
1081
+ :mtu => mtu,
1082
+ :numPorts => num_ports
1083
+ )
1084
+
1085
+ # add vSwitch to the host
1086
+ begin
1087
+ nws.AddVirtualSwitch(:vswitchName => name, :spec => vswitchspec)
1088
+ rescue StandardError => e
1089
+ raise "The standard vSwitch #{name} could not be \
1090
+ created. AddVirtualSwitch failed Reason: #{e.message}."
1091
+ end
1092
+
1093
+ @net_rollback << { :action => :delete_sw, :name => name }
1094
+
1095
+ name
1096
+ end
1097
+
1098
+ ########################################################################
1099
+ # Update a standard vcenter switch in an ESX host
1100
+ ########################################################################
1101
+ def update_vss(switch, name, pnics, num_ports, mtu)
1102
+ pnics = pnics.split(',') rescue []
1103
+
1104
+ # Backup switch spec for rollback
1105
+ orig_spec = switch.spec
1106
+
1107
+ # Compare current configuration and return if switch hasn't changed
1108
+ switch_has_pnics = switch
1109
+ .spec
1110
+ .respond_to?(
1111
+ :bridge
1112
+ ) && switch
1113
+ .spec
1114
+ .bridge
1115
+ .respond_to?(
1116
+ :nicDevice
1117
+ )
1118
+
1119
+ same_switch = switch.spec.respond_to?(:mtu) && switch
1120
+ .spec
1121
+ .mtu == mtu &&
1122
+ switch
1123
+ .spec
1124
+ .respond_to?(
1125
+ :numPorts
1126
+ ) && switch.spec.numPorts == num_ports &&
1127
+ (!switch_has_pnics && pnics.empty? ||
1128
+ switch_has_pnics && switch
1129
+ .spec
1130
+ .bridge
1131
+ .nicDevice
1132
+ .uniq
1133
+ .sort == pnics.uniq.sort)
1134
+ return if same_switch
1135
+
1136
+ # Let's create a new spec and update the switch
1137
+ hostbridge = nil
1138
+ nws = self['configManager.networkSystem']
1139
+ unless pnics.empty?
1140
+ hostbridge =
1141
+ RbVmomi::VIM::HostVirtualSwitchBondBridge(
1142
+ :nicDevice => pnics
1143
+ )
1144
+ end
1145
+ vswitchspec =
1146
+ RbVmomi::VIM::HostVirtualSwitchSpec(
1147
+ :bridge => hostbridge,
1148
+ :mtu => mtu,
1149
+ :numPorts => num_ports
1150
+ )
1151
+ begin
1152
+ nws
1153
+ .UpdateVirtualSwitch(
1154
+ :vswitchName => name,
1155
+ :spec => vswitchspec
1156
+ )
1157
+ rescue StandardError => e
1158
+ raise "The standard switch with name #{name} \
1159
+ could not be updated. Reason: #{e.message}"
1160
+ end
1161
+
1162
+ @net_rollback << {
1163
+ :action => :update_sw,
1164
+ :name => name,
1165
+ :spec => orig_spec
1166
+ }
1167
+ end
1168
+
1169
+ ########################################################################
1170
+ # Remove a standard vswitch from the host
1171
+ ########################################################################
1172
+ def remove_vss(vswitch_name)
1173
+ nws = self['configManager.networkSystem']
1174
+
1175
+ begin
1176
+ nws.RemoveVirtualSwitch(:vswitchName => vswitch_name)
1177
+ rescue RbVmomi::VIM::ResourceInUse
1178
+ STDERR.puts "The standard switch #{vswitch_name} \
1179
+ is in use so it cannot be deleted"
1180
+ return
1181
+ rescue RbVmomi::VIM::NotFound
1182
+ STDERR.puts "The standard switch #{vswitch_name} \
1183
+ was not found in vCenter"
1184
+ return
1185
+ rescue StandardError => e
1186
+ raise "There was a failure while deleting a vcenter \
1187
+ standard switch #{vswitch_name}. Reason: #{e.message}"
1188
+ end
1189
+
1190
+ vswitch_name
1191
+ end
1192
+
1193
+ ########################################################################
1194
+ # Get physical nics that are available in a host
1195
+ ########################################################################
1196
+ def available_pnics
1197
+ pnics_in_use = []
1198
+ pnics_available = []
1199
+
1200
+ # Get pnics in use in standard switches
1201
+ @item.config.network.vswitch.each do |vs|
1202
+ vs.pnic.each do |pnic|
1203
+ next unless pnic.instance_of?(String)
1204
+
1205
+ pnic.slice!('key-vim.host.PhysicalNic-')
1206
+ pnics_in_use << pnic
1207
+ end
1208
+ end
1209
+
1210
+ # Get pnics in host
1211
+ self['config.network'].pnic.each do |pnic|
1212
+ next if pnics_in_use
1213
+ .include?(pnic.device)
1214
+
1215
+ pnics_available << pnic
1216
+ .device
1217
+ end
1218
+
1219
+ pnics_available
1220
+ end
1221
+
1222
+ ########################################################################
1223
+ # Get networks inside a host
1224
+ ########################################################################
1225
+ def pg_inside_host
1226
+ pg_inside = {}
1227
+
1228
+ # Get pnics in use in standard switches
1229
+ @item.config.network.vswitch.each do |vs|
1230
+ pg_inside[vs.name] = []
1231
+ vs.portgroup.each do |pg|
1232
+ pg.slice!('key-vim.host.PortGroup-')
1233
+ pg_inside[vs.name] << pg
1234
+ end
1235
+ end
1236
+
1237
+ pg_inside
1238
+ end
1239
+
1240
+ ########################################################################
1241
+ # Check if proxy switch exists in host for distributed virtual switch
1242
+ ########################################################################
1243
+
1244
+ def proxy_switch_exists(switch_name)
1245
+ nws = self['configManager.networkSystem']
1246
+ proxy_switches = nws.networkInfo.proxySwitch
1247
+ proxy_switches
1248
+ .select {|ps| ps.dvsName == switch_name }
1249
+ .first rescue nil
1250
+ end
1251
+
1252
+ ########################################################################
1253
+ # Assign a host to a a distributed vcenter switch (proxy switch)
1254
+ ########################################################################
1255
+
1256
+ def assign_proxy_switch(dvs, switch_name, pnics, _pnics_available)
1257
+ dvs = dvs.item
1258
+
1259
+ # Return if host is already assigned
1260
+ return dvs unless dvs['config.host']
1261
+ .select do |host|
1262
+ host.config.host._ref == self['_ref']
1263
+ end.empty?
1264
+
1265
+ # Prepare spec for DVS reconfiguration
1266
+ config_spec = RbVmomi::VIM::VMwareDVSConfigSpec.new
1267
+ config_spec.name = switch_name
1268
+ config_spec.configVersion = dvs['config.configVersion']
1269
+
1270
+ # Check if host is already assigned to distributed switch
1271
+ operation = 'add'
1272
+ # #operation = "edit" if !dvs['config.host'].select
1273
+ # { |host| host.config.host._ref == self['_ref'] }.empty?
1274
+
1275
+ # Add host members to the distributed virtual switch
1276
+ host_member_spec =
1277
+ RbVmomi::VIM::DistributedVirtualSwitchHostMemberConfigSpec
1278
+ .new
1279
+ host_member_spec.host = @item
1280
+ host_member_spec.operation = operation
1281
+ host_member_spec.backing =
1282
+ RbVmomi::VIM::DistributedVirtualSwitchHostMemberPnicBacking
1283
+ .new
1284
+ host_member_spec.backing.pnicSpec = []
1285
+
1286
+ # If pnics are needed assign pnics for uplinks
1287
+ if pnics
1288
+ pnics = pnics.split(',')
1289
+ # Get uplink portgroup from dvswitch
1290
+ uplink_key = dvs['config.uplinkPortgroup'].select do |ul|
1291
+ ul.name == "#{switch_name}-uplink-pg"
1292
+ end.first.key rescue nil
1293
+
1294
+ unless uplink_key
1295
+ raise "Cannot find the uplink portgroup for #{switch_name}"
1296
+ end
1297
+
1298
+ pnics.each do |pnic|
1299
+ pnic_spec =
1300
+ RbVmomi::VIM::DistributedVirtualSwitchHostMemberPnicSpec
1301
+ .new
1302
+ pnic_spec.pnicDevice = pnic
1303
+ pnic_spec.uplinkPortgroupKey = uplink_key
1304
+ host_member_spec.backing.pnicSpec << pnic_spec
1305
+ end
1306
+ end
1307
+
1308
+ config_spec.host = [host_member_spec]
1309
+
1310
+ # The DVS must be reconfigured
1311
+ dvs_reconfigure_task = dvs.ReconfigureDvs_Task(:spec => config_spec)
1312
+ dvs_reconfigure_task.wait_for_completion
1313
+ if dvs_reconfigure_task.info.state != 'success'
1314
+ raise "It wasn't possible to assign host \
1315
+ #{self['name']} as a member of #{switch_name}'"
1316
+ end
1317
+
1318
+ dvs
1319
+ end
1320
+
1321
+ ########################################################################
1322
+ # Create a standard port group
1323
+ ########################################################################
1324
+
1325
+ def create_pg(pgname, vswitch, vlan = 0)
1326
+ spec = RbVmomi::VIM.HostPortGroupSpec(
1327
+ :name => pgname,
1328
+ :vlanId => vlan,
1329
+ :vswitchName => vswitch,
1330
+ :policy => RbVmomi::VIM.HostNetworkPolicy
1331
+ )
1332
+
1333
+ nws = self['configManager.networkSystem']
1334
+
1335
+ begin
1336
+ nws.AddPortGroup(:portgrp => spec)
1337
+ rescue StandardError => e
1338
+ raise "A port group with name #{pgname} \
1339
+ could not be created. Reason: #{e.message}"
1340
+ end
1341
+
1342
+ @net_rollback << { :action => :delete_pg, :name => pgname }
1343
+
1344
+ # wait until the network is ready and we have a reference
1345
+ networks = @item['network'].select {|net| net.name == pgname }
1346
+ (0..PG_CREATE_TIMEOUT).each do
1347
+ break unless networks.empty?
1348
+
1349
+ networks = @item['network'].select {|net| net.name == pgname }
1350
+ sleep 1
1351
+ end
1352
+
1353
+ if networks.empty?
1354
+ raise 'Cannot get VCENTER_NET_REF for new port group'
1355
+ end
1356
+
1357
+ networks.first._ref
1358
+ end
1359
+
1360
+ ########################################################################
1361
+ # Check if standard port group exists in host
1362
+ ########################################################################
1363
+
1364
+ def pg_exists(pg_name)
1365
+ nws = self['configManager.networkSystem']
1366
+ portgroups = nws.networkInfo.portgroup
1367
+ portgroups.select {|pg| pg.spec.name == pg_name }.first rescue nil
1368
+ end
1369
+
1370
+ ########################################################################
1371
+ # Is the switch for the pg different?
1372
+ ########################################################################
1373
+
1374
+ def pg_changes_sw?(pg, switch_name)
1375
+ pg
1376
+ .spec
1377
+ .respond_to?(
1378
+ :vswitchName
1379
+ ) && pg
1380
+ .spec
1381
+ .vswitchName != switch_name
1382
+ end
1383
+
1384
+ ########################################################################
1385
+ # Update a standard port group
1386
+ ########################################################################
1387
+
1388
+ def update_pg(pg, switch_name, vlan_id)
1389
+ unless pg.spec.respond_to?(:vlanId) && pg.spec.vlanId != vlan_id
1390
+ return; end
1391
+
1392
+ # Backup original spec
1393
+ orig_spec = pg.spec
1394
+
1395
+ # Create new spec
1396
+ pg_name = pg.spec.name
1397
+
1398
+ spec = RbVmomi::VIM.HostPortGroupSpec(
1399
+ :name => pg_name,
1400
+ :vlanId => vlan_id,
1401
+ :vswitchName => switch_name,
1402
+ :policy => RbVmomi::VIM.HostNetworkPolicy
1403
+ )
1404
+
1405
+ nws = self['configManager.networkSystem']
1406
+
1407
+ begin
1408
+ nws.UpdatePortGroup(:pgName => pg_name, :portgrp => spec)
1409
+ rescue StandardError => e
1410
+ raise "A port group with name #{pg_name} \
1411
+ could not be updated. Reason: #{e.message}"
1412
+ end
1413
+
1414
+ # Set rollback operation
1415
+ @net_rollback << {
1416
+ :action => :update_pg,
1417
+ :name => pg_name,
1418
+ :spec => orig_spec
1419
+ }
1420
+ end
1421
+
1422
+ ########################################################################
1423
+ # Remove a standard port group from the host
1424
+ ########################################################################
1425
+
1426
+ def remove_pg(pgname)
1427
+ nws = self['configManager.networkSystem']
1428
+
1429
+ swname = nil
1430
+ begin
1431
+ portgroups = nws.networkConfig.portgroup
1432
+ portgroups.each do |pg|
1433
+ if pg.spec.name == pgname
1434
+ swname = pg.spec.vswitchName
1435
+ break
1436
+ end
1437
+ end
1438
+ nws.RemovePortGroup(:pgName => pgname)
1439
+ rescue RbVmomi::VIM::ResourceInUse
1440
+ STDERR.puts "The standard portgroup \
1441
+ #{pgname} is in use so it cannot be deleted"
1442
+ return
1443
+ rescue RbVmomi::VIM::NotFound
1444
+ STDERR.puts "The standard portgroup \
1445
+ #{pgname} was not found in vCenter"
1446
+ return
1447
+ rescue StandardError => e
1448
+ raise "There was a failure while \
1449
+ deleting a standard portgroup #{pgname} \
1450
+ in vCenter. Reason: #{e.message}"
1451
+ end
1452
+
1453
+ swname
1454
+ end
1455
+
1456
+ def network_rollback
1457
+ nws = self['configManager.networkSystem']
1458
+
1459
+ @net_rollback.reverse_each do |nr|
1460
+ case nr[:action]
1461
+ when :update_pg
1462
+ begin
1463
+ nws
1464
+ .UpdatePortGroup(
1465
+ :pgName => nr[:name],
1466
+ :portgrp => nr[:spec]
1467
+ )
1468
+ rescue StandardError => e
1469
+ raise "A rollback operation for standard \
1470
+ port group #{nr[:name]} could not \
1471
+ be performed. Reason: #{e.message}"
1472
+ end
1473
+ when :update_sw
1474
+ begin
1475
+ nws
1476
+ .UpdateVirtualSwitch(
1477
+ :vswitchName => nr[:name],
1478
+ :spec => nr[:spec]
1479
+ )
1480
+ rescue StandardError => e
1481
+ raise "A rollback operation for standard \
1482
+ switch #{nr[:name]} could not \
1483
+ be performed. Reason: #{e.message}"
1484
+ end
1485
+ when :delete_sw
1486
+ begin
1487
+ nws.RemoveVirtualSwitch(:vswitchName=> nr[:name])
1488
+ rescue RbVmomi::VIM::ResourceInUse
1489
+ next # Ignore if switch in use
1490
+ rescue RbVmomi::VIM::NotFound
1491
+ next # Ignore if switch not found
1492
+ rescue StandardError => e
1493
+ raise "A rollback operation for standard \
1494
+ switch #{nr[:name]} could not \
1495
+ be performed. Reason: #{e.message}"
1496
+ end
1497
+ when :delete_pg
1498
+ begin
1499
+ nws.RemovePortGroup(:pgName => nr[:name])
1500
+ rescue RbVmomi::VIM::ResourceInUse
1501
+ next # Ignore if pg in use
1502
+ rescue RbVmomi::VIM::NotFound
1503
+ next # Ignore if pg not found
1504
+ rescue StandardError => e
1505
+ raise "A rollback operation for \
1506
+ standard port group #{nr[:name]} could \
1507
+ not be performed. Reason: #{e.message}"
1508
+ end
1509
+ end
1510
+ end
1511
+ end
1512
+
1513
+ end
1514
+ # class ESXHost
1515
+
1516
+ end
1517
+ # module VCenterDriver