Revision e6a57b0f src/vmm_mad/remotes/lib/vcenter_driver/host.rb

View differences:

src/vmm_mad/remotes/lib/vcenter_driver/host.rb
27 27

  
28 28
class ClusterComputeResource
29 29
    attr_accessor :item
30
    attr_accessor :rp_list
30 31

  
31 32
    include Memoize
32 33

  
33 34
    def initialize(item, vi_client=nil)
34 35
        @item = item
35 36
        @vi_client = vi_client
37
        @rp_list
36 38
    end
37 39

  
38 40
    def fetch_resource_pools(rp, rp_array = [])
......
53 55
        @resource_pools
54 56
    end
55 57

  
56
    def get_resource_pool_list(rp = nil, parent_prefix = "", rp_array = [])
57

  
58
    def get_resource_pool_list(rp = @item.resourcePool, parent_prefix = "", rp_array = [])
58 59
        current_rp = ""
59 60

  
60
        if rp.nil?
61
            rp = @item.resourcePool
62
        else
63
            if !parent_prefix.empty?
64
                current_rp << parent_prefix
65
                current_rp << "/"
66
            end
67
            current_rp << rp.name
61
        if !parent_prefix.empty?
62
            current_rp << parent_prefix
63
            current_rp << "/"
68 64
        end
69 65

  
70
        if rp.resourcePool.size == 0
71
            rp_info = {}
72
            rp_info[:name] = current_rp
73
            rp_info[:ref]  = rp._ref
74
            rp_array << rp_info
75
        else
76
            rp.resourcePool.each do |child_rp|
77
                get_resource_pool_list(child_rp, current_rp, rp_array)
78
            end
79
            rp_info = {}
80
            rp_info[:name] = current_rp
81
            rp_info[:ref]  = rp._ref
82
            rp_array << rp_info if !current_rp.empty?
66
        resource_pool, name = rp.collect("resourcePool","name")
67
        current_rp << name if name != "Resources"
68

  
69
        resource_pool.each do |child_rp|
70
            get_resource_pool_list(child_rp, current_rp, rp_array)
83 71
        end
84 72

  
73
        rp_info = {}
74
        rp_info[:name] = current_rp
75
        rp_info[:ref]  = rp._ref
76
        rp_array << rp_info if !current_rp.empty?
77

  
85 78
        rp_array
86 79
    end
87 80

  
88 81
    def monitor
89
        #Load the host systems
90
        summary = @item.summary
82
        total_cpu,
83
        num_cpu_cores,
84
        effective_cpu,
85
        total_memory,
86
        effective_mem,
87
        num_hosts,
88
        num_eff_hosts = @item.collect("summary.totalCpu",
89
                                      "summary.numCpuCores",
90
                                      "summary.effectiveCpu",
91
                                      "summary.totalMemory",
92
                                      "summary.effectiveMemory",
93
                                      "summary.numHosts",
94
                                      "summary.numEffectiveHosts"
95
        )
91 96

  
92
        mhz_core = summary.totalCpu.to_f / summary.numCpuCores.to_f
93
        eff_core = summary.effectiveCpu.to_f / mhz_core
97
        mhz_core = total_cpu.to_f / num_cpu_cores.to_f
98
        eff_core = effective_cpu.to_f / mhz_core
94 99

  
95 100
        free_cpu  = sprintf('%.2f', eff_core * 100).to_f
96
        total_cpu = summary.numCpuCores.to_f * 100
101
        total_cpu = num_cpu_cores.to_f * 100
97 102
        used_cpu  = sprintf('%.2f', total_cpu - free_cpu).to_f
98 103

  
99
        total_mem = summary.totalMemory.to_i / 1024
100
        free_mem  = summary.effectiveMemory.to_i * 1024
104
        total_mem = total_memory.to_i / 1024
105
        free_mem  = effective_mem.to_i * 1024
101 106

  
102 107
        str_info = ""
103 108

  
......
106 111

  
107 112
        # System
108 113
        str_info << "HYPERVISOR=vcenter\n"
109
        str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n"
110
        str_info << "AVAILHOST=" << summary.numEffectiveHosts.to_s << "\n"
114
        str_info << "TOTALHOST=" << num_hosts.to_s << "\n"
115
        str_info << "AVAILHOST=" << num_eff_hosts.to_s << "\n"
111 116

  
112 117
        # CPU
113 118
        str_info << "CPUSPEED=" << mhz_core.to_s   << "\n"
......
118 123
        # Memory
119 124
        str_info << "TOTALMEMORY=" << total_mem.to_s << "\n"
120 125
        str_info << "FREEMEMORY="  << free_mem.to_s << "\n"
121
        str_info << "USEDMEMORY="  << (total_mem - free_mem).to_s
126
        str_info << "USEDMEMORY="  << (total_mem - free_mem).to_s << "\n"
127

  
128
        str_info << "VCENTER_LAST_PERF_POLL=" << Time.now.to_i.to_s << "\n"
129

  
130
        str_info << monitor_resource_pools(mhz_core)
131
    end
132

  
133
    def monitor_resource_pools(mhz_core)
134

  
135
        @rp_list = get_resource_pool_list
136

  
137
        view = @vi_client.vim.serviceContent.viewManager.CreateContainerView({
138
            container: @item, #View for RPs inside this cluster
139
            type:      ['ResourcePool'],
140
            recursive: true
141
        })
142

  
143
        pc = @vi_client.vim.serviceContent.propertyCollector
144

  
145
        monitored_properties = [
146
            "config.cpuAllocation.expandableReservation",
147
            "config.cpuAllocation.limit",
148
            "config.cpuAllocation.reservation",
149
            "config.cpuAllocation.shares.level",
150
            "config.cpuAllocation.shares.shares",
151
            "config.memoryAllocation.expandableReservation",
152
            "config.memoryAllocation.limit",
153
            "config.memoryAllocation.reservation",
154
            "config.memoryAllocation.shares.level",
155
            "config.memoryAllocation.shares.shares"
156
        ]
157

  
158
        filterSpec = RbVmomi::VIM.PropertyFilterSpec(
159
            :objectSet => [
160
                :obj => view,
161
                :skip => true,
162
                :selectSet => [
163
                RbVmomi::VIM.TraversalSpec(
164
                    :name => 'traverseEntities',
165
                    :type => 'ContainerView',
166
                    :path => 'view',
167
                    :skip => false
168
                )
169
                ]
170
            ],
171
            :propSet => [
172
                { :type => 'ResourcePool', :pathSet => monitored_properties }
173
            ]
174
        )
122 175

  
176
        result = pc.RetrieveProperties(:specSet => [filterSpec])
123 177

  
124
        str_info << monitor_resource_pools(@item.resourcePool, "", mhz_core)
125
    end
178
        rps = {}
179
        result.each do |r|
180
            hashed_properties = r.to_hash
181
            if r.obj.is_a?(RbVmomi::VIM::ResourcePool)
182
                rps[r.obj._ref] = hashed_properties
183
            end
184
        end
126 185

  
127
    def monitor_resource_pools(parent_rp, parent_prefix, mhz_core)
128
        return "" if parent_rp.resourcePool.size == 0
186
        return "" if rps.empty?
129 187

  
130 188
        rp_info = ""
131 189

  
132
        parent_rp.resourcePool.each{|rp|
133
            rpcpu     = rp.config.cpuAllocation
134
            rpmem     = rp.config.memoryAllocation
190
        rps.each{|ref, info|
191

  
135 192
            # CPU
136
            cpu_expandable   = rpcpu.expandableReservation ? "YES" : "NO"
137
            cpu_limit        = rpcpu.limit == "-1" ? "UNLIMITED" : rpcpu.limit
138
            cpu_reservation  = rpcpu.reservation
139
            cpu_num          = rpcpu.reservation.to_f / mhz_core
140
            cpu_shares_level = rpcpu.shares.level
141
            cpu_shares       = rpcpu.shares.shares
193
            cpu_expandable   = info["config.cpuAllocation.expandableReservation"] ? "YES" : "NO"
194
            cpu_limit        = info["config.cpuAllocation.limit"] == "-1" ? "UNLIMITED" : info["config.cpuAllocation.limit"]
195
            cpu_reservation  = info["config.cpuAllocation.reservation"]
196
            cpu_num          = cpu_reservation.to_f / mhz_core
197
            cpu_shares_level = info["config.cpuAllocation.shares.level"]
198
            cpu_shares       = info["config.cpuAllocation.shares.shares"]
142 199

  
143 200
            # MEMORY
144
            mem_expandable   = rpmem.expandableReservation ? "YES" : "NO"
145
            mem_limit        = rpmem.limit == "-1" ? "UNLIMITED" : rpmem.limit
146
            mem_reservation  = rpmem.reservation.to_f
147
            mem_shares_level = rpmem.shares.level
148
            mem_shares       = rpmem.shares.shares
201
            mem_expandable   = info["config.memoryAllocation.expandableReservation"] ? "YES" : "NO"
202
            mem_limit        = info["config.memoryAllocation.limit"] == "-1" ? "UNLIMITED" : info["config.memoryAllocation.limit"]
203
            mem_reservation  = info["config.memoryAllocation.reservation"].to_f
204
            mem_shares_level = info["config.memoryAllocation.shares.level"]
205
            mem_shares       = info["config.memoryAllocation.shares.shares"]
206

  
207
            rp_name = rp_list.select { |item| item[:ref] == ref}.first[:name] rescue ""
149 208

  
150
            rp_name          = (parent_prefix.empty? ? "" : parent_prefix + "/")
151
            rp_name         += rp.name
209
            rp_name = "Resources" if rp_name.empty?
152 210

  
153 211
            rp_info << "\nVCENTER_RESOURCE_POOL_INFO = ["
154 212
            rp_info << "NAME=\"#{rp_name}\","
......
164 222
            rp_info << "MEM_SHARES=#{mem_shares},"
165 223
            rp_info << "MEM_SHARES_LEVEL=#{mem_shares_level}"
166 224
            rp_info << "]"
167

  
168
            if rp.resourcePool.size != 0
169
               rp_info << monitor_resource_pools(rp, rp_name, mhz_core)
170
            end
171 225
        }
172 226

  
227
        view.DestroyView
228

  
173 229
        return rp_info
174 230
    end
175 231

  
176 232
    def monitor_host_systems
177 233
        host_info = ""
178 234

  
179
        @item.host.each do |h|
180
            next if h.runtime.connectionState != "connected"
235
        view = @vi_client.vim.serviceContent.viewManager.CreateContainerView({
236
            container: @item, #View for Hosts inside this cluster
237
            type:      ['HostSystem'],
238
            recursive: true
239
        })
240

  
241
        pc = @vi_client.vim.serviceContent.propertyCollector
242

  
243
        monitored_properties = [
244
            "name",
245
            "runtime.connectionState",
246
            "summary.hardware.numCpuCores",
247
            "summary.hardware.memorySize",
248
            "summary.hardware.cpuModel",
249
            "summary.hardware.cpuMhz",
250
            "summary.quickStats.overallCpuUsage",
251
            "summary.quickStats.overallMemoryUsage"
252
        ]
253

  
254
        filterSpec = RbVmomi::VIM.PropertyFilterSpec(
255
            :objectSet => [
256
                :obj => view,
257
                :skip => true,
258
                :selectSet => [
259
                RbVmomi::VIM.TraversalSpec(
260
                    :name => 'traverseEntities',
261
                    :type => 'ContainerView',
262
                    :path => 'view',
263
                    :skip => false
264
                )
265
                ]
266
            ],
267
            :propSet => [
268
                { :type => 'HostSystem', :pathSet => monitored_properties }
269
            ]
270
        )
271

  
272
        result = pc.RetrieveProperties(:specSet => [filterSpec])
273

  
274
        hosts = {}
275
        result.each do |r|
276
            hashed_properties = r.to_hash
277
            if r.obj.is_a?(RbVmomi::VIM::HostSystem)
278
                hosts[r.obj._ref] = hashed_properties
279
            end
280
        end
181 281

  
182
            summary = h.summary
183
            hw      = summary.hardware
184
            stats   = summary.quickStats
282
        hosts.each do |ref, info|
283
            next if info["runtime.connectionState"] != "connected"
185 284

  
186
            total_cpu = hw.numCpuCores * 100
187
            used_cpu  = (stats.overallCpuUsage.to_f / hw.cpuMhz.to_f) * 100
285
            total_cpu = info["summary.hardware.numCpuCores"] * 100
286
            used_cpu  = (info["summary.quickStats.overallCpuUsage"].to_f / info["summary.hardware.cpuMhz"].to_f) * 100
188 287
            used_cpu  = sprintf('%.2f', used_cpu).to_f # Trim precission
189 288
            free_cpu  = total_cpu - used_cpu
190 289

  
191
            total_memory = hw.memorySize/1024
192
            used_memory  = stats.overallMemoryUsage*1024
290
            total_memory = info["summary.hardware.memorySize"]/1024
291
            used_memory  = info["summary.quickStats.overallMemoryUsage"]*1024
193 292
            free_memory  = total_memory - used_memory
194 293

  
195 294
            host_info << "\nHOST=["
196 295
            host_info << "STATE=on,"
197
            host_info << "HOSTNAME=\""  << h.name.to_s       << "\","
198
            host_info << "MODELNAME=\"" << hw.cpuModel.to_s  << "\","
199
            host_info << "CPUSPEED="    << hw.cpuMhz.to_s    << ","
296
            host_info << "HOSTNAME=\""  << info["name"].to_s       << "\","
297
            host_info << "MODELNAME=\"" << info["summary.hardware.cpuModel"].to_s  << "\","
298
            host_info << "CPUSPEED="    << info["summary.hardware.cpuMhz"].to_s    << ","
200 299
            host_info << "MAX_CPU="     << total_cpu.to_s    << ","
201 300
            host_info << "USED_CPU="    << used_cpu.to_s     << ","
202 301
            host_info << "FREE_CPU="    << free_cpu.to_s     << ","
......
206 305
            host_info << "]"
207 306
        end
208 307

  
308
        view.DestroyView # Destroy the view
309

  
209 310
        return host_info
210 311
    end
211 312

  
212 313
    def monitor_vms
213
        str_info = ""
314

  
315
        vc_uuid = @vi_client.vim.serviceContent.about.instanceUuid
316
        cluster_name = self["name"]
317
        cluster_ref = self["_ref"]
318

  
319
        # Get info of the host where the VM/template is located
320
        host_id = nil
321
        one_host = VCenterDriver::VIHelper.find_by_ref(OpenNebula::HostPool,
322
                                                       "TEMPLATE/VCENTER_CCR_REF",
323
                                                       cluster_ref,
324
                                                       vc_uuid)
325
        host_id = one_host["ID"] if one_host
326

  
327

  
328
        # Extract CPU info for each esx host in cluster
329
        esx_host_cpu = {}
330
        @item.host.each do |esx_host|
331
            esx_host_cpu[esx_host._ref] = esx_host.summary.hardware.cpuMhz.to_f
332
        end
333

  
214 334
        @monitored_vms = Set.new
215
        resource_pools.each do |rp|
216
            str_info << monitor_vms_in_rp(rp)
335
        str_info = ""
336

  
337
        view = @vi_client.vim.serviceContent.viewManager.CreateContainerView({
338
            container: @item, #View for VMs inside this cluster
339
            type:      ['VirtualMachine'],
340
            recursive: true
341
        })
342

  
343
        pc = @vi_client.vim.serviceContent.propertyCollector
344

  
345
        monitored_properties = [
346
            "name", #VM name
347
            "config.template", #To filter out templates
348
            "summary.runtime.powerState", #VM power state
349
            "summary.quickStats.hostMemoryUsage", #Memory usage
350
            "summary.quickStats.overallCpuUsage", #CPU used by VM
351
            "runtime.host", #ESX host
352
            "resourcePool", #RP
353
            "guest.guestFullName",
354
            "guest.net", #IP addresses as seen by guest tools,
355
            "guest.guestState",
356
            "guest.toolsVersion",
357
            "guest.toolsRunningStatus",
358
            "guest.toolsVersionStatus2", #IP addresses as seen by guest tools,
359
            "config.extraConfig", #VM extraconfig info e.g opennebula.vm.running
360
            "config.hardware.numCPU",
361
            "config.hardware.memoryMB",
362
            "config.annotation"
363
        ]
364

  
365
        filterSpec = RbVmomi::VIM.PropertyFilterSpec(
366
            :objectSet => [
367
                :obj => view,
368
                :skip => true,
369
                :selectSet => [
370
                RbVmomi::VIM.TraversalSpec(
371
                    :name => 'traverseEntities',
372
                    :type => 'ContainerView',
373
                    :path => 'view',
374
                    :skip => false
375
                )
376
                ]
377
            ],
378
            :propSet => [
379
                { :type => 'VirtualMachine', :pathSet => monitored_properties }
380
            ]
381
        )
382

  
383
        result = pc.RetrieveProperties(:specSet => [filterSpec])
384

  
385
        vms = {}
386
        vm_objects = []
387
        result.each do |r|
388
            hashed_properties = r.to_hash
389
            if r.obj.is_a?(RbVmomi::VIM::VirtualMachine)
390
                #Only take care of VMs, not templates
391
                if !hashed_properties["config.template"]
392
                    vms[r.obj._ref] = hashed_properties
393
                    vm_objects << r.obj
394
                end
395
            end
217 396
        end
218 397

  
219
        return str_info
220
    end
398
        pm = @vi_client.vim.serviceContent.perfManager
221 399

  
222
    def monitor_vms_in_rp(rp)
223
        str_info = ""
400
        stats = []
224 401

  
225
        host_pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool)
402
        max_samples = 9
403
        refresh_rate = 20 #Real time stats takes samples every 20 seconds
226 404

  
227
        ccr_host = {}
228
        host_pool.each do |host|
229
            ccr = host['TEMPLATE/VCENTER_CCR_REF']
230
            ccr_host[ccr] = host['ID'] if ccr
405
        last_mon_time = one_host["TEMPLATE/VCENTER_LAST_PERF_POLL"]
406

  
407
        if last_mon_time
408
            interval = (Time.now.to_i - last_mon_time.to_i)
409
            interval = 3601 if interval < 0
410
            samples = (interval / refresh_rate)
411
            samples = 1 if samples == 0
412
            max_samples =  interval > 3600 ? 9 : samples
231 413
        end
232 414

  
233
        rp.vm.each do |v|
415
        stats = pm.retrieve_stats(
416
                vm_objects,
417
                ['net.transmitted','net.bytesRx','net.bytesTx','net.received',
418
                'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged',
419
                'virtualDisk.read','virtualDisk.write'],
420
                {max_samples: max_samples}
421
        )
422

  
423
        get_resource_pool_list if !@rp_list
424

  
425
        vms.each do |vm_ref,info|
234 426
            begin
235
                vm = VirtualMachine.new(v, @vi_client)
427
                vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, @vi_client)
428
                info[:cluster_name] = cluster_name
429
                info[:cluster_ref] = cluster_ref
430
                info[:vc_uuid] = vc_uuid
431
                info[:host_id] = host_id
432
                info[:rp_list] = @rp_list
433

  
434
                vm.vm_info = info
236 435

  
237 436
                number = -1
238 437

  
239 438
                # Check the running flag
240
                running_flag = vm["config.extraConfig"].select do |val|
439
                running_flag = info["config.extraConfig"].select do |val|
241 440
                    val[:key] == "opennebula.vm.running"
242 441
                end
243 442

  
244
                if running_flag.size > 0 and running_flag[0]
443
                if !running_flag.empty? && running_flag.first
245 444
                    running_flag = running_flag[0][:value]
246 445
                end
247 446

  
248 447
                next if running_flag == "no"
249 448

  
250 449
                # Extract vmid if possible
251
                matches = vm["name"].match(/^one-(\d*)(-(.*))?$/)
450
                matches = info["name"].match(/^one-(\d*)(-(.*))?$/)
252 451
                number  = matches[1] if matches
253 452

  
254 453
                # Extract vmid from ref and vcenter instance uuid if possible
255
                vm_id = vm.get_vm_id
256

  
257
                number = vm_id if vm_id
454
                if number == -1
455
                    one_vm = VCenterDriver::VIHelper.find_by_ref(OpenNebula::VirtualMachinePool,
456
                                                                "DEPLOY_ID",
457
                                                                vm_ref,
458
                                                                vc_uuid)
459
                    number = one_vm["ID"] if one_vm
460
                end
258 461

  
259 462
                if number != -1
260 463
                    next if @monitored_vms.include? number
261 464
                    @monitored_vms << number
465
                    vm.one_item if vm.get_vm_id
262 466
                end
263 467

  
264
                vm.monitor
468
                vm.monitor(esx_host_cpu,stats)
265 469

  
266
                next if !vm["config"]
470
                vm_name = "#{info["name"]} - #{cluster_name}"
267 471

  
268 472
                str_info << %Q{
269 473
                VM = [
270 474
                    ID="#{number}",
271
                    VM_NAME="#{vm["name"]} - #{vm["runtime.host.parent.name"]}",
272
                    DEPLOY_ID="#{vm["_ref"]}",
475
                    VM_NAME="#{vm_name}",
476
                    DEPLOY_ID="#{vm_ref}",
273 477
                }
274 478

  
275 479
                if number == -1
276
                    vm_template_64 = Base64.encode64(vm.to_one).gsub("\n","")
480
                    vm_template_64 = Base64.encode64(vm.vm_to_one(vm_name)).gsub("\n","")
277 481

  
278 482
                    str_info << "IMPORT_TEMPLATE=\"#{vm_template_64}\","
279 483
                end
280 484

  
281 485
                str_info << "POLL=\"#{vm.info.gsub('"', "\\\"")}\"]"
486

  
282 487
            rescue Exception => e
283 488
                STDERR.puts e.inspect
284 489
                STDERR.puts e.backtrace
285 490
            end
286 491
        end
287 492

  
288
        return str_info.gsub(/^\s+/,"")
289
    end
493
        view.DestroyView # Destroy the view
290 494

  
495
        return str_info
496
    end
291 497

  
292 498
    def monitor_customizations
293 499
        customizations = self['_connection'].serviceContent.customizationSpecManager.info

Also available in: Unified diff