Statistics
| Branch: | Tag: | Revision:

one / src / cli / one_helper / onevm_helper.rb @ 0bdbdfbc

History | View | Annotate | Download (35.2 KB)

1
# -------------------------------------------------------------------------- #
2
# Copyright 2002-2017, 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
if !ONE_LOCATION
18
    MAD_LOCATION      = "/usr/lib/one/mads"
19
    VAR_LOCATION      = "/var/lib/one"
20
else
21
    MAD_LOCATION      = ONE_LOCATION + "/lib/mads"
22
    VAR_LOCATION      = ONE_LOCATION + "/var"
23
end
24

    
25
VMS_LOCATION = VAR_LOCATION + "/vms"
26

    
27
$: << MAD_LOCATION
28

    
29
require 'one_helper'
30
require 'optparse/time'
31

    
32
class String
33
    def red
34
        colorize(31)
35
    end
36

    
37
    def green
38
        colorize(32)
39
    end
40

    
41
private
42

    
43
    def colorize(color_code)
44
        "\e[#{color_code}m#{self}\e[0m"
45
    end
46
end
47

    
48

    
49
class OneVMHelper < OpenNebulaHelper::OneHelper
50
    MULTIPLE={
51
        :name  => "multiple",
52
        :short => "-m x",
53
        :large => "--multiple x",
54
        :format => Integer,
55
        :description => "Instance multiple VMs"
56
    }
57

    
58
    IMAGE = {
59
        :name   => "image",
60
        :short  => "-i id|name",
61
        :large  => "--image id|name" ,
62
        :description => "Selects the image",
63
        :format => String,
64
        :proc   => lambda { |o, options|
65
            OpenNebulaHelper.rname_to_id(o, "IMAGE")
66
        }
67
    }
68

    
69
    NETWORK = {
70
        :name   => "network",
71
        :short  => "-n id|name",
72
        :large  => "--network id|name" ,
73
        :description => "Selects the virtual network",
74
        :format => String,
75
        :proc   => lambda { |o, options|
76
            OpenNebulaHelper.rname_to_id(o, "VNET")
77
        }
78
    }
79

    
80
    IP={
81
        :name => "ip",
82
        :short => "-i ip",
83
        :large => "--ip ip",
84
        :format => String,
85
        :description => "IP address for the new NIC"
86
    }
87

    
88
    FILE = {
89
        :name   => "file",
90
        :short  => "-f file",
91
        :large  => "--file file" ,
92
        :description => "Selects the template file",
93
        :format => String,
94
        :proc   => lambda { |o, options|
95
            if File.file?(o)
96
                options[:file] = o
97
            else
98
                exit -1
99
            end
100
        }
101
    }
102

    
103
    HOLD = {
104
        :name  => "hold",
105
        :large => "--hold",
106
        :description => "Creates the new VM on hold state instead of pending"
107
    }
108

    
109
    SCHEDULE = {
110
        :name       => "schedule",
111
        :large      => "--schedule TIME",
112
        :description => "Schedules this action to be executed after" \
113
        "the given time. For example: onevm resume 0 --schedule \"09/23 14:15\"",
114
        :format     => Time
115
    }
116

    
117
    ALL_TEMPLATE = {
118
        :name       => "all",
119
        :large      => "--all",
120
        :description => "Show all template data"
121
    }
122

    
123
    LIVE = {
124
        :name        => "live",
125
        :large       => "--live",
126
        :description => "Do the action with the VM running"
127
    }
128

    
129
    HARD = {
130
        :name       => "hard",
131
        :large      => "--hard",
132
        :description=> "Does not communicate with the guest OS"
133
    }
134

    
135
    def self.rname
136
        "VM"
137
    end
138

    
139
    def self.conf_file
140
        "onevm.yaml"
141
    end
142

    
143
    def self.state_to_str(id, lcm_id)
144
        id = id.to_i
145
        state_str = VirtualMachine::VM_STATE[id]
146
        short_state_str = VirtualMachine::SHORT_VM_STATES[state_str]
147

    
148
        if short_state_str=="actv"
149
            lcm_id = lcm_id.to_i
150
            lcm_state_str = VirtualMachine::LCM_STATE[lcm_id]
151
            return VirtualMachine::SHORT_LCM_STATES[lcm_state_str]
152
        end
153

    
154
        return short_state_str
155
    end
156

    
157
    # Return the IP or several IPs of a VM
158
    def self.ip_str(vm)
159
        ips = []
160

    
161
        vm_nics = []
162

    
163
        if !vm["TEMPLATE"]["NIC"].nil?
164
            vm_nics = [vm["TEMPLATE"]['NIC']].flatten
165
        end
166

    
167
        if !vm["TEMPLATE"]["PCI"].nil?
168
            vm_nics = [vm_nics, vm["TEMPLATE"]['PCI']].flatten
169
        end
170

    
171
        vm_nics.each do |nic|
172
            ["IP", "IP6_GLOBAL", "IP6_ULA", "IP6",
173
             "VROUTER_IP", "VROUTER_IP6_GLOBAL", "VROUTER_IP6_ULA"].each do |attr|
174
                if nic.has_key?(attr)
175
                    ips.push(nic[attr])
176
                end
177
            end
178
        end
179

    
180
        VirtualMachine::EXTERNAL_IP_ATTRS.each do |attr|
181
            external_ip = vm["MONITORING"][attr]
182

    
183
            if !external_ip.nil? && !ips.include?(external_ip)
184
                ips.push(external_ip)
185
            end
186
        end
187

    
188
        if ips.empty?
189
            return "--"
190
        else
191
            return ips.join(",")
192
        end
193
    end
194

    
195
    def format_pool(options)
196
        config_file = self.class.table_conf
197

    
198
        # Get cluster names to use later in list
199
        cluster_pool = OpenNebula::ClusterPool.new(@client)
200
        rc = cluster_pool.info
201

    
202
        cluster_names = {}
203
        cluster_names["-1"] = "default"
204

    
205
        if !OpenNebula.is_error?(rc)
206
            cluster_pool.each do |c|
207
                cluster_names[c["ID"]] = c["NAME"]
208
            end
209
        end
210

    
211
        table = CLIHelper::ShowTable.new(config_file, self) do
212
            column :ID, "ONE identifier for Virtual Machine", :size=>6 do |d|
213
                d["ID"]
214
            end
215

    
216
            column :NAME, "Name of the Virtual Machine", :left,
217
                    :size=>15 do |d|
218
                if d["RESCHED"] == "1"
219
                    "*#{d["NAME"]}"
220
                else
221
                    d["NAME"]
222
                end
223
            end
224

    
225
            column :USER, "Username of the Virtual Machine owner", :left,
226
                    :size=>8 do |d|
227
                helper.user_name(d, options)
228
            end
229

    
230
            column :GROUP, "Group of the Virtual Machine", :left,
231
                    :size=>8 do |d|
232
                helper.group_name(d, options)
233
            end
234

    
235
            column :STAT, "Actual status", :size=>4 do |d,e|
236
                OneVMHelper.state_to_str(d["STATE"], d["LCM_STATE"])
237
            end
238

    
239
            column :UCPU, "CPU percentage used by the VM", :size=>4 do |d|
240
                cpu = d["MONITORING"]["CPU"]
241
                cpu = "0" if cpu.nil?
242

    
243
                cpu
244
            end
245

    
246
            column :UMEM, "Memory used by the VM", :size=>7 do |d|
247
                OpenNebulaHelper.unit_to_str(d["MONITORING"]["MEMORY"].to_i, options)
248
            end
249

    
250
            column :HOST, "Host where the VM is running", :left, :size=>10 do |d|
251
                if d['HISTORY_RECORDS'] && d['HISTORY_RECORDS']['HISTORY']
252
                    state_str = VirtualMachine::VM_STATE[d['STATE'].to_i]
253
                    if %w{ACTIVE SUSPENDED POWEROFF}.include? state_str
254
                        d['HISTORY_RECORDS']['HISTORY']['HOSTNAME']
255
                    end
256
                end
257
            end
258

    
259
            column :CLUSTER, "Cluster where the VM is running", :left,
260
                    :size=> 10 do |d|
261
                if d["HISTORY_RECORDS"]["HISTORY"]
262
                    history = [d["HISTORY_RECORDS"]["HISTORY"]].flatten
263
                    cluster_id = history.last["CID"]
264
                    cluster = cluster_names[cluster_id]
265

    
266
                    if !cluster
267
                        cluster_id
268
                    else
269
                        cluster
270
                    end
271
                else
272
                    "NONE"
273
                end
274
            end
275

    
276
            column :TIME, "Time since the VM was submitted", :size=>10 do |d|
277
                stime = d["STIME"].to_i
278
                etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
279
                dtime = etime-stime
280
                OpenNebulaHelper.period_to_str(dtime, false)
281
            end
282

    
283
            column :IP, "VM IP addresses", :left, :donottruncate, :size=>15 do |d|
284
                OneVMHelper.ip_str(d)
285
            end
286

    
287
            default :ID, :USER, :GROUP, :NAME, :STAT, :UCPU, :UMEM, :HOST,
288
                :TIME
289
        end
290

    
291
        table
292
    end
293

    
294

    
295
    def schedule_actions(ids,options,action)
296
        # Verbose by default
297
        options[:verbose] = true
298

    
299
        perform_actions(
300
            ids, options,
301
            "#{action} scheduled at #{options[:schedule]}") do |vm|
302

    
303
            rc = vm.info
304

    
305
            if OpenNebula.is_error?(rc)
306
                puts rc.message
307
                exit -1
308
            end
309

    
310
            ids = vm.retrieve_elements('USER_TEMPLATE/SCHED_ACTION/ID')
311

    
312
            id = 0
313
            if (!ids.nil? && !ids.empty?)
314
                ids.map! {|e| e.to_i }
315
                id = ids.max + 1
316
            end
317

    
318
            tmp_str = vm.user_template_str
319

    
320
            tmp_str << "\nSCHED_ACTION = [ID = #{id}, ACTION = #{action}, TIME = #{options[:schedule].to_i}]"
321

    
322
            vm.update(tmp_str)
323
        end
324
    end
325

    
326
    RECOVER_RETRY_STEPS = {
327
        :PROLOG_MIGRATE_FAILURE          => :migrate,
328
        :PROLOG_MIGRATE_POWEROFF_FAILURE => :migrate,
329
        :PROLOG_MIGRATE_SUSPEND_FAILURE  => :migrate,
330
        :PROLOG_MIGRATE_UNKNOWN_FAILURE  => :migrate,
331
        :PROLOG_FAILURE                  => :prolog,
332
        :PROLOG_RESUME_FAILURE           => :resume,
333
        :PROLOG_UNDEPLOY_FAILURE         => :resume,
334
        :EPILOG_FAILURE                  => :epilog,
335
        :EPILOG_STOP_FAILURE             => :stop,
336
        :EPILOG_UNDEPLOY_FAILURE         => :stop
337
    }
338

    
339
    def recover_retry_interactive(vm)
340
        begin
341
            require 'one_tm'
342
        rescue LoadError
343
            STDERR.puts <<-EOT
344
one_tm library not found. Make sure you execute recover --interactive
345
in the frontend machine.
346
            EOT
347
            exit(-1)
348
        end
349

    
350
        # Disable CTRL-C in the menu
351
        trap("SIGINT") { }
352

    
353
        if !File.readable?(VAR_LOCATION+"/config")
354
            STDERR.puts "Error reading #{VAR_LOCATION+'/config'}. The " <<
355
                "TM Debug Interactive Environment must be executed as " <<
356
                "oneadmin in the frontend."
357
            exit -1
358
        end
359

    
360
        rc = vm.info
361
        if OpenNebula.is_error?(rc)
362
            STDERR.puts rc.message
363
            exit -1
364
        end
365

    
366
        if !RECOVER_RETRY_STEPS.include?(vm.lcm_state_str.to_sym)
367
            STDERR.puts "Current LCM STATE '#{vm.lcm_state_str}' not " <<
368
                "compatible with RECOVER RETRY action."
369
            exit -1
370
        end
371

    
372
        seq = vm['/VM/HISTORY_RECORDS/HISTORY[last()]/SEQ']
373

    
374
        tm_action = RECOVER_RETRY_STEPS[vm.lcm_state_str.to_sym]
375

    
376
        tm_file = "#{VMS_LOCATION}/#{vm.id}/transfer.#{seq}.#{tm_action}"
377

    
378
        if !File.readable?(tm_file)
379
            STDERR.puts "Cannot read #{tm_file}"
380
            exit -1
381
        end
382

    
383
        @tm_action_list = File.read(tm_file)
384

    
385
        puts "TM Debug Interactive Environment.".green
386
        puts
387
        print_tm_action_list
388

    
389
        @tm = TransferManagerDriver.new(nil)
390
        i=0
391
        @tm_action_list.lines.each do |tm_command|
392
            i+=1
393
            success=false
394

    
395
            while !success
396
                puts "Current action (#{i}):".green
397
                puts tm_command
398
                puts
399

    
400
                puts <<-EOF.gsub(/^\s+/,"")
401
                Choose action:
402
                (r) Run action
403
                (n) Skip to next action
404
                (a) Show all actions
405
                (q) Quit
406
                EOF
407

    
408
                ans = ""
409
                while !%w(n a r q).include?(ans)
410
                    printf "> "
411
                    ans = STDIN.gets.strip.downcase
412

    
413
                    puts
414

    
415
                    case ans
416
                    when "n"
417
                        success = true
418
                    when "a"
419
                        print_tm_action_list
420
                    when "q"
421
                        exit -1
422
                    when "r"
423
                        result, result_message = @tm.do_transfer_action(@id, tm_command.split)
424

    
425
                        if result == "SUCCESS"
426
                            success = true
427
                            puts "#{result}"
428
                            puts
429
                        else
430
                            puts
431
                            puts "#{result}. Repeat command.".red
432
                            puts
433
                        end
434
                    end
435
                end
436
            end
437
        end
438

    
439
        puts "If all the TM actions have been successful and you want to"
440
        puts "recover the Virtual Machine to the RUNNING state execute this command:"
441
        puts "$ onevm recover #{vm.id} --success"
442
    end
443

    
444
    def print_tm_action_list
445
        puts "TM Action list:".green
446
        i=0
447
        @tm_action_list.lines.each do |line|
448
            i+=1
449
            puts "(#{i}) #{line}"
450
        end
451
        puts
452
    end
453

    
454
    private
455

    
456
    def factory(id=nil)
457
        if id
458
            OpenNebula::VirtualMachine.new_with_id(id, @client)
459
        else
460
            xml=OpenNebula::VirtualMachine.build_xml
461
            OpenNebula::VirtualMachine.new(xml, @client)
462
        end
463
    end
464

    
465
    def factory_pool(user_flag=-2)
466
        OpenNebula::VirtualMachinePool.new(@client, user_flag)
467
    end
468

    
469
    def format_resource(vm, options = {})
470
        str_h1="%-80s"
471
        str="%-20s: %-20s"
472

    
473
        cluster = nil
474

    
475
        vm_hash = vm.to_hash
476

    
477
        if %w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
478
            cluster_id = vm['/VM/HISTORY_RECORDS/HISTORY[last()]/CID']
479
        else
480
            cluster_id = nil
481
        end
482

    
483
        if cluster_id
484
            if cluster_id == "-1"
485
                cluster = "default"
486
            else
487
                clu = OpenNebula::Cluster.new(OpenNebula::Cluster.build_xml(cluster_id), @client)
488
                rc = clu.info
489
                if OpenNebula.is_error?(rc)
490
                    cluster = "ERROR"
491
                else
492
                    cluster = clu["NAME"]
493
                end
494
            end
495
        end
496

    
497
        CLIHelper.print_header(
498
            str_h1 % "VIRTUAL MACHINE #{vm['ID']} INFORMATION")
499
        puts str % ["ID", vm.id.to_s]
500
        puts str % ["NAME", vm.name]
501
        puts str % ["USER", vm['UNAME']]
502
        puts str % ["GROUP", vm['GNAME']]
503
        puts str % ["STATE", vm.state_str]
504
        puts str % ["LCM_STATE", vm.lcm_state_str]
505
        puts str % ["RESCHED", OpenNebulaHelper.boolean_to_str(vm['RESCHED'])]
506
        puts str % ["HOST",
507
            vm['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']] if
508
                %w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
509
        puts str % ["CLUSTER ID", cluster_id ] if cluster_id
510
        puts str % ["CLUSTER", cluster ] if cluster
511
        puts str % ["START TIME",
512
            OpenNebulaHelper.time_to_str(vm['/VM/STIME'])]
513
        puts str % ["END TIME",
514
            OpenNebulaHelper.time_to_str(vm['/VM/ETIME'])]
515
        value=vm['DEPLOY_ID']
516
        puts str % ["DEPLOY ID", value=="" ? "-" : value]
517
        value=vm['TEMPLATE/VROUTER_ID']
518
        puts str % ["VIRTUAL ROUTER ID", value] if value
519

    
520
        puts
521

    
522
        CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE MONITORING",false)
523

    
524
        vm_monitoring = vm_hash['VM']['MONITORING']
525

    
526
        # Find out if it is a hybrid VM to avoid showing local IPs
527
        isHybrid=false
528
        vm_monitoring.each{|key, value|
529
            if VirtualMachine::EXTERNAL_IP_ATTRS.include? key
530
                isHybrid=true
531
            end
532
        }
533

    
534
        order_attrs  = %w(CPU MEMORY NETTX NETRX)
535

    
536
        vm_monitoring_sort = []
537
        order_attrs.each do |key|
538
            if (val = vm_monitoring.delete(key))
539
                vm_monitoring_sort << [key, val]
540
            end
541
        end
542

    
543
        vm_monitoring_sort.sort{|a,b| a[0]<=>b[0]}
544

    
545
        filter_attrs = %w(STATE DISK_SIZE SNAPSHOT_SIZE)
546
        vm_monitoring.each do |key, val|
547
            if !filter_attrs.include?(key)
548
                vm_monitoring_sort << [key, val]
549
            end
550
        end
551

    
552
        vm_monitoring_sort.each do |k,v|
553
            if k == "MEMORY"
554
                puts str % [k, OpenNebulaHelper.unit_to_str(v.to_i, {})]
555
            elsif k  =~ /NET.X/
556
                puts str % [k, OpenNebulaHelper.unit_to_str(v.to_i/1024, {})]
557
            else
558
                puts str % [k, v]
559
            end
560
        end
561

    
562
        puts
563

    
564
        CLIHelper.print_header(str_h1 % "PERMISSIONS",false)
565

    
566
        ["OWNER", "GROUP", "OTHER"].each { |e|
567
            mask = "---"
568
            mask[0] = "u" if vm["PERMISSIONS/#{e}_U"] == "1"
569
            mask[1] = "m" if vm["PERMISSIONS/#{e}_M"] == "1"
570
            mask[2] = "a" if vm["PERMISSIONS/#{e}_A"] == "1"
571

    
572
            puts str % [e,  mask]
573
        }
574

    
575
        vm_disks = []
576

    
577
        if vm.has_elements?("/VM/TEMPLATE/DISK")
578
            vm_disks = [vm_hash['VM']['TEMPLATE']['DISK']].flatten
579
        end
580

    
581
        if vm.has_elements?("/VM/TEMPLATE/CONTEXT") && vm["/VM/HISTORY_RECORDS/HISTORY[1]/VM_MAD"] != 'vcenter'
582
            context_disk = vm_hash['VM']['TEMPLATE']['CONTEXT']
583

    
584
            context_disk["IMAGE"]     = "CONTEXT"
585
            context_disk["DATASTORE"] = "-"
586
            context_disk["TYPE"]      = "-"
587
            context_disk["READONLY"]  = "-"
588
            context_disk["SAVE"]      = "-"
589
            context_disk["CLONE"]     = "-"
590
            context_disk["SAVE_AS"]   = "-"
591

    
592
            vm_disks.push(context_disk)
593
        end
594

    
595
        # get monitoring data
596
        vm_disks.each do |disk|
597
            disk_id = disk["DISK_ID"]
598
            disk["MONITOR_SIZE"] = vm["MONITORING/DISK_SIZE[ID='#{disk_id}']/SIZE"]
599
        end
600

    
601
        if !vm_disks.empty?
602
            puts
603
            CLIHelper.print_header(str_h1 % "VM DISKS",false)
604
            CLIHelper::ShowTable.new(nil, self) do
605
                column :ID, "", :size=>3 do |d|
606
                    d["DISK_ID"]
607
                end
608

    
609
                column :DATASTORE, "", :left, :size=>10 do |d|
610
                    d["DATASTORE"]
611
                end
612

    
613
                column :TARGET, "", :left, :size=>6 do |d|
614
                    d["TARGET"]
615
                end
616

    
617
                column :IMAGE, "", :left, :size=>35 do |d|
618
                    if d["IMAGE"]
619
                        d["IMAGE"]
620
                    else
621
                        case d["TYPE"].upcase
622
                        when "FS"
623
                            "#{d["FORMAT"]} - "<<
624
                            OpenNebulaHelper.unit_to_str(d["SIZE"].to_i,
625
                                                         {}, "M")
626
                        when "SWAP"
627
                            OpenNebulaHelper.unit_to_str(d["SIZE"].to_i,
628
                                                         {}, "M")
629

    
630
                        end
631
                    end
632
                end
633

    
634
                column :SIZE, "", :left, :size=>9 do |d|
635
                    if d["SIZE"]
636
                        size = OpenNebulaHelper.unit_to_str(
637
                                    d['SIZE'].to_i,
638
                                    {},
639
                                    "M"
640
                                )
641
                    else
642
                        size = "-"
643
                    end
644

    
645
                    if d["MONITOR_SIZE"]
646
                        monitor_size = OpenNebulaHelper.unit_to_str(
647
                                    d['MONITOR_SIZE'].to_i,
648
                                    {},
649
                                    "M"
650
                                )
651
                    else
652
                        monitor_size = "-"
653
                    end
654

    
655
                    "#{monitor_size}/#{size}"
656
                end
657

    
658
                column :TYPE, "", :left, :size=>4 do |d|
659
                    d["TYPE"].downcase
660
                end
661

    
662
                column :"R/O", "", :size=>3 do |d|
663
                    d["READONLY"]
664
                end
665

    
666
                column :"SAVE", "", :size=>4 do |d|
667
                    d["SAVE"] || "NO"
668
                end
669

    
670
                column :"CLONE", "", :size=>5 do |d|
671
                    d["CLONE"]
672
                end
673

    
674
                default :ID, :DATASTORE, :TARGET, :IMAGE, :SIZE, :TYPE,
675
                    :SAVE
676
            end.show(vm_disks, {})
677

    
678
            while vm.has_elements?("/VM/TEMPLATE/DISK")
679
                vm.delete_element("/VM/TEMPLATE/DISK")
680
            end if !options[:all]
681
        end
682

    
683
        if vm.has_elements?("/VM/SNAPSHOTS")
684
            puts
685
            CLIHelper.print_header(str_h1 % "VM DISK SNAPSHOTS",false)
686
            format_snapshots(vm)
687
        end
688

    
689
        sg_nics = []
690

    
691
        if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS") ||
692
            vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]/SECURITY_GROUPS"))
693

    
694
            sg_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
695

    
696
            sg_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
697

    
698
            sg_pcis.each do |pci|
699
                if !pci['NIC_ID'].nil?
700
                    sg_nics << pci
701
                end
702
            end
703

    
704
            sg_nics.flatten!
705
            sg_nics.compact!
706
        end
707

    
708
        # This variable holds the extra IP's got from monitoring. Right
709
        # now it adds GUEST_IP and GUEST_IP_ADDRESSES from vcenter
710
        # monitoring. If other variables hold IPs just add them to this
711
        # array. Duplicate IPs are not shown.
712
        extra_ips = []
713

    
714
        if val=vm["/VM/MONITORING/GUEST_IP"]
715
            extra_ips << val if val && !val.empty?
716
        end
717

    
718
        if val=vm["/VM/MONITORING/GUEST_IP_ADDRESSES"]
719
            extra_ips += val.split(',') if val && !val.empty?
720
        end
721

    
722
        extra_ips.uniq!
723

    
724
        if vm.has_elements?("/VM/TEMPLATE/NIC") ||
725
           vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]") || !extra_ips.empty?
726

    
727
            puts
728
            CLIHelper.print_header(str_h1 % "VM NICS",false)
729

    
730
            nic_default = {"NETWORK" => "-",
731
                           "IP" => "-",
732
                           "MAC"=> "-",
733
                           "BRIDGE"=>"-"}
734

    
735
            shown_ips = []
736

    
737
            array_id = 0
738
            vm_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
739

    
740
            vm_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
741

    
742
            vm_pcis.each do |pci|
743
                if !pci['NIC_ID'].nil?
744
                    vm_nics << pci
745
                end
746
            end
747

    
748
            vm_nics.flatten!
749
            vm_nics.compact!
750

    
751
            vm_nics.each {|nic|
752

    
753
                next if nic.has_key?("CLI_DONE")
754

    
755
                ["IP6_LINK", "IP6_ULA", "IP6_GLOBAL", "IP6"].each do |attr|
756
                    if nic.has_key?(attr)
757
                        shown_ips << nic[attr]
758

    
759
                        ipstr = {"IP"           => nic.delete(attr),
760
                                 "CLI_DONE"     => true,
761
                                 "DOUBLE_ENTRY" => true}
762
                        vm_nics.insert(array_id+1,ipstr)
763

    
764
                        array_id += 1
765
                    end
766
                end
767

    
768
                ["VROUTER_IP", "VROUTER_IP6_LINK",
769
                 "VROUTER_IP6_ULA", "VROUTER_IP6_GLOBAL"].each do |attr|
770
                    if nic.has_key?(attr)
771
                        shown_ips << nic[attr]
772

    
773
                        ipstr = {"IP"           => nic.delete(attr) + " (VRouter)",
774
                                 "CLI_DONE"     => true,
775
                                 "DOUBLE_ENTRY" => true}
776
                        vm_nics.insert(array_id+1,ipstr)
777

    
778
                        array_id += 1
779
                    end
780
                end
781

    
782
                shown_ips << nic["IP"] if nic.has_key?("IP")
783

    
784
                nic.merge!(nic_default) {|k,v1,v2| v1}
785
                array_id += 1
786
            }
787

    
788
            extra_ips -= shown_ips
789

    
790
            # Add extra IPs to the VM NICS table
791
            extra_ips.each do |ip|
792
                vm_nics << {
793
                    "NIC_ID"        => "-",
794
                    "IP"            => ip,
795
                    "NETWORK"       => "Additional IP",
796
                    "BRIDGE"        => "-"
797
                }
798
            end
799

    
800
            CLIHelper::ShowTable.new(nil, self) do
801
                column :ID, "", :size=>3 do |d|
802
                    if d["DOUBLE_ENTRY"]
803
                        ""
804
                    else
805
                        d["NIC_ID"]
806
                    end
807
                end
808

    
809
                column :NETWORK, "", :left, :size=>20 do |d|
810
                    if d["DOUBLE_ENTRY"]
811
                        ""
812
                    else
813
                        d["NETWORK"]
814
                    end
815
                end
816

    
817
                column :BRIDGE, "", :left, :size=>12 do |d|
818
                    if d["DOUBLE_ENTRY"]
819
                        ""
820
                    else
821
                        d["BRIDGE"]
822
                    end
823
                end
824

    
825
                column :IP, "",:left, :donottruncate, :size=>15 do |d|
826
                    d["IP"]
827
                end
828

    
829
                column :MAC, "", :left, :size=>17 do |d|
830
                    if d["DOUBLE_ENTRY"]
831
                        ""
832
                    else
833
                        d["MAC"]
834
                    end
835
                end
836

    
837
                column :PCI_ID, "", :left, :size=>8 do |d|
838
                    if d["DOUBLE_ENTRY"]
839
                        ""
840
                    else
841
                        d["PCI_ID"]
842
                    end
843
                end
844

    
845
            end.show(vm_nics,{})
846

    
847
            while vm.has_elements?("/VM/TEMPLATE/NIC")
848
                vm.delete_element("/VM/TEMPLATE/NIC")
849
            end if !options[:all]
850
        end
851

    
852
        while vm.has_elements?("/VM/TEMPLATE/NIC")
853
            vm.delete_element("/VM/TEMPLATE/NIC")
854
        end if !options[:all]
855

    
856
        if vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE") and !isHybrid
857
            puts
858
            CLIHelper.print_header(str_h1 % "SECURITY",false)
859
            puts
860

    
861
            CLIHelper::ShowTable.new(nil, self) do
862
                column :NIC_ID, "", :size=>6 do |d|
863
                    d["NIC_ID"]
864
                end
865

    
866
                column :NETWORK, "", :left, :size=>25 do |d|
867
                    d["NETWORK"]
868
                end
869

    
870
                column :SECURITY_GROUPS, "", :left, :size=>47 do |d|
871
                    d["SECURITY_GROUPS"]
872
                end
873
            end.show(sg_nics,{})
874

    
875
            puts
876

    
877
            CLIHelper.print_header(str_h1 % "SECURITY GROUP   TYPE     PROTOCOL NETWORK                       RANGE          ",false)
878

    
879
            CLIHelper::ShowTable.new(nil, self) do
880
                column :ID, "", :size=>4 do |d|
881
                    d["SECURITY_GROUP_ID"]
882
                end
883

    
884
                column :NAME, "", :left, :size=>11 do |d|
885
                    d["SECURITY_GROUP_NAME"]
886
                end
887

    
888
                column :" ", "", :left, :size=>8 do |d|
889
                    d["RULE_TYPE"]
890
                end
891

    
892
                column :"  ", "", :left, :size=>8 do |d|
893
                    protocol = d["PROTOCOL"]
894

    
895
                    if(protocol.upcase == "ICMP")
896
                        icmp = d["ICMP_TYPE"].nil? ? "" : "-#{d["ICMP_TYPE"]}"
897
                        protocol += icmp
898
                    end
899

    
900
                    protocol
901
                end
902

    
903
                column :VNET, "", :size=>4 do |d|
904
                    d["NETWORK_ID"]
905
                end
906

    
907
                column :START, "", :left, :donottruncate, :size=>17 do |d|
908
                    network = ""
909

    
910
                    if(!d["IP"].nil? && d["IP"] != "")
911
                        network = d["IP"]
912
                    elsif(!d["MAC"].nil? && d["MAC"] != "")
913
                        network = d["MAC"]
914
                    end
915

    
916
                    network
917
                end
918

    
919
                column :SIZE, "", :left, :donottruncate, :size=>6 do |d|
920
                    d["SIZE"]
921
                end
922

    
923
                column :"   ", "", :left, :donottruncate, :size=>15 do |d|
924
                    d["RANGE"]
925
                end
926

    
927
            end.show([vm_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
928

    
929
            while vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE")
930
                vm.delete_element("/VM/TEMPLATE/SECURITY_GROUP_RULE")
931
            end if !options[:all]
932
        end
933

    
934
        if vm.has_elements?("/VM/TEMPLATE/SNAPSHOT")
935
            puts
936
            CLIHelper.print_header(str_h1 % "SNAPSHOTS",false)
937

    
938
            CLIHelper::ShowTable.new(nil, self) do
939

    
940
                column :"ID", "", :size=>4 do |d|
941
                    d["SNAPSHOT_ID"] if !d.nil?
942
                end
943

    
944
                column :"TIME", "", :size=>12 do |d|
945
                    OpenNebulaHelper.time_to_str(d["TIME"], false) if !d.nil?
946
                end
947

    
948
                column :"NAME", "", :left, :size=>46 do |d|
949
                    d["NAME"] if !d.nil?
950
                end
951

    
952
                column :"HYPERVISOR_ID", "", :left, :size=>15 do |d|
953
                    d["HYPERVISOR_ID"] if !d.nil?
954
                end
955

    
956
            end.show([vm_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
957

    
958
            vm.delete_element("/VM/TEMPLATE/SNAPSHOT")
959
        end
960

    
961
        if vm.has_elements?("/VM/HISTORY_RECORDS")
962
            puts
963

    
964
            CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE HISTORY",false)
965
            format_history(vm)
966
        end
967

    
968
        if vm.has_elements?("/VM/USER_TEMPLATE/SCHED_ACTION")
969
            puts
970
            CLIHelper.print_header(str_h1 % "SCHEDULED ACTIONS",false)
971

    
972
            CLIHelper::ShowTable.new(nil, self) do
973

    
974
                column :"ID", "", :size=>2 do |d|
975
                    d["ID"] if !d.nil?
976
                end
977

    
978
                column :"ACTION", "", :left, :size=>15 do |d|
979
                    d["ACTION"] if !d.nil?
980
                end
981

    
982
                column :"SCHEDULED", "", :size=>12 do |d|
983
                    OpenNebulaHelper.time_to_str(d["TIME"], false) if !d.nil?
984
                end
985

    
986
                column :"DONE", "", :size=>12 do |d|
987
                    OpenNebulaHelper.time_to_str(d["DONE"], false) if !d.nil?
988
                end
989

    
990
                column :"MESSAGE", "", :left, :donottruncate, :size=>35 do |d|
991
                    d["MESSAGE"] if !d.nil?
992
                end
993
            end.show([vm_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
994
        end
995

    
996
        if vm.has_elements?("/VM/USER_TEMPLATE")
997
            puts
998

    
999
            if !options[:all]
1000
                vm.delete_element("/VM/USER_TEMPLATE/SCHED_ACTION")
1001
            end
1002

    
1003
            CLIHelper.print_header(str_h1 % "USER TEMPLATE",false)
1004
            puts vm.template_like_str('USER_TEMPLATE')
1005
        end
1006

    
1007
        puts
1008
        CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE TEMPLATE",false)
1009
        puts vm.template_str
1010
    end
1011

    
1012
    def format_history(vm)
1013
        table=CLIHelper::ShowTable.new(nil, self) do
1014
            column :SEQ, "Sequence number", :size=>3 do |d|
1015
                d["SEQ"]
1016
            end
1017

    
1018
            column :UID, "UID of the user that performed the action",
1019
                :left, :size=>4 do |d|
1020
                if d["UID"] != "-1"
1021
                    d["UID"]
1022
                else
1023
                    "-"
1024
                end
1025
            end
1026

    
1027
            column :REQ, "Request ID of the action", :left, :size=>5 do |d|
1028
                if d["REQUEST_ID"] != "-1"
1029
                    d["REQUEST_ID"]
1030
                else
1031
                    "-"
1032
                end
1033
            end
1034

    
1035
            column :HOST, "Host name of the VM container", :left, :size=>12 do |d|
1036
                d["HOSTNAME"]
1037
            end
1038

    
1039
            column :"ACTION", "VM state change action", :left, :size=>10 do |d|
1040
                VirtualMachine.get_history_action d["ACTION"]
1041
            end
1042

    
1043
            column :DS, "System Datastore", :size=>4 do |d|
1044
                d["DS_ID"]
1045
            end
1046

    
1047
            column :START, "Time when the state changed", :size=>15 do |d|
1048
                OpenNebulaHelper.time_to_str(d['STIME'])
1049
            end
1050

    
1051
            column :TIME, "Total time in this state", :size=>11 do |d|
1052
                stime = d["STIME"].to_i
1053
                etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
1054
                dtime = etime-stime
1055
                OpenNebulaHelper.period_to_str(dtime, false)
1056
            end
1057

    
1058
            column :PROLOG, "Prolog time for this state", :size=>10 do |d|
1059
                stime = d["PSTIME"].to_i
1060
                if d["PSTIME"]=="0"
1061
                    etime=0
1062
                else
1063
                    etime = d["PETIME"]=="0" ? Time.now.to_i: d["PETIME"].to_i
1064
                end
1065
                dtime = etime-stime
1066
                OpenNebulaHelper.short_period_to_str(dtime)
1067
            end
1068

    
1069
            default :SEQ, :UID, :REQ, :HOST, :ACTION, :DS, :START, :TIME, :PROLOG
1070
        end
1071

    
1072
        vm_hash=vm.to_hash
1073

    
1074
        history=[vm_hash['VM']['HISTORY_RECORDS']['HISTORY']].flatten
1075

    
1076
        table.show(history)
1077
    end
1078

    
1079
    def format_snapshots(vm)
1080
        table=CLIHelper::ShowTable.new(nil, self) do
1081
            column :AC , "Is active", :left, :size => 2 do |d|
1082
                if d["ACTIVE"] == "YES"
1083
                    "=>"
1084
                else
1085
                    ""
1086
                end
1087
            end
1088
            column :ID, "Snapshot ID", :size=>3 do |d|
1089
                d["ID"]
1090
            end
1091

    
1092
            column :DISK, "Disk ID", :size=>4 do |d|
1093
                d["DISK_ID"]
1094
            end
1095

    
1096
            column :PARENT, "Snapshot Parent ID", :size=>6 do |d|
1097
                d["PARENT"]
1098
            end
1099

    
1100
            column :CHILDREN, "Snapshot Children IDs", :size=>10 do |d|
1101
                d["CHILDREN"]
1102
            end
1103

    
1104
            column :SIZE, "", :left, :size=>12 do |d|
1105
                if d["SIZE"]
1106
                    size = OpenNebulaHelper.unit_to_str(
1107
                                d['SIZE'].to_i,
1108
                                {},
1109
                                "M"
1110
                            )
1111
                else
1112
                    size = "-"
1113
                end
1114

    
1115
                if d["MONITOR_SIZE"]
1116
                    monitor_size = OpenNebulaHelper.unit_to_str(
1117
                                d['MONITOR_SIZE'].to_i,
1118
                                {},
1119
                                "M"
1120
                            )
1121
                else
1122
                    monitor_size = "-"
1123
                end
1124

    
1125
                "#{monitor_size}/#{size}"
1126
            end
1127

    
1128
            column :NAME, "Snapshot Name", :left, :size=>32 do |d|
1129
                d["NAME"]
1130
            end
1131

    
1132
            column :DATE, "Snapshot creation date", :size=>15 do |d|
1133
                OpenNebulaHelper.time_to_str(d["DATE"])
1134
            end
1135

    
1136
            default :AC, :ID, :DISK, :PARENT, :DATE, :SIZE, :NAME
1137
        end
1138

    
1139
        # Convert snapshot data to an array
1140
        vm_hash = vm.to_hash
1141
        vm_snapshots = [vm_hash['VM']['SNAPSHOTS']].flatten
1142

    
1143
        snapshots = []
1144

    
1145
        vm_snapshots.each do |disk|
1146
            disk_id = disk['DISK_ID']
1147

    
1148
            sshots = [disk['SNAPSHOT']].flatten
1149
            sshots.each do |snapshot|
1150
                data = snapshot.merge({ 'DISK_ID' => disk_id })
1151
                snapshots << data
1152
            end
1153
        end
1154

    
1155
        # get monitoring data
1156
        snapshots.each do |snapshot|
1157
            disk_id = snapshot["DISK_ID"]
1158
            snap_id = snapshot["ID"]
1159
            xpath = "MONITORING/SNAPSHOT_SIZE[ID='#{snap_id}' and DISK_ID='#{disk_id}']/SIZE"
1160
            snapshot["MONITOR_SIZE"] = vm[xpath]
1161
        end
1162

    
1163
        table.show(snapshots)
1164
    end
1165
end