morpheus-cli 8.0.1 → 8.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8074c5d41cd8ca2aa6f199a0b85f22f7c2b8d3647b2788604d42424b7abbd9b
4
- data.tar.gz: 8176b21a71b63466b537ca4d43933e06411ae374cbb159ab451f4e37042299e5
3
+ metadata.gz: b071ad7a069db88e11023de144dad8ad640f49b6a18becdfa60cd1e04312397f
4
+ data.tar.gz: b1deba83d4decb51b824fabfca0d8a615dbd17e6df7e07296de3a8dc3606f945
5
5
  SHA512:
6
- metadata.gz: 05414d569b3e9d323ca0ebf0ff86778e9656f84b92af1a2e6520e826351dc444eb1c6d6721ef7137ffbe603be703832dcd15f4e14c31f28005b6de7c2cc454f8
7
- data.tar.gz: fca09ddb93cf6cc58401d1652803a61d220fe9999427a931b0fed515c5a8e0a2933013299323722739a7f65c9b9b42edffe4a62972cad85e9b5651a4fcded2df
6
+ metadata.gz: '04509b5731b2f5713189498b3a166b62735911c7c178d6480c5d54d4fd68827ef16f21431d5b7c49ce2209dca14dc402c65dc59e90268979b310855a08705598'
7
+ data.tar.gz: 179f4442f70f2f634746a11211f435ae119abd9dc0839e06c16142018afa3809bcdc995cc96ca3967734d06e578b80f7a6a680dbe3ba7c4bf643cc6318cb03d2
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 8.0.1
3
+ RUN gem install morpheus-cli -v 8.0.3
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -1278,7 +1278,7 @@ module Morpheus
1278
1278
  elsif options[:remote_url]
1279
1279
  credentials = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url)
1280
1280
  unless options[:skip_login]
1281
- @wallet = credentials.request_credentials(options, @do_save_credentials)
1281
+ @wallet = credentials.request_credentials(options.merge({dry_run:false}), @do_save_credentials)
1282
1282
  end
1283
1283
  else
1284
1284
  credentials = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url)
@@ -1293,7 +1293,7 @@ module Morpheus
1293
1293
 
1294
1294
  if @wallet.nil? || @wallet['access_token'].nil?
1295
1295
  unless options[:skip_login]
1296
- @wallet = credentials.request_credentials(options, @do_save_credentials)
1296
+ @wallet = credentials.request_credentials(options.merge({dry_run:false}), @do_save_credentials)
1297
1297
  end
1298
1298
  end
1299
1299
 
@@ -1767,7 +1767,22 @@ module Morpheus
1767
1767
  output = records.collect { |record|
1768
1768
  options[:select_fields].collect { |field|
1769
1769
  value = get_object_value(record, field)
1770
- value.is_a?(String) ? value : JSON.fast_generate(value)
1770
+ if value.is_a?(String)
1771
+ value
1772
+ else
1773
+ if options[:json]
1774
+ as_json(value, options)
1775
+ elsif options[:yaml]
1776
+ output = as_yaml(value, options)
1777
+ elsif options[:csv]
1778
+ as_csv(value, nil, options)
1779
+ else
1780
+ # default behavior
1781
+ # value.is_a?(String) ? value : as_json(value, options)
1782
+ do_pretty = options.key?(:pretty_json) ? options[:pretty_json] : false # or true?
1783
+ do_pretty ? JSON.pretty_generate(value) : JSON.fast_generate(value)
1784
+ end
1785
+ end
1771
1786
  }.join(options[:delim] || ",")
1772
1787
  }.join(options[:newline] || "\n")
1773
1788
  elsif options[:json]
@@ -6,6 +6,7 @@ class Morpheus::Cli::Clusters
6
6
  include Morpheus::Cli::ProcessesHelper
7
7
  include Morpheus::Cli::WhoamiHelper
8
8
  include Morpheus::Cli::AccountsHelper
9
+ include Morpheus::Cli::ExecutionRequestHelper
9
10
 
10
11
  register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
11
12
  register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
@@ -607,7 +608,7 @@ class Morpheus::Cli::Clusters
607
608
  end
608
609
 
609
610
  # Controller type
610
- server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'}
611
+ server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'} unless ['kubernetes-cluster', 'mvm-cluster'].include?(cluster_type_code)
611
612
  controller_provision_type = nil
612
613
  resource_pool = nil
613
614
 
@@ -802,6 +803,9 @@ class Morpheus::Cli::Clusters
802
803
  opts.on('--managed [on|off]', String, "Can be used to enable / disable managed cluster. Default is on") do |val|
803
804
  options[:managed] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
804
805
  end
806
+ opts.on('--useAgent [on|off]', String, "Use the Agent to relay communications for the Kubernetes API instead of direct.") do |val|
807
+ options[:useAgent] = val.to_s
808
+ end
805
809
  opts.on('--autoRecoverPowerState [on|off]', String, "Automatically Power On VMs") do |val|
806
810
  options[:autoRecoverPowerState] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
807
811
  end
@@ -855,6 +859,7 @@ class Morpheus::Cli::Clusters
855
859
  cluster_payload['refresh'] = options[:refresh] if options[:refresh] == true
856
860
  cluster_payload['tenant'] = options[:tenant] if !options[:tenant].nil?
857
861
  cluster_payload['integrations'] = options[:integrations] if !options[:integrations].nil?
862
+ cluster_payload['useAgent'] = options[:useAgent] if !options[:useAgent].nil?
858
863
  payload = {"cluster" => cluster_payload}
859
864
  end
860
865
 
@@ -3004,6 +3009,12 @@ class Morpheus::Cli::Clusters
3004
3009
  options = {}
3005
3010
  optparse = Morpheus::Cli::OptionParser.new do |opts|
3006
3011
  opts.banner = subcommand_usage( "[cluster] [options]")
3012
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
3013
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
3014
+ end
3015
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
3016
+ options[:no_refresh] = true
3017
+ end
3007
3018
  build_option_type_options(opts, options, add_datastore_option_types)
3008
3019
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
3009
3020
  opts.footer = "Add datastore to a cluster.\n" +
@@ -3059,11 +3070,19 @@ class Morpheus::Cli::Clusters
3059
3070
  json_response = @clusters_interface.create_datastore(cluster['id'], payload)
3060
3071
  if options[:json]
3061
3072
  puts as_json(json_response)
3062
- elsif json_response['success']
3063
- if json_response['msg'] == nil
3064
- print_green_success "Added datastore to cluster #{cluster['name']}"
3073
+ else
3074
+ if json_response['success']
3075
+ if json_response['msg'] == nil
3076
+ print_green_success "Adding datastore to cluster #{cluster['name']}"
3077
+ else
3078
+ print_green_success json_response['msg']
3079
+ end
3080
+ execution_id = json_response['executionId']
3081
+ if !options[:no_refresh] && execution_id
3082
+ wait_for_execution_request(json_response['executionId'], options.merge({waiting_status:['new', 'pending', 'executing']}))
3083
+ end
3065
3084
  else
3066
- print_green_success json_response['msg']
3085
+ print_red_alert "Failed to create cluster datastore #{json_response['msg']}"
3067
3086
  end
3068
3087
  end
3069
3088
  return 0
@@ -3074,6 +3093,7 @@ class Morpheus::Cli::Clusters
3074
3093
  end
3075
3094
 
3076
3095
  def remove_datastore(args)
3096
+ default_refresh_interval = 5
3077
3097
  params = {}
3078
3098
  options = {}
3079
3099
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -3081,6 +3101,12 @@ class Morpheus::Cli::Clusters
3081
3101
  opts.on( '-f', '--force', "Force Delete" ) do
3082
3102
  params[:force] = 'on'
3083
3103
  end
3104
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
3105
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
3106
+ end
3107
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
3108
+ options[:no_refresh] = true
3109
+ end
3084
3110
  build_standard_remove_options(opts, options)
3085
3111
  opts.footer = "Delete a datastore from a cluster.\n" +
3086
3112
  "[cluster] is required. This is the name or id of an existing cluster.\n" +
@@ -3114,12 +3140,18 @@ class Morpheus::Cli::Clusters
3114
3140
  return
3115
3141
  end
3116
3142
  json_response = @clusters_interface.destroy_datastore(cluster['id'], datastore['id'], params)
3117
- render_response(json_response, options) do
3118
- msg = "Datastore #{datastore['name']} is being removed from cluster #{cluster['name']}..."
3119
- if json_response['msg']
3120
- msg = json_response['msg']
3143
+ if options[:json]
3144
+ puts as_json(json_response)
3145
+ else
3146
+ if json_response['success']
3147
+ print_green_success "Datastore #{datastore['name']} is being removed from cluster #{cluster['name']}"
3148
+ execution_id = json_response['executionId']
3149
+ if !options[:no_refresh] && execution_id
3150
+ wait_for_execution_request(execution_id, options.merge({waiting_status:['new', 'pending', 'executing']}))
3151
+ end
3152
+ else
3153
+ print_red_alert "Failed to remove cluster datastore #{json_response['msg']}"
3121
3154
  end
3122
- print_green_success msg
3123
3155
  end
3124
3156
  return 0, nil
3125
3157
  end
@@ -3752,7 +3784,7 @@ class Morpheus::Cli::Clusters
3752
3784
  subtitles << " Process ID: #{process_id}"
3753
3785
  subtitles += parse_list_subtitles(options)
3754
3786
  print_h1 title, subtitles, options
3755
- print_process_details(process)
3787
+ print_process_details(process, options)
3756
3788
 
3757
3789
  print_h2 "Process Events", options
3758
3790
  process_events = process['events'] || process['processEvents'] || []
@@ -3971,7 +4003,7 @@ class Morpheus::Cli::Clusters
3971
4003
  subtitles = []
3972
4004
  subtitles += parse_list_subtitles(options)
3973
4005
  print_h1 title, subtitles, options
3974
- print_process_event_details(process_event)
4006
+ print_process_event_details(process_event, options)
3975
4007
  print reset, "\n"
3976
4008
  return 0
3977
4009
  end
@@ -3983,37 +4015,6 @@ class Morpheus::Cli::Clusters
3983
4015
 
3984
4016
  private
3985
4017
 
3986
- def print_process_event_details(process_event, options={})
3987
- # process_event =~ process
3988
- description_cols = {
3989
- "Process ID" => lambda {|it| it['processId'] },
3990
- "Event ID" => lambda {|it| it['id'] },
3991
- "Name" => lambda {|it| it['displayName'] },
3992
- "Description" => lambda {|it| it['description'] },
3993
- "Process Type" => lambda {|it| it['processType'] ? (it['processType']['name'] || it['processType']['code']) : it['processTypeName'] },
3994
- "Created By" => lambda {|it| it['createdBy'] ? (it['createdBy']['displayName'] || it['createdBy']['username']) : '' },
3995
- "Start Date" => lambda {|it| format_local_dt(it['startDate']) },
3996
- "End Date" => lambda {|it| format_local_dt(it['endDate']) },
3997
- "Duration" => lambda {|it| format_process_duration(it) },
3998
- "Status" => lambda {|it| format_process_status(it) },
3999
- }
4000
- print_description_list(description_cols, process_event)
4001
-
4002
- if process_event['error']
4003
- print_h2 "Error", options
4004
- print reset
4005
- #puts format_process_error(process_event)
4006
- puts process_event['error'].to_s.strip
4007
- end
4008
-
4009
- if process_event['output']
4010
- print_h2 "Output", options
4011
- print reset
4012
- #puts format_process_error(process_event)
4013
- puts process_event['output'].to_s.strip
4014
- end
4015
- end
4016
-
4017
4018
  def print_clusters_table(clusters, opts={})
4018
4019
  table_color = opts[:color] || cyan
4019
4020
  rows = clusters.collect do |cluster|
@@ -4535,7 +4536,12 @@ class Morpheus::Cli::Clusters
4535
4536
  elsif resource_pool_options.count > 1 && !options[:no_prompt]
4536
4537
  resource_pool_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'resourcePool', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}],options[:options],api_client, {})['resourcePool']
4537
4538
  else
4538
- resource_pool_id = resource_pool_options.first['id']
4539
+ first_option = resource_pool_options.find {|it| !it['id'].nil? }
4540
+ if first_option.nil?
4541
+ print_red_alert "Cloud #{cloud['name']} has no available resource pools"
4542
+ exit 1
4543
+ end
4544
+ resource_pool_id = first_option['id']
4539
4545
  end
4540
4546
  if resource_pool_id.to_s["poolGroup-"]
4541
4547
  resource_pool = @resource_pool_groups_interface.get(resource_pool_id)['resourcePoolGroup']
@@ -1337,14 +1337,20 @@ class Morpheus::Cli::Hosts
1337
1337
  payload[:server][:plan] = {id: service_plan["id"]}
1338
1338
 
1339
1339
  # fetch volumes
1340
- volumes_response = @servers_interface.volumes(server['id'])
1341
- current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
1340
+ current_volumes = nil
1341
+ if server['volumes']
1342
+ current_volumes = server['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
1343
+ else
1344
+ volumes_response = @servers_interface.volumes(server['id'])
1345
+ current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
1346
+ end
1342
1347
 
1343
1348
  # prompt for volumes
1344
1349
  vol_options = options
1345
1350
  vol_options['siteId'] = group_id
1346
1351
  vol_options['zoneId'] = cloud_id
1347
- volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options)
1352
+ vol_options['resourcePoolId'] = server['resourcePool']['id'] if server['resourcePool']
1353
+ volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options, server)
1348
1354
  if !volumes.empty?
1349
1355
  payload[:volumes] = volumes
1350
1356
  end
@@ -2756,7 +2756,10 @@ class Morpheus::Cli::Instances
2756
2756
  connect(options)
2757
2757
  instance = find_instance_by_name_or_id(args[0])
2758
2758
  return 1, "instance not found" if instance.nil?
2759
-
2759
+ # need to load full instance details in case fetched by name
2760
+ if instance['containerDetails'].nil?
2761
+ instance = find_instance_by_id(instance['id'])
2762
+ end
2760
2763
  payload = {}
2761
2764
  if options[:payload]
2762
2765
  payload = options[:payload]
@@ -2811,13 +2814,24 @@ class Morpheus::Cli::Instances
2811
2814
  payload["instance"]["plan"] = {"id" => service_plan["id"]}
2812
2815
 
2813
2816
  volumes_response = @instances_interface.volumes(instance['id'])
2814
- current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
2817
+ current_volumes = nil
2815
2818
 
2816
2819
  # prompt for volumes
2817
2820
  vol_options = options
2818
2821
  vol_options['siteId'] = group_id
2819
2822
  vol_options['zoneId'] = cloud_id
2820
- volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options)
2823
+ vol_options['resourcePoolId'] = resource_pool_id # server['resourcePool']['id'] if server['resourcePool']
2824
+ server = instance['containerDetails'][0]['server'] rescue nil
2825
+ if server.nil?
2826
+ Morpheus::Logging::DarkPrinter.puts "Failed to load server info"
2827
+ volumes_response = @instances_interface.volumes(instance['id'])
2828
+ current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
2829
+ else
2830
+ # or just use instance['volumes'] ?
2831
+ current_volumes = server['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
2832
+ end
2833
+ vol_options['resourcePoolId'] = server['resourcePool']['id'] if server && server['resourcePool']
2834
+ volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options, server)
2821
2835
  if !volumes.empty?
2822
2836
  payload["volumes"] = volumes
2823
2837
  end
@@ -2907,6 +2921,12 @@ class Morpheus::Cli::Instances
2907
2921
  opts.on( '--description VALUE', String, "Snapshot Description." ) do |val|
2908
2922
  options[:options]['description'] = val
2909
2923
  end
2924
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
2925
+ options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
2926
+ end
2927
+ opts.on(nil, '--no-refresh', "Do not refresh" ) do
2928
+ options[:no_refresh] = true
2929
+ end
2910
2930
  build_standard_add_options(opts, options, [:auto_confirm])
2911
2931
  opts.footer = <<-EOT
2912
2932
  Create a snapshot for an instance.
@@ -2935,6 +2955,18 @@ EOT
2935
2955
  json_response = @instances_interface.snapshot(instance['id'], payload)
2936
2956
  render_response(json_response, options, 'snapshots') do
2937
2957
  print_green_success "Snapshot initiated."
2958
+ process_id = json_response['processIds'][0] rescue nil
2959
+ if process_id
2960
+ unless options[:no_refresh]
2961
+ process = wait_for_process_execution(process_id, options)
2962
+ snapshot_id = process['resultId']
2963
+ if snapshot_id
2964
+ Morpheus::Cli::Snapshots.new.handle(["get", snapshot_id] + (options[:remote] ? ["-r",options[:remote]] : []))
2965
+ end
2966
+ end
2967
+ else
2968
+ # puts "No process returned"
2969
+ end
2938
2970
  end
2939
2971
  return 0, nil
2940
2972
  end
@@ -3693,7 +3725,7 @@ EOT
3693
3725
  if options[:json]
3694
3726
  puts as_json(json_response, options)
3695
3727
  else
3696
- print_green_success "Snapshots attaced to instance #{instance['name']} queued for deletion."
3728
+ print_green_success "Snapshots attached to instance #{instance['name']} queued for deletion."
3697
3729
  end
3698
3730
  return 0
3699
3731
 
@@ -4482,7 +4514,7 @@ EOT
4482
4514
  subtitles << " Process ID: #{process_id}"
4483
4515
  subtitles += parse_list_subtitles(options)
4484
4516
  print_h1 title, subtitles, options
4485
- print_process_details(process)
4517
+ print_process_details(process, options)
4486
4518
 
4487
4519
  print_h2 "Process Events", options
4488
4520
  process_events = process['events'] || process['processEvents'] || []
@@ -5488,67 +5520,6 @@ private
5488
5520
  {'fieldName' => 'maxDisk', 'fieldLabel' => 'Max Disk', 'type' => 'number', 'description' => 'Maximum storage percent (0-100)'},
5489
5521
  ]
5490
5522
  end
5491
-
5492
- def print_process_details(process)
5493
- description_cols = {
5494
- "Process ID" => lambda {|it| it['id'] },
5495
- "Name" => lambda {|it| it['displayName'] },
5496
- "Description" => lambda {|it| it['description'] },
5497
- "Process Type" => lambda {|it| it['processType'] ? (it['processType']['name'] || it['processType']['code']) : it['processTypeName'] },
5498
- "Created By" => lambda {|it| it['createdBy'] ? (it['createdBy']['displayName'] || it['createdBy']['username']) : '' },
5499
- "Start Date" => lambda {|it| format_local_dt(it['startDate']) },
5500
- "End Date" => lambda {|it| format_local_dt(it['endDate']) },
5501
- "Duration" => lambda {|it| format_process_duration(it) },
5502
- "Status" => lambda {|it| format_process_status(it) },
5503
- # "# Events" => lambda {|it| (it['events'] || []).size() },
5504
- }
5505
- print_description_list(description_cols, process)
5506
-
5507
- if process['error']
5508
- print_h2 "Error", options
5509
- print reset
5510
- #puts format_process_error(process_event)
5511
- puts process['error'].to_s.strip
5512
- end
5513
-
5514
- if process['output']
5515
- print_h2 "Output", options
5516
- print reset
5517
- #puts format_process_error(process_event)
5518
- puts process['output'].to_s.strip
5519
- end
5520
- end
5521
-
5522
- def print_process_event_details(process_event, options={})
5523
- # process_event =~ process
5524
- description_cols = {
5525
- "Process ID" => lambda {|it| it['processId'] },
5526
- "Event ID" => lambda {|it| it['id'] },
5527
- "Name" => lambda {|it| it['displayName'] },
5528
- "Description" => lambda {|it| it['description'] },
5529
- "Process Type" => lambda {|it| it['processType'] ? (it['processType']['name'] || it['processType']['code']) : it['processTypeName'] },
5530
- "Created By" => lambda {|it| it['createdBy'] ? (it['createdBy']['displayName'] || it['createdBy']['username']) : '' },
5531
- "Start Date" => lambda {|it| format_local_dt(it['startDate']) },
5532
- "End Date" => lambda {|it| format_local_dt(it['endDate']) },
5533
- "Duration" => lambda {|it| format_process_duration(it) },
5534
- "Status" => lambda {|it| format_process_status(it) },
5535
- }
5536
- print_description_list(description_cols, process_event)
5537
-
5538
- if process_event['error']
5539
- print_h2 "Error", options
5540
- print reset
5541
- #puts format_process_error(process_event)
5542
- puts process_event['error'].to_s.strip
5543
- end
5544
-
5545
- if process_event['output']
5546
- print_h2 "Output", options
5547
- print reset
5548
- #puts format_process_error(process_event)
5549
- puts process_event['output'].to_s.strip
5550
- end
5551
- end
5552
5523
 
5553
5524
  def update_wiki_page_option_types
5554
5525
  [
@@ -845,7 +845,7 @@ class Morpheus::Cli::LibraryClusterLayoutsCommand
845
845
  end
846
846
 
847
847
  def find_layout_by_name(name)
848
- layouts = @library_cluster_layouts_interface.list(instance_type_id, {name: name.to_s})['layouts']
848
+ layouts = @library_cluster_layouts_interface.list({name: name.to_s})['layouts']
849
849
  if layouts.empty?
850
850
  print_red_alert "Cluster layout not found by name #{name}"
851
851
  return nil
@@ -295,7 +295,7 @@ class Morpheus::Cli::Processes
295
295
  subtitles << " Process ID: #{process_id}"
296
296
  subtitles += parse_list_subtitles(options)
297
297
  print_h1 title, subtitles
298
- print_process_details(process)
298
+ print_process_details(process, options)
299
299
 
300
300
  print_h2 "Process Events"
301
301
  process_events = process['events'] || process['processEvents'] || []
@@ -456,7 +456,7 @@ EOT
456
456
  subtitles = []
457
457
  subtitles += parse_list_subtitles(options)
458
458
  print_h1 title, subtitles
459
- print_process_event_details(process_event)
459
+ print_process_event_details(process_event, options)
460
460
  print reset, "\n"
461
461
  return 0
462
462
  end
@@ -635,8 +635,8 @@ class Morpheus::Cli::Shell
635
635
  # @return Hash like {:commands => [], :command_count => total}
636
636
  def load_history_commands(options={})
637
637
  phrase = options[:phrase]
638
- sort_key = options[:sort] ? options[:sort].to_sym : nil
639
-
638
+ #sort_key = options[:sort] ? options[:sort].to_sym : nil
639
+ #direction = options[:direction] # default sort is reversed to get newest first
640
640
  offset = options[:offset].to_i > 0 ? options[:offset].to_i : 0
641
641
  max = options[:max].to_i > 0 ? options[:max].to_i : 25
642
642
 
@@ -648,40 +648,21 @@ class Morpheus::Cli::Shell
648
648
  # collect records as [{:number => 1, :command => "instances list"}, etc]
649
649
  history_records = []
650
650
  history_count = 0
651
-
652
- # sort is a bit different for this command, the default sort is by number
653
- # it sorts oldest -> newest, but shows the very last page by default.
654
- if options[:sort] && ![:number, :command].include?(options[:sort])
655
- sort_key = :number # nil
656
- end
657
651
 
658
- if options[:phrase] || sort_key || options[:direction] || options[:offset]
659
- # this could be a large object...need to index our shell_history file lol
660
- sort_key ||= :number
661
- history_records = @history.keys.collect { |k| {number: k, command: @history[k]} }
662
- if options[:direction] == 'desc'
663
- history_records = history_records.sort {|x,y| y[sort_key] <=> x[sort_key] }
664
- else
665
- history_records = history_records.sort {|x,y| x[sort_key] <=> y[sort_key] }
666
- end
667
- if phrase
668
- history_records = history_records.select {|it| it[:command].include?(phrase) || it[:number].to_s == phrase }
669
- end
670
- command_count = history_records.size
671
- history_records = history_records[offset..(max-1)]
672
- else
673
- # default should try to be as fast as possible..
674
- # no searching or sorting, default order by :number works
675
- if offset != 0
676
- cmd_numbers = @history.keys.last(max + offset).first(max)
677
- else
678
- cmd_numbers = @history.keys.last(max)
679
- end
680
- history_records = cmd_numbers.collect { |k| {number: k, command: @history[k]} }
681
- command_count = @history.size
652
+ # only go so far back in command history, 1 million commands
653
+ # this could be a large object...need to index our shell_history file lol
654
+ # todo: this max needs to be done in load_history_from_log_file()
655
+ history_keys = @history.keys.last(1000000).reverse
656
+ # filter by phrase
657
+ if phrase
658
+ history_keys = history_keys.select {|k| (@history[k] && @history[k].include?(phrase)) || k.to_s == phrase }
682
659
  end
660
+ # no offset, just max
661
+ history_records = history_keys.first(max).collect { |k| {number: k, command: @history[k]} }
662
+ command_count = history_keys.size
663
+
683
664
  meta = {size:history_records.size, total:command_count.to_i, max:max, offset:offset}
684
- return {:commands => history_records, :command_count => command_count, :meta => meta}
665
+ return {commands: history_records, command_count: command_count, meta: meta}
685
666
  end
686
667
 
687
668
  def print_history(options={})
@@ -696,16 +677,14 @@ class Morpheus::Cli::Shell
696
677
  end
697
678
  else
698
679
  print cyan
680
+ # by default show old->new as the shell history should bash history
681
+ history_records.reverse! unless options[:direction] == "desc"
699
682
  history_records.each do |history_record|
700
683
  puts "#{history_record[:number].to_s.rjust(3, ' ')} #{history_record[:command]}"
701
684
  end
702
685
  if options[:show_pagination]
703
- if options[:phrase] || options[:sort] || options[:direction] || options[:offset]
704
- print_results_pagination(history_result[:meta])
705
- else
706
- # default order is weird, it's the last page of results, 1-25 is misleading and showing the indexes is stranger
707
- print_results_pagination(history_result[:meta], {:message =>"Viewing most recent %{size} of %{total} %{label}"})
708
- end
686
+ pagination_msg = options[:phrase] ? "Viewing most recent %{size} of %{total} commands matching '#{options[:phrase]}'" : "Viewing most recent %{size} of %{total} commands"
687
+ print_results_pagination(history_result[:meta], {:message =>pagination_msg})
709
688
  print reset, "\n"
710
689
  else
711
690
  print reset
@@ -73,15 +73,15 @@ class Morpheus::Cli::Snapshots
73
73
  "Name" => 'name',
74
74
  "Description" => 'description',
75
75
  "External Id" => 'externalId',
76
- "Status" => 'status',
77
- "State" => 'state',
76
+ # "State" => 'state',
78
77
  "Snapshot Type" => 'snapshotType',
79
- "Snapshot Created" => 'snapshotCreated',
80
- "Cloud" => 'zone.name',
81
- "Datastore" => 'datastore',
82
- "Parent Snapshot" => 'parentSnapshot',
83
- "Active" => 'currentlyActive',
84
- "Date Created" => 'dateCreated'
78
+ "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
79
+ "Cloud" => lambda {|it| format_name_and_id(it['zone']) },
80
+ "Datastore" => lambda {|it| format_name_and_id(it['datastore']) },
81
+ "Parent Snapshot" => lambda {|it| format_name_and_id(it['parentSnapshot']) },
82
+ "Active" => lambda {|it| format_boolean(it['currentlyActive']) },
83
+ "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
84
+ "Status" => lambda {|it| format_snapshot_status(it) }
85
85
  }
86
86
  print_description_list(description_cols, snapshot)
87
87
 
@@ -134,4 +134,20 @@ class Morpheus::Cli::Snapshots
134
134
  exit 1
135
135
  end
136
136
  end
137
+
138
+ protected
139
+
140
+ def format_snapshot_status(snapshot, return_color=cyan)
141
+ out = ""
142
+ status_string = snapshot['status'].to_s
143
+ if status_string == 'complete'
144
+ out << "#{green}#{status_string.upcase}#{return_color}"
145
+ elsif status_string == 'failed'
146
+ out << "#{red}#{status_string.upcase}#{return_color}"
147
+ else
148
+ out << "#{cyan}#{status_string.upcase}#{return_color}"
149
+ end
150
+ out
151
+ end
152
+
137
153
  end