Statistics
| Branch: | Tag: | Revision:

one / src / cli / one_helper / onevm_helper.rb @ 809fa79a

History | View | Annotate | Download (33 KB)

1
# -------------------------------------------------------------------------- #
2
# Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs        #
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
EXTERNAL_IP_ATTRS = [
49
    'GUEST_IP',
50
    'AWS_IP_ADDRESS',
51
    'AZ_IPADDRESS',
52
    'SL_PRIMARYIPADDRESS'
53
];
54

    
55

    
56
class OneVMHelper < OpenNebulaHelper::OneHelper
57
    MULTIPLE={
58
        :name  => "multiple",
59
        :short => "-m x",
60
        :large => "--multiple x",
61
        :format => Integer,
62
        :description => "Instance multiple VMs"
63
    }
64

    
65
    IMAGE = {
66
        :name   => "image",
67
        :short  => "-i id|name",
68
        :large  => "--image id|name" ,
69
        :description => "Selects the image",
70
        :format => String,
71
        :proc   => lambda { |o, options|
72
            OpenNebulaHelper.rname_to_id(o, "IMAGE")
73
        }
74
    }
75

    
76
    NETWORK = {
77
        :name   => "network",
78
        :short  => "-n id|name",
79
        :large  => "--network id|name" ,
80
        :description => "Selects the virtual network",
81
        :format => String,
82
        :proc   => lambda { |o, options|
83
            OpenNebulaHelper.rname_to_id(o, "VNET")
84
        }
85
    }
86

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

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

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

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

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

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

    
134
    RECREATE = {
135
        :name       => "recreate",
136
        :large      => "--recreate",
137
        :description=> "Resubmits a fresh VM"
138
    }
139

    
140
    def self.rname
141
        "VM"
142
    end
143

    
144
    def self.conf_file
145
        "onevm.yaml"
146
    end
147

    
148
    def self.state_to_str(id, lcm_id)
149
        id = id.to_i
150
        state_str = VirtualMachine::VM_STATE[id]
151
        short_state_str = VirtualMachine::SHORT_VM_STATES[state_str]
152

    
153
        if short_state_str=="actv"
154
            lcm_id = lcm_id.to_i
155
            lcm_state_str = VirtualMachine::LCM_STATE[lcm_id]
156
            return VirtualMachine::SHORT_LCM_STATES[lcm_state_str]
157
        end
158

    
159
        return short_state_str
160
    end
161

    
162
    # Return the IP or several IPs of a VM
163
    def self.ip_str(vm)
164
        ips = []
165

    
166
        vm_nics = []
167

    
168
        if !vm["TEMPLATE"]["NIC"].nil?
169
            vm_nics = [vm["TEMPLATE"]['NIC']].flatten
170
        end
171

    
172
        vm_nics.each do |nic|
173
            if nic.has_key?("IP")
174
                ips.push(nic["IP"])
175
            end
176

    
177
            if nic.has_key?("IP6_GLOBAL")
178
                ips.push(nic["IP6_GLOBAL"])
179
            end
180

    
181
            if nic.has_key?("IP6_ULA")
182
                ips.push(nic["IP6_ULA"])
183
            end
184
        end
185

    
186
        VirtualMachine::EXTERNAL_IP_ATTRS.each do |attr|
187
            external_ip = vm["MONITORING"][attr]
188

    
189
            if !external_ip.nil? && !ips.include?(external_ip)
190
                ips.push(external_ip)
191
            end
192
        end
193

    
194
        if ips.empty?
195
            return "--"
196
        else
197
            return ips.join(",")
198
        end
199
    end
200

    
201
    def format_pool(options)
202
        config_file = self.class.table_conf
203

    
204
        # Get cluster names to use later in list
205
        cluster_pool = OpenNebula::ClusterPool.new(@client)
206
        rc = cluster_pool.info
207

    
208
        cluster_names = {}
209
        cluster_names["-1"] = "default"
210

    
211
        if !OpenNebula.is_error?(rc)
212
            cluster_pool.each do |c|
213
                cluster_names[c["ID"]] = c["NAME"]
214
            end
215
        end
216

    
217
        table = CLIHelper::ShowTable.new(config_file, self) do
218
            column :ID, "ONE identifier for Virtual Machine", :size=>6 do |d|
219
                d["ID"]
220
            end
221

    
222
            column :NAME, "Name of the Virtual Machine", :left,
223
                    :size=>15 do |d|
224
                if d["RESCHED"] == "1"
225
                    "*#{d["NAME"]}"
226
                else
227
                    d["NAME"]
228
                end
229
            end
230

    
231
            column :USER, "Username of the Virtual Machine owner", :left,
232
                    :size=>8 do |d|
233
                helper.user_name(d, options)
234
            end
235

    
236
            column :GROUP, "Group of the Virtual Machine", :left,
237
                    :size=>8 do |d|
238
                helper.group_name(d, options)
239
            end
240

    
241
            column :STAT, "Actual status", :size=>4 do |d,e|
242
                OneVMHelper.state_to_str(d["STATE"], d["LCM_STATE"])
243
            end
244

    
245
            column :UCPU, "CPU percentage used by the VM", :size=>4 do |d|
246
                d["CPU"]
247
            end
248

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

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

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

    
269
                    if !cluster
270
                        cluster_id
271
                    else
272
                        cluster
273
                    end
274
                else
275
                    "NONE"
276
                end
277
            end
278

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

    
286
            column :IP, "VM IP addresses", :left, :donottruncate, :size=>15 do |d|
287
                OneVMHelper.ip_str(d)
288
            end
289

    
290
            default :ID, :USER, :GROUP, :NAME, :STAT, :UCPU, :UMEM, :HOST,
291
                :TIME
292
        end
293

    
294
        table
295
    end
296

    
297

    
298
    def schedule_actions(ids,options,action)
299
        # Verbose by default
300
        options[:verbose] = true
301

    
302
        perform_actions(
303
            ids, options,
304
            "#{action} scheduled at #{options[:schedule]}") do |vm|
305

    
306
            rc = vm.info
307

    
308
            if OpenNebula.is_error?(rc)
309
                puts rc.message
310
                exit -1
311
            end
312

    
313
            ids = vm.retrieve_elements('USER_TEMPLATE/SCHED_ACTION/ID')
314

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

    
321
            tmp_str = vm.user_template_str
322

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

    
325
            vm.update(tmp_str)
326
        end
327
    end
328

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

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

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

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

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

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

    
374
        seq = vm['/VM/HISTORY_RECORDS/HISTORY[last()]/SEQ']
375

    
376
        tm_action = RECOVER_RETRY_STEPS[vm.lcm_state_str.to_sym]
377

    
378
        tm_file = "#{VMS_LOCATION}/#{vm.id}/transfer.#{seq}.#{tm_action}"
379

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

    
385
        @tm_action_list = File.read(tm_file)
386

    
387
        puts "TM Debug Interactive Environment.".green
388
        puts
389
        print_tm_action_list
390

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

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

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

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

    
415
                    puts
416

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

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

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

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

    
456
    private
457

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

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

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

    
475
        cluster = nil
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

    
518
        puts
519

    
520
        CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE MONITORING",false)
521

    
522
        vm_monitoring = vm.to_hash['VM']['MONITORING']
523

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

    
532
        order_attrs  = %w(CPU MEMORY NETTX NETRX)
533

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

    
541
        vm_monitoring_sort.sort{|a,b| a[0]<=>b[0]}
542

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

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

    
560
        puts
561

    
562
        CLIHelper.print_header(str_h1 % "PERMISSIONS",false)
563

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

    
570
            puts str % [e,  mask]
571
        }
572

    
573
        vm_disks = []
574

    
575
        if vm.has_elements?("/VM/TEMPLATE/DISK")
576
            vm_disks = [vm.to_hash['VM']['TEMPLATE']['DISK']].flatten
577
        end
578

    
579
        if vm.has_elements?("/VM/TEMPLATE/CONTEXT")
580
            context_disk = vm.to_hash['VM']['TEMPLATE']['CONTEXT']
581

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

    
590
            vm_disks.push(context_disk)
591
        end
592

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

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

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

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

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

    
628
                        end
629
                    end
630
                end
631

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

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

    
653
                    "#{monitor_size}/#{size}"
654
                end
655

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

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

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

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

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

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

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

    
687
        sg_nics = []
688

    
689
        if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS"))
690
            sg_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten
691

    
692
            sg_nics.each do |nic|
693
                sg = nic["SECURITY_GROUPS"]
694

    
695
                if sg.nil?
696
                    next
697
                end
698
            end
699
        end
700

    
701
        if vm.has_elements?("/VM/TEMPLATE/NIC") and !isHybrid
702
            puts
703
            CLIHelper.print_header(str_h1 % "VM NICS",false)
704

    
705
            nic_default = {"NETWORK" => "-",
706
                           "IP" => "-",
707
                           "MAC"=> "-",
708
                           "VLAN"=>"no",
709
                           "BRIDGE"=>"-"}
710

    
711
            array_id = 0
712
            vm_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten
713
            vm_nics.each {|nic|
714

    
715
                next if nic.has_key?("CLI_DONE")
716

    
717
                if nic.has_key?("IP6_LINK")
718
                    ip6_link = {"IP"           => nic.delete("IP6_LINK"),
719
                                "CLI_DONE"     => true,
720
                                "DOUBLE_ENTRY" => true}
721
                    vm_nics.insert(array_id+1,ip6_link)
722

    
723
                    array_id += 1
724
                end
725

    
726
                if nic.has_key?("IP6_ULA")
727
                    ip6_link = {"IP"           => nic.delete("IP6_ULA"),
728
                                "CLI_DONE"     => true,
729
                                "DOUBLE_ENTRY" => true}
730
                    vm_nics.insert(array_id+1,ip6_link)
731

    
732
                    array_id += 1
733
                end
734

    
735
                if nic.has_key?("IP6_GLOBAL")
736
                    ip6_link = {"IP"           => nic.delete("IP6_GLOBAL"),
737
                                "CLI_DONE"     => true,
738
                                "DOUBLE_ENTRY" => true}
739
                    vm_nics.insert(array_id+1,ip6_link)
740

    
741
                    array_id += 1
742
                end
743

    
744
                nic.merge!(nic_default) {|k,v1,v2| v1}
745
                array_id += 1
746
            }
747

    
748
            CLIHelper::ShowTable.new(nil, self) do
749
                column :ID, "", :size=>3 do |d|
750
                    if d["DOUBLE_ENTRY"]
751
                        ""
752
                    else
753
                        d["NIC_ID"]
754
                    end
755
                end
756

    
757
                column :NETWORK, "", :left, :size=>20 do |d|
758
                    if d["DOUBLE_ENTRY"]
759
                        ""
760
                    else
761
                        d["NETWORK"]
762
                    end
763
                end
764

    
765
                column :VLAN, "", :size=>4 do |d|
766
                    if d["DOUBLE_ENTRY"]
767
                        ""
768
                    else
769
                        d["VLAN"].downcase
770
                    end
771
                end
772

    
773
                column :BRIDGE, "", :left, :size=>12 do |d|
774
                    if d["DOUBLE_ENTRY"]
775
                        ""
776
                    else
777
                        d["BRIDGE"]
778
                    end
779
                end
780

    
781
                column :IP, "",:left, :donottruncate, :size=>15 do |d|
782
                    d["IP"]
783
                end
784

    
785
                column :MAC, "", :left, :size=>17 do |d|
786
                    if d["DOUBLE_ENTRY"]
787
                        ""
788
                    else
789
                        d["MAC"]
790
                    end
791
                end
792

    
793
            end.show(vm_nics,{})
794

    
795
            while vm.has_elements?("/VM/TEMPLATE/NIC")
796
                vm.delete_element("/VM/TEMPLATE/NIC")
797
            end if !options[:all]
798
        end
799

    
800
        while vm.has_elements?("/VM/TEMPLATE/NIC")
801
            vm.delete_element("/VM/TEMPLATE/NIC")
802
        end if !options[:all]
803

    
804
        if vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE") and !isHybrid
805
            puts
806
            CLIHelper.print_header(str_h1 % "SECURITY",false)
807
            puts
808

    
809
            CLIHelper::ShowTable.new(nil, self) do
810
                column :NIC_ID, "", :size=>6 do |d|
811
                    d["NIC_ID"]
812
                end
813

    
814
                column :NETWORK, "", :left, :size=>25 do |d|
815
                    d["NETWORK"]
816
                end
817

    
818
                column :SECURITY_GROUPS, "", :left, :size=>47 do |d|
819
                    d["SECURITY_GROUPS"]
820
                end
821
            end.show(sg_nics,{})
822

    
823
            puts
824

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

    
827
            CLIHelper::ShowTable.new(nil, self) do
828
                column :ID, "", :size=>4 do |d|
829
                    d["SECURITY_GROUP_ID"]
830
                end
831

    
832
                column :NAME, "", :left, :size=>11 do |d|
833
                    d["SECURITY_GROUP_NAME"]
834
                end
835

    
836
                column :" ", "", :left, :size=>8 do |d|
837
                    d["RULE_TYPE"]
838
                end
839

    
840
                column :"  ", "", :left, :size=>8 do |d|
841
                    protocol = d["PROTOCOL"]
842

    
843
                    if(protocol.upcase == "ICMP")
844
                        icmp = d["ICMP_TYPE"].nil? ? "" : "-#{d["ICMP_TYPE"]}"
845
                        protocol += icmp
846
                    end
847

    
848
                    protocol
849
                end
850

    
851
                column :VNET, "", :size=>4 do |d|
852
                    d["NETWORK_ID"]
853
                end
854

    
855
                column :START, "", :left, :donottruncate, :size=>17 do |d|
856
                    network = ""
857

    
858
                    if(!d["IP"].nil? && d["IP"] != "")
859
                        network = d["IP"]
860
                    elsif(!d["MAC"].nil? && d["MAC"] != "")
861
                        network = d["MAC"]
862
                    end
863

    
864
                    network
865
                end
866

    
867
                column :SIZE, "", :left, :donottruncate, :size=>6 do |d|
868
                    d["SIZE"]
869
                end
870

    
871
                column :"   ", "", :left, :donottruncate, :size=>15 do |d|
872
                    d["RANGE"]
873
                end
874

    
875
            end.show([vm.to_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
876

    
877
            while vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE")
878
                vm.delete_element("/VM/TEMPLATE/SECURITY_GROUP_RULE")
879
            end if !options[:all]
880
        end
881

    
882
        if vm.has_elements?("/VM/TEMPLATE/SNAPSHOT")
883
            puts
884
            CLIHelper.print_header(str_h1 % "SNAPSHOTS",false)
885

    
886
            CLIHelper::ShowTable.new(nil, self) do
887

    
888
                column :"ID", "", :size=>4 do |d|
889
                    d["SNAPSHOT_ID"] if !d.nil?
890
                end
891

    
892
                column :"TIME", "", :size=>12 do |d|
893
                    OpenNebulaHelper.time_to_str(d["TIME"], false) if !d.nil?
894
                end
895

    
896
                column :"NAME", "", :left, :size=>46 do |d|
897
                    d["NAME"] if !d.nil?
898
                end
899

    
900
                column :"HYPERVISOR_ID", "", :left, :size=>15 do |d|
901
                    d["HYPERVISOR_ID"] if !d.nil?
902
                end
903

    
904
            end.show([vm.to_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
905

    
906
            vm.delete_element("/VM/TEMPLATE/SNAPSHOT")
907
        end
908

    
909
        if vm.has_elements?("/VM/HISTORY_RECORDS")
910
            puts
911

    
912
            CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE HISTORY",false)
913
            format_history(vm)
914
        end
915

    
916
        if vm.has_elements?("/VM/USER_TEMPLATE/SCHED_ACTION")
917
            puts
918
            CLIHelper.print_header(str_h1 % "SCHEDULED ACTIONS",false)
919

    
920
            CLIHelper::ShowTable.new(nil, self) do
921

    
922
                column :"ID", "", :size=>2 do |d|
923
                    d["ID"] if !d.nil?
924
                end
925

    
926
                column :"ACTION", "", :left, :size=>15 do |d|
927
                    d["ACTION"] if !d.nil?
928
                end
929

    
930
                column :"SCHEDULED", "", :size=>12 do |d|
931
                    OpenNebulaHelper.time_to_str(d["TIME"], false) if !d.nil?
932
                end
933

    
934
                column :"DONE", "", :size=>12 do |d|
935
                    OpenNebulaHelper.time_to_str(d["DONE"], false) if !d.nil?
936
                end
937

    
938
                column :"MESSAGE", "", :left, :donottruncate, :size=>35 do |d|
939
                    d["MESSAGE"] if !d.nil?
940
                end
941
            end.show([vm.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
942
        end
943

    
944
        if vm.has_elements?("/VM/USER_TEMPLATE")
945
            puts
946

    
947
            if !options[:all]
948
                vm.delete_element("/VM/USER_TEMPLATE/SCHED_ACTION")
949
            end
950

    
951
            CLIHelper.print_header(str_h1 % "USER TEMPLATE",false)
952
            puts vm.template_like_str('USER_TEMPLATE')
953
        end
954

    
955
        puts
956
        CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE TEMPLATE",false)
957
        puts vm.template_str
958
    end
959

    
960
    def format_history(vm)
961
        table=CLIHelper::ShowTable.new(nil, self) do
962
            column :SEQ, "Sequence number", :size=>3 do |d|
963
                d["SEQ"]
964
            end
965

    
966
            column :HOST, "Host name of the VM container", :left, :size=>15 do |d|
967
                d["HOSTNAME"]
968
            end
969

    
970
            column :"ACTION", "VM state change action", :left, :size=>16 do |d|
971
                VirtualMachine.get_history_action d["ACTION"]
972
            end
973

    
974
            column :REASON, "VM state change reason", :left, :size=>4 do |d|
975
                VirtualMachine.get_reason d["REASON"]
976
            end
977

    
978
            column :DS, "System Datastore", :size=>4 do |d|
979
                d["DS_ID"]
980
            end
981

    
982
            column :START, "Time when the state changed", :size=>15 do |d|
983
                OpenNebulaHelper.time_to_str(d['STIME'])
984
            end
985

    
986
            column :TIME, "Total time in this state", :size=>11 do |d|
987
                stime = d["STIME"].to_i
988
                etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
989
                dtime = etime-stime
990
                OpenNebulaHelper.period_to_str(dtime, false)
991
            end
992

    
993
            column :PROLOG, "Prolog time for this state", :size=>10 do |d|
994
                stime = d["PSTIME"].to_i
995
                if d["PSTIME"]=="0"
996
                    etime=0
997
                else
998
                    etime = d["PETIME"]=="0" ? Time.now.to_i: d["PETIME"].to_i
999
                end
1000
                dtime = etime-stime
1001
                OpenNebulaHelper.short_period_to_str(dtime)
1002
            end
1003

    
1004
            default :SEQ, :HOST, :ACTION, :DS, :START, :TIME, :PROLOG
1005
        end
1006

    
1007
        vm_hash=vm.to_hash
1008

    
1009
        history=[vm_hash['VM']['HISTORY_RECORDS']['HISTORY']].flatten
1010

    
1011
        table.show(history)
1012
    end
1013

    
1014
    def format_snapshots(vm)
1015
        table=CLIHelper::ShowTable.new(nil, self) do
1016
            column :AC , "Is active", :left, :size => 2 do |d|
1017
                if d["ACTIVE"] == "YES"
1018
                    "=>"
1019
                else
1020
                    ""
1021
                end
1022
            end
1023
            column :ID, "Snapshot ID", :size=>3 do |d|
1024
                d["ID"]
1025
            end
1026

    
1027
            column :DISK, "Disk ID", :size=>4 do |d|
1028
                d["DISK_ID"]
1029
            end
1030

    
1031
            column :PARENT, "Snapshot Parent ID", :size=>6 do |d|
1032
                d["PARENT"]
1033
            end
1034

    
1035
            column :CHILDREN, "Snapshot Children IDs", :size=>10 do |d|
1036
                d["CHILDREN"]
1037
            end
1038

    
1039
            column :SIZE, "", :left, :size=>12 do |d|
1040
                if d["SIZE"]
1041
                    size = OpenNebulaHelper.unit_to_str(
1042
                                d['SIZE'].to_i,
1043
                                {},
1044
                                "M"
1045
                            )
1046
                else
1047
                    size = "-"
1048
                end
1049

    
1050
                if d["MONITOR_SIZE"]
1051
                    monitor_size = OpenNebulaHelper.unit_to_str(
1052
                                d['MONITOR_SIZE'].to_i,
1053
                                {},
1054
                                "M"
1055
                            )
1056
                else
1057
                    monitor_size = "-"
1058
                end
1059

    
1060
                "#{monitor_size}/#{size}"
1061
            end
1062

    
1063
            column :NAME, "Snapshot Name", :left, :size=>32 do |d|
1064
                d["NAME"]
1065
            end
1066

    
1067
            column :DATE, "Snapshot creation date", :size=>15 do |d|
1068
                OpenNebulaHelper.time_to_str(d["DATE"])
1069
            end
1070

    
1071
            default :AC, :ID, :DISK, :PARENT, :DATE, :SIZE, :NAME
1072
        end
1073

    
1074
        # Convert snapshot data to an array
1075
        vm_hash = vm.to_hash
1076
        vm_snapshots = [vm_hash['VM']['SNAPSHOTS']].flatten
1077

    
1078
        snapshots = []
1079

    
1080
        vm_snapshots.each do |disk|
1081
            disk_id = disk['DISK_ID']
1082

    
1083
            sshots = [disk['SNAPSHOT']].flatten
1084
            sshots.each do |snapshot|
1085
                data = snapshot.merge({ 'DISK_ID' => disk_id })
1086
                snapshots << data
1087
            end
1088
        end
1089

    
1090
        # get monitoring data
1091
        snapshots.each do |snapshot|
1092
            disk_id = snapshot["DISK_ID"]
1093
            snap_id = snapshot["ID"]
1094
            xpath = "MONITORING/SNAPSHOT_SIZE[ID='#{snap_id}' and DISK_ID='#{disk_id}']/SIZE"
1095
            snapshot["MONITOR_SIZE"] = vm[xpath]
1096
        end
1097

    
1098
        table.show(snapshots)
1099
    end
1100
end