morpheus-cli 4.2.22 → 5.2.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/lib/morpheus/api/api_client.rb +30 -0
- data/lib/morpheus/api/billing_interface.rb +34 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
- data/lib/morpheus/api/deploy_interface.rb +1 -1
- data/lib/morpheus/api/deployments_interface.rb +20 -1
- data/lib/morpheus/api/forgot_password_interface.rb +17 -0
- data/lib/morpheus/api/instances_interface.rb +16 -2
- data/lib/morpheus/api/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- data/lib/morpheus/api/search_interface.rb +13 -0
- data/lib/morpheus/api/servers_interface.rb +14 -0
- data/lib/morpheus/api/service_catalog_interface.rb +89 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +7 -3
- data/lib/morpheus/cli/apps.rb +6 -27
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/catalog_item_types_command.rb +622 -0
- data/lib/morpheus/cli/cli_command.rb +70 -21
- data/lib/morpheus/cli/commands/standard/curl_command.rb +3 -5
- data/lib/morpheus/cli/commands/standard/history_command.rb +3 -1
- data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
- data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
- data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
- data/lib/morpheus/cli/containers_command.rb +14 -24
- data/lib/morpheus/cli/cypher_command.rb +6 -2
- data/lib/morpheus/cli/deploy.rb +199 -90
- data/lib/morpheus/cli/deployments.rb +341 -28
- data/lib/morpheus/cli/deploys.rb +206 -41
- data/lib/morpheus/cli/error_handler.rb +7 -0
- data/lib/morpheus/cli/forgot_password.rb +133 -0
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/health_command.rb +59 -2
- data/lib/morpheus/cli/hosts.rb +295 -35
- data/lib/morpheus/cli/instances.rb +247 -130
- data/lib/morpheus/cli/invoices_command.rb +37 -19
- data/lib/morpheus/cli/library_option_lists_command.rb +15 -7
- data/lib/morpheus/cli/library_option_types_command.rb +5 -2
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +12 -7
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -3
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -21
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
- data/lib/morpheus/cli/option_types.rb +271 -22
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/remote.rb +35 -12
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +453 -113
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/tasks.rb +29 -32
- data/lib/morpheus/cli/usage_command.rb +203 -0
- data/lib/morpheus/cli/user_settings_command.rb +1 -0
- data/lib/morpheus/cli/users.rb +12 -1
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +429 -254
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +33 -40
- data/lib/morpheus/formatters.rb +75 -7
- data/lib/morpheus/terminal.rb +6 -2
- metadata +14 -2
data/lib/morpheus/cli/groups.rb
CHANGED
@@ -52,7 +52,7 @@ class Morpheus::Cli::Groups
|
|
52
52
|
end
|
53
53
|
json_response = @groups_interface.list(params)
|
54
54
|
exit_code, err = 0, nil
|
55
|
-
render_response(json_response, options) do
|
55
|
+
render_response(json_response, options, "groups") do
|
56
56
|
groups = json_response['groups']
|
57
57
|
subtitles = []
|
58
58
|
subtitles += parse_list_subtitles(options)
|
@@ -30,6 +30,7 @@ class Morpheus::Cli::HealthCommand
|
|
30
30
|
opts.on('-a', '--all', "Display all details: CPU, Memory, Database, etc." ) do
|
31
31
|
options[:details] = true
|
32
32
|
options[:show_cpu] = true
|
33
|
+
options[:show_threads] = true
|
33
34
|
options[:show_memory] = true
|
34
35
|
options[:show_database] = true
|
35
36
|
options[:show_elastic] = true
|
@@ -47,6 +48,9 @@ class Morpheus::Cli::HealthCommand
|
|
47
48
|
opts.on('--cpu', "Display CPU details" ) do
|
48
49
|
options[:show_cpu] = true
|
49
50
|
end
|
51
|
+
opts.on('--threads', "Display Thread details" ) do
|
52
|
+
options[:show_threads] = true
|
53
|
+
end
|
50
54
|
opts.on('--memory', "Display Memory details" ) do
|
51
55
|
options[:show_memory] = true
|
52
56
|
end
|
@@ -184,6 +188,59 @@ class Morpheus::Cli::HealthCommand
|
|
184
188
|
end
|
185
189
|
end
|
186
190
|
|
191
|
+
# Threads ()
|
192
|
+
if options[:show_threads]
|
193
|
+
print_h2 "Threads", options
|
194
|
+
if health['threads'].nil?
|
195
|
+
print yellow,"No thread information returned.",reset,"\n\n"
|
196
|
+
else
|
197
|
+
print cyan
|
198
|
+
|
199
|
+
thread_summary_columns = {
|
200
|
+
"Thread Count" => lambda {|it| it['totalThreads'].size rescue '' },
|
201
|
+
"Busy Threads" => lambda {|it| it['busyThreads'].size rescue '' },
|
202
|
+
"Running Threads" => lambda {|it| it['runningThreads'].size rescue '' },
|
203
|
+
"Blocked Threads" => lambda {|it| it['blockedThreads'].size rescue '' },
|
204
|
+
}
|
205
|
+
print_description_list(thread_summary_columns, health['threads'], options)
|
206
|
+
|
207
|
+
|
208
|
+
thread_columns = [
|
209
|
+
{"Name".upcase => lambda {|it| it['name']} },
|
210
|
+
{"Status".upcase => lambda {|it|
|
211
|
+
# hrmm
|
212
|
+
status_string = (it['status'] || it['state']).to_s.downcase
|
213
|
+
status_color = cyan
|
214
|
+
# if status_string.include?('waiting')
|
215
|
+
# status_color = yellow
|
216
|
+
# end
|
217
|
+
"#{status_color}#{status_string.upcase}#{cyan}"
|
218
|
+
} },
|
219
|
+
# {"CPU Time" => lambda {|it| it['cpuTime'].to_s } },
|
220
|
+
# {"CPU Time" => lambda {|it| format_human_duration(it['cpuTime'].to_f / 1000) rescue '' } },
|
221
|
+
{"CPU Percent" => lambda {|it| it['cpuPercent'].to_i.to_s + '%' } }
|
222
|
+
]
|
223
|
+
|
224
|
+
if health['threads']['busyThreads'] && health['threads']['busyThreads'].size > 0
|
225
|
+
print_h2 "Busy Threads"
|
226
|
+
print cyan
|
227
|
+
print as_pretty_table(health['threads']['busyThreads'], thread_columns, options)
|
228
|
+
end
|
229
|
+
|
230
|
+
if health['threads']['runningThreads'] && health['threads']['runningThreads'].size > 0
|
231
|
+
print_h2 "Running Threads"
|
232
|
+
print cyan
|
233
|
+
print as_pretty_table(health['threads']['runningThreads'], thread_columns, options)
|
234
|
+
end
|
235
|
+
|
236
|
+
if health['threads']['blockedThreads'] && health['threads']['blockedThreads'].size > 0
|
237
|
+
print_h2 "Blocked Threads"
|
238
|
+
print cyan
|
239
|
+
print as_pretty_table(health['threads']['blockedThreads'], thread_columns, options)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
187
244
|
# Memory
|
188
245
|
if options[:show_memory]
|
189
246
|
if health['memory'].nil?
|
@@ -475,8 +532,8 @@ class Morpheus::Cli::HealthCommand
|
|
475
532
|
opts.footer = "List health logs. These are the logs of the morpheus appliance itself."
|
476
533
|
end
|
477
534
|
optparse.parse!(args)
|
478
|
-
if args.count
|
479
|
-
|
535
|
+
if args.count > 0
|
536
|
+
options[:phrase] = args.join(" ")
|
480
537
|
end
|
481
538
|
connect(options)
|
482
539
|
begin
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -16,10 +16,11 @@ class Morpheus::Cli::Hosts
|
|
16
16
|
include Morpheus::Cli::LogsHelper
|
17
17
|
set_command_name :hosts
|
18
18
|
set_command_description "View and manage hosts (servers)."
|
19
|
-
register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize,
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize,
|
20
|
+
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software,
|
21
|
+
{:'types' => :list_types},
|
22
|
+
{:exec => :execution_request},
|
23
|
+
:wiki, :update_wiki
|
23
24
|
alias_subcommand :details, :get
|
24
25
|
set_default_subcommand :list
|
25
26
|
|
@@ -53,9 +54,6 @@ class Morpheus::Cli::Hosts
|
|
53
54
|
params = {}
|
54
55
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
55
56
|
opts.banner = subcommand_usage()
|
56
|
-
opts.on( '-a', '--account ACCOUNT', "Account Name or ID" ) do |val|
|
57
|
-
options[:account] = val
|
58
|
-
end
|
59
57
|
opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
60
58
|
options[:group] = val
|
61
59
|
end
|
@@ -81,6 +79,17 @@ class Morpheus::Cli::Hosts
|
|
81
79
|
# params[:clusterId] = val
|
82
80
|
options[:cluster] = val
|
83
81
|
end
|
82
|
+
opts.on( '--plan NAME', String, "Filter by Plan name(s)" ) do |val|
|
83
|
+
# commas used in names a lot so use --plan one --plan two
|
84
|
+
params['plan'] ||= []
|
85
|
+
params['plan'] << val
|
86
|
+
end
|
87
|
+
opts.on( '--plan-id ID', String, "Filter by Plan id(s)" ) do |val|
|
88
|
+
params['planId'] = parse_id_list(val)
|
89
|
+
end
|
90
|
+
opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
|
91
|
+
params['planCode'] = parse_id_list(val)
|
92
|
+
end
|
84
93
|
opts.on( '', '--vm', "Show only virtual machines" ) do |val|
|
85
94
|
params[:vm] = true
|
86
95
|
end
|
@@ -105,8 +114,16 @@ class Morpheus::Cli::Hosts
|
|
105
114
|
opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
|
106
115
|
options[:created_by] = val
|
107
116
|
end
|
108
|
-
opts.on('--
|
109
|
-
options[:
|
117
|
+
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
118
|
+
options[:account] = val
|
119
|
+
end
|
120
|
+
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
121
|
+
val.split(",").each do |value_pair|
|
122
|
+
k,v = value_pair.strip.split("=")
|
123
|
+
options[:tags] ||= {}
|
124
|
+
options[:tags][k] ||= []
|
125
|
+
options[:tags][k] << (v || '')
|
126
|
+
end
|
110
127
|
end
|
111
128
|
opts.on('--tag-compliant', "Displays only servers that are valid according to applied tag policies. Does not show servers that do not have tag policies." ) do
|
112
129
|
params[:tagCompliant] = true
|
@@ -114,11 +131,21 @@ class Morpheus::Cli::Hosts
|
|
114
131
|
opts.on('--non-tag-compliant', "Displays only servers with tag compliance warnings." ) do
|
115
132
|
params[:tagCompliant] = false
|
116
133
|
end
|
117
|
-
|
134
|
+
opts.on('--stats', "Display values for memory and storage usage used / max values." ) do
|
135
|
+
options[:stats] = true
|
136
|
+
end
|
137
|
+
opts.on('-a', '--details', "Display all details: hostname, private ip, plan, stats, etc." ) do
|
138
|
+
options[:details] = true
|
139
|
+
end
|
140
|
+
build_standard_list_options(opts, options)
|
118
141
|
opts.footer = "List hosts."
|
119
142
|
end
|
120
143
|
optparse.parse!(args)
|
121
144
|
connect(options)
|
145
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
146
|
+
if args.count > 0
|
147
|
+
options[:phrase] = args.join(" ")
|
148
|
+
end
|
122
149
|
begin
|
123
150
|
params.merge!(parse_list_options(options))
|
124
151
|
account = nil
|
@@ -159,6 +186,11 @@ class Morpheus::Cli::Hosts
|
|
159
186
|
params['clusterId'] = cluster['id']
|
160
187
|
end
|
161
188
|
end
|
189
|
+
if options[:tags] && !options[:tags].empty?
|
190
|
+
options[:tags].each do |k,v|
|
191
|
+
params['tags.' + k] = v
|
192
|
+
end
|
193
|
+
end
|
162
194
|
|
163
195
|
@servers_interface.setopts(options)
|
164
196
|
if options[:dry_run]
|
@@ -190,6 +222,9 @@ class Morpheus::Cli::Hosts
|
|
190
222
|
multi_tenant = json_response['multiTenant'] == true
|
191
223
|
title = "Morpheus Hosts"
|
192
224
|
subtitles = []
|
225
|
+
if account
|
226
|
+
subtitles << "Tenant: #{account['name']}".strip
|
227
|
+
end
|
193
228
|
if group
|
194
229
|
subtitles << "Group: #{group['name']}".strip
|
195
230
|
end
|
@@ -230,7 +265,7 @@ class Morpheus::Cli::Hosts
|
|
230
265
|
cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
|
231
266
|
memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
|
232
267
|
storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
|
233
|
-
if options[:details]
|
268
|
+
if options[:details] || options[:stats]
|
234
269
|
if stats['maxMemory'] && stats['maxMemory'].to_i != 0
|
235
270
|
memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
|
236
271
|
end
|
@@ -240,31 +275,76 @@ class Morpheus::Cli::Hosts
|
|
240
275
|
end
|
241
276
|
row = {
|
242
277
|
id: server['id'],
|
243
|
-
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
244
278
|
name: server['name'],
|
279
|
+
external_name: server['externalName'],
|
280
|
+
hostname: server['hostname'],
|
245
281
|
platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
|
246
|
-
cloud: server['zone'] ? server['zone']['name'] : '',
|
247
282
|
type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
|
283
|
+
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
284
|
+
owner: server['owner'] ? server['owner']['username'] : server['owner'],
|
285
|
+
cloud: server['zone'] ? server['zone']['name'] : '',
|
286
|
+
plan: server['plan'] ? server['plan']['name'] : '',
|
287
|
+
ip: server['externalIp'],
|
288
|
+
internal_ip: server['internalIp'],
|
248
289
|
nodes: server['containers'] ? server['containers'].size : '',
|
249
|
-
status: format_server_status(server, cyan),
|
290
|
+
# status: format_server_status(server, cyan),
|
291
|
+
status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
|
250
292
|
power: format_server_power_state(server, cyan),
|
251
293
|
cpu: cpu_usage_str + cyan,
|
252
294
|
memory: memory_usage_str + cyan,
|
253
|
-
storage: storage_usage_str + cyan
|
295
|
+
storage: storage_usage_str + cyan,
|
296
|
+
created: format_local_dt(server['dateCreated']),
|
297
|
+
updated: format_local_dt(server['lastUpdated']),
|
254
298
|
}
|
255
299
|
row
|
256
300
|
}
|
257
|
-
columns = [:id, :name, :type, :cloud, :nodes, :status, :power]
|
258
|
-
|
259
|
-
|
301
|
+
# columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
|
302
|
+
columns = {
|
303
|
+
"ID" => :id,
|
304
|
+
"Name" => :name,
|
305
|
+
"External Name" => :external_name,
|
306
|
+
"Hostname" => :hostname,
|
307
|
+
"Type" => :type,
|
308
|
+
"Owner" => :owner,
|
309
|
+
"Tenant" => :tenant,
|
310
|
+
"Cloud" => :cloud,
|
311
|
+
"Plan" => :plan,
|
312
|
+
"IP" => :ip,
|
313
|
+
"Private IP" => :internal_ip,
|
314
|
+
"Nodes" => :nodes,
|
315
|
+
"Status" => :status,
|
316
|
+
"Power" => :power,
|
317
|
+
"CPU" => :cpu,
|
318
|
+
"Memory" => :memory,
|
319
|
+
"Storage" => :storage,
|
320
|
+
"Created" => :created,
|
321
|
+
"Updated" => :updated,
|
322
|
+
}
|
323
|
+
if options[:details] != true
|
324
|
+
columns.delete("External Name")
|
325
|
+
columns.delete("Hostname")
|
326
|
+
columns.delete("Plan")
|
327
|
+
columns.delete("Private IP")
|
328
|
+
columns.delete("Owner")
|
329
|
+
columns.delete("Tenant")
|
330
|
+
columns.delete("Power")
|
331
|
+
columns.delete("Created")
|
332
|
+
columns.delete("Updated")
|
333
|
+
end
|
334
|
+
# hide External Name if there are none
|
335
|
+
if !servers.find {|it| it['externalName'] && it['externalName'] != it['name']}
|
336
|
+
columns.delete("External Name")
|
260
337
|
end
|
261
|
-
|
262
|
-
|
263
|
-
if options[:include_fields]
|
264
|
-
columns = options[:include_fields]
|
338
|
+
if !multi_tenant
|
339
|
+
columns.delete("Tenant")
|
265
340
|
end
|
341
|
+
# columns += [:cpu, :memory, :storage]
|
342
|
+
# # custom pretty table columns ...
|
343
|
+
# if options[:include_fields]
|
344
|
+
# columns = options[:include_fields]
|
345
|
+
# end
|
266
346
|
print cyan
|
267
|
-
print as_pretty_table(rows, columns
|
347
|
+
print as_pretty_table(rows, columns.upcase_keys!, options)
|
268
348
|
print reset
|
269
349
|
print_results_pagination(json_response)
|
270
350
|
end
|
@@ -281,7 +361,7 @@ class Morpheus::Cli::Hosts
|
|
281
361
|
options = {}
|
282
362
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
283
363
|
opts.banner = subcommand_usage("[options]")
|
284
|
-
opts.on( '
|
364
|
+
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
285
365
|
options[:account] = val
|
286
366
|
end
|
287
367
|
opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
@@ -392,6 +472,9 @@ class Morpheus::Cli::Hosts
|
|
392
472
|
options = {}
|
393
473
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
394
474
|
opts.banner = subcommand_usage("[name]")
|
475
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
476
|
+
options[:include_costs] = true
|
477
|
+
end
|
395
478
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is provisioned,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
396
479
|
options[:refresh_until_status] ||= "provisioned,failed"
|
397
480
|
if !val.to_s.empty?
|
@@ -447,28 +530,46 @@ class Morpheus::Cli::Hosts
|
|
447
530
|
puts records_as_csv([json_response['server']], options)
|
448
531
|
return 0
|
449
532
|
end
|
450
|
-
server = json_response['server']
|
533
|
+
server = json_response['server'] || json_response['host'] || {}
|
451
534
|
#stats = server['stats'] || json_response['stats'] || {}
|
452
535
|
stats = json_response['stats'] || {}
|
536
|
+
tags = server['tags'] || server['metadata']
|
453
537
|
title = "Host Details"
|
454
538
|
print_h1 title, [], options
|
455
539
|
print cyan
|
456
|
-
|
540
|
+
server_columns = {
|
457
541
|
"ID" => 'id',
|
458
542
|
"Name" => 'name',
|
543
|
+
"Hostname" => 'hostname',
|
459
544
|
"Description" => 'description',
|
460
|
-
"
|
545
|
+
"Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
|
546
|
+
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
547
|
+
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
461
548
|
#"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
|
462
549
|
"Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
|
550
|
+
"IP" => lambda {|it| it['externalIp'] },
|
551
|
+
"Private IP" => lambda {|it| it['internalIp'] },
|
463
552
|
"Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
|
464
553
|
"Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
|
465
554
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
555
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
556
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
466
557
|
"Agent" => lambda {|it| it['agentInstalled'] ? "#{server['agentVersion'] || ''} updated at #{format_local_dt(server['lastAgentUpdate'])}" : '(not installed)' },
|
467
|
-
"Status" => lambda {|it| format_server_status(it) },
|
468
558
|
"Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
|
469
|
-
"
|
470
|
-
|
471
|
-
|
559
|
+
# "Status" => lambda {|it| format_server_status(it) },
|
560
|
+
# "Power" => lambda {|it| format_server_power_state(it) },
|
561
|
+
"Status" => lambda {|it| format_server_status_friendly(it) }, # combo
|
562
|
+
}
|
563
|
+
server_columns.delete("Hostname") if server['hostname'].to_s.empty? || server['hostname'] == server['name']
|
564
|
+
server_columns.delete("IP") if server['externalIp'].to_s.empty?
|
565
|
+
server_columns.delete("Private IP") if server['internalIp'].to_s.empty?
|
566
|
+
# server_columns.delete("Tenant") if multi_tenant != true
|
567
|
+
server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
|
568
|
+
server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
|
569
|
+
server_columns.delete("Tags") if tags.nil? || tags.empty?
|
570
|
+
|
571
|
+
print_description_list(server_columns, server)
|
572
|
+
|
472
573
|
if server['statusMessage']
|
473
574
|
print_h2 "Status Message", options
|
474
575
|
if server['status'] == 'failed'
|
@@ -485,6 +586,16 @@ class Morpheus::Cli::Hosts
|
|
485
586
|
|
486
587
|
print_h2 "Host Usage", options
|
487
588
|
print_stats_usage(stats)
|
589
|
+
|
590
|
+
if options[:include_costs]
|
591
|
+
print_h2 "Host Cost"
|
592
|
+
cost_columns = {
|
593
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
594
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
595
|
+
}
|
596
|
+
print_description_list(cost_columns, server)
|
597
|
+
end
|
598
|
+
|
488
599
|
print reset, "\n"
|
489
600
|
|
490
601
|
|
@@ -882,6 +993,19 @@ class Morpheus::Cli::Hosts
|
|
882
993
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
883
994
|
params['powerScheduleType'] = val == "null" ? nil : val
|
884
995
|
end
|
996
|
+
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
997
|
+
options[:tags] = val
|
998
|
+
end
|
999
|
+
opts.on('--metadata LIST', String, "Alias for --tags.") do |val|
|
1000
|
+
options[:tags] = val
|
1001
|
+
end
|
1002
|
+
opts.add_hidden_option('--metadata')
|
1003
|
+
opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
|
1004
|
+
options[:add_tags] = val
|
1005
|
+
end
|
1006
|
+
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|
|
1007
|
+
options[:remove_tags] = val
|
1008
|
+
end
|
885
1009
|
# opts.on('--created-by ID', String, "Created By User ID") do |val|
|
886
1010
|
# params['createdById'] = val
|
887
1011
|
# end
|
@@ -900,6 +1024,18 @@ class Morpheus::Cli::Hosts
|
|
900
1024
|
new_group = nil
|
901
1025
|
passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
|
902
1026
|
params.deep_merge!(passed_options) unless passed_options.empty?
|
1027
|
+
# metadata tags
|
1028
|
+
if options[:tags]
|
1029
|
+
params['tags'] = parse_metadata(options[:tags])
|
1030
|
+
else
|
1031
|
+
# params['tags'] = prompt_metadata(options)
|
1032
|
+
end
|
1033
|
+
if options[:add_tags]
|
1034
|
+
params['addTags'] = parse_metadata(options[:add_tags])
|
1035
|
+
end
|
1036
|
+
if options[:remove_tags]
|
1037
|
+
params['removeTags'] = parse_metadata(options[:remove_tags])
|
1038
|
+
end
|
903
1039
|
payload = nil
|
904
1040
|
if options[:payload]
|
905
1041
|
payload = options[:payload]
|
@@ -1781,6 +1917,103 @@ class Morpheus::Cli::Hosts
|
|
1781
1917
|
end
|
1782
1918
|
end
|
1783
1919
|
|
1920
|
+
def snapshots(args)
|
1921
|
+
options = {}
|
1922
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1923
|
+
opts.banner = subcommand_usage("[host]")
|
1924
|
+
# no pagination yet
|
1925
|
+
# build_standard_list_options(opts, options)
|
1926
|
+
build_standard_get_options(opts, options)
|
1927
|
+
end
|
1928
|
+
optparse.parse!(args)
|
1929
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
1930
|
+
connect(options)
|
1931
|
+
begin
|
1932
|
+
server = find_host_by_name_or_id(args[0])
|
1933
|
+
return 1 if server.nil?
|
1934
|
+
params = {}
|
1935
|
+
@servers_interface.setopts(options)
|
1936
|
+
if options[:dry_run]
|
1937
|
+
print_dry_run @servers_interface.dry.snapshots(server['id'], params)
|
1938
|
+
return
|
1939
|
+
end
|
1940
|
+
json_response = @servers_interface.snapshots(server['id'], params)
|
1941
|
+
snapshots = json_response['snapshots']
|
1942
|
+
render_response(json_response, options, 'snapshots') do
|
1943
|
+
print_h1 "Snapshots: #{server['name']}", [], options
|
1944
|
+
if snapshots.empty?
|
1945
|
+
print cyan,"No snapshots found",reset,"\n"
|
1946
|
+
else
|
1947
|
+
snapshot_column_definitions = {
|
1948
|
+
"ID" => lambda {|it| it['id'] },
|
1949
|
+
"Name" => lambda {|it| it['name'] },
|
1950
|
+
"Description" => lambda {|it| it['description'] },
|
1951
|
+
# "Type" => lambda {|it| it['snapshotType'] },
|
1952
|
+
"Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
|
1953
|
+
"Status" => lambda {|it| format_snapshot_status(it) }
|
1954
|
+
}
|
1955
|
+
print cyan
|
1956
|
+
print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
|
1957
|
+
print_results_pagination({size: snapshots.size, total: snapshots.size})
|
1958
|
+
end
|
1959
|
+
print reset, "\n"
|
1960
|
+
end
|
1961
|
+
return 0
|
1962
|
+
rescue RestClient::Exception => e
|
1963
|
+
print_rest_exception(e, options)
|
1964
|
+
exit 1
|
1965
|
+
end
|
1966
|
+
end
|
1967
|
+
|
1968
|
+
def software(args)
|
1969
|
+
options = {}
|
1970
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1971
|
+
opts.banner = subcommand_usage("[host]")
|
1972
|
+
build_standard_list_options(opts, options)
|
1973
|
+
end
|
1974
|
+
optparse.parse!(args)
|
1975
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
1976
|
+
connect(options)
|
1977
|
+
begin
|
1978
|
+
server = find_host_by_name_or_id(args[0])
|
1979
|
+
return 1 if server.nil?
|
1980
|
+
params = {}
|
1981
|
+
params.merge!(parse_list_options(options))
|
1982
|
+
@servers_interface.setopts(options)
|
1983
|
+
if options[:dry_run]
|
1984
|
+
print_dry_run @servers_interface.dry.software(server['id'], params)
|
1985
|
+
return
|
1986
|
+
end
|
1987
|
+
json_response = @servers_interface.software(server['id'], params)
|
1988
|
+
software = json_response['software']
|
1989
|
+
render_response(json_response, options, 'software') do
|
1990
|
+
print_h1 "Software: #{server['name']}", [], options
|
1991
|
+
if software.empty?
|
1992
|
+
print cyan,"No software found",reset,"\n"
|
1993
|
+
else
|
1994
|
+
software_column_definitions = {
|
1995
|
+
# "ID" => lambda {|it| it['id'] },
|
1996
|
+
"Name" => lambda {|it| it['name'] },
|
1997
|
+
"Version" => lambda {|it| it['packageVersion'] },
|
1998
|
+
"Publisher" => lambda {|it| it['packagePublisher'] },
|
1999
|
+
# "Release" => lambda {|it| it['packageRelease'] },
|
2000
|
+
# "Type" => lambda {|it| it['packageType'] },
|
2001
|
+
# "Architecture" => lambda {|it| it['architecture'] },
|
2002
|
+
# "Install Date" => lambda {|it| format_local_dt(it['installDate']) },
|
2003
|
+
}
|
2004
|
+
print cyan
|
2005
|
+
print as_pretty_table(software, software_column_definitions.upcase_keys!, options)
|
2006
|
+
print_results_pagination({size: software.size, total: software.size})
|
2007
|
+
end
|
2008
|
+
print reset, "\n"
|
2009
|
+
end
|
2010
|
+
return 0
|
2011
|
+
rescue RestClient::Exception => e
|
2012
|
+
print_rest_exception(e, options)
|
2013
|
+
exit 1
|
2014
|
+
end
|
2015
|
+
end
|
2016
|
+
|
1784
2017
|
private
|
1785
2018
|
|
1786
2019
|
def find_host_by_id(id)
|
@@ -1897,16 +2130,43 @@ class Morpheus::Cli::Hosts
|
|
1897
2130
|
|
1898
2131
|
def format_server_status(server, return_color=cyan)
|
1899
2132
|
out = ""
|
1900
|
-
status_string = server['status']
|
1901
|
-
|
1902
|
-
|
2133
|
+
status_string = server['status'].to_s.downcase
|
2134
|
+
if status_string == 'provisioned'
|
2135
|
+
out = "#{cyan}#{status_string.upcase}#{return_color}"
|
2136
|
+
elsif status_string == 'provisioning'
|
2137
|
+
out = "#{cyan}#{status_string.upcase}#{cyan}"
|
2138
|
+
elsif status_string == 'failed' or status_string == 'error'
|
2139
|
+
out = "#{red}#{status_string.upcase}#{return_color}"
|
2140
|
+
else
|
2141
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
2142
|
+
end
|
1903
2143
|
out
|
1904
2144
|
end
|
1905
2145
|
|
2146
|
+
def format_server_status_friendly(server, return_color=cyan)
|
2147
|
+
out = ""
|
2148
|
+
status_string = server['status'].to_s.downcase
|
2149
|
+
if status_string == 'provisioned'
|
2150
|
+
# out = format_server_power_state(server, return_color)
|
2151
|
+
# make it looks like format_instance_status
|
2152
|
+
if server['powerState'] == 'on'
|
2153
|
+
out << "#{green}RUNNING#{return_color}"
|
2154
|
+
elsif server['powerState'] == 'off'
|
2155
|
+
out << "#{red}STOPPED#{return_color}"
|
2156
|
+
else
|
2157
|
+
out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
|
2158
|
+
end
|
2159
|
+
else
|
2160
|
+
out = format_server_status(server, return_color)
|
2161
|
+
end
|
2162
|
+
out
|
2163
|
+
end
|
2164
|
+
|
2165
|
+
|
1906
2166
|
def make_managed_option_types(connected=true)
|
1907
2167
|
[
|
1908
2168
|
#{'fieldName' => 'account', 'fieldLabel' => 'Account', 'type' => 'select', 'optionSource' => 'accounts', 'required' => true},
|
1909
|
-
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text'
|
2169
|
+
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text'},
|
1910
2170
|
{'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false},
|
1911
2171
|
{'fieldName' => 'serverOs', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false},
|
1912
2172
|
]
|