opennebula-cli 5.11.90.pre → 5.12.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,6 +17,7 @@
17
17
  require 'one_helper'
18
18
  require 'one_helper/onevm_helper'
19
19
  require 'rubygems'
20
+ require 'time'
20
21
 
21
22
  # implements onehost command
22
23
  class OneHostHelper < OpenNebulaHelper::OneHelper
@@ -75,6 +76,15 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
75
76
 
76
77
  VERSION_XPATH = "#{TEMPLATE_XPATH}/VERSION"
77
78
 
79
+ MONITORING = {
80
+ 'FREE_CPU' => 'CAPACITY',
81
+ 'FREE_MEMORY' => 'CAPACITY',
82
+ 'USED_CPU' => 'CAPACITY',
83
+ 'USED_MEMORY' => 'CAPACITY',
84
+ 'NETRX' => 'SYSTEM',
85
+ 'NETTX' => 'SYSTEM'
86
+ }
87
+
78
88
  def self.rname
79
89
  'HOST'
80
90
  end
@@ -93,7 +103,7 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
93
103
  def format_pool(options)
94
104
  config_file = self.class.table_conf
95
105
 
96
- table = CLIHelper::ShowTable.new(config_file, self) do
106
+ CLIHelper::ShowTable.new(config_file, self) do
97
107
  column :ID, 'ONE identifier for Host', :size => 4 do |d|
98
108
  d['ID']
99
109
  end
@@ -223,8 +233,6 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
223
233
  default :ID, :NAME, :CLUSTER, :TVM,
224
234
  :ALLOCATED_CPU, :ALLOCATED_MEM, :STAT
225
235
  end
226
-
227
- table
228
236
  end
229
237
 
230
238
  def set_hybrid(type, path)
@@ -425,8 +433,7 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
425
433
  rc = pool.info
426
434
  return -1, rc.message if OpenNebula.is_error?(rc)
427
435
 
428
- # Assign hosts to threads
429
- queue = []
436
+ host_errors = []
430
437
 
431
438
  pool.each do |host|
432
439
  if host_ids
@@ -435,7 +442,6 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
435
442
  next if host['CLUSTER_ID'].to_i != cluster_id
436
443
  end
437
444
 
438
- vm_mad = host['VM_MAD'].downcase
439
445
  state = host['STATE']
440
446
 
441
447
  # Skip this host from remote syncing if it's a PUBLIC_CLOUD host
@@ -444,60 +450,104 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
444
450
  # Skip this host from remote syncing if it's OFFLINE
445
451
  next if Host::HOST_STATES[state.to_i] == 'OFFLINE'
446
452
 
447
- # Skip this host if it is a vCenter cluster
448
- next if vm_mad == 'vcenter'
453
+ rc = host.forceupdate
449
454
 
450
- queue << host
455
+ host_errors << host['NAME'] if OpenNebula.is_error?(rc)
451
456
  end
452
457
 
453
- # Run the jobs in threads
454
- host_errors = []
455
- queue_lock = Mutex.new
456
- error_lock = Mutex.new
457
- total = queue.length
458
+ if host_errors.empty?
459
+ puts 'All hosts updated successfully.'
460
+ 0
461
+ else
462
+ STDERR.puts 'Failed to update the following hosts:'
463
+ host_errors.each {|h| STDERR.puts "* #{h}" }
464
+ -1
465
+ end
466
+ end
458
467
 
459
- if total.zero?
460
- puts 'No hosts are going to be forced.'
461
- exit(0)
468
+ def monitoring(host, attr, options)
469
+ unit = options[:unit] || 'G'
470
+ start_d = options[:start]
471
+ end_d = options[:end]
472
+ n_elems = options[:n_elems] || 8
473
+
474
+ # Different available size units
475
+ units = %w[K M G T]
476
+
477
+ # Attrs that need units conversion
478
+ attrs = %w[FREE_MEMORY USED_MEMORY]
479
+
480
+ if unit && !units.include?(unit)
481
+ STDERR.puts "Invalid unit `#{unit}`"
482
+ exit(-1)
462
483
  end
463
484
 
464
- ts = (1..NUM_THREADS).map do |_t|
465
- Thread.new do
466
- loop do
467
- host = nil
468
- size = 0
485
+ attr = attr.upcase
486
+ start_d = Time.parse(start_d) if start_d
487
+ end_d = Time.parse(end_d) if end_d
469
488
 
470
- queue_lock.synchronize do
471
- host = queue.shift
472
- size = queue.length
473
- end
489
+ # Get monitoring data from user path
490
+ #
491
+ # 0 -> timestamp
492
+ # 1 -> data retrieved
493
+ monitoring_data = host.monitoring(["#{MONITORING[attr]}/#{attr}"])
494
+ monitoring_data = monitoring_data["#{MONITORING[attr]}/#{attr}"]
474
495
 
475
- break unless host
496
+ if monitoring_data.empty?
497
+ STDERR.puts 'No monitoring data found'
498
+ return
499
+ end
476
500
 
477
- hn = host['NAME']
501
+ # Get data max and min date
502
+ start_d ||= Time.at(monitoring_data.min {|v| v[0].to_i }[0].to_i)
503
+ end_d ||= Time.at(monitoring_data.max {|v| v[0].to_i }[0].to_i)
478
504
 
479
- system("onehost offline #{hn} && onehost enable #{hn}")
480
- if !$CHILD_STATUS.success?
481
- error_lock.synchronize do
482
- host_errors << hn
483
- end
484
- else
485
- puts "#{hn} monitoring forced"
486
- end
487
- end
505
+ # Filter data betwen dates
506
+ monitoring_data.reject! do |v|
507
+ v[0].to_i < start_d.to_i || v[0].to_i > end_d.to_i
508
+ end
509
+
510
+ if monitoring_data.empty?
511
+ STDERR.puts "No monitoring data found between #{start_d} " \
512
+ "and #{end_d}"
513
+ return
514
+ end
515
+
516
+ start_d = start_d.strftime('%d/%m/%Y %H:%M')
517
+ end_d = end_d.strftime('%d/%m/%Y %H:%M')
518
+
519
+ # Parse dcollected data
520
+ x = monitoring_data.collect {|v| Time.at(v[0].to_i).strftime('%H:%M') }
521
+ y = monitoring_data.collect do |v|
522
+ if attrs.include?(attr)
523
+ # GB is the default unit
524
+ v = OpenNebulaHelper.bytes_to_unit(v[1].to_i, unit).round(2)
525
+ "#{v} #{unit}B"
526
+ else
527
+ v[1]
488
528
  end
489
529
  end
490
530
 
491
- # Wait for threads to finish
492
- ts.each {|t| t.join }
531
+ title = ''
532
+ title << "Host #{host.id} #{attr} "
533
+ title << "in #{unit}B " if unit && attrs.include?(attr)
534
+ title << "from #{start_d} to #{end_d}"
493
535
 
494
- if host_errors.empty?
495
- puts 'All hosts updated successfully.'
496
- 0
536
+ x = x.last(n_elems)
537
+ y = y.last(n_elems)
538
+
539
+ if options[:table]
540
+ print_monitoring_table(x, y, title)
541
+ elsif options[:csv]
542
+ csv = ''
543
+
544
+ csv << "TIME#{options[:csv]}VALUE\n"
545
+
546
+ x.zip(y) {|x_v, y_v| csv << "#{x_v}#{options[:csv]}#{y_v}\n" }
547
+
548
+ puts csv
497
549
  else
498
- STDERR.puts 'Failed to update the following hosts:'
499
- host_errors.each {|h| STDERR.puts "* #{h}" }
500
- -1
550
+ puts OpenNebulaHelper.get_plot(x, y, attr, title)
501
551
  end
502
552
  end
503
553
 
@@ -920,4 +970,30 @@ class OneHostHelper < OpenNebulaHelper::OneHelper
920
970
  table.show(hugepages)
921
971
  end
922
972
 
973
+ def print_monitoring_table(x, y, title)
974
+ puts
975
+ CLIHelper.print_header(title, true)
976
+ puts
977
+
978
+ table = CLIHelper::ShowTable.new(nil, self) do
979
+ column :TIME, 'Timestamp', :size => 8, :left => false do |d|
980
+ d['TIME']
981
+ end
982
+
983
+ column :VALUE, 'Value', :size => 8, :left => false do |d|
984
+ d['VALUE']
985
+ end
986
+
987
+ default :TIME, :VALUE
988
+ end
989
+
990
+ data = []
991
+
992
+ x.zip(y) do |x_v, y_v|
993
+ data << { 'TIME' => x_v, 'VALUE' => y_v }
994
+ end
995
+
996
+ table.show(data)
997
+ end
998
+
923
999
  end
@@ -192,7 +192,7 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
192
192
  def format_pool(options)
193
193
  config_file = self.class.table_conf
194
194
 
195
- table = CLIHelper::ShowTable.new(config_file, self) do
195
+ CLIHelper::ShowTable.new(config_file, self) do
196
196
  column :ID, 'ONE identifier for the Image', :size=>4 do |d|
197
197
  d['ID']
198
198
  end
@@ -246,8 +246,6 @@ class OneImageHelper < OpenNebulaHelper::OneHelper
246
246
  default :ID, :USER, :GROUP, :NAME, :DATASTORE, :SIZE, :TYPE,
247
247
  :PERSISTENT, :STAT, :RVMS
248
248
  end
249
-
250
- table
251
249
  end
252
250
 
253
251
  def check_orphans
@@ -49,7 +49,7 @@ class OneProvisionHelper < OpenNebulaHelper::OneHelper
49
49
  def format_pool
50
50
  config_file = self.class.table_conf
51
51
 
52
- table = CLIHelper::ShowTable.new(config_file, self) do
52
+ CLIHelper::ShowTable.new(config_file, self) do
53
53
  column :ID, 'Identifier for the Provision', :size => 36 do |p|
54
54
  p['ID']
55
55
  end
@@ -80,8 +80,6 @@ class OneProvisionHelper < OpenNebulaHelper::OneHelper
80
80
 
81
81
  default :ID, :NAME, :CLUSTERS, :HOSTS, :NETWORKS, :DATASTORES, :STAT
82
82
  end
83
-
84
- table
85
83
  end
86
84
 
87
85
  #######################################################################
@@ -228,11 +226,9 @@ class OneProvisionHelper < OpenNebulaHelper::OneHelper
228
226
  end
229
227
 
230
228
  def names_to_ids(objects, type)
231
- objects = [objects].flatten.map do |obj|
229
+ [objects].flatten.map do |obj|
232
230
  OpenNebulaHelper.rname_to_id(obj.to_s, type)[1]
233
231
  end
234
-
235
- objects
236
232
  end
237
233
 
238
234
  def get_list(provision_list)
@@ -237,11 +237,11 @@ class OneVcenterHelper < OpenNebulaHelper::OneHelper
237
237
  d[:import_id]
238
238
  end
239
239
 
240
- column :REF, "ref", :left, :size=>config[:REF] || 15 do |d|
240
+ column :REF, "ref", :left, :adjust, :size=>config[:REF] || 15 do |d|
241
241
  d[:ref]
242
242
  end
243
243
 
244
- column :NAME, "Name", :left, :size=>config[:NAME] || 20 do |d|
244
+ column :NAME, "Name", :left, :expand, :size=>config[:NAME] || 20 do |d|
245
245
  d[:name] || d[:simple_name]
246
246
  end
247
247
 
@@ -250,7 +250,7 @@ class OneVcenterHelper < OpenNebulaHelper::OneHelper
250
250
  d[:one_ids] || d[:cluster].to_s
251
251
  end
252
252
 
253
- column :PATH, "PATH", :left, :size=>config[:PATH] || 10 do |d|
253
+ column :PATH, "PATH", :left, :expand, :size=>config[:PATH] || 10 do |d|
254
254
  d[:path]
255
255
  end
256
256
 
@@ -354,7 +354,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
354
354
 
355
355
  column :MEM, 'Memory asigned to the VM', :size => 7 do |d|
356
356
  OpenNebulaHelper.unit_to_str(d['TEMPLATE']['MEMORY'].to_i,
357
- options)
357
+ options, 'M')
358
358
  end
359
359
 
360
360
  column :HOST, 'Host where the VM is running',
@@ -402,7 +402,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
402
402
  table
403
403
  end
404
404
 
405
- def schedule_actions(ids, options, action)
405
+ def schedule_actions(ids, options, action, warning = nil)
406
406
  # Verbose by default
407
407
  options[:verbose] = true
408
408
 
@@ -453,18 +453,74 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
453
453
  id = ids.max + 1
454
454
  end
455
455
 
456
+ sched = options[:schedule]
457
+
458
+ # If the action is set to be executed from VM start to an specific
459
+ # amount of time later, we should preserve the + symbol
460
+ if ((sched.is_a? String) && !sched.include?('+')) ||
461
+ !(sched.is_a? String)
462
+ sched = sched.to_i
463
+ end
464
+
456
465
  tmp_str = vm.user_template_str
457
466
 
458
467
  tmp_str << "\nSCHED_ACTION = "
459
468
  tmp_str << "[ID = #{id}, ACTION = #{action}, "
469
+ tmp_str << "WARNING = #{warning}," if warning
460
470
  tmp_str << "ARGS = \"#{options[:args]}\"," if options[:args]
461
- tmp_str << "TIME = #{options[:schedule].to_i}"
471
+ tmp_str << "TIME = #{sched}"
462
472
  tmp_str << str_periodic << ']'
463
473
 
464
474
  vm.update(tmp_str)
465
475
  end
466
476
  end
467
477
 
478
+ # Update schedule action
479
+ #
480
+ # @param vm_id [Integer] Virtual Machine ID
481
+ # @param action_id [Integer] Sched action ID
482
+ # @param file [String] File path with update content
483
+ def update_schedule_action(vm_id, action_id, file)
484
+ perform_action(vm_id, {}, 'Sched action updated') do |vm|
485
+ rc = vm.info
486
+
487
+ if OpenNebula.is_error?(rc)
488
+ STDERR.puts "Error #{rc.message}"
489
+ exit(-1)
490
+ end
491
+
492
+ xpath = "USER_TEMPLATE/SCHED_ACTION[ID=#{action_id}]"
493
+
494
+ unless vm.retrieve_elements(xpath)
495
+ STDERR.puts "Sched action #{action_id} not found"
496
+ exit(-1)
497
+ end
498
+
499
+ # Get user information
500
+ if file
501
+ str = File.read(file)
502
+ else
503
+ str = OpenNebulaHelper.update_template(vm_id, vm, nil, xpath)
504
+ end
505
+
506
+ # Delete the current sched action
507
+ vm.delete_element(xpath)
508
+
509
+ # Add the modified sched action
510
+ tmp_str = vm.user_template_str
511
+ tmp_str << "\nSCHED_ACTION = ["
512
+ tmp_str << str.split("\n").join(',')
513
+ tmp_str << ']'
514
+
515
+ rc = vm.update(tmp_str)
516
+
517
+ if OpenNebula.is_error?(rc)
518
+ STDERR.puts "Error updating: #{rc.message}"
519
+ exit(-1)
520
+ end
521
+ end
522
+ end
523
+
468
524
  RECOVER_RETRY_STEPS = {
469
525
  :PROLOG_MIGRATE_FAILURE => :migrate,
470
526
  :PROLOG_MIGRATE_POWEROFF_FAILURE => :migrate,
@@ -602,6 +658,16 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
602
658
  end
603
659
  end
604
660
 
661
+ # Get charters configuration
662
+ #
663
+ # @return [Array]
664
+ # - action
665
+ # - time
666
+ # - warning
667
+ def get_charters
668
+ YAML.load_file(self.class.table_conf)[:charters]
669
+ end
670
+
605
671
  private
606
672
 
607
673
  def factory(id = nil)
@@ -1144,24 +1210,24 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
1144
1210
  CLIHelper.print_header(str_h1 % 'SCHEDULED ACTIONS', false)
1145
1211
 
1146
1212
  CLIHelper::ShowTable.new(nil, self) do
1147
- column :ID, '', :size => 2 do |d|
1213
+ column :ID, '', :adjust => true do |d|
1148
1214
  d['ID'] unless d.nil?
1149
1215
  end
1150
1216
 
1151
- column :ACTION, '', :left, :size => 15 do |d|
1217
+ column :ACTION, '', :adjust => true do |d|
1152
1218
  d['ACTION'] unless d.nil?
1153
1219
  end
1154
1220
 
1155
- column :ARGS, '', :left, :size => 15 do |d|
1221
+ column :ARGS, '', :adjust => true do |d|
1156
1222
  d['ARGS'] ? d['ARGS'] : '-'
1157
1223
  end
1158
1224
 
1159
- column :SCHEDULED, '', :size => 12 do |d|
1225
+ column :SCHEDULED, '', :adjust => true do |d|
1160
1226
  OpenNebulaHelper.time_to_str(d['TIME'], false) \
1161
1227
  unless d.nil?
1162
1228
  end
1163
1229
 
1164
- column :REPEAT, '', :size => 20 do |d|
1230
+ column :REPEAT, '', :adjust => true do |d|
1165
1231
  str_rep = ''
1166
1232
  if !d.nil? && d.key?('REPEAT')
1167
1233
  if d['REPEAT'] == '0'
@@ -1180,7 +1246,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
1180
1246
  str_rep unless d.nil?
1181
1247
  end
1182
1248
 
1183
- column :END, '', :size => 20 do |d|
1249
+ column :END, '', :adjust => true do |d|
1184
1250
  str_end = ''
1185
1251
  if !d.nil? && d.key?('END_TYPE')
1186
1252
  if d['END_TYPE'] == '0'
@@ -1197,25 +1263,50 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
1197
1263
  str_end unless d.nil?
1198
1264
  end
1199
1265
 
1200
- column :DONE, '', :size => 12 do |d|
1266
+ column :DONE, '', :adjust => true do |d|
1201
1267
  OpenNebulaHelper.time_to_str(d['DONE'], false) \
1202
1268
  unless d.nil?
1203
1269
  end
1204
1270
 
1205
- column :MESSAGE, '', :left, :adjust, :size => 35 do |d|
1206
- d['MESSAGE'] unless d.nil?
1271
+ column :MESSAGE, '', :size => 35 do |d|
1272
+ d['MESSAGE'] ? d['MESSAGE'] : '-'
1273
+ end
1274
+
1275
+ column :CHARTER, '', :left, :adjust, :size => 15 do |d|
1276
+ t1 = Time.now
1277
+ t2 = Time.at(vm['STIME'].to_i + d['TIME'].to_i)
1278
+
1279
+ days = ((t2 - t1) / (24 * 3600)).round(2)
1280
+ hours = ((t2 - t1) / 3600).round(2)
1281
+ minutes = ((t2 - t1) / 60).round(2)
1282
+
1283
+ if days > 1
1284
+ show = "In #{days} days"
1285
+ elsif days < 1 && hours > 1
1286
+ show = "In #{hours} hours"
1287
+ elsif minutes > 0
1288
+ show = "In #{minutes} minutes"
1289
+ else
1290
+ show = 'Already done'
1291
+ end
1292
+
1293
+ if (t1 - vm['STIME'].to_i).to_i > d['WARNING'].to_i
1294
+ "#{show} *"
1295
+ else
1296
+ show
1297
+ end
1207
1298
  end
1208
1299
  end.show([vm_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten,
1209
1300
  {})
1210
1301
  end
1211
1302
 
1303
+ if !options[:all]
1304
+ vm.delete_element('/VM/USER_TEMPLATE/SCHED_ACTION')
1305
+ end
1306
+
1212
1307
  if vm.has_elements?('/VM/USER_TEMPLATE')
1213
1308
  puts
1214
1309
 
1215
- if !options[:all]
1216
- vm.delete_element('/VM/USER_TEMPLATE/SCHED_ACTION')
1217
- end
1218
-
1219
1310
  CLIHelper.print_header(str_h1 % 'USER TEMPLATE', false)
1220
1311
  puts vm.template_like_str('USER_TEMPLATE')
1221
1312
  end