morpheus-cli 5.2.0 → 5.2.4.1
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/.gitignore +1 -0
- data/Dockerfile +1 -1
- data/README.md +3 -3
- data/lib/morpheus/api/instances_interface.rb +21 -0
- data/lib/morpheus/api/invoices_interface.rb +12 -3
- data/lib/morpheus/cli/backup_jobs_command.rb +1 -1
- data/lib/morpheus/cli/backups_command.rb +2 -3
- data/lib/morpheus/cli/budgets_command.rb +389 -319
- data/lib/morpheus/cli/cli_command.rb +19 -9
- data/lib/morpheus/cli/commands/standard/curl_command.rb +25 -10
- data/lib/morpheus/cli/commands/standard/history_command.rb +6 -2
- data/lib/morpheus/cli/dashboard_command.rb +260 -20
- data/lib/morpheus/cli/hosts.rb +43 -2
- data/lib/morpheus/cli/instances.rb +189 -44
- data/lib/morpheus/cli/invoices_command.rb +73 -55
- data/lib/morpheus/cli/jobs_command.rb +94 -92
- data/lib/morpheus/cli/library_option_types_command.rb +5 -3
- data/lib/morpheus/cli/mixins/print_helper.rb +13 -6
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +12 -5
- data/lib/morpheus/cli/projects_command.rb +1 -1
- data/lib/morpheus/cli/user_sources_command.rb +118 -134
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +1 -1
- data/lib/morpheus/formatters.rb +21 -11
- metadata +2 -2
|
@@ -466,11 +466,16 @@ module Morpheus
|
|
|
466
466
|
|
|
467
467
|
when :list
|
|
468
468
|
opts.on( '-m', '--max MAX', "Max Results" ) do |val|
|
|
469
|
-
max
|
|
470
|
-
if
|
|
471
|
-
|
|
469
|
+
# api supports max=-1 for all at the moment..
|
|
470
|
+
if val.to_s == "all" || val.to_s == "-1"
|
|
471
|
+
options[:max] = "-1"
|
|
472
|
+
else
|
|
473
|
+
max = val.to_i
|
|
474
|
+
if max <= 0
|
|
475
|
+
raise ::OptionParser::InvalidArgument.new("must be a positive integer")
|
|
476
|
+
end
|
|
477
|
+
options[:max] = max
|
|
472
478
|
end
|
|
473
|
-
options[:max] = max
|
|
474
479
|
end
|
|
475
480
|
|
|
476
481
|
opts.on( '-o', '--offset OFFSET', "Offset Results" ) do |val|
|
|
@@ -486,12 +491,17 @@ module Morpheus
|
|
|
486
491
|
end
|
|
487
492
|
|
|
488
493
|
opts.on( '-S', '--sort ORDER', "Sort Order. DIRECTION may be included as \"ORDER [asc|desc]\"." ) do |v|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
options[:sort] = v_parts[0]
|
|
492
|
-
options[:direction] = (v_parts[1].strip == "desc") ? "desc" : "asc"
|
|
493
|
-
else
|
|
494
|
+
if v.to_s.include?(",")
|
|
495
|
+
# sorting on multiple properties, just pass it as is, newer api supports multiple fields
|
|
494
496
|
options[:sort] = v
|
|
497
|
+
else
|
|
498
|
+
v_parts = v.to_s.split(" ")
|
|
499
|
+
if v_parts.size > 1
|
|
500
|
+
options[:sort] = v_parts[0]
|
|
501
|
+
options[:direction] = (v_parts[1].strip == "desc") ? "desc" : "asc"
|
|
502
|
+
else
|
|
503
|
+
options[:sort] = v
|
|
504
|
+
end
|
|
495
505
|
end
|
|
496
506
|
end
|
|
497
507
|
|
|
@@ -26,8 +26,8 @@ class Morpheus::Cli::CurlCommand
|
|
|
26
26
|
options = {}
|
|
27
27
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
|
28
28
|
opts.banner = "Usage: morpheus curl [path] -- [*args]"
|
|
29
|
-
opts.on( '-p', '--pretty', "Print result as parsed JSON." ) do
|
|
30
|
-
options[:
|
|
29
|
+
opts.on( '-p', '--pretty', "Print result as parsed JSON. Alias for -j" ) do
|
|
30
|
+
options[:json] = true
|
|
31
31
|
end
|
|
32
32
|
opts.on( '-X', '--request METHOD', "HTTP request method. Default is GET" ) do |val|
|
|
33
33
|
curl_method = val
|
|
@@ -134,29 +134,44 @@ EOT
|
|
|
134
134
|
print reset
|
|
135
135
|
return 0
|
|
136
136
|
end
|
|
137
|
+
exit_code, err = 0, nil
|
|
137
138
|
# print cyan
|
|
138
139
|
# print "#{cyan}#{curl_cmd_str}#{reset}"
|
|
139
140
|
# print "\n\n"
|
|
140
141
|
print reset
|
|
141
142
|
# print result
|
|
142
143
|
curl_output = `#{curl_cmd}`
|
|
143
|
-
|
|
144
|
+
|
|
145
|
+
if $?.success? != true
|
|
146
|
+
exit_code = $?.exitstatus
|
|
147
|
+
err = "curl command exited non-zero"
|
|
148
|
+
end
|
|
149
|
+
json_response = {}
|
|
150
|
+
other_output = nil
|
|
151
|
+
if options[:json] || options[:yaml] || options[:csv]
|
|
144
152
|
output_lines = curl_output.split("\n")
|
|
145
153
|
last_line = output_lines.pop
|
|
146
154
|
if output_lines.size > 0
|
|
147
|
-
|
|
155
|
+
other_output = output_lines.join("\n")
|
|
148
156
|
end
|
|
149
157
|
begin
|
|
150
|
-
|
|
158
|
+
json_response = JSON.parse(last_line)
|
|
151
159
|
rescue => ex
|
|
152
|
-
|
|
153
|
-
|
|
160
|
+
puts_error curl_output
|
|
161
|
+
print_red_alert "failed to parse curl result as JSON data Error: #{ex.message}"
|
|
162
|
+
|
|
163
|
+
exit_code = 2
|
|
164
|
+
err = "failed to parse curl result as JSON data Error: #{ex.message}"
|
|
165
|
+
return exit_code, err
|
|
154
166
|
end
|
|
155
167
|
else
|
|
156
|
-
|
|
168
|
+
other_output = curl_output
|
|
157
169
|
end
|
|
158
|
-
|
|
159
|
-
|
|
170
|
+
curl_object_key = nil # json_response.keys.first
|
|
171
|
+
render_response(json_response, options, curl_object_key) do
|
|
172
|
+
puts other_output
|
|
173
|
+
end
|
|
174
|
+
return exit_code, err
|
|
160
175
|
end
|
|
161
176
|
|
|
162
177
|
def command_available?(cmd)
|
|
@@ -15,7 +15,7 @@ class Morpheus::Cli::HistoryCommand
|
|
|
15
15
|
def handle(args)
|
|
16
16
|
options = {show_pagination:false}
|
|
17
17
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
|
18
|
-
opts.banner = "Usage: morpheus #{command_name}"
|
|
18
|
+
opts.banner = "Usage: morpheus #{command_name} [search]"
|
|
19
19
|
# -n is a hidden alias for -m
|
|
20
20
|
opts.on( '-n', '--max-commands MAX', "Alias for -m, --max option." ) do |val|
|
|
21
21
|
options[:max] = val
|
|
@@ -35,6 +35,7 @@ The --flush option can be used to purge the history.
|
|
|
35
35
|
Examples:
|
|
36
36
|
history
|
|
37
37
|
history -m 100
|
|
38
|
+
history "instances list"
|
|
38
39
|
history --flush
|
|
39
40
|
|
|
40
41
|
The most recently executed commands are seen by default. Use --reverse to see the oldest commands.
|
|
@@ -42,7 +43,10 @@ EOT
|
|
|
42
43
|
end
|
|
43
44
|
raw_cmd = "#{command_name} #{args.join(' ')}"
|
|
44
45
|
optparse.parse!(args)
|
|
45
|
-
verify_args!(args:args, count: 0, optparse:optparse)
|
|
46
|
+
# verify_args!(args:args, count: 0, optparse:optparse)
|
|
47
|
+
if args.count > 0
|
|
48
|
+
options[:phrase] = args.join(" ")
|
|
49
|
+
end
|
|
46
50
|
if options[:do_flush]
|
|
47
51
|
command_count = Morpheus::Cli::Shell.instance.history_commands_count
|
|
48
52
|
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to flush your command history (#{format_number(command_count)} #{command_count == 1 ? 'command' : 'commands'})?")
|
|
@@ -4,8 +4,9 @@ require 'json'
|
|
|
4
4
|
|
|
5
5
|
class Morpheus::Cli::DashboardCommand
|
|
6
6
|
include Morpheus::Cli::CliCommand
|
|
7
|
+
include Morpheus::Cli::ProvisioningHelper
|
|
7
8
|
set_command_name :dashboard
|
|
8
|
-
|
|
9
|
+
set_command_description "View Morpheus Dashboard"
|
|
9
10
|
|
|
10
11
|
def initialize()
|
|
11
12
|
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
|
@@ -28,34 +29,273 @@ class Morpheus::Cli::DashboardCommand
|
|
|
28
29
|
options = {}
|
|
29
30
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
30
31
|
opts.banner = usage
|
|
31
|
-
|
|
32
|
+
opts.on('-a', '--details', "Display all details: more instance usage stats, etc" ) do
|
|
33
|
+
options[:details] = true
|
|
34
|
+
end
|
|
35
|
+
build_standard_list_options(opts, options)
|
|
36
|
+
opts.footer = <<-EOT
|
|
37
|
+
View Morpheus Dashboard.
|
|
38
|
+
This includes instance and backup counts, favorite instances, monitoring and recent activity.
|
|
39
|
+
EOT
|
|
32
40
|
end
|
|
33
41
|
optparse.parse!(args)
|
|
34
|
-
|
|
42
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
|
35
43
|
connect(options)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
params = {}
|
|
45
|
+
params.merge!(parse_list_options(options))
|
|
46
|
+
@dashboard_interface.setopts(options)
|
|
47
|
+
if options[:dry_run]
|
|
48
|
+
print_dry_run @dashboard_interface.dry.get(params)
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
json_response = @dashboard_interface.get(params)
|
|
52
|
+
render_response(json_response, options) do
|
|
53
|
+
print_h1 "Morpheus Dashboard", [], options
|
|
54
|
+
|
|
55
|
+
## STATUS
|
|
56
|
+
|
|
57
|
+
status_column_definitions = {
|
|
58
|
+
"Instances" => lambda {|it|
|
|
59
|
+
format_number(it['instanceStats']['total']) rescue nil
|
|
60
|
+
},
|
|
61
|
+
"Running" => lambda {|it|
|
|
62
|
+
format_number(it['instanceStats']['running']) rescue nil
|
|
63
|
+
},
|
|
64
|
+
# "Used Storage" => lambda {|it|
|
|
65
|
+
# ((it['instanceStats']['maxStorage'].to_i > 0) ? ((it['instanceStats']['usedStorage'].to_f / it['instanceStats']['maxStorage'].to_f) * 100).round(1) : 0).to_s + '%' rescue nil
|
|
66
|
+
# },
|
|
67
|
+
}
|
|
68
|
+
print as_description_list(json_response, status_column_definitions, options)
|
|
69
|
+
# print reset,"\n"
|
|
70
|
+
|
|
71
|
+
stats = json_response['instanceStats']
|
|
72
|
+
if stats
|
|
73
|
+
print_h2 "Instance Usage", options
|
|
74
|
+
print_stats_usage(stats, {include: [:max_cpu, :avg_cpu, :memory, :storage]})
|
|
42
75
|
end
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
open_incident_count = json_response['monitoring']['openIncidents'] rescue (json_response['appStatus']['openIncidents'] rescue nil)
|
|
80
|
+
|
|
81
|
+
avg_response_time = json_response['monitoring']['avgResponseTime'] rescue nil
|
|
82
|
+
warning_apps = json_response['monitoring']['warningApps'] rescue 0
|
|
83
|
+
warning_checks = json_response['monitoring']['warningChecks'] rescue 0
|
|
84
|
+
fail_checks = json_response['monitoring']['failChecks'] rescue 0
|
|
85
|
+
fail_apps = json_response['monitoring']['failApps'] rescue 0
|
|
86
|
+
success_checks = json_response['monitoring']['successChecks'] rescue 0
|
|
87
|
+
success_apps = json_response['monitoring']['successApps'] rescue 0
|
|
88
|
+
monitoring_status_color = cyan
|
|
89
|
+
if fail_checks > 0 || fail_apps > 0
|
|
90
|
+
monitoring_status_color = red
|
|
91
|
+
elsif warning_checks > 0 || warning_apps > 0
|
|
92
|
+
monitoring_status_color = yellow
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
print_h2 "Monitoring"
|
|
96
|
+
|
|
97
|
+
monitoring_column_definitions = {
|
|
98
|
+
"Status" => lambda {|it|
|
|
99
|
+
if fail_apps > 0 # || fail_checks > 0
|
|
100
|
+
# check_summary = [fail_apps > 0 ? "#{fail_apps} Apps" : nil,fail_checks > 0 ? "#{fail_checks} Checks" : nil].compact.join(", ")
|
|
101
|
+
# red + "ERROR" + " (" + check_summary + ")" + cyan
|
|
102
|
+
red + "ERROR" + cyan
|
|
103
|
+
elsif warning_apps > 0 || warning_checks > 0
|
|
104
|
+
# check_summary = [warning_apps > 0 ? "#{warning_apps} Apps" : nil,warning_checks > 0 ? "#{warning_checks} Checks" : nil].compact.join(", ")
|
|
105
|
+
# red + "WARNING" + " (" + check_summary + ")" + cyan
|
|
106
|
+
yellow + "WARNING" + cyan
|
|
107
|
+
else
|
|
108
|
+
cyan + "HEALTHY" + cyan
|
|
109
|
+
end
|
|
110
|
+
},
|
|
111
|
+
# "Availability" => lambda {|it|
|
|
112
|
+
# # todo
|
|
113
|
+
# },
|
|
114
|
+
"Response Time" => lambda {|it|
|
|
115
|
+
# format_number(avg_response_time).to_s + "ms"
|
|
116
|
+
(avg_response_time.round).to_s + "ms"
|
|
117
|
+
},
|
|
118
|
+
"Open Incidents" => lambda {|it|
|
|
119
|
+
monitoring_status_color = cyan
|
|
120
|
+
# if fail_checks > 0 || fail_apps > 0
|
|
121
|
+
# monitoring_status_color = red
|
|
122
|
+
# elsif warning_checks > 0 || warning_apps > 0
|
|
123
|
+
# monitoring_status_color = yellow
|
|
124
|
+
# end
|
|
125
|
+
if open_incident_count.nil?
|
|
126
|
+
yellow + "n/a" + cyan + "\n"
|
|
127
|
+
elsif open_incident_count == 0
|
|
128
|
+
monitoring_status_color + "0 Open Incidents" + cyan
|
|
129
|
+
elsif open_incident_count == 1
|
|
130
|
+
monitoring_status_color + "1 Open Incident" + cyan
|
|
131
|
+
else
|
|
132
|
+
monitoring_status_color + "#{open_incident_count} Open Incidents" + cyan
|
|
133
|
+
end
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
#print as_description_list(json_response, monitoring_column_definitions, options)
|
|
137
|
+
print as_pretty_table([json_response], monitoring_column_definitions.upcase_keys!, options)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if json_response['logStats']
|
|
141
|
+
# todo: should come from monitoring.startMs-endMs
|
|
142
|
+
log_period_display = "7 Days"
|
|
143
|
+
print_h2 "Logs (#{log_period_display})", options
|
|
144
|
+
error_log_data = json_response['logStats']['data'].find {|it| it['key'].to_s.upcase == 'ERROR' }
|
|
145
|
+
error_count = error_log_data["count"] rescue 0
|
|
146
|
+
fatal_log_data = json_response['logStats']['data'].find {|it| it['key'].to_s.upcase == 'FATAL' }
|
|
147
|
+
fatal_count = fatal_log_data["count"] rescue 0
|
|
148
|
+
# total error is actaully error + fatal
|
|
149
|
+
total_error_count = error_count + fatal_count
|
|
150
|
+
# if total_error_count.nil?
|
|
151
|
+
# print yellow + "n/a" + cyan + "\n"
|
|
152
|
+
# elsif total_error_count == 0
|
|
153
|
+
# print cyan + "0 Errors" + cyan + "\n"
|
|
154
|
+
# elsif total_error_count == 1
|
|
155
|
+
# print red + "1 Error" + cyan + "\n"
|
|
156
|
+
# else
|
|
157
|
+
# print red + "#{total_error_count} Errors" + cyan + "\n"
|
|
158
|
+
# end
|
|
159
|
+
if total_error_count == 0
|
|
160
|
+
print cyan + "(0 Errors)" + cyan + "\n"
|
|
161
|
+
#print cyan + "0-0-0-0-0-0-0-0 (0 Errors)" + cyan + "\n"
|
|
162
|
+
end
|
|
163
|
+
if error_count > 0
|
|
164
|
+
if error_log_data["values"]
|
|
165
|
+
log_plot = ""
|
|
166
|
+
plot_index = 0
|
|
167
|
+
error_log_data["values"].each do |k, v|
|
|
168
|
+
if v.to_i == 0
|
|
169
|
+
log_plot << cyan + v.to_s
|
|
170
|
+
else
|
|
171
|
+
log_plot << red + v.to_s
|
|
172
|
+
end
|
|
173
|
+
if plot_index != error_log_data["values"].size - 1
|
|
174
|
+
log_plot << cyan + "-"
|
|
175
|
+
end
|
|
176
|
+
plot_index +=1
|
|
177
|
+
end
|
|
178
|
+
print log_plot
|
|
179
|
+
print " "
|
|
180
|
+
if error_count == 0
|
|
181
|
+
print cyan + "(0 Errors)" + cyan
|
|
182
|
+
elsif error_count == 1
|
|
183
|
+
print red + "(1 Errors)" + cyan
|
|
184
|
+
else
|
|
185
|
+
print red + "(#{error_count} Errors)" + cyan
|
|
186
|
+
end
|
|
187
|
+
print reset + "\n"
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
if fatal_count > 0
|
|
191
|
+
if fatal_log_data["values"]
|
|
192
|
+
log_plot = ""
|
|
193
|
+
plot_index = 0
|
|
194
|
+
fatal_log_data["values"].each do |k, v|
|
|
195
|
+
if v.to_i == 0
|
|
196
|
+
log_plot << cyan + v.to_s
|
|
197
|
+
else
|
|
198
|
+
log_plot << red + v.to_s
|
|
199
|
+
end
|
|
200
|
+
if plot_index != fatal_log_data["values"].size - 1
|
|
201
|
+
log_plot << cyan + "-"
|
|
202
|
+
end
|
|
203
|
+
plot_index +=1
|
|
204
|
+
end
|
|
205
|
+
print log_plot
|
|
206
|
+
print " "
|
|
207
|
+
if fatal_count == 0
|
|
208
|
+
print cyan + "(0 FATAL)" + cyan
|
|
209
|
+
elsif fatal_count == 1
|
|
210
|
+
print red + "(1 FATAL)" + cyan
|
|
211
|
+
else
|
|
212
|
+
print red + "(#{fatal_count} FATAL)" + cyan
|
|
213
|
+
end
|
|
214
|
+
print reset + "\n"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
print_h2 "Backups (7 Days)"
|
|
220
|
+
backup_status_column_definitions = {
|
|
221
|
+
# "Total" => lambda {|it|
|
|
222
|
+
# it['backups']['accountStats']['lastSevenDays']['completed'] rescue nil
|
|
223
|
+
# },
|
|
224
|
+
"Successful" => lambda {|it|
|
|
225
|
+
it['backups']['accountStats']['lastSevenDays']['successful'] rescue nil
|
|
226
|
+
},
|
|
227
|
+
"Failed" => lambda {|it|
|
|
228
|
+
n = it['backups']['accountStats']['lastSevenDays']['failed'] rescue nil
|
|
229
|
+
if n == 0
|
|
230
|
+
cyan + n.to_s + reset
|
|
231
|
+
else
|
|
232
|
+
red + n.to_s + reset
|
|
233
|
+
end
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
print as_description_list(json_response, backup_status_column_definitions, options)
|
|
237
|
+
#print as_pretty_table([json_response], backup_status_column_definitions, options)
|
|
238
|
+
# print reset,"\n"
|
|
239
|
+
|
|
240
|
+
favorite_instances = json_response["provisioning"]["favoriteInstances"] || [] rescue []
|
|
241
|
+
if favorite_instances.empty?
|
|
242
|
+
# print cyan, "No favorite instances.",reset,"\n"
|
|
47
243
|
else
|
|
244
|
+
print_h2 "My Instances"
|
|
245
|
+
favorite_instances_columns = {
|
|
246
|
+
"ID" => lambda {|instance|
|
|
247
|
+
instance['id']
|
|
248
|
+
},
|
|
249
|
+
"Name" => lambda {|instance|
|
|
250
|
+
instance['name']
|
|
251
|
+
},
|
|
252
|
+
"Type" => lambda {|instance|
|
|
253
|
+
instance['instanceType']['name'] rescue nil
|
|
254
|
+
},
|
|
255
|
+
"IP/PORT" => lambda {|instance|
|
|
256
|
+
format_instance_connection_string(instance)
|
|
257
|
+
},
|
|
258
|
+
"Status" => lambda {|it| format_instance_status(it) }
|
|
259
|
+
}
|
|
260
|
+
#print as_description_list(json_response, status_column_definitions, options)
|
|
261
|
+
print as_pretty_table(favorite_instances, favorite_instances_columns, options)
|
|
262
|
+
# print reset,"\n"
|
|
263
|
+
end
|
|
48
264
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
265
|
+
# RECENT ACTIVITY
|
|
266
|
+
activity = json_response["activity"] || json_response["recentActivity"] || []
|
|
267
|
+
print_h2 "Recent Activity", [], options
|
|
268
|
+
if activity.empty?
|
|
269
|
+
print cyan, "No activity found.",reset,"\n"
|
|
270
|
+
else
|
|
271
|
+
columns = [
|
|
272
|
+
# {"SEVERITY" => lambda {|record| format_activity_severity(record['severity']) } },
|
|
273
|
+
{"TYPE" => lambda {|record| record['activityType'] } },
|
|
274
|
+
{"NAME" => lambda {|record| record['name'] } },
|
|
275
|
+
{"RESOURCE" => lambda {|record| "#{record['objectType']} #{record['objectId']}" } },
|
|
276
|
+
{"MESSAGE" => lambda {|record| record['message'] || '' } },
|
|
277
|
+
{"USER" => lambda {|record| record['user'] ? record['user']['username'] : record['userName'] } },
|
|
278
|
+
#{"DATE" => lambda {|record| "#{format_duration_ago(record['ts'] || record['timestamp'])}" } },
|
|
279
|
+
{"DATE" => lambda {|record|
|
|
280
|
+
# show full time if searching for custom timerange, otherwise the default is to show relative time
|
|
281
|
+
if params['start'] || params['end'] || params['timeframe']
|
|
282
|
+
"#{format_local_dt(record['ts'] || record['timestamp'])}"
|
|
283
|
+
else
|
|
284
|
+
"#{format_duration_ago(record['ts'] || record['timestamp'])}"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
} },
|
|
288
|
+
]
|
|
289
|
+
print as_pretty_table(activity, columns, options)
|
|
290
|
+
# print_results_pagination(json_response)
|
|
291
|
+
# print reset,"\n"
|
|
53
292
|
|
|
54
293
|
end
|
|
55
|
-
|
|
56
|
-
print_rest_exception(e, options)
|
|
57
|
-
exit 1
|
|
294
|
+
|
|
58
295
|
end
|
|
296
|
+
print reset,"\n"
|
|
297
|
+
return 0, nil
|
|
59
298
|
end
|
|
60
299
|
|
|
300
|
+
|
|
61
301
|
end
|
data/lib/morpheus/cli/hosts.rb
CHANGED
|
@@ -117,6 +117,12 @@ class Morpheus::Cli::Hosts
|
|
|
117
117
|
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
|
118
118
|
options[:account] = val
|
|
119
119
|
end
|
|
120
|
+
opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
|
|
121
|
+
val.split(",").each do |k|
|
|
122
|
+
options[:labels] ||= []
|
|
123
|
+
options[:labels] << k.strip
|
|
124
|
+
end
|
|
125
|
+
end
|
|
120
126
|
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
|
121
127
|
val.split(",").each do |value_pair|
|
|
122
128
|
k,v = value_pair.strip.split("=")
|
|
@@ -186,6 +192,7 @@ class Morpheus::Cli::Hosts
|
|
|
186
192
|
params['clusterId'] = cluster['id']
|
|
187
193
|
end
|
|
188
194
|
end
|
|
195
|
+
params['labels'] = options[:labels] if options[:labels]
|
|
189
196
|
if options[:tags] && !options[:tags].empty?
|
|
190
197
|
options[:tags].each do |k,v|
|
|
191
198
|
params['tags.' + k] = v
|
|
@@ -530,9 +537,10 @@ class Morpheus::Cli::Hosts
|
|
|
530
537
|
puts records_as_csv([json_response['server']], options)
|
|
531
538
|
return 0
|
|
532
539
|
end
|
|
533
|
-
server = json_response['server']
|
|
540
|
+
server = json_response['server'] || json_response['host'] || {}
|
|
534
541
|
#stats = server['stats'] || json_response['stats'] || {}
|
|
535
542
|
stats = json_response['stats'] || {}
|
|
543
|
+
tags = server['tags'] || server['metadata']
|
|
536
544
|
title = "Host Details"
|
|
537
545
|
print_h1 title, [], options
|
|
538
546
|
print cyan
|
|
@@ -541,6 +549,8 @@ class Morpheus::Cli::Hosts
|
|
|
541
549
|
"Name" => 'name',
|
|
542
550
|
"Hostname" => 'hostname',
|
|
543
551
|
"Description" => 'description',
|
|
552
|
+
"Labels" => lambda {|it| it['labels'] ? it['labels'].join(',') : '' },
|
|
553
|
+
"Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
|
|
544
554
|
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
|
545
555
|
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
|
546
556
|
#"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
|
|
@@ -564,6 +574,8 @@ class Morpheus::Cli::Hosts
|
|
|
564
574
|
# server_columns.delete("Tenant") if multi_tenant != true
|
|
565
575
|
server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
|
|
566
576
|
server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
|
|
577
|
+
server_columns.delete("Labels") if server['labels'].nil? || server['labels'].empty?
|
|
578
|
+
server_columns.delete("Tags") if tags.nil? || tags.empty?
|
|
567
579
|
|
|
568
580
|
print_description_list(server_columns, server)
|
|
569
581
|
|
|
@@ -990,6 +1002,22 @@ class Morpheus::Cli::Hosts
|
|
|
990
1002
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
|
991
1003
|
params['powerScheduleType'] = val == "null" ? nil : val
|
|
992
1004
|
end
|
|
1005
|
+
opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
1006
|
+
params['labels'] = val.to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
|
1007
|
+
end
|
|
1008
|
+
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
|
1009
|
+
options[:tags] = val
|
|
1010
|
+
end
|
|
1011
|
+
opts.on('--metadata LIST', String, "Alias for --tags.") do |val|
|
|
1012
|
+
options[:tags] = val
|
|
1013
|
+
end
|
|
1014
|
+
opts.add_hidden_option('--metadata')
|
|
1015
|
+
opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
|
|
1016
|
+
options[:add_tags] = val
|
|
1017
|
+
end
|
|
1018
|
+
opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
|
|
1019
|
+
options[:remove_tags] = val
|
|
1020
|
+
end
|
|
993
1021
|
# opts.on('--created-by ID', String, "Created By User ID") do |val|
|
|
994
1022
|
# params['createdById'] = val
|
|
995
1023
|
# end
|
|
@@ -1008,6 +1036,18 @@ class Morpheus::Cli::Hosts
|
|
|
1008
1036
|
new_group = nil
|
|
1009
1037
|
passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
|
|
1010
1038
|
params.deep_merge!(passed_options) unless passed_options.empty?
|
|
1039
|
+
# metadata tags
|
|
1040
|
+
if options[:tags]
|
|
1041
|
+
params['tags'] = parse_metadata(options[:tags])
|
|
1042
|
+
else
|
|
1043
|
+
# params['tags'] = prompt_metadata(options)
|
|
1044
|
+
end
|
|
1045
|
+
if options[:add_tags]
|
|
1046
|
+
params['addTags'] = parse_metadata(options[:add_tags])
|
|
1047
|
+
end
|
|
1048
|
+
if options[:remove_tags]
|
|
1049
|
+
params['removeTags'] = parse_metadata(options[:remove_tags])
|
|
1050
|
+
end
|
|
1011
1051
|
payload = nil
|
|
1012
1052
|
if options[:payload]
|
|
1013
1053
|
payload = options[:payload]
|
|
@@ -1919,7 +1959,8 @@ class Morpheus::Cli::Hosts
|
|
|
1919
1959
|
snapshot_column_definitions = {
|
|
1920
1960
|
"ID" => lambda {|it| it['id'] },
|
|
1921
1961
|
"Name" => lambda {|it| it['name'] },
|
|
1922
|
-
"Description" => lambda {|it| it['
|
|
1962
|
+
"Description" => lambda {|it| it['description'] },
|
|
1963
|
+
# "Type" => lambda {|it| it['snapshotType'] },
|
|
1923
1964
|
"Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
|
|
1924
1965
|
"Status" => lambda {|it| format_snapshot_status(it) }
|
|
1925
1966
|
}
|