morpheus-cli 2.10.3 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +5 -96
  3. data/lib/morpheus/api/api_client.rb +23 -1
  4. data/lib/morpheus/api/checks_interface.rb +106 -0
  5. data/lib/morpheus/api/incidents_interface.rb +102 -0
  6. data/lib/morpheus/api/monitoring_apps_interface.rb +47 -0
  7. data/lib/morpheus/api/monitoring_contacts_interface.rb +47 -0
  8. data/lib/morpheus/api/monitoring_groups_interface.rb +47 -0
  9. data/lib/morpheus/api/monitoring_interface.rb +36 -0
  10. data/lib/morpheus/api/option_type_lists_interface.rb +47 -0
  11. data/lib/morpheus/api/option_types_interface.rb +47 -0
  12. data/lib/morpheus/api/roles_interface.rb +0 -1
  13. data/lib/morpheus/api/setup_interface.rb +19 -9
  14. data/lib/morpheus/cli.rb +20 -1
  15. data/lib/morpheus/cli/accounts.rb +8 -3
  16. data/lib/morpheus/cli/app_templates.rb +19 -11
  17. data/lib/morpheus/cli/apps.rb +52 -37
  18. data/lib/morpheus/cli/cli_command.rb +229 -53
  19. data/lib/morpheus/cli/cli_registry.rb +48 -40
  20. data/lib/morpheus/cli/clouds.rb +55 -26
  21. data/lib/morpheus/cli/command_error.rb +12 -0
  22. data/lib/morpheus/cli/credentials.rb +68 -26
  23. data/lib/morpheus/cli/curl_command.rb +98 -0
  24. data/lib/morpheus/cli/dashboard_command.rb +2 -7
  25. data/lib/morpheus/cli/deployments.rb +4 -4
  26. data/lib/morpheus/cli/deploys.rb +1 -2
  27. data/lib/morpheus/cli/dot_file.rb +5 -8
  28. data/lib/morpheus/cli/error_handler.rb +179 -15
  29. data/lib/morpheus/cli/groups.rb +21 -13
  30. data/lib/morpheus/cli/hosts.rb +220 -110
  31. data/lib/morpheus/cli/instance_types.rb +2 -2
  32. data/lib/morpheus/cli/instances.rb +257 -167
  33. data/lib/morpheus/cli/key_pairs.rb +15 -9
  34. data/lib/morpheus/cli/library.rb +673 -27
  35. data/lib/morpheus/cli/license.rb +2 -2
  36. data/lib/morpheus/cli/load_balancers.rb +4 -4
  37. data/lib/morpheus/cli/log_level_command.rb +6 -4
  38. data/lib/morpheus/cli/login.rb +17 -3
  39. data/lib/morpheus/cli/logout.rb +25 -11
  40. data/lib/morpheus/cli/man_command.rb +388 -0
  41. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  42. data/lib/morpheus/cli/mixins/monitoring_helper.rb +434 -0
  43. data/lib/morpheus/cli/mixins/print_helper.rb +620 -112
  44. data/lib/morpheus/cli/mixins/provisioning_helper.rb +1 -1
  45. data/lib/morpheus/cli/monitoring_apps_command.rb +29 -0
  46. data/lib/morpheus/cli/monitoring_checks_command.rb +427 -0
  47. data/lib/morpheus/cli/monitoring_contacts_command.rb +373 -0
  48. data/lib/morpheus/cli/monitoring_groups_command.rb +29 -0
  49. data/lib/morpheus/cli/monitoring_incidents_command.rb +711 -0
  50. data/lib/morpheus/cli/option_types.rb +10 -1
  51. data/lib/morpheus/cli/recent_activity_command.rb +2 -5
  52. data/lib/morpheus/cli/remote.rb +874 -134
  53. data/lib/morpheus/cli/roles.rb +54 -27
  54. data/lib/morpheus/cli/security_group_rules.rb +2 -2
  55. data/lib/morpheus/cli/security_groups.rb +23 -19
  56. data/lib/morpheus/cli/set_prompt_command.rb +50 -0
  57. data/lib/morpheus/cli/shell.rb +222 -157
  58. data/lib/morpheus/cli/tasks.rb +19 -15
  59. data/lib/morpheus/cli/users.rb +27 -17
  60. data/lib/morpheus/cli/version.rb +1 -1
  61. data/lib/morpheus/cli/virtual_images.rb +28 -13
  62. data/lib/morpheus/cli/whoami.rb +131 -52
  63. data/lib/morpheus/cli/workflows.rb +24 -9
  64. data/lib/morpheus/formatters.rb +195 -3
  65. data/lib/morpheus/logging.rb +86 -0
  66. data/lib/morpheus/terminal.rb +371 -0
  67. data/scripts/generate_morpheus_commands_help.morpheus +60 -0
  68. metadata +21 -2
@@ -52,7 +52,7 @@ class Morpheus::Cli::InstanceTypes
52
52
  if instance_type.nil?
53
53
  puts yellow,"No instance type found by name #{name}.",reset
54
54
  else
55
- print "\n" ,cyan, bold, "Instance Type Details\n","==================", reset, "\n\n"
55
+ print_h1 "Instance Type Details"
56
56
  versions = instance_type['versions'].join(', ')
57
57
  print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
58
58
  layout_names = instance_type['instanceTypeLayouts'].collect { |layout| layout['name'] }.uniq.sort
@@ -97,7 +97,7 @@ class Morpheus::Cli::InstanceTypes
97
97
  end
98
98
 
99
99
  instance_types = json_response['instanceTypes']
100
- print "\n" ,cyan, bold, "Morpheus Instance Types\n","==================", reset, "\n\n"
100
+ print_h1 "Morpheus Instance Types"
101
101
  if instance_types.empty?
102
102
  puts yellow,"No instance types currently configured.",reset
103
103
  else
@@ -11,7 +11,7 @@ class Morpheus::Cli::Instances
11
11
  include Morpheus::Cli::CliCommand
12
12
  include Morpheus::Cli::ProvisioningHelper
13
13
 
14
- register_subcommands :list, :get, :add, :update, :remove, :stats, :stop, :start, :restart, :suspend, :eject, :backup, :backups, :stop_service, :start_service, :restart_service, :resize, :clone, :envs, :setenv, :delenv, :security_groups, :apply_security_groups, :firewall_enable, :firewall_disable, :run_workflow, :import_snapshot, :console, :status_check
14
+ register_subcommands :list, :get, :add, :update, :remove, :logs, :stats, :stop, :start, :restart, :suspend, :eject, :backup, :backups, :stop_service, :start_service, :restart_service, :resize, :clone, :envs, :setenv, :delenv, :security_groups, :apply_security_groups, :firewall_enable, :firewall_disable, :run_workflow, :import_snapshot, :console, :status_check
15
15
  alias_subcommand :details, :get
16
16
  set_default_subcommand :list
17
17
 
@@ -83,8 +83,7 @@ class Morpheus::Cli::Instances
83
83
  end
84
84
  json_response = @instances_interface.create(payload)
85
85
  if options[:json]
86
- print JSON.pretty_generate(json_response)
87
- print "\n"
86
+ puts as_json(json_response, options)
88
87
  else
89
88
  instance_name = json_response["instance"]["name"]
90
89
  print_green_success "Provisioning instance #{instance_name}"
@@ -145,8 +144,7 @@ class Morpheus::Cli::Instances
145
144
  json_response = @instances_interface.update(instance["id"], payload)
146
145
 
147
146
  if options[:json]
148
- print JSON.pretty_generate(json_response)
149
- print "\n"
147
+ puts as_json(json_response, options)
150
148
  else
151
149
  print_green_success "Updated instance #{instance['name']}"
152
150
  list([])
@@ -179,7 +177,7 @@ class Morpheus::Cli::Instances
179
177
  end
180
178
  if options[:json]
181
179
  mock_json = {status: instance['status'], exit: exit_code}
182
- out << JSON.pretty_generate(mock_json)
180
+ out << as_json(mock_json, options)
183
181
  out << "\n"
184
182
  elsif !options[:quiet]
185
183
  out << cyan
@@ -195,7 +193,7 @@ class Morpheus::Cli::Instances
195
193
  options = {}
196
194
  optparse = OptionParser.new do|opts|
197
195
  opts.banner = subcommand_usage("[name]")
198
- build_common_options(opts, options, [:json, :dry_run, :remote])
196
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
199
197
  end
200
198
  optparse.parse!(args)
201
199
  if args.count < 1
@@ -203,33 +201,40 @@ class Morpheus::Cli::Instances
203
201
  exit 1
204
202
  end
205
203
  connect(options)
204
+ ids = args
205
+ id_list = parse_id_list(args)
206
+ return run_command_for_each_arg(id_list) do |arg|
207
+ _stats(arg, options)
208
+ end
209
+ end
210
+
211
+ def _stats(arg, options)
206
212
  begin
207
- instance = find_instance_by_name_or_id(args[0])
213
+ instance = find_instance_by_name_or_id(arg)
208
214
  if options[:dry_run]
209
215
  print_dry_run @instances_interface.dry.get(instance['id'])
210
- return
216
+ return 0
211
217
  end
212
218
  json_response = @instances_interface.get(instance['id'])
213
219
  if options[:json]
214
- print JSON.pretty_generate(json_response), "\n"
215
- return
220
+ puts as_json(json_response, options)
221
+ return 0
222
+ elsif options[:yaml]
223
+ if options[:include_fields]
224
+ json_response = {"stats" => filter_data(json_response["stats"], options[:include_fields]) }
225
+ end
226
+ puts as_yaml(json_response, options)
227
+ return 0
216
228
  end
217
229
  instance = json_response['instance']
218
230
  stats = json_response['stats'] || {}
219
- print "\n" ,cyan, bold, "Instance Stats: #{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
220
- puts "Status: #{format_instance_status(instance)}"
221
- print "\n"
222
- if ((stats['maxMemory'].to_i != 0) || (stats['maxStorage'].to_i != 0))
223
- # stats_map = {}
224
- # stats_map[:memory] = "#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}"
225
- # stats_map[:storage] = "#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}"
226
- # stats_map[:cpu] = "#{stats['usedCpu'].to_f.round(2)}%"
227
- # tp [stats_map], :memory,:storage,:cpu
228
- # print "\n"
229
- print_stats_usage(stats)
230
- else
231
- print cyan, "No data.", "\n", reset
232
- end
231
+ title = "Instance Stats: #{instance['name']} (#{instance['instanceType']['name']})"
232
+ print_h1 title
233
+ puts cyan + "Status: ".rjust(12) + format_instance_status(instance).to_s
234
+ puts cyan + "Nodes: ".rjust(12) + (instance['containers'] ? instance['containers'].count : '').to_s
235
+ # print "\n"
236
+ #print_h2 "Instance Usage"
237
+ print_stats_usage(stats)
233
238
  print reset, "\n"
234
239
  rescue RestClient::Exception => e
235
240
  print_rest_exception(e, options)
@@ -281,7 +286,7 @@ class Morpheus::Cli::Instances
281
286
  opts.on( '-n', '--node NODE_ID', "Scope logs to specific Container or VM" ) do |node_id|
282
287
  options[:node_id] = node_id.to_i
283
288
  end
284
- build_common_options(opts, options, [:list, :json, :dry_run, :remote])
289
+ build_common_options(opts, options, [:list, :json, :csv, :dry_run, :remote])
285
290
  end
286
291
  optparse.parse!(args)
287
292
  if args.count < 1
@@ -295,32 +300,52 @@ class Morpheus::Cli::Instances
295
300
  if options[:node_id] && container_ids.include?(options[:node_id])
296
301
  container_ids = [options[:node_id]]
297
302
  end
298
- query_params = { max: options[:max] || 100, offset: options[:offset] || 0, query: options[:phrase]}
303
+ params = {}
304
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
305
+ params[k] = options[k] unless options[k].nil?
306
+ end
307
+ params[:query] = params.delete(:phrase) unless params[:phrase].nil?
299
308
  if options[:dry_run]
300
- print_dry_run @logs_interface.dry.container_logs(container_ids, query_params)
309
+ print_dry_run @logs_interface.dry.server_logs([server['id']], params)
301
310
  return
302
311
  end
303
- logs = @logs_interface.container_logs(container_ids, query_params)
312
+ if options[:dry_run]
313
+ print_dry_run @logs_interface.dry.container_logs(container_ids, params)
314
+ return
315
+ end
316
+ logs = @logs_interface.container_logs(container_ids, params)
317
+ output = ""
304
318
  if options[:json]
305
- puts logs
319
+ output << as_json(logs, options)
306
320
  else
307
- logs['data'].reverse.each do |log_entry|
308
- log_level = ''
309
- case log_entry['level']
310
- when 'INFO'
311
- log_level = "#{blue}#{bold}INFO#{reset}"
312
- when 'DEBUG'
313
- log_level = "#{white}#{bold}DEBUG#{reset}"
314
- when 'WARN'
315
- log_level = "#{yellow}#{bold}WARN#{reset}"
316
- when 'ERROR'
317
- log_level = "#{red}#{bold}ERROR#{reset}"
318
- when 'FATAL'
319
- log_level = "#{red}#{bold}FATAL#{reset}"
321
+ title = "Instance Logs: #{instance['name']} (#{instance['instanceType'] ? instance['instanceType']['name'] : ''})"
322
+ subtitles = []
323
+ if params[:query]
324
+ subtitles << "Search: #{params[:query]}".strip
325
+ end
326
+ # todo: startMs, endMs, sorts insteaad of sort..etc
327
+ print_h1 title, subtitles
328
+ if logs['data'].empty?
329
+ output << "#{cyan}No logs found.#{reset}\n"
330
+ else
331
+ logs['data'].reverse.each do |log_entry|
332
+ log_level = ''
333
+ case log_entry['level']
334
+ when 'INFO'
335
+ log_level = "#{blue}#{bold}INFO#{reset}"
336
+ when 'DEBUG'
337
+ log_level = "#{white}#{bold}DEBUG#{reset}"
338
+ when 'WARN'
339
+ log_level = "#{yellow}#{bold}WARN#{reset}"
340
+ when 'ERROR'
341
+ log_level = "#{red}#{bold}ERROR#{reset}"
342
+ when 'FATAL'
343
+ log_level = "#{red}#{bold}FATAL#{reset}"
344
+ end
345
+ output << "[#{log_entry['ts']}] #{log_level} - #{log_entry['message']}\n"
320
346
  end
321
- puts "[#{log_entry['ts']}] #{log_level} - #{log_entry['message']}"
322
347
  end
323
- print reset,"\n"
348
+ print output, reset, "\n"
324
349
  end
325
350
  rescue RestClient::Exception => e
326
351
  print_rest_exception(e, options)
@@ -332,7 +357,7 @@ class Morpheus::Cli::Instances
332
357
  options = {}
333
358
  optparse = OptionParser.new do|opts|
334
359
  opts.banner = subcommand_usage("[name]")
335
- build_common_options(opts, options, [:json, :dry_run, :remote])
360
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
336
361
  end
337
362
  optparse.parse!(args)
338
363
  if args.count < 1
@@ -340,54 +365,67 @@ class Morpheus::Cli::Instances
340
365
  exit 1
341
366
  end
342
367
  connect(options)
368
+ id_list = parse_id_list(args)
369
+ return run_command_for_each_arg(id_list) do |arg|
370
+ _get(arg, options)
371
+ end
372
+ end
373
+
374
+ def _get(arg, options)
343
375
  begin
344
376
  if options[:dry_run]
345
- if args[0].to_s =~ /\A\d{1,}\Z/
346
- print_dry_run @instances_interface.dry.get(args[0].to_i)
377
+ if arg.to_s =~ /\A\d{1,}\Z/
378
+ print_dry_run @instances_interface.dry.get(arg.to_i)
347
379
  else
348
- print_dry_run @instances_interface.dry.get({name:args[0]})
380
+ print_dry_run @instances_interface.dry.get({name:arg})
349
381
  end
350
382
  return
351
383
  end
352
- instance = find_instance_by_name_or_id(args[0])
384
+ instance = find_instance_by_name_or_id(arg)
353
385
  json_response = @instances_interface.get(instance['id'])
354
386
  if options[:json]
355
- print JSON.pretty_generate(json_response), "\n"
356
- return
387
+ if options[:include_fields]
388
+ json_response = {"instance" => filter_data(json_response["instance"], options[:include_fields]) }
389
+ end
390
+ puts as_json(json_response, options)
391
+ return 0
392
+ elsif options[:yaml]
393
+ if options[:include_fields]
394
+ json_response = {"instance" => filter_data(json_response["instance"], options[:include_fields]) }
395
+ end
396
+ puts as_yaml(json_response, options)
397
+ return 0
398
+ end
399
+
400
+ if options[:csv]
401
+ puts records_as_csv([json_response['instance']], options)
402
+ return 0
357
403
  end
358
404
  instance = json_response['instance']
359
405
  stats = json_response['stats'] || {}
360
406
  # load_balancers = stats = json_response['loadBalancers'] || {}
361
407
 
362
- connection_string = ''
363
- if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
364
- connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
365
- end
366
-
367
- print "\n" ,cyan, bold, "Instance Details\n","==================", reset, "\n\n"
408
+ print_h1 "Instance Details"
368
409
  print cyan
369
- puts "ID: #{instance['id']}"
370
- puts "Name: #{instance['name']}"
371
- puts "Description: #{instance['description']}"
372
- puts "Group: #{instance['group'] ? instance['group']['name'] : ''}"
373
- puts "Cloud: #{instance['cloud'] ? instance['cloud']['name'] : ''}"
374
- puts "Type: #{instance['instanceType']['name']}"
375
- puts "Plan: #{instance['plan'] ? instance['plan']['name'] : ''}"
376
- puts "Environment: #{instance['instanceContext']}"
377
- puts "Nodes: #{instance['containers'] ? instance['containers'].count : 0}"
378
- puts "Connection: #{connection_string}"
379
- #puts "Account: #{instance['account'] ? instance['account']['name'] : ''}"
380
- puts "Status: #{format_instance_status(instance)}"
381
- if ((stats['maxMemory'].to_i != 0) || (stats['maxStorage'].to_i != 0))
382
- print "\n"
383
- # stats_map = {}
384
- # stats_map[:memory] = "#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}"
385
- # stats_map[:storage] = "#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}"
386
- # stats_map[:cpu] = "#{stats['usedCpu'].to_f.round(2)}%"
387
- # tp [stats_map], :memory,:storage,:cpu
410
+ description_cols = {
411
+ "ID" => 'id',
412
+ "Name" => 'name',
413
+ "Description" => 'description',
414
+ "Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
415
+ "Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
416
+ "Type" => lambda {|it| it['instanceType']['name'] },
417
+ "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
418
+ "Environment" => 'instanceContext',
419
+ "Nodes" => lambda {|it| it['containers'] ? it['containers'].count : 0 },
420
+ "Connection" => lambda {|it| format_instance_connection_string(it) },
421
+ #"Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
422
+ "Status" => lambda {|it| format_instance_status(it) }
423
+ }
424
+ print_description_list(description_cols, instance)
425
+
426
+ if (stats)
427
+ print_h2 "Instance Usage"
388
428
  print_stats_usage(stats)
389
- else
390
- # print cyan, "No data.", "\n", reset
391
429
  end
392
430
  print reset, "\n"
393
431
 
@@ -419,19 +457,14 @@ class Morpheus::Cli::Instances
419
457
  end
420
458
  json_response = @instances_interface.backups(instance['id'], params)
421
459
  if options[:json]
422
- print JSON.pretty_generate(json_response), "\n"
460
+ puts as_json(json_response, options)
423
461
  return
424
462
  end
425
463
  backups = json_response['backups']
426
464
  stats = json_response['stats'] || {}
427
465
  # load_balancers = stats = json_response['loadBalancers'] || {}
428
466
 
429
- print "\n" ,cyan, bold, "Instance Backups\n","==================", reset, "\n\n"
430
- print cyan
431
- puts "ID: #{instance['id']}"
432
- puts "Name: #{instance['name']}"
433
- print "\n"
434
- puts "Backups:"
467
+ print_h1 "Instance Backups: #{instance['name']} (#{instance['instanceType']['name']})"
435
468
  backup_rows = backups.collect {|it| {id: it['id'], name: it['name'], dateCreated: it['dateCreated']} }
436
469
  print cyan
437
470
  tp backup_rows, [
@@ -494,8 +527,7 @@ class Morpheus::Cli::Instances
494
527
  end
495
528
  json_response = @instances_interface.clone(instance['id'], payload)
496
529
  if options[:json]
497
- print JSON.pretty_generate(json_response)
498
- print "\n"
530
+ puts as_json(json_response, options)
499
531
  else
500
532
  print_green_success "Cloning instance #{instance['name']} to '#{payload['name']}'"
501
533
  end
@@ -527,16 +559,17 @@ class Morpheus::Cli::Instances
527
559
  end
528
560
  json_response = @instances_interface.get_envs(instance['id'])
529
561
  if options[:json]
530
- print JSON.pretty_generate(json_response), "\n"
562
+ puts as_json(json_response, options)
531
563
  return
532
564
  end
533
- print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
565
+ print_h1 "Instance Envs: #{instance['name']} (#{instance['instanceType']['name']})"
566
+ print cyan
534
567
  envs = json_response['envs'] || {}
535
568
  if json_response['readOnlyEnvs']
536
569
  envs += json_response['readOnlyEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value'], :export => true}}
537
570
  end
538
571
  tp envs, :name, :value, :export
539
- print "\n" ,cyan, bold, "Imported Envs\n","==================", "\n\n", reset, cyan
572
+ print_h2 "Imported Envs"
540
573
  imported_envs = json_response['importedEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value']}}
541
574
  tp imported_envs
542
575
  print reset, "\n"
@@ -575,7 +608,7 @@ class Morpheus::Cli::Instances
575
608
  end
576
609
  json_response = @instances_interface.create_env(instance['id'], payload)
577
610
  if options[:json]
578
- print JSON.pretty_generate(json_response), "\n"
611
+ puts as_json(json_response, options)
579
612
  return
580
613
  end
581
614
  if !options[:quiet]
@@ -607,7 +640,7 @@ class Morpheus::Cli::Instances
607
640
  end
608
641
  json_response = @instances_interface.del_env(instance['id'], args[1])
609
642
  if options[:json]
610
- print JSON.pretty_generate(json_response), "\n"
643
+ puts as_json(json_response, options)
611
644
  return
612
645
  end
613
646
  if !options[:quiet]
@@ -642,7 +675,7 @@ class Morpheus::Cli::Instances
642
675
  end
643
676
  json_response = @instances_interface.stop(instance['id'])
644
677
  if options[:json]
645
- print JSON.pretty_generate(json_response)
678
+ puts as_json(json_response, options)
646
679
  print "\n"
647
680
  end
648
681
  return
@@ -672,8 +705,8 @@ class Morpheus::Cli::Instances
672
705
  end
673
706
  json_response = @instances_interface.start(instance['id'])
674
707
  if options[:json]
675
- print JSON.pretty_generate(json_response)
676
- print "\n"
708
+ puts as_json(json_response, options)
709
+ return 0
677
710
  end
678
711
  return
679
712
  rescue RestClient::Exception => e
@@ -705,8 +738,7 @@ class Morpheus::Cli::Instances
705
738
  end
706
739
  json_response = @instances_interface.restart(instance['id'])
707
740
  if options[:json]
708
- print JSON.pretty_generate(json_response)
709
- print "\n"
741
+ puts as_json(json_response, options)
710
742
  end
711
743
  return
712
744
  rescue RestClient::Exception => e
@@ -738,10 +770,9 @@ class Morpheus::Cli::Instances
738
770
  end
739
771
  json_response = @instances_interface.suspend(instance['id'])
740
772
  if options[:json]
741
- print JSON.pretty_generate(json_response)
742
- print "\n"
773
+ puts as_json(json_response, options)
743
774
  end
744
- return
775
+ return 0
745
776
  rescue RestClient::Exception => e
746
777
  print_rest_exception(e, options)
747
778
  exit 1
@@ -771,10 +802,9 @@ class Morpheus::Cli::Instances
771
802
  end
772
803
  json_response = @instances_interface.eject(instance['id'])
773
804
  if options[:json]
774
- print JSON.pretty_generate(json_response)
775
- print "\n"
805
+ puts as_json(json_response, options)
776
806
  end
777
- return
807
+ return 0
778
808
  rescue RestClient::Exception => e
779
809
  print_rest_exception(e, options)
780
810
  exit 1
@@ -804,12 +834,11 @@ class Morpheus::Cli::Instances
804
834
  end
805
835
  json_response = @instances_interface.stop(instance['id'],false)
806
836
  if options[:json]
807
- print JSON.pretty_generate(json_response)
808
- print "\n"
837
+ puts as_json(json_response, options)
809
838
  else
810
839
  puts "Stopping service on #{args[0]}"
811
840
  end
812
- return
841
+ return 0
813
842
  rescue RestClient::Exception => e
814
843
  print_rest_exception(e, options)
815
844
  exit 1
@@ -836,12 +865,11 @@ class Morpheus::Cli::Instances
836
865
  end
837
866
  json_response = @instances_interface.start(instance['id'],false)
838
867
  if options[:json]
839
- print JSON.pretty_generate(json_response)
840
- print "\n"
868
+ puts as_json(json_response, options)
841
869
  else
842
870
  puts "Starting service on #{args[0]}"
843
871
  end
844
- return
872
+ return 0
845
873
  rescue RestClient::Exception => e
846
874
  print_rest_exception(e, options)
847
875
  exit 1
@@ -871,8 +899,7 @@ class Morpheus::Cli::Instances
871
899
  end
872
900
  json_response = @instances_interface.restart(instance['id'],false)
873
901
  if options[:json]
874
- print JSON.pretty_generate(json_response)
875
- print "\n"
902
+ puts as_json(json_response, options)
876
903
  else
877
904
  puts "Restarting service on instance #{args[0]}"
878
905
  end
@@ -947,8 +974,8 @@ class Morpheus::Cli::Instances
947
974
  end
948
975
  json_response = @instances_interface.resize(instance['id'], payload)
949
976
  if options[:json]
950
- print JSON.pretty_generate(json_response)
951
- print "\n"
977
+ puts as_json(json_response, options)
978
+ return 0
952
979
  else
953
980
  print_green_success "Resizing instance #{instance['name']}"
954
981
  list([])
@@ -982,12 +1009,12 @@ class Morpheus::Cli::Instances
982
1009
  end
983
1010
  json_response = @instances_interface.backup(instance['id'])
984
1011
  if options[:json]
985
- print JSON.pretty_generate(json_response)
986
- print "\n"
1012
+ puts as_json(json_response, options)
1013
+ return 0
987
1014
  else
988
1015
  puts "Backup initiated."
1016
+ return 0
989
1017
  end
990
- return
991
1018
  rescue RestClient::Exception => e
992
1019
  print_rest_exception(e, options)
993
1020
  exit 1
@@ -1004,7 +1031,7 @@ class Morpheus::Cli::Instances
1004
1031
  opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
1005
1032
  options[:cloud] = val
1006
1033
  end
1007
- build_common_options(opts, options, [:list, :json, :dry_run, :remote])
1034
+ build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
1008
1035
  end
1009
1036
  optparse.parse!(args)
1010
1037
  connect(options)
@@ -1032,8 +1059,26 @@ class Morpheus::Cli::Instances
1032
1059
  end
1033
1060
  json_response = @instances_interface.get(params)
1034
1061
  if options[:json]
1035
- print JSON.pretty_generate(json_response)
1036
- print "\n"
1062
+ if options[:include_fields]
1063
+ json_response = {"instances" => filter_data(json_response["instances"], options[:include_fields]) }
1064
+ end
1065
+ puts as_json(json_response, options)
1066
+ return 0
1067
+ elsif options[:yaml]
1068
+ if options[:include_fields]
1069
+ json_response = {"instances" => filter_data(json_response["instances"], options[:include_fields]) }
1070
+ end
1071
+ puts as_yaml(json_response, options)
1072
+ return 0
1073
+ elsif options[:csv]
1074
+ # merge stats to be nice here..
1075
+ if json_response['instances']
1076
+ all_stats = json_response['stats'] || {}
1077
+ json_response['instances'].each do |it|
1078
+ it['stats'] ||= all_stats[it['id'].to_s] || all_stats[it['id']]
1079
+ end
1080
+ end
1081
+ puts records_as_csv(json_response['instances'], options)
1037
1082
  else
1038
1083
  instances = json_response['instances']
1039
1084
 
@@ -1048,12 +1093,55 @@ class Morpheus::Cli::Instances
1048
1093
  if params[:phrase]
1049
1094
  subtitles << "Search: #{params[:phrase]}".strip
1050
1095
  end
1051
- subtitle = subtitles.join(', ')
1052
- print "\n" ,cyan, bold, title, (subtitle.empty? ? "" : " - #{subtitle}"), "\n", "==================", reset, "\n\n"
1096
+ print_h1 title, subtitles
1053
1097
  if instances.empty?
1054
- puts yellow,"No instances found.",reset
1098
+ print yellow,"No instances found.",reset,"\n"
1055
1099
  else
1056
- print_instances_table(instances)
1100
+ # print_instances_table(instances)
1101
+ # server returns stats in a separate key stats => {"id" => {} }
1102
+ # the id is a string right now..for some reason..
1103
+ all_stats = json_response['stats'] || {}
1104
+ instances.each do |it|
1105
+ if !it['stats']
1106
+ found_stats = all_stats[it['id'].to_s] || all_stats[it['id']]
1107
+ it['stats'] = found_stats # || {}
1108
+ end
1109
+ end
1110
+
1111
+ rows = instances.collect {|instance|
1112
+ stats = instance['stats']
1113
+ cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
1114
+ memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
1115
+ storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
1116
+ row = {
1117
+ id: instance['id'],
1118
+ name: instance['name'],
1119
+ connection: format_instance_connection_string(instance),
1120
+ environment: instance['instanceContext'],
1121
+ nodes: instance['containers'].count,
1122
+ status: format_instance_status(instance, cyan),
1123
+ type: instance['instanceType']['name'],
1124
+ group: !instance['group'].nil? ? instance['group']['name'] : nil,
1125
+ cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil,
1126
+ version: instance['instanceVersion'] ? instance['instanceVersion'] : '',
1127
+ cpu: cpu_usage_str + cyan,
1128
+ memory: memory_usage_str + cyan,
1129
+ storage: storage_usage_str + cyan
1130
+ }
1131
+ row
1132
+ }
1133
+ columns = [:id, :name, :group, :cloud, :type, :version, :environment, :nodes, {:connection => {max_width: 20}}, :status]
1134
+ term_width = current_terminal_width()
1135
+ if term_width > 190
1136
+ columns += [:cpu, :memory, :storage]
1137
+ end
1138
+ # custom pretty table columns ...
1139
+ if options[:include_fields]
1140
+ columns = options[:include_fields]
1141
+ end
1142
+ print cyan
1143
+ print as_pretty_table(rows, columns, options)
1144
+ print reset
1057
1145
  print_results_pagination(json_response)
1058
1146
  end
1059
1147
  print reset,"\n"
@@ -1095,8 +1183,8 @@ class Morpheus::Cli::Instances
1095
1183
  end
1096
1184
  json_response = @instances_interface.destroy(instance['id'],query_params)
1097
1185
  if options[:json]
1098
- print JSON.pretty_generate(json_response)
1099
- print "\n"
1186
+ print as_json(json_response, options), "\n"
1187
+ return
1100
1188
  elsif !options[:quiet]
1101
1189
  list([])
1102
1190
  end
@@ -1126,8 +1214,8 @@ class Morpheus::Cli::Instances
1126
1214
  end
1127
1215
  json_response = @instances_interface.firewall_disable(instance['id'])
1128
1216
  if options[:json]
1129
- print JSON.pretty_generate(json_response)
1130
- print "\n"
1217
+ print as_json(json_response, options), "\n"
1218
+ return
1131
1219
  elsif !options[:quiet]
1132
1220
  security_groups([args[0]])
1133
1221
  end
@@ -1157,8 +1245,8 @@ class Morpheus::Cli::Instances
1157
1245
  end
1158
1246
  json_response = @instances_interface.firewall_enable(instance['id'])
1159
1247
  if options[:json]
1160
- print JSON.pretty_generate(json_response)
1161
- print "\n"
1248
+ print as_json(json_response, options), "\n"
1249
+ return
1162
1250
  elsif !options[:quiet]
1163
1251
  security_groups([args[0]])
1164
1252
  end
@@ -1188,21 +1276,24 @@ class Morpheus::Cli::Instances
1188
1276
  end
1189
1277
  json_response = @instances_interface.security_groups(instance['id'])
1190
1278
  if options[:json]
1191
- print JSON.pretty_generate(json_response)
1192
- print "\n"
1279
+ print as_json(json_response, options), "\n"
1193
1280
  return
1194
1281
  end
1195
1282
  securityGroups = json_response['securityGroups']
1196
- print "\n" ,cyan, bold, "Morpheus Security Groups for Instance: #{instance['name']}\n","==================", reset, "\n\n"
1197
- print cyan, "Firewall Enabled=#{json_response['firewallEnabled']}\n\n"
1283
+ print_h1 "Morpheus Security Groups for Instance: #{instance['name']}"
1284
+ print cyan
1285
+ print_description_list({"Firewall Enabled" => lambda {|it| format_boolean it['firewallEnabled'] } }, json_response)
1286
+ #print cyan, "Firewall Enabled=#{json_response['firewallEnabled']}\n\n"
1198
1287
  if securityGroups.empty?
1199
- puts yellow,"No security groups currently applied.",reset
1288
+ print yellow,"\n","No security groups currently applied.",reset,"\n"
1200
1289
  else
1290
+ print "\n"
1201
1291
  securityGroups.each do |securityGroup|
1202
1292
  print cyan, "= #{securityGroup['id']} (#{securityGroup['name']}) - (#{securityGroup['description']})\n"
1203
1293
  end
1294
+ print "\n"
1204
1295
  end
1205
- print reset,"\n"
1296
+ print reset, "\n"
1206
1297
 
1207
1298
  rescue RestClient::Exception => e
1208
1299
  print_rest_exception(e, options)
@@ -1245,8 +1336,7 @@ class Morpheus::Cli::Instances
1245
1336
  end
1246
1337
  json_response = @instances_interface.apply_security_groups(instance['id'], payload)
1247
1338
  if options[:json]
1248
- print JSON.pretty_generate(json_response)
1249
- print "\n"
1339
+ print as_json(json_response, options), "\n"
1250
1340
  return
1251
1341
  end
1252
1342
  if !options[:quiet]
@@ -1303,8 +1393,8 @@ class Morpheus::Cli::Instances
1303
1393
  end
1304
1394
  json_response = @instances_interface.workflow(instance['id'],workflow['id'], workflow_payload)
1305
1395
  if options[:json]
1306
- print JSON.pretty_generate(json_response)
1307
- print "\n"
1396
+ print as_json(json_response, options), "\n"
1397
+ return
1308
1398
  else
1309
1399
  puts "Running workflow..."
1310
1400
  end
@@ -1358,12 +1448,11 @@ class Morpheus::Cli::Instances
1358
1448
  end
1359
1449
  json_response = @instances_interface.import_snapshot(instance['id'], payload)
1360
1450
  if options[:json]
1361
- print JSON.pretty_generate(json_response)
1362
- print "\n"
1451
+ puts as_json(json_response, options)
1363
1452
  else
1364
1453
  puts "Snapshot import initiated."
1365
1454
  end
1366
- return
1455
+ return 0
1367
1456
  rescue RestClient::Exception => e
1368
1457
  print_rest_exception(e, options)
1369
1458
  exit 1
@@ -1405,30 +1494,25 @@ class Morpheus::Cli::Instances
1405
1494
  end
1406
1495
  end
1407
1496
 
1408
- def print_instances_table(instances, opts={})
1409
- table_color = opts[:color] || cyan
1410
- rows = instances.collect do |instance|
1411
- connection_string = ''
1412
- if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
1413
- connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
1414
- end
1415
- {
1416
- id: instance['id'],
1417
- name: instance['name'],
1418
- connection: connection_string,
1419
- environment: instance['instanceContext'],
1420
- nodes: instance['containers'].count,
1421
- status: format_instance_status(instance, table_color),
1422
- type: instance['instanceType']['name'],
1423
- group: !instance['group'].nil? ? instance['group']['name'] : nil,
1424
- cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil
1425
- }
1426
- end
1427
-
1428
- print table_color
1429
- tp rows, :id, :name, :group, :cloud, :type, :environment, :nodes, :connection, :status
1430
- print reset
1431
- end
1497
+ # def print_instances_table(instances, opts={})
1498
+ # table_color = opts[:color] || cyan
1499
+ # rows = instances.collect {|instance|
1500
+ # {
1501
+ # id: instance['id'],
1502
+ # name: instance['name'],
1503
+ # connection: format_instance_connection_string(instance),
1504
+ # environment: instance['instanceContext'],
1505
+ # nodes: instance['containers'].count,
1506
+ # status: format_instance_status(instance, table_color),
1507
+ # type: instance['instanceType']['name'],
1508
+ # group: !instance['group'].nil? ? instance['group']['name'] : nil,
1509
+ # cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil
1510
+ # }
1511
+ # }
1512
+ # print table_color
1513
+ # tp rows, :id, :name, :group, :cloud, :type, :environment, :nodes, :connection, :status
1514
+ # print reset
1515
+ # end
1432
1516
 
1433
1517
  def format_instance_status(instance, return_color=cyan)
1434
1518
  out = ""
@@ -1445,6 +1529,12 @@ class Morpheus::Cli::Instances
1445
1529
  out
1446
1530
  end
1447
1531
 
1532
+ def format_instance_connection_string(instance)
1533
+ if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
1534
+ connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
1535
+ end
1536
+ end
1537
+
1448
1538
  def clone_instance_option_types(connected=true)
1449
1539
  [
1450
1540
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for the new instance'},