opennebula-cli 6.6.2 → 6.7.80.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/one_helper.rb CHANGED
@@ -17,44 +17,50 @@
17
17
  require 'cli_helper'
18
18
  require 'open3'
19
19
  require 'io/console'
20
+ require 'time'
21
+ require 'io/wait'
20
22
 
21
23
  begin
22
24
  require 'opennebula'
23
25
  rescue Exception => e
24
- puts "Error: "+e.message.to_s
26
+ puts 'Error: '+e.message.to_s
25
27
  exit(-1)
26
28
  end
27
29
 
28
30
  include OpenNebula
29
31
 
30
32
  module OpenNebulaHelper
31
- ONE_VERSION=<<-EOT
32
- OpenNebula #{OpenNebula::VERSION}
33
- Copyright 2002-2023, OpenNebula Project, OpenNebula Systems
34
- EOT
33
+
34
+ ONE_VERSION=<<~EOT
35
+ OpenNebula #{OpenNebula::VERSION}
36
+ Copyright 2002-2023, OpenNebula Project, OpenNebula Systems
37
+ EOT
35
38
 
36
39
  if ONE_LOCATION
37
- TABLE_CONF_PATH = ONE_LOCATION + "/etc/cli"
38
- VAR_LOCATION = ONE_LOCATION + "/var" if !defined?(VAR_LOCATION)
39
- CLI_ADDONS_LOCATION = ONE_LOCATION + "/lib/ruby/cli/addons"
40
+ TABLE_CONF_PATH = ONE_LOCATION + '/etc/cli'
41
+ VAR_LOCATION = ONE_LOCATION + '/var' unless defined?(VAR_LOCATION)
42
+ CLI_ADDONS_LOCATION = ONE_LOCATION + '/lib/ruby/cli/addons'
40
43
  XSD_PATH = ONE_LOCATION + '/share/schemas/xsd'
41
44
  else
42
- TABLE_CONF_PATH = "/etc/one/cli"
43
- VAR_LOCATION = "/var/lib/one" if !defined?(VAR_LOCATION)
44
- CLI_ADDONS_LOCATION = "/usr/lib/one/ruby/cli/addons"
45
+ TABLE_CONF_PATH = '/etc/one/cli'
46
+ VAR_LOCATION = '/var/lib/one' unless defined?(VAR_LOCATION)
47
+ CLI_ADDONS_LOCATION = '/usr/lib/one/ruby/cli/addons'
45
48
  XSD_PATH = '/usr/share/one/schemas/xsd'
46
49
  end
47
50
 
48
51
  EDITOR_PATH='/usr/bin/vi'
49
52
 
53
+ TEMPLATE_INPUT = 'A template can be passed as a file with or the content via STDIN
54
+ Bash symbols must be escaped on STDIN passing'
55
+
50
56
  ########################################################################
51
57
  # Options
52
58
  ########################################################################
53
59
  XML={
54
- :name => "xml",
55
- :short => "-x",
56
- :large => "--xml",
57
- :description => "Show the resource in xml format"
60
+ :name => 'xml',
61
+ :short => '-x',
62
+ :large => '--xml',
63
+ :description => 'Show the resource in xml format'
58
64
  }
59
65
 
60
66
  JSON = {
@@ -75,30 +81,46 @@ EOT
75
81
  }
76
82
 
77
83
  NUMERIC={
78
- :name => "numeric",
79
- :short => "-n",
80
- :large => "--numeric",
81
- :description => "Do not translate user and group IDs"
84
+ :name => 'numeric',
85
+ :short => '-n',
86
+ :large => '--numeric',
87
+ :description => 'Do not translate user and group IDs'
82
88
  }
83
89
 
84
90
  KILOBYTES={
85
- :name => "kilobytes",
86
- :short => "-k",
87
- :large => "--kilobytes",
88
- :description => "Show units in kilobytes"
91
+ :name => 'kilobytes',
92
+ :short => '-k',
93
+ :large => '--kilobytes',
94
+ :description => 'Show units in kilobytes'
89
95
  }
90
96
 
91
97
  DESCRIBE={
92
- :name => "describe",
93
- :large => "--describe",
94
- :description => "Describe list columns"
98
+ :name => 'describe',
99
+ :large => '--describe',
100
+ :description => 'Describe list columns'
95
101
  }
96
102
 
97
103
  APPEND = {
98
- :name => "append",
99
- :short => "-a",
100
- :large => "--append",
101
- :description => "Append new attributes to the current template"
104
+ :name => 'append',
105
+ :short => '-a',
106
+ :large => '--append',
107
+ :description => 'Append new attributes to the current template'
108
+ }
109
+
110
+ FILE = {
111
+ :name => 'file',
112
+ :short => '-f file',
113
+ :large => '--file file',
114
+ :description => 'Selects the template file',
115
+ :format => String,
116
+ :proc => lambda {|o, options|
117
+ if File.file?(o)
118
+ options[:file] = o
119
+ else
120
+ STDERR.puts "File `#{options[:file]}` doesn't exist"
121
+ exit(-1)
122
+ end
123
+ }
102
124
  }
103
125
 
104
126
  # Command line VM template options
@@ -122,7 +144,7 @@ EOT
122
144
  :large => '--user name',
123
145
  :description => 'User name used to connect to OpenNebula',
124
146
  :format => String,
125
- :proc => lambda do |o, options|
147
+ :proc => lambda do |o, _options|
126
148
  OneHelper.set_user(o)
127
149
  [0, o]
128
150
  end
@@ -132,7 +154,7 @@ EOT
132
154
  :large => '--password password',
133
155
  :description => 'Password to authenticate with OpenNebula',
134
156
  :format => String,
135
- :proc => lambda do |o, options|
157
+ :proc => lambda do |o, _options|
136
158
  OneHelper.set_password(o)
137
159
  [0, o]
138
160
  end
@@ -142,7 +164,7 @@ EOT
142
164
  :large => '--endpoint endpoint',
143
165
  :description => 'URL of OpenNebula xmlrpc frontend',
144
166
  :format => String,
145
- :proc => lambda do |o, options|
167
+ :proc => lambda do |o, _options|
146
168
  OneHelper.set_endpoint(o)
147
169
  [0, o]
148
170
  end
@@ -153,7 +175,7 @@ EOT
153
175
  {
154
176
  :name => 'name',
155
177
  :large => '--name name',
156
- :short => "-n",
178
+ :short => '-n',
157
179
  :description =>
158
180
  'Name for the new group',
159
181
  :format => String
@@ -161,7 +183,7 @@ EOT
161
183
  {
162
184
  :name => 'admin_user',
163
185
  :large => '--admin_user name',
164
- :short => "-u",
186
+ :short => '-u',
165
187
  :description =>
166
188
  'Creates an admin user for the group with name',
167
189
  :format => String
@@ -169,7 +191,7 @@ EOT
169
191
  {
170
192
  :name => 'admin_password',
171
193
  :large => '--admin_password pass',
172
- :short => "-p",
194
+ :short => '-p',
173
195
  :description =>
174
196
  'Password for the admin user of the group',
175
197
  :format => String
@@ -177,7 +199,7 @@ EOT
177
199
  {
178
200
  :name => 'admin_driver',
179
201
  :large => '--admin_driver driver',
180
- :short => "-d",
202
+ :short => '-d',
181
203
  :description =>
182
204
  'Auth driver for the admin user of the group',
183
205
  :format => String
@@ -185,43 +207,43 @@ EOT
185
207
  {
186
208
  :name => 'resources',
187
209
  :large => '--resources res_str',
188
- :short => "-r",
210
+ :short => '-r',
189
211
  :description =>
190
- "Which resources can be created by group users "<<
191
- "(VM+NET+IMAGE+TEMPLATE by default)",
212
+ 'Which resources can be created by group users '<<
213
+ '(VM+NET+IMAGE+TEMPLATE by default)',
192
214
  :format => String
193
215
  }
194
216
  ]
195
217
 
196
218
  AS_USER = {
197
- :name => 'as_uid',
219
+ :name => 'as_uid',
198
220
  :large => '--as_uid uid',
199
221
  :format => Integer,
200
222
  :description => 'The User ID to instantiate the VM'
201
223
  }
202
224
 
203
225
  AS_GROUP = {
204
- :name => 'as_gid',
226
+ :name => 'as_gid',
205
227
  :large => '--as_gid gid',
206
228
  :format => Integer,
207
229
  :description => 'The Group ID to instantiate the VM'
208
230
  }
209
231
 
210
- #NOTE: Other options defined using this array, add new options at the end
232
+ # NOTE: Other options defined using this array, add new options at the end
211
233
  TEMPLATE_OPTIONS=[
212
234
  {
213
235
  :name => 'cpu',
214
236
  :large => '--cpu cpu',
215
237
  :description =>
216
238
  "CPU percentage reserved for the VM (1=100% one\n"<<
217
- " "*31<<"CPU)",
239
+ ' '*31<<'CPU)',
218
240
  :format => Float
219
241
  },
220
242
  {
221
243
  :name => 'vcpu',
222
244
  :large => '--vcpu vcpu',
223
245
  :description =>
224
- "Number of virtualized CPUs",
246
+ 'Number of virtualized CPUs',
225
247
  :format => Integer
226
248
  },
227
249
  {
@@ -236,20 +258,20 @@ EOT
236
258
  :large => '--memory memory',
237
259
  :description => 'Memory amount given to the VM. By default the '<<
238
260
  "unit is megabytes. To use gigabytes add a 'g', floats "<<
239
- "can be used: 8g=8192, 0.5g=512",
261
+ 'can be used: 8g=8192, 0.5g=512',
240
262
  :format => String,
241
- :proc => lambda do |o,options|
263
+ :proc => lambda do |o, _options|
242
264
  m=o.strip.match(/^(\d+(?:\.\d+)?)(m|mb|g|gb)?$/i)
243
265
 
244
266
  if !m
245
267
  [-1, 'Memory value malformed']
246
268
  else
247
269
  multiplier=case m[2]
248
- when /(g|gb)/i
249
- 1024
250
- else
251
- 1
252
- end
270
+ when /(g|gb)/i
271
+ 1024
272
+ else
273
+ 1
274
+ end
253
275
 
254
276
  value=m[1].to_f*multiplier
255
277
 
@@ -260,29 +282,29 @@ EOT
260
282
  {
261
283
  :name => 'disk',
262
284
  :large => '--disk image0,image1',
263
- :description => "Disks to attach. To use an image owned by"<<
264
- " other user use user[disk]. Add any additional"<<
285
+ :description => 'Disks to attach. To use an image owned by'<<
286
+ ' other user use user[disk]. Add any additional'<<
265
287
  " attributes separated by ':' and in the shape of"<<
266
- " KEY=VALUE. For example, if the disk must be"<<
267
- " resized, use image0:size=1000 . Or"<<
268
- " image0:size=1000:target=vda,image1:target=vdb",
288
+ ' KEY=VALUE. For example, if the disk must be'<<
289
+ ' resized, use image0:size=1000 . Or'<<
290
+ ' image0:size=1000:target=vda,image1:target=vdb',
269
291
  :format => Array
270
292
  },
271
293
  {
272
294
  :name => 'nic',
273
295
  :large => '--nic network0,network1',
274
- :description => "Networks to attach. To use a network owned by"<<
275
- " other user use user[network]. Additional"<<
276
- " attributes are supported like with the --disk"<<
277
- " option. Also you can use auto if you want that" <<
278
- " OpenNebula select automatically the network",
296
+ :description => 'Networks to attach. To use a network owned by'<<
297
+ ' other user use user[network]. Additional'<<
298
+ ' attributes are supported like with the --disk'<<
299
+ ' option. Also you can use auto if you want that' <<
300
+ ' OpenNebula select automatically the network',
279
301
  :format => Array
280
302
  },
281
303
  {
282
304
  :name => 'raw',
283
305
  :large => '--raw string',
284
306
  :description => "Raw string to add to the template. Not to be\n"<<
285
- " "*31<<"confused with the RAW attribute",
307
+ ' '*31<<'confused with the RAW attribute',
286
308
  :format => String
287
309
  },
288
310
  {
@@ -338,9 +360,9 @@ EOT
338
360
  :large => '--ssh [file]',
339
361
  :description => "Add an ssh public key to the context. If the \n"<<
340
362
  (' '*31) << "file is omited then the user variable \n"<<
341
- (' '*31) << "SSH_PUBLIC_KEY will be used.",
363
+ (' '*31) << 'SSH_PUBLIC_KEY will be used.',
342
364
  :format => String,
343
- :proc => lambda do |o, options|
365
+ :proc => lambda do |o, _options|
344
366
  if !o
345
367
  [0, true]
346
368
  else
@@ -393,8 +415,8 @@ EOT
393
415
  :name => 'vcenter_vm_folder',
394
416
  :large => '--vcenter_vm_folder path',
395
417
  :format => String,
396
- :description => "In a vCenter environment sets the the VMs and Template folder where the VM will be placed in." \
397
- " The path uses slashes to separate folders. For example: --vcenter_vm_folder \"/Management/VMs\""
418
+ :description => 'In a vCenter environment sets the the VMs and Template folder where the VM will be placed in.' \
419
+ ' The path uses slashes to separate folders. For example: --vcenter_vm_folder "/Management/VMs"'
398
420
  },
399
421
  {
400
422
  :name => 'user_inputs',
@@ -417,6 +439,59 @@ EOT
417
439
  options[:user_inputs] = o.join("\n")
418
440
  end
419
441
  },
442
+ {
443
+ :name => 'video',
444
+ :large => '--video type',
445
+ :format => String,
446
+ :description => 'Add a custom video device (none, vga, cirrus, virtio)'
447
+ },
448
+ {
449
+ :name => 'video_iommu',
450
+ :large => '--video-iommu',
451
+ :description => 'Enable IOMMU (I/O Memory Management Unit) for the video device'
452
+ },
453
+ {
454
+ :name => 'video_ats',
455
+ :large => '--video-ats',
456
+ :description => 'Enable ATS (Address Translation Services) for the video device'
457
+ },
458
+ {
459
+ :name => 'video_vram',
460
+ :large => '--video-vram vram',
461
+ :description => 'VRAM allocated to the video device. By default the ' +
462
+ "unit is megabytes. To use gigabytes add a 'g', floats " +
463
+ 'can be used: 8g=8192, 0.5g=512',
464
+ :format => String,
465
+ :proc => lambda do |o, _options|
466
+ m=o.strip.match(/^(\d+(?:\.\d+)?)(m|mb|g|gb)?$/i)
467
+
468
+ if !m
469
+ [-1, 'VRAM value malformed']
470
+ else
471
+ multiplier=case m[2]
472
+ when /(g|gb)/i
473
+ 1048576 # = 1024 * 1024
474
+ else
475
+ 1024
476
+ end
477
+
478
+ value=m[1].to_f*multiplier
479
+
480
+ [0, value.floor]
481
+ end
482
+ end
483
+ },
484
+ {
485
+ :name => 'video_resolution',
486
+ :large => '--video-resolution resolution',
487
+ :format => String,
488
+ :description => 'Video resolution, in format like: 1280x720 or 1920x1080',
489
+ :proc => lambda do |_o, _options|
490
+ if !m.match?(/\d{3,4}x\d{3,4}/)
491
+ [-1, 'Video Resolution value malformed']
492
+ end
493
+ end
494
+ },
420
495
  AS_GROUP,
421
496
  AS_USER
422
497
  ]
@@ -439,22 +514,90 @@ EOT
439
514
  :description => 'Get decrypted attributes'
440
515
  }
441
516
 
517
+ SCHEDULE_OPTIONS=[
518
+ SCHEDULE = {
519
+ :name => 'schedule',
520
+ :large => '--schedule TIME',
521
+ :description => 'Schedules this action to be executed after' \
522
+ 'the given time. For example: onevm resume 0 --schedule "09/23 14:15"',
523
+ :format => String,
524
+ :proc => lambda {|o, options|
525
+ if o[0] == '+'
526
+ options[:schedule] = o
527
+ elsif o == 'now'
528
+ options[:schedule] = Time.now.to_i
529
+ else
530
+ begin
531
+ options[:schedule] = Time.parse(o).to_i
532
+ rescue StandardError
533
+ STDERR.puts "Error parsing time spec: #{o}"
534
+ exit(-1)
535
+ end
536
+ end
537
+ }
538
+ },
539
+
540
+ WEEKLY = {
541
+ :name => 'weekly',
542
+ :large => '--weekly days',
543
+ :description => 'Repeats the schedule action the days of the week ' \
544
+ 'specified, it can be a number between 0 (Sunday) to 6 (Saturday) ' \
545
+ 'separated with commas. ' \
546
+ 'For example: onevm resume 0 --schedule "09/23 14:15" --weekly 0,2,4',
547
+ :format => String
548
+ },
549
+
550
+ MONTHLY = {
551
+ :name => 'monthly',
552
+ :large => '--monthly days',
553
+ :description => 'Repeats the schedule action the days of the month ' \
554
+ 'specified, it can be a number between 1,31 separated with commas. ' \
555
+ 'For example: onevm resume 0 --schedule "09/23 14:15" --monthly 1,14',
556
+ :format => String
557
+ },
558
+
559
+ YEARLY = {
560
+ :name => 'yearly',
561
+ :large => '--yearly days',
562
+ :description => 'Repeats the schedule action the days of the year ' \
563
+ 'specified, it can be a number between 0,365 separated with commas. ' \
564
+ 'For example: onevm resume 0 --schedule "09/23 14:15" --yearly 30,60',
565
+ :format => String
566
+ },
567
+
568
+ HOURLY = {
569
+ :name => 'hourly',
570
+ :large => '--hourly hour',
571
+ :description => 'Repeats the schedule action with the given hourly frequency. ' \
572
+ 'For example (every 5 hours): onevm resume 0 --schedule "09/23 14:15" --hourly 5',
573
+ :format => Numeric
574
+ },
575
+
576
+ END_TIME = {
577
+ :name => 'end',
578
+ :large => '--end number|TIME',
579
+ :description => '----',
580
+ :format => String
581
+ }
582
+ ]
583
+
442
584
  TEMPLATE_OPTIONS_VM = [TEMPLATE_NAME_VM] + TEMPLATE_OPTIONS + [DRY]
443
585
 
444
586
  CAPACITY_OPTIONS_VM = [TEMPLATE_OPTIONS[0], TEMPLATE_OPTIONS[1],
445
- TEMPLATE_OPTIONS[3]]
587
+ TEMPLATE_OPTIONS[3]]
446
588
 
447
589
  UPDATECONF_OPTIONS_VM = TEMPLATE_OPTIONS[6..15] + [TEMPLATE_OPTIONS[2],
448
- TEMPLATE_OPTIONS[17], TEMPLATE_OPTIONS[18]]
590
+ TEMPLATE_OPTIONS[17], TEMPLATE_OPTIONS[18]]
449
591
 
450
592
  FORMAT = [XML, JSON, YAML]
451
593
 
452
594
  OPTIONS = FORMAT, EXTENDED, NUMERIC, KILOBYTES
453
595
 
454
596
  class OneHelper
597
+
455
598
  attr_accessor :client
456
599
 
457
- def self.get_client(options={}, force=false)
600
+ def self.get_client(options = {}, force = false)
458
601
  if !force && defined?(@@client)
459
602
  @@client
460
603
  else
@@ -470,7 +613,7 @@ EOT
470
613
  end
471
614
 
472
615
  if user
473
- password=password||options[:password]||self.get_password
616
+ password=password||options[:password]||get_password
474
617
  secret="#{user}:#{password}"
475
618
  end
476
619
 
@@ -497,7 +640,7 @@ EOT
497
640
  if defined?(@@client)
498
641
  @@client
499
642
  else
500
- self.get_client
643
+ get_client
501
644
  end
502
645
  end
503
646
 
@@ -513,10 +656,10 @@ EOT
513
656
  @@endpoint=endpoint
514
657
  end
515
658
 
516
- if RUBY_VERSION>="1.9.3"
659
+ if RUBY_VERSION>='1.9.3'
517
660
  require 'io/console'
518
661
  def self.get_password
519
- print "Password: "
662
+ print 'Password: '
520
663
  pass=nil
521
664
  STDIN.noecho {|io| pass=io.gets }
522
665
  puts
@@ -528,25 +671,33 @@ EOT
528
671
  else
529
672
  # This function is copied from ruby net/imap.rb
530
673
  def self.get_password
531
- print "Password: "
532
- system("stty", "-echo")
674
+ print 'Password: '
675
+ system('stty', '-echo')
533
676
  begin
534
677
  @@password = STDIN.gets.chop
535
- return @@password
678
+ @@password
536
679
  ensure
537
- system("stty", "echo")
680
+ system('stty', 'echo')
538
681
  print "\n"
539
682
  end
540
683
  end
541
684
  end
542
685
 
543
- def initialize(secret=nil, endpoint=nil)
686
+ def self.list_layout_help
687
+ "The default columns and their layout can be configured in #{conf_file}"
688
+ end
689
+
690
+ def self.template_input_help(object_name)
691
+ "#{TEMPLATE_INPUT}\nWhen using a template add only one #{object_name} instance."
692
+ end
693
+
694
+ def initialize(_secret = nil, _endpoint = nil)
544
695
  @client=nil
545
696
 
546
697
  @translation_hash = nil
547
698
  end
548
699
 
549
- def set_client(options, client=nil)
700
+ def set_client(options, client = nil)
550
701
  if client.nil?
551
702
  @client=OpenNebulaHelper::OneHelper.get_client(options, true)
552
703
  else
@@ -554,15 +705,15 @@ EOT
554
705
  end
555
706
  end
556
707
 
557
- def create_resource(options, &block)
708
+ def create_resource(_options, &block)
558
709
  resource = factory
559
710
 
560
711
  rc = block.call(resource)
561
712
  if OpenNebula.is_error?(rc)
562
- return -1, rc.message
713
+ [-1, rc.message]
563
714
  else
564
- puts "ID: #{resource.id.to_s}"
565
- return 0
715
+ puts "ID: #{resource.id}"
716
+ 0
566
717
  end
567
718
  end
568
719
 
@@ -596,7 +747,7 @@ EOT
596
747
  p_w.close
597
748
  p_r.close
598
749
 
599
- return lpid
750
+ lpid
600
751
  end
601
752
 
602
753
  def stop_pager(lpid)
@@ -605,7 +756,7 @@ EOT
605
756
  begin
606
757
  Process.wait(lpid)
607
758
  rescue Interrupt
608
- Process.kill("TERM", lpid)
759
+ Process.kill('TERM', lpid)
609
760
  Process.wait(lpid)
610
761
  rescue Errno::ECHILD
611
762
  end
@@ -613,7 +764,7 @@ EOT
613
764
 
614
765
  def print_page(pool, options)
615
766
  elements = 0
616
- page = ""
767
+ page = ''
617
768
 
618
769
  if options[:xml]
619
770
  elements += 1
@@ -640,20 +791,20 @@ EOT
640
791
  end
641
792
  end
642
793
 
643
- return elements, page
794
+ [elements, page]
644
795
  end
645
796
 
646
797
  #-----------------------------------------------------------------------
647
798
  # List the pool in table form, it uses pagination for interactive
648
799
  # output
649
800
  #-----------------------------------------------------------------------
650
- def list_pool_table(table, pool, options, filter_flag)
651
- if $stdout.isatty and (!options.key?:no_pager)
801
+ def list_pool_table(table, pool, options, _filter_flag)
802
+ if $stdout.isatty and (!options.key? :no_pager)
652
803
  size = $stdout.winsize[0] - 1
653
804
 
654
805
  # ----------- First page, check if pager is needed -------------
655
806
  rc = pool.get_page(size, 0, false, options[:state])
656
- ps = ""
807
+ ps = ''
657
808
 
658
809
  return -1, rc.message if OpenNebula.is_error?(rc)
659
810
 
@@ -719,21 +870,21 @@ EOT
719
870
  table.show(hash, options)
720
871
  end
721
872
 
722
- return 0
873
+ 0
723
874
  end
724
875
 
725
876
  #-----------------------------------------------------------------------
726
877
  # List pool in XML format, pagination is used in interactive output
727
878
  #-----------------------------------------------------------------------
728
- def list_pool_xml(pool, options, filter_flag)
879
+ def list_pool_xml(pool, options, _filter_flag)
729
880
  extended = options.include?(:extended) && options[:extended]
730
881
 
731
- if $stdout.isatty and (!options.key?:no_pager)
882
+ if $stdout.isatty and (!options.key? :no_pager)
732
883
  size = $stdout.winsize[0] - 1
733
884
 
734
885
  # ----------- First page, check if pager is needed -------------
735
886
  rc = pool.get_page(size, 0, extended, options[:state])
736
- ps = ""
887
+ ps = ''
737
888
 
738
889
  return -1, rc.message if OpenNebula.is_error?(rc)
739
890
 
@@ -789,7 +940,7 @@ EOT
789
940
 
790
941
  stop_pager(ppid)
791
942
  else
792
- if pool.pool_name == "VM_POOL" && extended
943
+ if pool.pool_name == 'VM_POOL' && extended
793
944
  rc = pool.info_all_extended
794
945
  else
795
946
  rc = pool.info
@@ -800,21 +951,21 @@ EOT
800
951
  puts pool.to_xml(true)
801
952
  end
802
953
 
803
- return 0
954
+ 0
804
955
  end
805
956
 
806
957
  #-----------------------------------------------------------------------
807
958
  # List pool in JSON format, pagination is used in interactive output
808
959
  #-----------------------------------------------------------------------
809
- def list_pool_format(pool, options, filter_flag)
960
+ def list_pool_format(pool, options, _filter_flag)
810
961
  extended = options.include?(:extended) && options[:extended]
811
962
 
812
- if $stdout.isatty and (!options.key?:no_pager)
963
+ if $stdout.isatty and (!options.key? :no_pager)
813
964
  size = $stdout.winsize[0] - 1
814
965
 
815
966
  # ----------- First page, check if pager is needed -------------
816
967
  rc = pool.get_page(size, 0, extended, options[:state])
817
- ps = ""
968
+ ps = ''
818
969
 
819
970
  return -1, rc.message if OpenNebula.is_error?(rc)
820
971
 
@@ -865,7 +1016,7 @@ EOT
865
1016
 
866
1017
  stop_pager(ppid)
867
1018
  else
868
- if pool.pool_name == "VM_POOL" && extended
1019
+ if pool.pool_name == 'VM_POOL' && extended
869
1020
  rc = pool.info_all_extended
870
1021
  else
871
1022
  rc = pool.info
@@ -876,26 +1027,25 @@ EOT
876
1027
  yield(pool) if block_given?
877
1028
  end
878
1029
 
879
- return 0
1030
+ 0
880
1031
  end
881
1032
 
882
1033
  #-----------------------------------------------------------------------
883
1034
  # List pool table in top-like form
884
1035
  #-----------------------------------------------------------------------
885
1036
  def list_pool_top(table, pool, options)
886
- table.top(options) {
1037
+ table.top(options) do
887
1038
  array = pool.get_hash
888
1039
 
889
1040
  return -1, array.message if OpenNebula.is_error?(array)
890
1041
 
891
1042
  array
892
- }
1043
+ end
893
1044
 
894
- return 0
1045
+ 0
895
1046
  end
896
1047
 
897
-
898
- def list_pool(options, top=false, filter_flag=nil)
1048
+ def list_pool(options, top = false, filter_flag = nil)
899
1049
  # Capture Broken pipe
900
1050
  Signal.trap('PIPE', 'EXIT')
901
1051
 
@@ -919,19 +1069,19 @@ EOT
919
1069
  return list_pool_xml(pool, options, filter_flag)
920
1070
  elsif options[:json]
921
1071
  list_pool_format(pool, options, filter_flag) do |pool|
922
- hash = check_resource_xsd(pool, pname)
1072
+ hash = check_resource_xsd(pool, pname)
923
1073
  puts ::JSON.pretty_generate(hash)
924
1074
  end
925
1075
  elsif options[:yaml]
926
1076
  list_pool_format(pool, options, filter_flag) do |pool|
927
- hash = check_resource_xsd(pool, pname)
1077
+ hash = check_resource_xsd(pool, pname)
928
1078
  puts hash.to_yaml(:indent => 4)
929
1079
  end
930
1080
  else
931
1081
  return list_pool_table(table, pool, options, filter_flag)
932
1082
  end
933
1083
 
934
- return 0
1084
+ 0
935
1085
  rescue SystemExit, Interrupt
936
1086
  # Rescue ctrl + c when paginated
937
1087
  0
@@ -972,21 +1122,21 @@ EOT
972
1122
  return -1, rc.message if OpenNebula.is_error?(rc)
973
1123
 
974
1124
  if options[:xml]
975
- return 0, resource.to_xml(true)
1125
+ [0, resource.to_xml(true)]
976
1126
  elsif options[:json]
977
1127
  # If body is set, the resource contains a JSON inside
978
1128
  if options[:body]
979
- return 0, check_resource_xsd(resource)
1129
+ [0, check_resource_xsd(resource)]
980
1130
  else
981
- return 0, ::JSON.pretty_generate(
1131
+ [0, ::JSON.pretty_generate(
982
1132
  check_resource_xsd(resource)
983
- )
1133
+ )]
984
1134
  end
985
1135
  elsif options[:yaml]
986
- return 0, check_resource_xsd(resource).to_yaml(:indent => 4)
1136
+ [0, check_resource_xsd(resource).to_yaml(:indent => 4)]
987
1137
  else
988
1138
  format_resource(resource, options)
989
- return 0
1139
+ 0
990
1140
  end
991
1141
  end
992
1142
 
@@ -995,19 +1145,19 @@ EOT
995
1145
 
996
1146
  rc = block.call(resource)
997
1147
  if OpenNebula.is_error?(rc)
998
- return -1, rc.message
1148
+ [-1, rc.message]
999
1149
  else
1000
1150
  if options[:verbose]
1001
1151
  puts "#{self.class.rname} #{id}: #{verbose}"
1002
1152
  end
1003
- return 0
1153
+ 0
1004
1154
  end
1005
1155
  end
1006
1156
 
1007
- def perform_actions(ids,options,verbose,&block)
1157
+ def perform_actions(ids, options, verbose, &block)
1008
1158
  exit_code = 0
1009
1159
  ids.each do |id|
1010
- rc = perform_action(id,options,verbose,&block)
1160
+ rc = perform_action(id, options, verbose, &block)
1011
1161
 
1012
1162
  unless rc[0]==0
1013
1163
  STDERR.puts rc[1]
@@ -1021,7 +1171,7 @@ EOT
1021
1171
  ########################################################################
1022
1172
  # Id translation
1023
1173
  ########################################################################
1024
- def user_name(resource, options={})
1174
+ def user_name(resource, options = {})
1025
1175
  if options[:numeric]
1026
1176
  resource['UID']
1027
1177
  else
@@ -1029,7 +1179,7 @@ EOT
1029
1179
  end
1030
1180
  end
1031
1181
 
1032
- def group_name(resource, options={})
1182
+ def group_name(resource, options = {})
1033
1183
  if options[:numeric]
1034
1184
  resource['GID']
1035
1185
  else
@@ -1053,7 +1203,7 @@ EOT
1053
1203
  end
1054
1204
 
1055
1205
  def self.to_id_desc
1056
- "OpenNebula #{self.rname} name or id"
1206
+ "OpenNebula #{rname} name or id"
1057
1207
  end
1058
1208
 
1059
1209
  def list_to_id(names)
@@ -1063,7 +1213,7 @@ EOT
1063
1213
  pool = rc[1]
1064
1214
  poolname = self.class.rname
1065
1215
 
1066
- result = names.split(',').collect { |name|
1216
+ result = names.split(',').collect do |name|
1067
1217
  if name.match(/^[0123456789]+$/)
1068
1218
  name.to_i
1069
1219
  else
@@ -1075,76 +1225,70 @@ EOT
1075
1225
 
1076
1226
  rc[1]
1077
1227
  end
1078
- }
1228
+ end
1079
1229
 
1080
- return 0, result
1230
+ [0, result]
1081
1231
  end
1082
1232
 
1083
1233
  def self.list_to_id_desc
1084
- "Comma-separated list of OpenNebula #{self.rname} names or ids"
1234
+ "Comma-separated list of OpenNebula #{rname} names or ids"
1085
1235
  end
1086
1236
 
1087
1237
  def self.name_to_id(name, pool, ename)
1088
- if ename=="CLUSTER" and name.upcase=="ALL"
1089
- return 0, "ALL"
1238
+ if ename=='CLUSTER' and name.upcase=='ALL'
1239
+ return 0, 'ALL'
1090
1240
  end
1091
1241
 
1092
1242
  objects=pool.select {|object| object.name==name }
1093
1243
 
1094
- if objects.length>0
1095
- if objects.length>1
1096
- return -1, "There are multiple #{ename}s with name #{name}."
1097
- else
1098
- result = objects.first.id
1099
- end
1100
- else
1101
- return -1, "#{ename} named #{name} not found."
1102
- end
1244
+ return -1, "#{ename} named #{name} not found." unless objects.length>0
1245
+ return -1, "There are multiple #{ename}s with name #{name}." if objects.length>1
1103
1246
 
1104
- return 0, result
1247
+ result = objects.first.id
1248
+
1249
+ [0, result]
1105
1250
  end
1106
1251
 
1107
1252
  def filterflag_to_i(str)
1108
1253
  filter_flag = case str
1109
- when "a", "all" then OpenNebula::Pool::INFO_ALL
1110
- when "m", "mine" then OpenNebula::Pool::INFO_MINE
1111
- when "g", "group" then OpenNebula::Pool::INFO_GROUP
1112
- when "G", "primary group" then OpenNebula::Pool::INFO_PRIMARY_GROUP
1113
- else
1114
- if str.match(/^[0123456789]+$/)
1115
- str.to_i
1116
- else
1117
- rc = OpenNebulaHelper.rname_to_id(str, "USER")
1118
- if rc.first==-1
1119
- return rc
1120
- else
1121
- rc[1]
1122
- end
1123
- end
1124
- end
1254
+ when 'a', 'all' then OpenNebula::Pool::INFO_ALL
1255
+ when 'm', 'mine' then OpenNebula::Pool::INFO_MINE
1256
+ when 'g', 'group' then OpenNebula::Pool::INFO_GROUP
1257
+ when 'G', 'primary group' then OpenNebula::Pool::INFO_PRIMARY_GROUP
1258
+ else
1259
+ if str.match(/^[0123456789]+$/)
1260
+ str.to_i
1261
+ else
1262
+ rc = OpenNebulaHelper.rname_to_id(str, 'USER')
1263
+ return rc if rc.first==-1
1264
+
1265
+ rc[1]
1125
1266
 
1126
- return 0, filter_flag
1267
+ end
1268
+ end
1269
+
1270
+ [0, filter_flag]
1127
1271
  end
1128
1272
 
1129
1273
  def self.filterflag_to_i_desc
1130
- desc=<<-EOT
1131
- a, all all the known #{self.rname}s
1132
- m, mine the #{self.rname} belonging to the user in ONE_AUTH
1133
- g, group 'mine' plus the #{self.rname} belonging to the groups
1134
- the user is member of
1135
- G, primary group the #{self.rname} owned the user's primary group
1136
- uid #{self.rname} of the user identified by this uid
1137
- user #{self.rname} of the user identified by the username
1138
- EOT
1139
- end
1140
-
1141
- def self.table_conf(conf_file=self.conf_file)
1142
- path = "#{ENV["HOME"]}/.one/cli/#{conf_file}"
1143
-
1144
- if File.exists?(path)
1145
- return path
1274
+ desc=<<~EOT
1275
+ a, all all the known #{rname}s
1276
+ m, mine the #{rname} belonging to the user in ONE_AUTH
1277
+ g, group 'mine' plus the #{rname} belonging to the groups
1278
+ the user is member of
1279
+ G, primary group the #{rname} owned the user's primary group
1280
+ uid #{rname} of the user identified by this uid
1281
+ user #{rname} of the user identified by the username
1282
+ EOT
1283
+ end
1284
+
1285
+ def self.table_conf(conf_file = self.conf_file)
1286
+ path = "#{ENV['HOME']}/.one/cli/#{conf_file}"
1287
+
1288
+ if File.exist?(path)
1289
+ path
1146
1290
  else
1147
- return "#{TABLE_CONF_PATH}/#{conf_file}"
1291
+ "#{TABLE_CONF_PATH}/#{conf_file}"
1148
1292
  end
1149
1293
  end
1150
1294
 
@@ -1171,7 +1315,7 @@ EOT
1171
1315
  phash = [phash["#{rname}_POOL"]["#{rname}"]]
1172
1316
  end
1173
1317
  else
1174
- phash = Array.new
1318
+ phash = []
1175
1319
  end
1176
1320
 
1177
1321
  phash
@@ -1183,15 +1327,14 @@ EOT
1183
1327
 
1184
1328
  rc = pool.info
1185
1329
  if OpenNebula.is_error?(rc)
1186
- if rc.message.empty?
1187
- return -1, "OpenNebula #{self.class.rname} name not " <<
1188
- "found, use the ID instead"
1189
- else
1190
- return -1,rc.message
1191
- end
1330
+ return -1, rc.message unless rc.message.empty?
1331
+
1332
+ return -1, "OpenNebula #{self.class.rname} name not " <<
1333
+ 'found, use the ID instead'
1334
+
1192
1335
  end
1193
1336
 
1194
- return 0, pool
1337
+ [0, pool]
1195
1338
  end
1196
1339
 
1197
1340
  def get_format_size(pool, options)
@@ -1217,7 +1360,7 @@ EOT
1217
1360
  # @return [Object] Hash with correct values
1218
1361
  def check_resource_xsd(resource, ename = nil)
1219
1362
  hash = resource.to_hash
1220
- ename = hash.keys.first unless ename
1363
+ ename ||= hash.keys.first
1221
1364
  xsd = read_xsd(ename)
1222
1365
 
1223
1366
  return hash unless xsd
@@ -1228,14 +1371,13 @@ EOT
1228
1371
  xsd = xsd['element']
1229
1372
  end
1230
1373
 
1231
- xsd = [ xsd ] unless xsd.is_a? Array
1374
+ xsd = [xsd] unless xsd.is_a? Array
1232
1375
 
1233
1376
  check_xsd(hash[ename], xsd)
1234
1377
 
1235
1378
  hash
1236
1379
  end
1237
1380
 
1238
-
1239
1381
  # Replaces refs in xsd definition
1240
1382
  # limited func: only traverse hashes (not arrays), but works well for pools
1241
1383
  #
@@ -1248,21 +1390,22 @@ EOT
1248
1390
  if h.keys.include? 'ref'
1249
1391
  ref_xsd = read_xsd(h['ref'])
1250
1392
  return ref_xsd unless ref_xsd.nil?
1251
- return h
1393
+
1394
+ h
1252
1395
  else
1253
- h.each do |k,v|
1396
+ h.each do |k, v|
1254
1397
  h[k] = replace_refs(v)
1255
1398
  end
1256
1399
  end
1257
1400
  end
1258
1401
 
1259
-
1260
1402
  # Read XSD file and parse to XML
1261
1403
  #
1262
1404
  # @param ename [String] Element name to read XSD
1263
1405
  #
1264
1406
  # @return [Hash] XSD in hash format, nil if not found
1265
1407
  def read_xsd(ename)
1408
+ require 'active_support'
1266
1409
  require 'active_support/core_ext/hash/conversions'
1267
1410
 
1268
1411
  # Try GEM directory
@@ -1275,16 +1418,14 @@ EOT
1275
1418
 
1276
1419
  unless File.exist?(file)
1277
1420
  STDERR.puts "WARNING: XSD for #{ename} not found, skipping check"
1278
- return nil
1421
+ return
1279
1422
  end
1280
1423
 
1281
1424
  hash = Hash.from_xml(Nokogiri::XML(File.read(file)).to_s)
1282
1425
 
1283
1426
  hash = hash['schema']['element']
1284
1427
 
1285
- hash = replace_refs(hash)
1286
-
1287
- hash
1428
+ replace_refs(hash)
1288
1429
  end
1289
1430
 
1290
1431
  # Decides if given xsd definiton should be array in xml
@@ -1298,6 +1439,7 @@ EOT
1298
1439
  def is_array?(e)
1299
1440
  return false if e.nil?
1300
1441
  return false unless e.is_a? Hash
1442
+
1301
1443
  e['maxOccurs'] == 'unbounded' || e['maxOccurs'].to_i > 1
1302
1444
  end
1303
1445
 
@@ -1338,16 +1480,15 @@ EOT
1338
1480
  return unless hash or hash.empty?
1339
1481
 
1340
1482
  hash.each do |k, v|
1341
-
1342
1483
  # find the elem definition in xsd array
1343
- xsd_elem = xsd.select { |e| e['name'] == k }.first unless xsd.nil?
1484
+ xsd_elem = xsd.select {|e| e['name'] == k }.first unless xsd.nil?
1344
1485
 
1345
1486
  if xsd_complex_sequence?(xsd_elem) || xsd_complex_all?(xsd_elem)
1346
1487
 
1347
1488
  # go deeper in xsd, xsd is ehter complex sequence or all
1348
1489
  begin
1349
1490
  inner_xsd = xsd_elem['complexType']['sequence']['element']
1350
- rescue
1491
+ rescue StandardError
1351
1492
  inner_xsd = xsd_elem['complexType']['all']['element']
1352
1493
  end
1353
1494
 
@@ -1365,81 +1506,82 @@ EOT
1365
1506
  end
1366
1507
 
1367
1508
  # if XSD requires array, do so in resource if missing
1368
- if is_array?(xsd_elem) && (! v.is_a? Array)
1369
- hash[k] = [ v ]
1509
+ if is_array?(xsd_elem) && (!v.is_a? Array)
1510
+ hash[k] = [v]
1370
1511
  end
1371
1512
  end
1372
1513
  end
1514
+
1373
1515
  end
1374
1516
 
1375
- def OpenNebulaHelper.rname_to_id(name, poolname)
1517
+ def self.rname_to_id(name, poolname)
1376
1518
  return 0, name.to_i if name.match(/^[0123456789]+$/)
1377
1519
 
1378
1520
  client=OneHelper.client
1379
1521
 
1380
1522
  pool = case poolname
1381
- when "HOST" then OpenNebula::HostPool.new(client)
1382
- when "HOOK" then OpenNebula::HookPool.new(client)
1383
- when "GROUP" then OpenNebula::GroupPool.new(client)
1384
- when "USER" then OpenNebula::UserPool.new(client)
1385
- when "DATASTORE" then OpenNebula::DatastorePool.new(client)
1386
- when "CLUSTER" then OpenNebula::ClusterPool.new(client)
1387
- when "VNET" then OpenNebula::VirtualNetworkPool.new(client)
1388
- when "IMAGE" then OpenNebula::ImagePool.new(client)
1389
- when "VMTEMPLATE" then OpenNebula::TemplatePool.new(client)
1390
- when "VNTEMPLATES" then OpenNebula::VNTemplatePool.new(client)
1391
- when "VM" then OpenNebula::VirtualMachinePool.new(client)
1392
- when "ZONE" then OpenNebula::ZonePool.new(client)
1393
- when "MARKETPLACE" then OpenNebula::MarketPlacePool.new(client)
1394
- when "FLOWTEMPLATES" then OpenNebula::ServiceTemplatePool.new(client)
1395
- end
1523
+ when 'HOST' then OpenNebula::HostPool.new(client)
1524
+ when 'HOOK' then OpenNebula::HookPool.new(client)
1525
+ when 'GROUP' then OpenNebula::GroupPool.new(client)
1526
+ when 'USER' then OpenNebula::UserPool.new(client)
1527
+ when 'DATASTORE' then OpenNebula::DatastorePool.new(client)
1528
+ when 'CLUSTER' then OpenNebula::ClusterPool.new(client)
1529
+ when 'VNET' then OpenNebula::VirtualNetworkPool.new(client)
1530
+ when 'IMAGE' then OpenNebula::ImagePool.new(client)
1531
+ when 'VMTEMPLATE' then OpenNebula::TemplatePool.new(client)
1532
+ when 'VNTEMPLATES' then OpenNebula::VNTemplatePool.new(client)
1533
+ when 'VM' then OpenNebula::VirtualMachinePool.new(client)
1534
+ when 'ZONE' then OpenNebula::ZonePool.new(client)
1535
+ when 'MARKETPLACE' then OpenNebula::MarketPlacePool.new(client)
1536
+ when 'FLOWTEMPLATES' then OpenNebula::ServiceTemplatePool.new(client)
1537
+ end
1396
1538
 
1397
1539
  rc = pool.info
1398
1540
  if OpenNebula.is_error?(rc)
1399
1541
  return -1, "OpenNebula #{poolname} name not found," <<
1400
- " use the ID instead"
1542
+ ' use the ID instead'
1401
1543
  end
1402
1544
 
1403
1545
  OneHelper.name_to_id(name, pool, poolname)
1404
1546
  end
1405
1547
 
1406
- def OpenNebulaHelper.size_in_mb(size)
1548
+ def self.size_in_mb(size)
1407
1549
  m = size.match(/^(\d+(?:\.\d+)?)(t|tb|m|mb|g|gb)?$/i)
1408
1550
 
1409
1551
  if !m
1410
1552
  # return OpenNebula::Error.new('Size value malformed')
1411
- return -1, 'Size value malformed'
1553
+ [-1, 'Size value malformed']
1412
1554
  else
1413
1555
  multiplier=case m[2]
1414
- when /(t|tb)/i
1415
- 1024*1024
1416
- when /(g|gb)/i
1417
- 1024
1418
- else
1419
- 1
1420
- end
1556
+ when /(t|tb)/i
1557
+ 1024*1024
1558
+ when /(g|gb)/i
1559
+ 1024
1560
+ else
1561
+ 1
1562
+ end
1421
1563
 
1422
1564
  value=m[1].to_f*multiplier
1423
1565
 
1424
1566
  # return value.ceil
1425
- return 0, value.ceil
1567
+ [0, value.ceil]
1426
1568
  end
1427
1569
  end
1428
1570
 
1429
- def OpenNebulaHelper.rname_to_id_desc(poolname)
1571
+ def self.rname_to_id_desc(poolname)
1430
1572
  "OpenNebula #{poolname} name or id"
1431
1573
  end
1432
1574
 
1433
- def OpenNebulaHelper.boolean_to_str(str)
1575
+ def self.boolean_to_str(str)
1434
1576
  if str.to_i == 1
1435
- "Yes"
1577
+ 'Yes'
1436
1578
  else
1437
- "No"
1579
+ 'No'
1438
1580
  end
1439
1581
  end
1440
1582
 
1441
- def OpenNebulaHelper.time_to_str(time, print_seconds=true,
1442
- print_hours=true, print_years=false)
1583
+ def self.time_to_str(time, print_seconds = true,
1584
+ print_hours = true, print_years = false)
1443
1585
 
1444
1586
  value = time.to_i
1445
1587
 
@@ -1449,63 +1591,63 @@ EOT
1449
1591
  if print_hours
1450
1592
  if print_seconds
1451
1593
  if print_years
1452
- value=Time.at(value).strftime("%m/%d/%y %H:%M:%S")
1594
+ value=Time.at(value).strftime('%m/%d/%y %H:%M:%S')
1453
1595
  else
1454
- value=Time.at(value).strftime("%m/%d %H:%M:%S")
1596
+ value=Time.at(value).strftime('%m/%d %H:%M:%S')
1455
1597
  end
1456
1598
  else
1457
1599
  if print_years
1458
- value=Time.at(value).strftime("%m/%d/%y %H:%M")
1600
+ value=Time.at(value).strftime('%m/%d/%y %H:%M')
1459
1601
  else
1460
- value=Time.at(value).strftime("%m/%d %H:%M")
1602
+ value=Time.at(value).strftime('%m/%d %H:%M')
1461
1603
  end
1462
1604
  end
1463
1605
  else
1464
1606
  if print_years
1465
- value=Time.at(value).strftime("%m/%d/%y")
1607
+ value=Time.at(value).strftime('%m/%d/%y')
1466
1608
  else
1467
- value=Time.at(value).strftime("%m/%d")
1609
+ value=Time.at(value).strftime('%m/%d')
1468
1610
  end
1469
1611
  end
1470
1612
  end
1471
1613
 
1472
- return value
1614
+ value
1473
1615
  end
1474
1616
 
1475
- def OpenNebulaHelper.period_to_str(time, print_seconds=true)
1617
+ def self.period_to_str(time, print_seconds = true)
1476
1618
  seconds=time.to_i
1477
1619
  minutes, seconds=seconds.divmod(60)
1478
1620
  hours, minutes=minutes.divmod(60)
1479
1621
  days, hours=hours.divmod(24)
1480
1622
 
1481
1623
  if print_seconds
1482
- "%3dd %02dh%02dm%02ds" % [days, hours, minutes, seconds]
1624
+ format('%3dd %02dh%02dm%02ds', days, hours, minutes, seconds)
1483
1625
  else
1484
- "%3dd %02dh%02dm" % [days, hours, minutes]
1626
+ format('%3dd %02dh%02dm', days, hours, minutes)
1485
1627
  end
1486
1628
  end
1487
1629
 
1488
- def OpenNebulaHelper.short_period_to_str(time, print_seconds=true)
1630
+ def self.short_period_to_str(time, print_seconds = true)
1489
1631
  seconds=time.to_i
1490
1632
  minutes, seconds=seconds.divmod(60)
1491
1633
  hours, minutes=minutes.divmod(60)
1492
1634
 
1493
1635
  if print_seconds
1494
- "%3dh%02dm%02ds" % [hours, minutes, seconds]
1636
+ format('%3dh%02dm%02ds', hours, minutes, seconds)
1495
1637
  else
1496
- "%3dh%02dm" % [hours, minutes]
1638
+ format('%3dh%02dm', hours, minutes)
1497
1639
  end
1498
1640
  end
1499
1641
 
1500
- BinarySufix = ["K", "M", "G", "T" ]
1642
+ BinarySufix = ['K', 'M', 'G', 'T']
1501
1643
 
1502
- def OpenNebulaHelper.unit_to_str(value, options, unit="K")
1644
+ def self.unit_to_str(value, options, unit = 'K')
1503
1645
  if options[:kilobytes]
1504
1646
  value
1505
1647
  else
1506
1648
  i=BinarySufix.index(unit).to_i
1507
1649
 
1508
- while value > 1024 && i < 3 do
1650
+ while value > 1024 && i < 3
1509
1651
  value /= 1024.0
1510
1652
  i+=1
1511
1653
  end
@@ -1517,11 +1659,11 @@ EOT
1517
1659
  end
1518
1660
  end
1519
1661
 
1520
- def OpenNebulaHelper.bytes_to_unit(value, unit = 'K')
1662
+ def self.bytes_to_unit(value, unit = 'K')
1521
1663
  j = 0
1522
1664
  i = BinarySufix.index(unit).to_i
1523
1665
 
1524
- while j < i do
1666
+ while j < i
1525
1667
  value /= 1024.0
1526
1668
  j += 1
1527
1669
  end
@@ -1533,51 +1675,52 @@ EOT
1533
1675
  #
1534
1676
  # @param str [String || Hash] Cluster name, or empty Hash (when <CLUSTER/>)
1535
1677
  # @return [String] the same Cluster name, or '-' if it is empty
1536
- def OpenNebulaHelper.cluster_str(str)
1537
- if str != nil && !str.empty?
1678
+ def self.cluster_str(str)
1679
+ if !str.nil? && !str.empty?
1538
1680
  str
1539
1681
  else
1540
- "-"
1682
+ '-'
1541
1683
  end
1542
1684
  end
1543
1685
 
1544
- def OpenNebulaHelper.clusters_str(clusters)
1686
+ def self.clusters_str(clusters)
1545
1687
  if clusters.nil?
1546
- "-"
1688
+ '-'
1547
1689
  else
1548
1690
  [clusters].flatten.join(',')
1549
1691
  end
1550
-
1551
1692
  end
1552
1693
 
1553
- def OpenNebulaHelper.update_template(id, resource, path=nil, xpath='TEMPLATE')
1554
- return update_template_helper(false, id, resource, path, xpath)
1694
+ def self.update_template(id, resource, path = nil, xpath = 'TEMPLATE')
1695
+ update_template_helper(false, id, resource, path, xpath)
1555
1696
  end
1556
1697
 
1557
- def OpenNebulaHelper.append_template(id, resource, path=nil, xpath='TEMPLATE')
1558
- return update_template_helper(true, id, resource, path, xpath)
1698
+ def self.append_template(id, resource, path = nil, xpath = 'TEMPLATE')
1699
+ update_template_helper(true, id, resource, path, xpath)
1559
1700
  end
1560
1701
 
1561
- def OpenNebulaHelper.update_template_helper(append, id, resource, path, xpath, update=true)
1702
+ def self.update_template_helper(append, _id, resource, path, xpath, update = true)
1562
1703
  if path
1563
- return File.read(path)
1704
+ File.read(path)
1705
+ elsif STDIN.wait_readable(0)
1706
+ STDIN.read
1564
1707
  elsif append
1565
- return editor_input()
1708
+ editor_input
1566
1709
  else
1567
1710
  if update
1568
1711
  rc = resource.info
1569
1712
 
1570
1713
  if OpenNebula.is_error?(rc)
1571
1714
  puts rc.message
1572
- exit -1
1715
+ exit(-1)
1573
1716
  end
1574
1717
  end
1575
1718
 
1576
- return editor_input(resource.template_like_str(xpath))
1719
+ editor_input(resource.template_like_str(xpath))
1577
1720
  end
1578
1721
  end
1579
1722
 
1580
- def OpenNebulaHelper.update_obj(obj, file, plain = false)
1723
+ def self.update_obj(obj, file, plain = false)
1581
1724
  rc = obj.info(true)
1582
1725
 
1583
1726
  return rc if OpenNebula.is_error?(rc)
@@ -1614,28 +1757,27 @@ EOT
1614
1757
  end
1615
1758
  end
1616
1759
 
1617
- def OpenNebulaHelper.editor_input(contents=nil)
1760
+ def self.editor_input(contents = nil)
1618
1761
  require 'tempfile'
1619
1762
 
1620
- tmp = Tempfile.new("one_cli")
1763
+ tmp = Tempfile.new('one_cli')
1621
1764
 
1622
1765
  if contents
1623
1766
  tmp << contents
1624
1767
  tmp.flush
1625
1768
  end
1626
1769
 
1627
- editor_path = ENV["EDITOR"] ? ENV["EDITOR"] : EDITOR_PATH
1770
+ editor_path = ENV['EDITOR'] ? ENV['EDITOR'] : EDITOR_PATH
1628
1771
  system("#{editor_path} #{tmp.path}")
1629
1772
 
1630
1773
  unless $?.exitstatus == 0
1631
- puts "Editor not defined"
1632
- exit -1
1774
+ puts 'Editor not defined'
1775
+ exit(-1)
1633
1776
  end
1634
1777
 
1635
1778
  tmp.close
1636
1779
 
1637
- str = File.read(tmp.path)
1638
- return str
1780
+ File.read(tmp.path)
1639
1781
  end
1640
1782
 
1641
1783
  def self.parse_user_object(user_object)
@@ -1643,7 +1785,7 @@ EOT
1643
1785
 
1644
1786
  m=user_object.match(reg)
1645
1787
 
1646
- return nil if !m
1788
+ return unless m
1647
1789
 
1648
1790
  user=nil
1649
1791
  if m[2]
@@ -1660,7 +1802,7 @@ EOT
1660
1802
  template=''
1661
1803
 
1662
1804
  objects.each do |obj|
1663
- obj, *extra_attributes = obj.split(":")
1805
+ obj, *extra_attributes = obj.split(':')
1664
1806
 
1665
1807
  # When extra attributes do not contain = character include
1666
1808
  # them in the previous value. Fixes adding MAC addresses. These
@@ -1673,26 +1815,27 @@ EOT
1673
1815
  #
1674
1816
  attrs = []
1675
1817
  extra_attributes.each do |str|
1676
- if str.include?("=")
1818
+ if str.include?('=')
1677
1819
  attrs << str
1678
1820
  else
1679
1821
  attrs.last << ":#{str}"
1680
- end
1822
+ end
1681
1823
  end
1682
1824
 
1683
1825
  extra_attributes = attrs
1684
1826
 
1685
1827
  res=parse_user_object(obj)
1686
- return [-1, "#{section.capitalize} \"#{obj}\" malformed"] if !res
1828
+ return [-1, "#{section.capitalize} \"#{obj}\" malformed"] unless res
1829
+
1687
1830
  user, object=*res
1688
1831
 
1689
1832
  template<<"#{section.upcase}=[\n"
1690
- if object.downcase == "auto"
1833
+ if object.downcase == 'auto'
1691
1834
  template<<" NETWORK_MODE=\"#{object}\"\n"
1692
1835
  else
1693
1836
  template<<" #{name.upcase}_UNAME=\"#{user}\",\n" if user
1694
1837
  extra_attributes.each do |extra_attribute|
1695
- key, value = extra_attribute.split("=")
1838
+ key, value = extra_attribute.split('=')
1696
1839
  template<<" #{key.upcase}=\"#{value}\",\n"
1697
1840
  end
1698
1841
  if object.match(/^\d+$/)
@@ -1708,13 +1851,14 @@ EOT
1708
1851
  end
1709
1852
 
1710
1853
  def self.create_context(options)
1711
- context_options = [:ssh, :net_context, :context, :init, :files_ds, :startscript, :report_ready]
1854
+ context_options = [:ssh, :net_context, :context, :init, :files_ds, :startscript,
1855
+ :report_ready]
1712
1856
  if !(options.keys & context_options).empty?
1713
1857
  lines=[]
1714
1858
 
1715
1859
  if options[:ssh]
1716
1860
  if options[:ssh]==true
1717
- lines<<"SSH_PUBLIC_KEY=\"$USER[SSH_PUBLIC_KEY]\""
1861
+ lines<<'SSH_PUBLIC_KEY="$USER[SSH_PUBLIC_KEY]"'
1718
1862
  else
1719
1863
  begin
1720
1864
  key=File.read(options[:ssh]).strip
@@ -1727,7 +1871,7 @@ EOT
1727
1871
  end
1728
1872
 
1729
1873
  if options[:net_context]
1730
- lines << "NETWORK = \"YES\""
1874
+ lines << 'NETWORK = "YES"'
1731
1875
  end
1732
1876
 
1733
1877
  lines+=options[:context] if options[:context]
@@ -1735,7 +1879,7 @@ EOT
1735
1879
  if options[:files_ds]
1736
1880
  text='FILES_DS="'
1737
1881
  text << options[:files_ds].map do |file|
1738
- %Q<$FILE[IMAGE=\\"#{file}\\"]>
1882
+ %($FILE[IMAGE=\\"#{file}\\"])
1739
1883
  end.join(' ')
1740
1884
  text << '"'
1741
1885
 
@@ -1743,7 +1887,7 @@ EOT
1743
1887
  end
1744
1888
 
1745
1889
  if options[:init]
1746
- lines << %Q<INIT_SCRIPTS="#{options[:init].join(' ')}">
1890
+ lines << %(INIT_SCRIPTS="#{options[:init].join(' ')}")
1747
1891
  end
1748
1892
 
1749
1893
  if options[:startscript]
@@ -1754,16 +1898,16 @@ EOT
1754
1898
  STDERR.puts e.message
1755
1899
  exit(-1)
1756
1900
  end
1757
- script = Base64::strict_encode64(script)
1901
+ script = Base64.strict_encode64(script)
1758
1902
  lines<<"START_SCRIPT_BASE64=\"#{script}\""
1759
1903
  end
1760
1904
 
1761
1905
  if options[:report_ready]
1762
- lines << "REPORT_READY = \"YES\""
1906
+ lines << 'REPORT_READY = "YES"'
1763
1907
  end
1764
1908
 
1765
1909
  if !lines.empty?
1766
- "CONTEXT=[\n" << lines.map{|l| " " << l }.join(",\n") << "\n]\n"
1910
+ "CONTEXT=[\n" << lines.map {|l| ' ' << l }.join(",\n") << "\n]\n"
1767
1911
  else
1768
1912
  nil
1769
1913
  end
@@ -1772,7 +1916,7 @@ EOT
1772
1916
  end
1773
1917
  end
1774
1918
 
1775
- def self.create_template(options, template_obj=nil)
1919
+ def self.create_template(options, template_obj = nil)
1776
1920
  template=''
1777
1921
 
1778
1922
  template<<"NAME=\"#{options[:name]}\"\n" if options[:name]
@@ -1812,7 +1956,7 @@ EOT
1812
1956
  end
1813
1957
 
1814
1958
  if options[:vnc]
1815
- vnc_listen=options[:vnc_listen] || "0.0.0.0"
1959
+ vnc_listen=options[:vnc_listen] || '0.0.0.0'
1816
1960
  template<<"GRAPHICS=[ TYPE=\"vnc\", LISTEN=\"#{vnc_listen}\""
1817
1961
  if options[:vnc_password]
1818
1962
  template << ", PASSWD=\"#{options[:vnc_password]}\""
@@ -1824,7 +1968,7 @@ EOT
1824
1968
  end
1825
1969
 
1826
1970
  if options[:spice]
1827
- spice_listen=options[:spice_listen] || "0.0.0.0"
1971
+ spice_listen=options[:spice_listen] || '0.0.0.0'
1828
1972
  template<<"GRAPHICS=[ TYPE=\"spice\", LISTEN=\"#{spice_listen}\""
1829
1973
  if options[:spice_password]
1830
1974
  template << ", PASSWD=\"#{options[:spice_password]}\""
@@ -1835,20 +1979,29 @@ EOT
1835
1979
  template<<' ]' << "\n"
1836
1980
  end
1837
1981
 
1982
+ if options[:video]
1983
+ template<<"VIDEO=[ TYPE=\"#{options[:video]}\""
1984
+ template<<', IOMMU="YES"' if options[:video_iommu]
1985
+ template<<', ATS="YES"' if options[:video_ats]
1986
+ template<<", VRAM=\"#{options[:video_vram]}\"" if options[:video_vram]
1987
+ template<<", RESOLUTION=\"#{options[:video_resolution]}\""
1988
+ template<<' ]' << "\n"
1989
+ end
1990
+
1838
1991
  template<<"VCENTER_VM_FOLDER=#{options[:vcenter_vm_folder]}\n" if options[:vcenter_vm_folder]
1839
1992
 
1840
1993
  context=create_context(options)
1841
1994
  template<<context if context
1842
1995
 
1843
- if options[:userdata] && !template_obj.nil?
1844
- if template_obj.has_elements?('TEMPLATE/EC2')
1845
- template_obj.add_element(
1846
- 'TEMPLATE/EC2',
1847
- 'USERDATA' => options[:userdata])
1996
+ if options[:userdata] && !template_obj.nil? && template_obj.has_elements?('TEMPLATE/EC2')
1997
+ template_obj.add_element(
1998
+ 'TEMPLATE/EC2',
1999
+ 'USERDATA' => options[:userdata]
2000
+ )
1848
2001
 
1849
- template << template_obj.template_like_str(
1850
- 'TEMPLATE', false, 'EC2')
1851
- end
2002
+ template << template_obj.template_like_str(
2003
+ 'TEMPLATE', false, 'EC2'
2004
+ )
1852
2005
  end
1853
2006
 
1854
2007
  [0, template]
@@ -1946,21 +2099,21 @@ EOT
1946
2099
 
1947
2100
  def self.sunstone_url
1948
2101
  if (one_sunstone = ENV['ONE_SUNSTONE'])
1949
- one_sunstone
2102
+ one_sunstone
1950
2103
  elsif (one_xmlrpc = ENV['ONE_XMLRPC'])
1951
2104
  uri = URI(one_xmlrpc)
1952
2105
  "#{uri.scheme}://#{uri.host}:9869"
1953
2106
  else
1954
- "http://localhost:9869"
2107
+ 'http://localhost:9869'
1955
2108
  end
1956
2109
  end
1957
2110
 
1958
- def self.download_resource_sunstone(kind, id, path, force)
2111
+ def self.download_resource_sunstone(kind, id, path, _force)
1959
2112
  client = OneHelper.client
1960
- user, password = client.one_auth.split(":", 2)
2113
+ user, password = client.one_auth.split(':', 2)
1961
2114
 
1962
2115
  # Step 1: Build Session to get Cookie
1963
- uri = URI(File.join(sunstone_url,"login"))
2116
+ uri = URI(File.join(sunstone_url, 'login'))
1964
2117
 
1965
2118
  req = Net::HTTP::Post.new(uri)
1966
2119
  req.basic_auth user, password
@@ -1969,14 +2122,14 @@ EOT
1969
2122
  res = Net::HTTP.start(uri.hostname, uri.port) do |http|
1970
2123
  http.request(req)
1971
2124
  end
1972
- rescue
2125
+ rescue StandardError
1973
2126
  return OpenNebula::Error.new("Error connecting to '#{uri}'.")
1974
2127
  end
1975
2128
 
1976
2129
  cookie = res.response['set-cookie'].split('; ')[0]
1977
2130
 
1978
2131
  if cookie.nil?
1979
- return OpenNebula::Error.new("Unable to get Cookie. Is OpenNebula running?")
2132
+ return OpenNebula::Error.new('Unable to get Cookie. Is OpenNebula running?')
1980
2133
  end
1981
2134
 
1982
2135
  # Step 2: Open '/' to get the csrftoken
@@ -1989,7 +2142,7 @@ EOT
1989
2142
  res = Net::HTTP.start(uri.hostname, uri.port) do |http|
1990
2143
  http.request(req)
1991
2144
  end
1992
- rescue
2145
+ rescue StandardError
1993
2146
  return OpenNebula::Error.new("Error connecting to '#{uri}'.")
1994
2147
  end
1995
2148
 
@@ -1997,7 +2150,7 @@ EOT
1997
2150
  csrftoken = m[1] rescue nil
1998
2151
 
1999
2152
  if csrftoken.nil?
2000
- return OpenNebula::Error.new("Unable to get csrftoken.")
2153
+ return OpenNebula::Error.new('Unable to get csrftoken.')
2001
2154
  end
2002
2155
 
2003
2156
  # Step 3: Download resource
@@ -2009,7 +2162,7 @@ EOT
2009
2162
  req = Net::HTTP::Get.new(uri)
2010
2163
 
2011
2164
  req['Cookie'] = cookie
2012
- req['User-Agent'] = "OpenNebula CLI"
2165
+ req['User-Agent'] = 'OpenNebula CLI'
2013
2166
 
2014
2167
  begin
2015
2168
  File.open(path, 'wb') do |f|
@@ -2022,7 +2175,7 @@ EOT
2022
2175
  end
2023
2176
  end
2024
2177
  rescue Errno::EACCES
2025
- return OpenNebula::Error.new("Target file not writable.")
2178
+ return OpenNebula::Error.new('Target file not writable.')
2026
2179
  end
2027
2180
 
2028
2181
  error_message = nil
@@ -2039,30 +2192,30 @@ EOT
2039
2192
  error_message = m[1] if m
2040
2193
  end
2041
2194
 
2042
- if error_message
2043
- File.unlink(path)
2044
- return OpenNebula::Error.new("Remote server error: #{error_message}")
2045
- end
2195
+ return unless error_message
2196
+
2197
+ File.unlink(path)
2198
+ OpenNebula::Error.new("Remote server error: #{error_message}")
2046
2199
  end
2047
2200
 
2048
- def OpenNebulaHelper.level_lock_to_str(str)
2201
+ def self.level_lock_to_str(str)
2049
2202
  level = str.to_i
2050
2203
  if level == 0
2051
- "None"
2204
+ 'None'
2052
2205
  elsif level == 1
2053
- "Use"
2206
+ 'Use'
2054
2207
  elsif level == 2
2055
- "Manage"
2208
+ 'Manage'
2056
2209
  elsif level == 3
2057
- "Admin"
2210
+ 'Admin'
2058
2211
  elsif level == 4
2059
- "All"
2212
+ 'All'
2060
2213
  else
2061
- "-"
2214
+ '-'
2062
2215
  end
2063
2216
  end
2064
2217
 
2065
- def OpenNebulaHelper.parse_user_inputs(inputs, keys = [])
2218
+ def self.parse_user_inputs(inputs, keys = [])
2066
2219
  unless inputs.keys == keys
2067
2220
  puts 'There are some parameters that require user input. ' \
2068
2221
  'Use the string <<EDITOR>> to launch an editor ' \
@@ -2132,7 +2285,7 @@ EOT
2132
2285
  # use default in case it's empty
2133
2286
  answer = initial if answer.empty?
2134
2287
 
2135
- unless %w[YES NO].include?(answer)
2288
+ unless ['YES', 'NO'].include?(answer)
2136
2289
  STDERR.puts "Invalid boolean '#{answer}'"
2137
2290
  STDERR.puts 'Boolean has to be YES or NO'
2138
2291
  exit(-1)
@@ -2160,8 +2313,8 @@ EOT
2160
2313
  answer = STDIN.readline.chop
2161
2314
 
2162
2315
  answer = initial if answer == ''
2163
- noanswer = ((answer == '') && optional)
2164
- end while !noanswer && (answer =~ exp) == nil
2316
+ noanswer = ((answer == '') && optional)
2317
+ end while !noanswer && (answer =~ exp).nil?
2165
2318
 
2166
2319
  if noanswer
2167
2320
  next
@@ -2198,7 +2351,7 @@ EOT
2198
2351
  answer = initial if answer == ''
2199
2352
 
2200
2353
  noanswer = (answer == '') && optional
2201
- end while !noanswer && ((answer =~ exp) == nil ||
2354
+ end while !noanswer && ((answer =~ exp).nil? ||
2202
2355
  answer.to_f < min || answer.to_f > max)
2203
2356
 
2204
2357
  if noanswer
@@ -2257,7 +2410,7 @@ EOT
2257
2410
  # @param title [String] Plot title
2258
2411
  #
2259
2412
  # @return Gnuplot plot object
2260
- def OpenNebulaHelper.get_plot(x, y, attr, title)
2413
+ def self.get_plot(x, y, attr, title)
2261
2414
  # Require gnuplot gem only here
2262
2415
  begin
2263
2416
  require 'gnuplot'
@@ -2307,7 +2460,7 @@ EOT
2307
2460
  # @param perm [String] Permissions in human readbale format
2308
2461
  #
2309
2462
  # @return [String] Permissions in octet format
2310
- def OpenNebulaHelper.to_octet(perm)
2463
+ def self.to_octet(perm)
2311
2464
  begin
2312
2465
  Integer(perm)
2313
2466
  perm
@@ -2353,4 +2506,148 @@ EOT
2353
2506
  end
2354
2507
  end
2355
2508
 
2509
+ def self.schedule_action_tmpl(options, action, warning = nil)
2510
+ str_periodic = ''
2511
+
2512
+ if options.key?(:weekly)
2513
+ str_periodic << ", REPEAT = 0, DAYS = \"#{options[:weekly]}\""
2514
+ elsif options.key?(:monthly)
2515
+ str_periodic << ", REPEAT = 1, DAYS = \"#{options[:monthly]}\""
2516
+ elsif options.key?(:yearly)
2517
+ str_periodic << ", REPEAT = 2, DAYS = \"#{options[:yearly]}\""
2518
+ elsif options.key?(:hourly)
2519
+ str_periodic << ", REPEAT = 3, DAYS = \"#{options[:hourly]}\""
2520
+ end
2521
+
2522
+ if options.key?(:end)
2523
+ begin
2524
+ end_date = Date.parse(options[:end])
2525
+ str_periodic << ", END_TYPE = 2, END_VALUE = #{end_date.to_time.to_i}"
2526
+ rescue ArgumentError
2527
+ if options[:end].to_i > 0
2528
+ str_periodic << ", END_TYPE = 1, END_VALUE = #{options[:end].to_i}"
2529
+ end
2530
+ end
2531
+ elsif str_periodic != ''
2532
+ str_periodic << ', END_TYPE = 0'
2533
+ end
2534
+
2535
+ tmp_str = 'SCHED_ACTION = ['
2536
+ tmp_str << "ACTION = #{action}, " if action
2537
+ tmp_str << "WARNING = #{warning}," if warning
2538
+ tmp_str << "ARGS = \"#{options[:args]}\"," if options[:args]
2539
+ tmp_str << "TIME = #{options[:schedule]}"
2540
+ tmp_str << str_periodic << ']'
2541
+
2542
+ tmp_str
2543
+ end
2544
+
2545
+ def self.scheduled_action_table(object)
2546
+ CLIHelper::ShowTable.new(nil, object) do
2547
+ column :ID, '', :adjust => true do |d|
2548
+ d['ID']
2549
+ end
2550
+
2551
+ column :ACTION, '', :adjust => true do |d|
2552
+ d['ACTION']
2553
+ end
2554
+
2555
+ column :ARGS, '', :adjust => true do |d|
2556
+ d['ARGS'] && !d['ARGS'].empty? ? d['ARGS'] : '-'
2557
+ end
2558
+
2559
+ column :SCHEDULED, '', :adjust => true do |d|
2560
+ t = d['TIME'].to_i
2561
+
2562
+ # relative action for VMs
2563
+ if d['TIME'] !~ /^[0-9].*/ && !object['STIME'].nil?
2564
+ t += object['STIME'].to_i
2565
+ end
2566
+
2567
+ OpenNebulaHelper.time_to_str(t, false) unless d.nil?
2568
+ end
2569
+
2570
+ column :REPEAT, '', :adjust => true do |d|
2571
+ begin
2572
+ str_rep = ''
2573
+
2574
+ case d['REPEAT']
2575
+ when '0'
2576
+ str_rep << 'Weekly '
2577
+ when '1'
2578
+ str_rep << 'Monthly '
2579
+ when '2'
2580
+ str_rep << 'Yearly '
2581
+ when '3'
2582
+ str_rep << 'Each ' << d['DAYS'] << ' hours'
2583
+ end
2584
+
2585
+ if d['REPEAT'] != '3'
2586
+ str_rep << d['DAYS']
2587
+ end
2588
+
2589
+ str_rep
2590
+ rescue StandardError
2591
+ ''
2592
+ end
2593
+ end
2594
+
2595
+ column :END, '', :adjust => true do |d|
2596
+ begin
2597
+ str_end = ''
2598
+
2599
+ case d['END_TYPE']
2600
+ when '0'
2601
+ str_end << 'None'
2602
+ when '1'
2603
+ str_end << 'After ' << d['END_VALUE'] << ' times'
2604
+ when '2'
2605
+ str_end << 'On ' << \
2606
+ OpenNebulaHelper.time_to_str(d['END_VALUE'], false, false, true)
2607
+ end
2608
+
2609
+ str_end
2610
+ rescue StandardError
2611
+ ''
2612
+ end
2613
+ end
2614
+
2615
+ column :STATUS, '', :left, :size => 50 do |d|
2616
+ begin
2617
+ if d['DONE'].to_i > 0 && d['REPEAT'].to_i < 0
2618
+ "Done on #{OpenNebulaHelper.time_to_str(d['DONE'], false)}"
2619
+ elsif d['MESSAGE'] && !d['MESSAGE'].empty?
2620
+ "Error! #{d['MESSAGE']}"
2621
+ else
2622
+ t1 = Time.now
2623
+ t2 = d['TIME'].to_i
2624
+
2625
+ # relative action for VMs
2626
+ if (d['TIME'] !~ /^[0-9].*/) && !object['STIME'].nil?
2627
+ t2 += object['STIME'].to_i
2628
+ end
2629
+
2630
+ t2 = Time.at(t2)
2631
+
2632
+ days = ((t2 - t1) / (24 * 3600)).round(2)
2633
+ hours = ((t2 - t1) / 3600).round(2)
2634
+ minutes = ((t2 - t1) / 60).round(2)
2635
+
2636
+ if days > 1
2637
+ "Next in #{days} days"
2638
+ elsif days <= 1 && hours > 1
2639
+ "Next in #{hours} hours"
2640
+ elsif minutes > 0
2641
+ "Next in #{minutes} minutes"
2642
+ else
2643
+ 'Overdue!'
2644
+ end
2645
+ end
2646
+ rescue StandardError
2647
+ ''
2648
+ end
2649
+ end
2650
+ end
2651
+ end
2652
+
2356
2653
  end