morpheus-cli 8.0.1 → 8.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/cli/cli_command.rb +18 -3
- data/lib/morpheus/cli/commands/clusters.rb +50 -44
- data/lib/morpheus/cli/commands/hosts.rb +9 -3
- data/lib/morpheus/cli/commands/instances.rb +37 -66
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +1 -1
- data/lib/morpheus/cli/commands/processes_command.rb +2 -2
- data/lib/morpheus/cli/commands/shell.rb +18 -39
- data/lib/morpheus/cli/commands/snapshots.rb +24 -8
- data/lib/morpheus/cli/commands/virtual_images.rb +71 -17
- data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/processes_helper.rb +34 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -324
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +1 -1
- data/test/cli/auth_test.rb +6 -0
- data/test/cli/roles_test.rb +15 -2
- data/test/test_case.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b071ad7a069db88e11023de144dad8ad640f49b6a18becdfa60cd1e04312397f
|
4
|
+
data.tar.gz: b1deba83d4decb51b824fabfca0d8a615dbd17e6df7e07296de3a8dc3606f945
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '04509b5731b2f5713189498b3a166b62735911c7c178d6480c5d54d4fd68827ef16f21431d5b7c49ce2209dca14dc402c65dc59e90268979b310855a08705598'
|
7
|
+
data.tar.gz: 179f4442f70f2f634746a11211f435ae119abd9dc0839e06c16142018afa3809bcdc995cc96ca3967734d06e578b80f7a6a680dbe3ba7c4bf643cc6318cb03d2
|
data/Dockerfile
CHANGED
@@ -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)
|
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
|
-
|
3063
|
-
if json_response['
|
3064
|
-
|
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
|
-
|
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
|
-
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
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
|
-
|
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
|
-
|
1341
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
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(
|
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
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
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 {:
|
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
|
-
|
704
|
-
|
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
|
-
"
|
77
|
-
"State" => 'state',
|
76
|
+
# "State" => 'state',
|
78
77
|
"Snapshot Type" => 'snapshotType',
|
79
|
-
"
|
80
|
-
"Cloud" => 'zone
|
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
|