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 +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
|