morpheus-cli 6.1.2 → 6.2.0
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/api/api_client.rb +8 -0
- data/lib/morpheus/api/backup_jobs_interface.rb +4 -0
- data/lib/morpheus/api/backup_restores_interface.rb +23 -0
- data/lib/morpheus/api/backup_results_interface.rb +28 -0
- data/lib/morpheus/api/backups_interface.rb +5 -4
- data/lib/morpheus/cli/cli_command.rb +172 -45
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +7 -19
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/backup_jobs_command.rb +77 -20
- data/lib/morpheus/cli/commands/backup_restores_command.rb +144 -0
- data/lib/morpheus/cli/commands/backup_results_command.rb +149 -0
- data/lib/morpheus/cli/commands/backups_command.rb +214 -93
- data/lib/morpheus/cli/commands/hosts.rb +15 -2
- data/lib/morpheus/cli/commands/instances.rb +18 -3
- data/lib/morpheus/cli/commands/service_catalog_command.rb +50 -83
- data/lib/morpheus/cli/commands/view.rb +20 -20
- data/lib/morpheus/cli/mixins/backups_helper.rb +58 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +27 -4
- data/lib/morpheus/cli/option_types.rb +10 -7
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +1 -1
- data/lib/morpheus/routes.rb +18 -3
- metadata +6 -2
@@ -560,27 +560,17 @@ EOT
|
|
560
560
|
# fetch current cart
|
561
561
|
# cart = @service_catalog_interface.get_cart()['cart']
|
562
562
|
update_cart_object_key = 'order'
|
563
|
-
|
563
|
+
parse_payload(options, update_cart_object_key) do |payload|
|
564
564
|
payload.deep_merge!({update_cart_object_key => parse_passed_options(options)})
|
565
565
|
if payload[update_cart_object_key].empty? # || options[:no_prompt]
|
566
566
|
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
567
567
|
end
|
568
568
|
end
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
next
|
574
|
-
end
|
575
|
-
json_response = @service_catalog_interface.update_cart(payload)
|
576
|
-
#cart = json_response['cart']
|
577
|
-
#cart = @service_catalog_interface.get_cart()['cart']
|
578
|
-
render_response(json_response, options, 'cart') do
|
579
|
-
print_green_success "Updated cart"
|
580
|
-
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
581
|
-
end
|
569
|
+
execute_api(@service_catalog_interface, :update_cart, [params], options, "cart") do |json_response|
|
570
|
+
#cart = json_response["cart"]
|
571
|
+
print_green_success "Updated cart"
|
572
|
+
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
582
573
|
end
|
583
|
-
return 0, nil
|
584
574
|
end
|
585
575
|
|
586
576
|
def add(args)
|
@@ -600,6 +590,7 @@ EOT
|
|
600
590
|
end
|
601
591
|
opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips adding the item.") do
|
602
592
|
options[:validate_only] = true
|
593
|
+
params['validate'] = true
|
603
594
|
end
|
604
595
|
opts.on('--context [instance|server]', String, "Context Type for operational workflow types") do |val|
|
605
596
|
workflow_context = val.to_s
|
@@ -608,7 +599,7 @@ EOT
|
|
608
599
|
workflow_target = val.to_s
|
609
600
|
end
|
610
601
|
opts.add_hidden_option('--sigdig')
|
611
|
-
|
602
|
+
build_standard_add_many_options(opts, options, [:sigdig])
|
612
603
|
opts.footer = <<-EOT
|
613
604
|
Add an item to your cart
|
614
605
|
[type] is required, this is name or id of a catalog item type.
|
@@ -622,7 +613,7 @@ EOT
|
|
622
613
|
type_id = args.join(" ")
|
623
614
|
end
|
624
615
|
add_item_object_key = 'item'
|
625
|
-
|
616
|
+
parse_payload(options, add_item_object_key) do |payload|
|
626
617
|
payload.deep_merge!({add_item_object_key => parse_passed_options(options)})
|
627
618
|
# prompt for Type
|
628
619
|
if type_id
|
@@ -712,46 +703,35 @@ EOT
|
|
712
703
|
end
|
713
704
|
end
|
714
705
|
end
|
715
|
-
|
716
|
-
params['validate'] = true
|
717
|
-
end
|
718
|
-
process_payloads(payloads, options) do |payload|
|
719
|
-
@service_catalog_interface.setopts(options)
|
720
|
-
if options[:dry_run]
|
721
|
-
print_dry_run @service_catalog_interface.dry.create_cart_item(payload, params)
|
722
|
-
next
|
723
|
-
end
|
724
|
-
json_response = @service_catalog_interface.create_cart_item(payload, params)
|
706
|
+
execute_api(@service_catalog_interface, :create_cart_item, [params], options, 'item') do |json_response|
|
725
707
|
cart_item = json_response['item']
|
726
|
-
|
727
|
-
if
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
print reset, "\n"
|
747
|
-
else
|
748
|
-
# not needed because it will be http 400
|
749
|
-
print_rest_errors(json_response, options)
|
750
|
-
end
|
708
|
+
if options[:validate_only]
|
709
|
+
if json_response['success']
|
710
|
+
print_h2 "Validated Cart Item", [], options
|
711
|
+
cart_item_columns = {
|
712
|
+
"Type" => lambda {|it| it['type']['name'] rescue '' },
|
713
|
+
#"Qty" => lambda {|it| it['quantity'] },
|
714
|
+
"Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" },
|
715
|
+
"Status" => lambda {|it|
|
716
|
+
status_string = format_catalog_item_status(it)
|
717
|
+
if it['errorMessage'].to_s != ""
|
718
|
+
status_string << " - #{it['errorMessage']}"
|
719
|
+
end
|
720
|
+
status_string
|
721
|
+
},
|
722
|
+
#"Config" => lambda {|it| truncate_string(format_name_values(it['config']), 50) }
|
723
|
+
}
|
724
|
+
print as_pretty_table([cart_item], cart_item_columns.upcase_keys!)
|
725
|
+
print reset, "\n"
|
726
|
+
print_green_success(json_response['msg'] || "Item is valid")
|
727
|
+
print reset, "\n"
|
751
728
|
else
|
752
|
-
|
753
|
-
|
729
|
+
# not needed because it will be http 400
|
730
|
+
print_rest_errors(json_response, options)
|
754
731
|
end
|
732
|
+
else
|
733
|
+
print_green_success "Added item to cart"
|
734
|
+
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
755
735
|
end
|
756
736
|
end
|
757
737
|
end
|
@@ -935,6 +915,7 @@ EOT
|
|
935
915
|
end
|
936
916
|
opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips creating the order.") do
|
937
917
|
options[:validate_only] = true
|
918
|
+
params['validate'] = true
|
938
919
|
end
|
939
920
|
opts.on('-a', '--details', "Display all details: item configuration." ) do
|
940
921
|
options[:details] = true
|
@@ -962,7 +943,7 @@ EOT
|
|
962
943
|
end
|
963
944
|
payload = {}
|
964
945
|
order_object_key = 'order'
|
965
|
-
|
946
|
+
parse_payload(options, order_object_key) do |payload|
|
966
947
|
payload.deep_merge!({order_object_key => {}})
|
967
948
|
# Prompt for 1-N Types
|
968
949
|
# still_prompting = options[:no_prompt] != true
|
@@ -1076,38 +1057,24 @@ EOT
|
|
1076
1057
|
end
|
1077
1058
|
end
|
1078
1059
|
|
1079
|
-
end
|
1080
|
-
|
1081
|
-
|
1060
|
+
end
|
1082
1061
|
end
|
1083
|
-
|
1084
|
-
params['validate'] = true
|
1085
|
-
#payload['validate'] = true
|
1086
|
-
end
|
1087
|
-
process_payloads(payloads, options) do |payload|
|
1088
|
-
@service_catalog_interface.setopts(options)
|
1089
|
-
if options[:dry_run]
|
1090
|
-
print_dry_run @service_catalog_interface.dry.create_order(payload, params)
|
1091
|
-
next
|
1092
|
-
end
|
1093
|
-
json_response = @service_catalog_interface.create_order(payload, params)
|
1062
|
+
execute_api(@service_catalog_interface, :create_order, [params], options, "order") do |json_response|
|
1094
1063
|
order = json_response['order'] || json_response['cart']
|
1095
|
-
|
1096
|
-
if
|
1097
|
-
|
1098
|
-
print_h2 "Review Order", [], options
|
1099
|
-
print_order_details(order, options)
|
1100
|
-
print_green_success(json_response['msg'] || "Order is valid")
|
1101
|
-
print reset, "\n"
|
1102
|
-
else
|
1103
|
-
# not needed because it will be http 400
|
1104
|
-
print_rest_errors(json_response, options)
|
1105
|
-
end
|
1106
|
-
else
|
1107
|
-
print_green_success "Order placed"
|
1108
|
-
print_h2 "Order Details", [], options
|
1064
|
+
if options[:validate_only]
|
1065
|
+
if json_response['success']
|
1066
|
+
print_h2 "Review Order", [], options
|
1109
1067
|
print_order_details(order, options)
|
1068
|
+
print_green_success(json_response['msg'] || "Order is valid")
|
1069
|
+
print reset, "\n"
|
1070
|
+
else
|
1071
|
+
# not needed because it will be http 400
|
1072
|
+
print_rest_errors(json_response, options)
|
1110
1073
|
end
|
1074
|
+
else
|
1075
|
+
print_green_success "Order placed"
|
1076
|
+
print_h2 "Order Details", [], options
|
1077
|
+
print_order_details(order, options)
|
1111
1078
|
end
|
1112
1079
|
end
|
1113
1080
|
end
|
@@ -46,20 +46,22 @@ Examples:
|
|
46
46
|
EOT
|
47
47
|
end
|
48
48
|
optparse.parse!(args)
|
49
|
-
|
49
|
+
verify_args!(args:args, optparse:optparse, min: 0, max: 2)
|
50
50
|
connect(options)
|
51
51
|
# todo: it would actually be cool to use the params and include them on the path..
|
52
52
|
# params.merge!(parse_query_options(options))
|
53
|
-
|
53
|
+
# input, *ids = args
|
54
|
+
input = args[0]
|
55
|
+
id = args[1]
|
54
56
|
# default to index page "/"
|
55
|
-
path =
|
57
|
+
path = input || "/"
|
56
58
|
if options[:absolute_path] != true
|
57
59
|
if path.start_with?("/")
|
58
60
|
# treat like absolute path, no lookup
|
59
61
|
else
|
60
62
|
# lookup best matching route from sitemap
|
61
63
|
# lookup plural routes first, so 'app' finds apps and not approvals
|
62
|
-
found_route = Morpheus::Routes.lookup(path)
|
64
|
+
found_route = Morpheus::Routes.lookup(path, id)
|
63
65
|
if found_route
|
64
66
|
# Morpheus::Logging::DarkPrinter.puts "Found matching route: '#{path}' => '#{found_route}'" if Morpheus::Logging.debug?
|
65
67
|
path = found_route
|
@@ -69,26 +71,24 @@ EOT
|
|
69
71
|
end
|
70
72
|
# always add a leading slash
|
71
73
|
path = path.start_with?("/") ? path : "/#{path}"
|
72
|
-
# append id
|
73
|
-
if
|
74
|
-
# convert
|
74
|
+
# append id to path if passed
|
75
|
+
if id
|
76
|
+
# convert name to id
|
75
77
|
# assume the last part of path is the type and use generic finder
|
76
78
|
# only lookup names, and allow any id
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
record['id'].to_s
|
87
|
-
else
|
88
|
-
id
|
79
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
80
|
+
# record type is just args[0]
|
81
|
+
record_type = input
|
82
|
+
# assume the last part of path is the type
|
83
|
+
# record_type = path.split("/").last
|
84
|
+
# record_type.sub!('#!', '')
|
85
|
+
record = find_by_name(record_type, id)
|
86
|
+
if record.nil?
|
87
|
+
raise_command_error("[id] is invalid. No #{record_type} found for '#{id}'", args, optparse)
|
89
88
|
end
|
89
|
+
id = record['id'].to_s
|
90
90
|
end
|
91
|
-
path = "#{path}
|
91
|
+
path = "#{path}/#{id}"
|
92
92
|
end
|
93
93
|
end
|
94
94
|
# build the link to use, either our path or oauth-redirect to that path
|
@@ -110,4 +110,62 @@ module Morpheus::Cli::BackupsHelper
|
|
110
110
|
return backup_jobs[0]
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
## Backup Results
|
115
|
+
|
116
|
+
def backup_result_list_column_definitions()
|
117
|
+
{
|
118
|
+
"ID" => 'id',
|
119
|
+
"Backup" => lambda {|it| it['backup']['name'] rescue '' },
|
120
|
+
"Status" => lambda {|it| format_backup_result_status(it) },
|
121
|
+
#"Duration" => lambda {|it| format_duration(it['startDate'], it['endDate']) },
|
122
|
+
"Duration" => lambda {|it| format_duration_milliseconds(it['durationMillis']) },
|
123
|
+
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
124
|
+
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
125
|
+
"Size" => lambda {|it| format_bytes(it['sizeInMb'], 'MB') },
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
def backup_result_column_definitions()
|
130
|
+
backup_result_list_column_definitions()
|
131
|
+
end
|
132
|
+
|
133
|
+
def format_backup_result_status(backup_result, return_color=cyan)
|
134
|
+
out = ""
|
135
|
+
status_string = backup_result['status'].to_s.upcase
|
136
|
+
if status_string == 'SUCCEEDED' || status_string == 'SUCCESS'
|
137
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
138
|
+
elsif status_string == 'FAILED'
|
139
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
140
|
+
elsif status_string
|
141
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
142
|
+
else
|
143
|
+
out << ""
|
144
|
+
end
|
145
|
+
out
|
146
|
+
end
|
147
|
+
|
148
|
+
## Backup Restores
|
149
|
+
|
150
|
+
def backup_restore_list_column_definitions()
|
151
|
+
{
|
152
|
+
"ID" => 'id',
|
153
|
+
"Backup" => lambda {|it| it['backup']['name'] rescue '' },
|
154
|
+
"Backup Result ID" => lambda {|it| it['backupResultId'] rescue '' },
|
155
|
+
"Target" => lambda {|it| it['instance']['name'] rescue '' },
|
156
|
+
"Status" => lambda {|it| format_backup_result_status(it) },
|
157
|
+
#"Duration" => lambda {|it| format_duration(it['startDate'], it['endDate']) },
|
158
|
+
"Duration" => lambda {|it| format_duration_milliseconds(it['durationMillis']) },
|
159
|
+
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
160
|
+
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
def backup_restore_column_definitions()
|
165
|
+
backup_restore_list_column_definitions()
|
166
|
+
end
|
167
|
+
|
168
|
+
def format_backup_restore_status(backup_restore, return_color=cyan)
|
169
|
+
format_backup_result_status(backup_restore, return_color)
|
170
|
+
end
|
113
171
|
end
|
@@ -191,7 +191,24 @@ module Morpheus::Cli::PrintHelper
|
|
191
191
|
output = ""
|
192
192
|
if api_request[:curl] || options[:curl]
|
193
193
|
output = format_curl_command(http_method, url, headers, payload, options)
|
194
|
+
elsif options[:json]
|
195
|
+
# --dry --json should print the payload only
|
196
|
+
payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
|
197
|
+
output = as_json(payload_object, options)
|
198
|
+
elsif options[:yaml]
|
199
|
+
# --dry --yaml should print the payload only as yaml
|
200
|
+
payload_object = payload.is_a?(String) ? JSON.parse(payload) : payload
|
201
|
+
output = as_yaml(payload_object, options)
|
194
202
|
else
|
203
|
+
# default format is
|
204
|
+
# DRY RUN
|
205
|
+
# REQUEST
|
206
|
+
# GET https://server/api/things
|
207
|
+
#
|
208
|
+
# JSON
|
209
|
+
# {
|
210
|
+
# "thing": { ... }
|
211
|
+
# }
|
195
212
|
output = format_api_request(http_method, url, headers, payload, options)
|
196
213
|
end
|
197
214
|
# this is an extra scrub, should remove
|
@@ -210,14 +227,20 @@ module Morpheus::Cli::PrintHelper
|
|
210
227
|
if api_request[:curl] || options[:curl]
|
211
228
|
print "\n"
|
212
229
|
print "#{cyan}#{bold}#{dark}CURL COMMAND#{reset}\n"
|
230
|
+
print output
|
231
|
+
print reset, "\n"
|
232
|
+
print reset
|
233
|
+
elsif options[:json] || options[:yaml]
|
234
|
+
# print just the just payload
|
235
|
+
print output, "\n"
|
213
236
|
else
|
214
237
|
print "\n"
|
215
238
|
print "#{cyan}#{bold}#{dark}REQUEST#{reset}\n"
|
239
|
+
print output
|
240
|
+
print reset, "\n"
|
241
|
+
print reset
|
216
242
|
end
|
217
|
-
|
218
|
-
print reset, "\n"
|
219
|
-
print reset
|
220
|
-
return
|
243
|
+
return output
|
221
244
|
end
|
222
245
|
|
223
246
|
def print_system_command_dry_run(cmd, options={})
|
@@ -48,6 +48,7 @@ module Morpheus
|
|
48
48
|
|
49
49
|
# supresses prompting unless --prompt has been passed
|
50
50
|
def self.no_prompt(option_types, options={}, api_client=nil,api_params={})
|
51
|
+
options[:edit_mode] = true # hack used for updates to avoid default values being used
|
51
52
|
if options[:always_prompt]
|
52
53
|
prompt(option_types, options, api_client, api_params)
|
53
54
|
else
|
@@ -218,7 +219,7 @@ module Morpheus
|
|
218
219
|
|
219
220
|
# credential type
|
220
221
|
handle_credential_type = -> {
|
221
|
-
credential_type = select_prompt(option_type.merge({'defaultValue' => value}), api_client, option_params.merge({'credentialTypes' => option_type['config']['credentialTypes']}), !value.nil?, nil, paging_enabled, ignore_empty)
|
222
|
+
credential_type = select_prompt(option_type.merge({'defaultValue' => value}), api_client, option_params.merge({'credentialTypes' => option_type['config']['credentialTypes']}), !value.nil?, nil, paging_enabled, ignore_empty, options[:edit_mode])
|
222
223
|
# continue prompting for local creds
|
223
224
|
if credential_type == 'local'
|
224
225
|
parent_context_map.reject! {|k,v| k == 'credential'}
|
@@ -247,14 +248,14 @@ module Morpheus
|
|
247
248
|
end
|
248
249
|
# these select prompts should just fall down through below, with the extra params no_prompt, use_value
|
249
250
|
elsif option_type['type'] == 'select'
|
250
|
-
value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty)
|
251
|
+
value = select_prompt(option_type.merge({'defaultValue' => value, 'defaultInputValue' => input_value}), api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
|
251
252
|
elsif option_type['type'] == 'multiSelect'
|
252
253
|
# support value as csv like "thing1, thing2"
|
253
254
|
value_list = value.is_a?(String) ? value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [value].flatten
|
254
255
|
input_value_list = input_value.is_a?(String) ? input_value.parse_csv.collect {|v| v ? v.to_s.strip : v } : [input_value].flatten
|
255
256
|
select_value_list = []
|
256
257
|
value_list.each_with_index do |v, i|
|
257
|
-
select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty)
|
258
|
+
select_value_list << select_prompt(option_type.merge({'defaultValue' => v, 'defaultInputValue' => input_value_list[i]}), api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
|
258
259
|
end
|
259
260
|
value = select_value_list
|
260
261
|
elsif option_type['type'] == 'typeahead'
|
@@ -302,7 +303,7 @@ module Morpheus
|
|
302
303
|
next
|
303
304
|
end
|
304
305
|
if ['select', 'multiSelect'].include?(option_type['type'])
|
305
|
-
value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty)
|
306
|
+
value = select_prompt(option_type, api_client, option_params, true, nil, false, ignore_empty, options[:edit_mode])
|
306
307
|
value_found = !!value
|
307
308
|
end
|
308
309
|
if ['typeahead', 'multiTypeahead'].include?(option_type['type'])
|
@@ -347,12 +348,12 @@ module Morpheus
|
|
347
348
|
# I suppose the entered value should take precedence
|
348
349
|
# api_params = api_params.merge(options) # this might be good enough
|
349
350
|
# dup it
|
350
|
-
value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
|
351
|
+
value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty, options[:edit_mode])
|
351
352
|
if value && option_type['type'] == 'multiSelect'
|
352
353
|
value = [value]
|
353
354
|
recommended_count = (option_type['config'] || {})['recommendedCount'] || 0
|
354
355
|
while self.confirm("Add another #{option_type['fieldLabel']}?", {:default => recommended_count > value.count}) do
|
355
|
-
if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty)
|
356
|
+
if addn_value = select_prompt(option_type, api_client, option_params, options[:no_prompt], nil, paging_enabled, ignore_empty, options[:edit_mode])
|
356
357
|
value << addn_value
|
357
358
|
else
|
358
359
|
break
|
@@ -476,7 +477,7 @@ module Morpheus
|
|
476
477
|
Thread.current[:_last_select]
|
477
478
|
end
|
478
479
|
|
479
|
-
def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false)
|
480
|
+
def self.select_prompt(option_type, api_client, api_params={}, no_prompt=false, use_value=nil, paging_enabled=false, ignore_empty=false, edit_mode=false)
|
480
481
|
paging_enabled = false if Morpheus::Cli.windows?
|
481
482
|
field_key = [option_type['fieldContext'], option_type['fieldName']].select {|it| it && it != '' }.join('.')
|
482
483
|
help_field_key = option_type[:help_field_prefix] ? "#{option_type[:help_field_prefix]}.#{field_key}" : field_key
|
@@ -550,6 +551,8 @@ module Morpheus
|
|
550
551
|
print "\n"
|
551
552
|
exit 1
|
552
553
|
end
|
554
|
+
elsif edit_mode
|
555
|
+
# do not use a default value for edit mode
|
553
556
|
# skipSingleOption is no longer supported
|
554
557
|
# elsif !select_options.nil? && select_options.count == 1 && option_type['skipSingleOption'] == true
|
555
558
|
# value_found = true
|
data/lib/morpheus/cli/version.rb
CHANGED
data/lib/morpheus/formatters.rb
CHANGED
@@ -134,7 +134,7 @@ end
|
|
134
134
|
|
135
135
|
def format_duration_milliseconds(milliseconds, format="human", ms_threshold=1000)
|
136
136
|
out = ""
|
137
|
-
milliseconds = milliseconds.abs
|
137
|
+
milliseconds = milliseconds.to_i.abs
|
138
138
|
if ms_threshold && ms_threshold > milliseconds
|
139
139
|
out = "#{milliseconds}ms"
|
140
140
|
else
|
data/lib/morpheus/routes.rb
CHANGED
@@ -100,7 +100,13 @@ module Morpheus::Routes
|
|
100
100
|
],
|
101
101
|
},
|
102
102
|
backups: {
|
103
|
-
|
103
|
+
list: {},
|
104
|
+
show: {},
|
105
|
+
jobs: {},
|
106
|
+
history: [
|
107
|
+
"#!restores",
|
108
|
+
],
|
109
|
+
services: {}
|
104
110
|
},
|
105
111
|
monitoring: {
|
106
112
|
status: {},
|
@@ -162,9 +168,10 @@ module Morpheus::Routes
|
|
162
168
|
|
163
169
|
# lookup a route in the morpheus UI
|
164
170
|
# @param path [String] The input to lookup a route for eg. "dashboard"
|
171
|
+
# @param id [String] ID indicates the show route is needed for a resource for cases where it varies ie. backups
|
165
172
|
# @return full path like "/operations/dashboard"
|
166
|
-
def self.lookup(
|
167
|
-
path =
|
173
|
+
def self.lookup(path, id=nil)
|
174
|
+
path = path.to_s
|
168
175
|
if path.start_with?("/")
|
169
176
|
# absolute path is being looked up
|
170
177
|
return path
|
@@ -174,6 +181,14 @@ module Morpheus::Routes
|
|
174
181
|
|
175
182
|
# map well known aliases
|
176
183
|
case(path.dasherize.pluralize)
|
184
|
+
when "backups"
|
185
|
+
path = id ? "/backups/show" : "/backups/list"
|
186
|
+
when "backup-jobs"
|
187
|
+
path = "/backups/jobs"
|
188
|
+
when "backup-results"
|
189
|
+
path = "/backups/history"
|
190
|
+
when "backup-restores", "restores"
|
191
|
+
path = "/backups/history/#!restores"
|
177
192
|
when "servers","hosts","vms","virtual-machines"
|
178
193
|
# actually should be "/infrastructure/inventory" unless id is passed, show route uses /servers though
|
179
194
|
path = "/infrastructure/servers"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2023-
|
14
|
+
date: 2023-07-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -199,6 +199,8 @@ files:
|
|
199
199
|
- lib/morpheus/api/audit_interface.rb
|
200
200
|
- lib/morpheus/api/auth_interface.rb
|
201
201
|
- lib/morpheus/api/backup_jobs_interface.rb
|
202
|
+
- lib/morpheus/api/backup_restores_interface.rb
|
203
|
+
- lib/morpheus/api/backup_results_interface.rb
|
202
204
|
- lib/morpheus/api/backup_service_types_interface.rb
|
203
205
|
- lib/morpheus/api/backup_services_interface.rb
|
204
206
|
- lib/morpheus/api/backup_settings_interface.rb
|
@@ -371,6 +373,8 @@ files:
|
|
371
373
|
- lib/morpheus/cli/commands/archives_command.rb
|
372
374
|
- lib/morpheus/cli/commands/audit.rb
|
373
375
|
- lib/morpheus/cli/commands/backup_jobs_command.rb
|
376
|
+
- lib/morpheus/cli/commands/backup_restores_command.rb
|
377
|
+
- lib/morpheus/cli/commands/backup_results_command.rb
|
374
378
|
- lib/morpheus/cli/commands/backup_services_command.rb
|
375
379
|
- lib/morpheus/cli/commands/backup_settings_command.rb
|
376
380
|
- lib/morpheus/cli/commands/backups_command.rb
|