morpheus-cli 4.2.19 → 5.0.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/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +26 -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 +7 -0
- 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 +7 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +6 -3
- data/lib/morpheus/cli/apps.rb +3 -4
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/budgets_command.rb +4 -4
- data/lib/morpheus/cli/catalog_command.rb +507 -0
- data/lib/morpheus/cli/cli_command.rb +45 -20
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
- data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -12
- 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 -0
- data/lib/morpheus/cli/deploy.rb +199 -90
- data/lib/morpheus/cli/deployments.rb +342 -29
- 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/health_command.rb +2 -2
- data/lib/morpheus/cli/hosts.rb +193 -28
- data/lib/morpheus/cli/instances.rb +102 -33
- data/lib/morpheus/cli/invoices_command.rb +33 -16
- data/lib/morpheus/cli/jobs_command.rb +28 -6
- data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
- data/lib/morpheus/cli/library_option_lists_command.rb +14 -6
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -6
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/catalog_helper.rb +66 -0
- 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 +24 -4
- data/lib/morpheus/cli/network_pools_command.rb +14 -6
- data/lib/morpheus/cli/option_types.rb +266 -17
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
- data/lib/morpheus/cli/remote.rb +35 -12
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +305 -3
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- 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 +20 -21
- data/lib/morpheus/cli/tenants_command.rb +1 -1
- 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 +280 -199
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +34 -41
- data/lib/morpheus/formatters.rb +48 -5
- data/lib/morpheus/terminal.rb +6 -2
- metadata +13 -2
|
@@ -475,8 +475,8 @@ class Morpheus::Cli::HealthCommand
|
|
|
475
475
|
opts.footer = "List health logs. These are the logs of the morpheus appliance itself."
|
|
476
476
|
end
|
|
477
477
|
optparse.parse!(args)
|
|
478
|
-
if args.count
|
|
479
|
-
|
|
478
|
+
if args.count > 0
|
|
479
|
+
options[:phrase] = args.join(" ")
|
|
480
480
|
end
|
|
481
481
|
connect(options)
|
|
482
482
|
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,
|
|
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,13 @@ 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(
|
|
57
|
-
options[:
|
|
57
|
+
opts.on('-a', '--all', "Display all details: memory and storage usage used / max values." ) do
|
|
58
|
+
options[:details] = true
|
|
59
|
+
end
|
|
60
|
+
opts.on('--details', "Display all details: alias for --all" ) do
|
|
61
|
+
options[:details] = true
|
|
58
62
|
end
|
|
63
|
+
opts.add_hidden_option('--details')
|
|
59
64
|
opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
|
60
65
|
options[:group] = val
|
|
61
66
|
end
|
|
@@ -105,20 +110,35 @@ class Morpheus::Cli::Hosts
|
|
|
105
110
|
opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
|
|
106
111
|
options[:created_by] = val
|
|
107
112
|
end
|
|
113
|
+
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
|
114
|
+
options[:account] = val
|
|
115
|
+
end
|
|
108
116
|
opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
|
|
109
117
|
options[:details] = true
|
|
110
118
|
end
|
|
119
|
+
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
|
120
|
+
val.split(",").each do |value_pair|
|
|
121
|
+
k,v = value_pair.strip.split("=")
|
|
122
|
+
options[:tags] ||= {}
|
|
123
|
+
options[:tags][k] ||= []
|
|
124
|
+
options[:tags][k] << (v || '')
|
|
125
|
+
end
|
|
126
|
+
end
|
|
111
127
|
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
128
|
params[:tagCompliant] = true
|
|
113
129
|
end
|
|
114
130
|
opts.on('--non-tag-compliant', "Displays only servers with tag compliance warnings." ) do
|
|
115
131
|
params[:tagCompliant] = false
|
|
116
132
|
end
|
|
117
|
-
|
|
133
|
+
build_standard_list_options(opts, options)
|
|
118
134
|
opts.footer = "List hosts."
|
|
119
135
|
end
|
|
120
136
|
optparse.parse!(args)
|
|
121
137
|
connect(options)
|
|
138
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
|
139
|
+
if args.count > 0
|
|
140
|
+
options[:phrase] = args.join(" ")
|
|
141
|
+
end
|
|
122
142
|
begin
|
|
123
143
|
params.merge!(parse_list_options(options))
|
|
124
144
|
account = nil
|
|
@@ -159,6 +179,11 @@ class Morpheus::Cli::Hosts
|
|
|
159
179
|
params['clusterId'] = cluster['id']
|
|
160
180
|
end
|
|
161
181
|
end
|
|
182
|
+
if options[:tags] && !options[:tags].empty?
|
|
183
|
+
options[:tags].each do |k,v|
|
|
184
|
+
params['tags.' + k] = v
|
|
185
|
+
end
|
|
186
|
+
end
|
|
162
187
|
|
|
163
188
|
@servers_interface.setopts(options)
|
|
164
189
|
if options[:dry_run]
|
|
@@ -190,6 +215,9 @@ class Morpheus::Cli::Hosts
|
|
|
190
215
|
multi_tenant = json_response['multiTenant'] == true
|
|
191
216
|
title = "Morpheus Hosts"
|
|
192
217
|
subtitles = []
|
|
218
|
+
if account
|
|
219
|
+
subtitles << "Tenant: #{account['name']}".strip
|
|
220
|
+
end
|
|
193
221
|
if group
|
|
194
222
|
subtitles << "Group: #{group['name']}".strip
|
|
195
223
|
end
|
|
@@ -240,31 +268,66 @@ class Morpheus::Cli::Hosts
|
|
|
240
268
|
end
|
|
241
269
|
row = {
|
|
242
270
|
id: server['id'],
|
|
243
|
-
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
|
244
271
|
name: server['name'],
|
|
272
|
+
hostname: server['hostname'],
|
|
245
273
|
platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
|
|
246
|
-
cloud: server['zone'] ? server['zone']['name'] : '',
|
|
247
274
|
type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
|
|
275
|
+
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
|
276
|
+
owner: server['owner'] ? server['owner']['username'] : server['owner'],
|
|
277
|
+
cloud: server['zone'] ? server['zone']['name'] : '',
|
|
278
|
+
ip: server['externalIp'],
|
|
279
|
+
internal_ip: server['internalIp'],
|
|
248
280
|
nodes: server['containers'] ? server['containers'].size : '',
|
|
249
|
-
status: format_server_status(server, cyan),
|
|
281
|
+
# status: format_server_status(server, cyan),
|
|
282
|
+
status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
|
|
250
283
|
power: format_server_power_state(server, cyan),
|
|
251
284
|
cpu: cpu_usage_str + cyan,
|
|
252
285
|
memory: memory_usage_str + cyan,
|
|
253
|
-
storage: storage_usage_str + cyan
|
|
286
|
+
storage: storage_usage_str + cyan,
|
|
287
|
+
created: format_local_dt(server['dateCreated']),
|
|
288
|
+
updated: format_local_dt(server['lastUpdated']),
|
|
254
289
|
}
|
|
255
290
|
row
|
|
256
291
|
}
|
|
257
|
-
columns = [:id, :name, :type, :cloud, :nodes, :status, :power]
|
|
258
|
-
|
|
259
|
-
|
|
292
|
+
# columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
|
|
293
|
+
columns = {
|
|
294
|
+
"ID" => :id,
|
|
295
|
+
"Name" => :name,
|
|
296
|
+
"Hostname" => :hostname,
|
|
297
|
+
"Type" => :type,
|
|
298
|
+
"Owner" => :owner,
|
|
299
|
+
"Tenant" => :tenant,
|
|
300
|
+
"Cloud" => :cloud,
|
|
301
|
+
"IP" => :ip,
|
|
302
|
+
"Private IP" => :internal_ip,
|
|
303
|
+
"Nodes" => :nodes,
|
|
304
|
+
"Status" => :status,
|
|
305
|
+
"Power" => :power,
|
|
306
|
+
"CPU" => :cpu,
|
|
307
|
+
"Memory" => :memory,
|
|
308
|
+
"Storage" => :storage,
|
|
309
|
+
"Created" => :created,
|
|
310
|
+
"Updated" => :updated,
|
|
311
|
+
}
|
|
312
|
+
if options[:details] != true
|
|
313
|
+
columns.delete("Hostname")
|
|
314
|
+
columns.delete("Private IP")
|
|
315
|
+
columns.delete("Owner")
|
|
316
|
+
columns.delete("Tenant")
|
|
317
|
+
columns.delete("Power")
|
|
318
|
+
columns.delete("Created")
|
|
319
|
+
columns.delete("Updated")
|
|
260
320
|
end
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if options[:include_fields]
|
|
264
|
-
columns = options[:include_fields]
|
|
321
|
+
if !multi_tenant
|
|
322
|
+
columns.delete("Tenant")
|
|
265
323
|
end
|
|
324
|
+
# columns += [:cpu, :memory, :storage]
|
|
325
|
+
# # custom pretty table columns ...
|
|
326
|
+
# if options[:include_fields]
|
|
327
|
+
# columns = options[:include_fields]
|
|
328
|
+
# end
|
|
266
329
|
print cyan
|
|
267
|
-
print as_pretty_table(rows, columns
|
|
330
|
+
print as_pretty_table(rows, columns.upcase_keys!, options)
|
|
268
331
|
print reset
|
|
269
332
|
print_results_pagination(json_response)
|
|
270
333
|
end
|
|
@@ -392,6 +455,9 @@ class Morpheus::Cli::Hosts
|
|
|
392
455
|
options = {}
|
|
393
456
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
394
457
|
opts.banner = subcommand_usage("[name]")
|
|
458
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
|
459
|
+
options[:include_costs] = true
|
|
460
|
+
end
|
|
395
461
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is provisioned,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
|
396
462
|
options[:refresh_until_status] ||= "provisioned,failed"
|
|
397
463
|
if !val.to_s.empty?
|
|
@@ -453,22 +519,37 @@ class Morpheus::Cli::Hosts
|
|
|
453
519
|
title = "Host Details"
|
|
454
520
|
print_h1 title, [], options
|
|
455
521
|
print cyan
|
|
456
|
-
|
|
522
|
+
server_columns = {
|
|
457
523
|
"ID" => 'id',
|
|
458
524
|
"Name" => 'name',
|
|
525
|
+
"Hostname" => 'hostname',
|
|
459
526
|
"Description" => 'description',
|
|
460
|
-
"
|
|
527
|
+
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
|
528
|
+
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
|
461
529
|
#"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
|
|
462
530
|
"Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
|
|
531
|
+
"IP" => lambda {|it| it['externalIp'] },
|
|
532
|
+
"Private IP" => lambda {|it| it['internalIp'] },
|
|
463
533
|
"Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
|
|
464
534
|
"Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
|
|
465
535
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
|
536
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
537
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
466
538
|
"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
539
|
"Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
|
|
469
|
-
"
|
|
470
|
-
|
|
471
|
-
|
|
540
|
+
# "Status" => lambda {|it| format_server_status(it) },
|
|
541
|
+
# "Power" => lambda {|it| format_server_power_state(it) },
|
|
542
|
+
"Status" => lambda {|it| format_server_status_friendly(it) }, # combo
|
|
543
|
+
}
|
|
544
|
+
server_columns.delete("Hostname") if server['hostname'].to_s.empty? || server['hostname'] == server['name']
|
|
545
|
+
server_columns.delete("IP") if server['externalIp'].to_s.empty?
|
|
546
|
+
server_columns.delete("Private IP") if server['internalIp'].to_s.empty?
|
|
547
|
+
# server_columns.delete("Tenant") if multi_tenant != true
|
|
548
|
+
server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
|
|
549
|
+
server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
|
|
550
|
+
|
|
551
|
+
print_description_list(server_columns, server)
|
|
552
|
+
|
|
472
553
|
if server['statusMessage']
|
|
473
554
|
print_h2 "Status Message", options
|
|
474
555
|
if server['status'] == 'failed'
|
|
@@ -485,6 +566,16 @@ class Morpheus::Cli::Hosts
|
|
|
485
566
|
|
|
486
567
|
print_h2 "Host Usage", options
|
|
487
568
|
print_stats_usage(stats)
|
|
569
|
+
|
|
570
|
+
if options[:include_costs]
|
|
571
|
+
print_h2 "Host Cost"
|
|
572
|
+
cost_columns = {
|
|
573
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
574
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
575
|
+
}
|
|
576
|
+
print_description_list(cost_columns, server)
|
|
577
|
+
end
|
|
578
|
+
|
|
488
579
|
print reset, "\n"
|
|
489
580
|
|
|
490
581
|
|
|
@@ -1781,6 +1872,53 @@ class Morpheus::Cli::Hosts
|
|
|
1781
1872
|
end
|
|
1782
1873
|
end
|
|
1783
1874
|
|
|
1875
|
+
def snapshots(args)
|
|
1876
|
+
options = {}
|
|
1877
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
1878
|
+
opts.banner = subcommand_usage("[host]")
|
|
1879
|
+
# no pagination yet
|
|
1880
|
+
# build_standard_list_options(opts, options)
|
|
1881
|
+
build_standard_get_options(opts, options)
|
|
1882
|
+
end
|
|
1883
|
+
optparse.parse!(args)
|
|
1884
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
1885
|
+
connect(options)
|
|
1886
|
+
begin
|
|
1887
|
+
server = find_host_by_name_or_id(args[0])
|
|
1888
|
+
return 1 if server.nil?
|
|
1889
|
+
params = {}
|
|
1890
|
+
@servers_interface.setopts(options)
|
|
1891
|
+
if options[:dry_run]
|
|
1892
|
+
print_dry_run @servers_interface.dry.snapshots(server['id'], params)
|
|
1893
|
+
return
|
|
1894
|
+
end
|
|
1895
|
+
json_response = @servers_interface.snapshots(server['id'], params)
|
|
1896
|
+
snapshots = json_response['snapshots']
|
|
1897
|
+
render_response(json_response, options, 'snapshots') do
|
|
1898
|
+
print_h1 "Snapshots: #{server['name']}", [], options
|
|
1899
|
+
if snapshots.empty?
|
|
1900
|
+
print cyan,"No snapshots found",reset,"\n"
|
|
1901
|
+
else
|
|
1902
|
+
snapshot_column_definitions = {
|
|
1903
|
+
"ID" => lambda {|it| it['id'] },
|
|
1904
|
+
"Name" => lambda {|it| it['name'] },
|
|
1905
|
+
"Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
|
|
1906
|
+
"Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
|
|
1907
|
+
"Status" => lambda {|it| format_snapshot_status(it) }
|
|
1908
|
+
}
|
|
1909
|
+
print cyan
|
|
1910
|
+
print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
|
|
1911
|
+
print_results_pagination({size: snapshots.size, total: snapshots.size})
|
|
1912
|
+
end
|
|
1913
|
+
print reset, "\n"
|
|
1914
|
+
end
|
|
1915
|
+
return 0
|
|
1916
|
+
rescue RestClient::Exception => e
|
|
1917
|
+
print_rest_exception(e, options)
|
|
1918
|
+
exit 1
|
|
1919
|
+
end
|
|
1920
|
+
end
|
|
1921
|
+
|
|
1784
1922
|
private
|
|
1785
1923
|
|
|
1786
1924
|
def find_host_by_id(id)
|
|
@@ -1897,11 +2035,38 @@ class Morpheus::Cli::Hosts
|
|
|
1897
2035
|
|
|
1898
2036
|
def format_server_status(server, return_color=cyan)
|
|
1899
2037
|
out = ""
|
|
1900
|
-
status_string = server['status']
|
|
1901
|
-
|
|
1902
|
-
|
|
2038
|
+
status_string = server['status'].to_s.downcase
|
|
2039
|
+
if status_string == 'provisioned'
|
|
2040
|
+
out = "#{cyan}#{status_string.upcase}#{return_color}"
|
|
2041
|
+
elsif status_string == 'provisioning'
|
|
2042
|
+
out = "#{cyan}#{status_string.upcase}#{cyan}"
|
|
2043
|
+
elsif status_string == 'failed' or status_string == 'error'
|
|
2044
|
+
out = "#{red}#{status_string.upcase}#{return_color}"
|
|
2045
|
+
else
|
|
2046
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2047
|
+
end
|
|
2048
|
+
out
|
|
2049
|
+
end
|
|
2050
|
+
|
|
2051
|
+
def format_server_status_friendly(server, return_color=cyan)
|
|
2052
|
+
out = ""
|
|
2053
|
+
status_string = server['status'].to_s.downcase
|
|
2054
|
+
if status_string == 'provisioned'
|
|
2055
|
+
# out = format_server_power_state(server, return_color)
|
|
2056
|
+
# make it looks like format_instance_status
|
|
2057
|
+
if server['powerState'] == 'on'
|
|
2058
|
+
out << "#{green}RUNNING#{return_color}"
|
|
2059
|
+
elsif server['powerState'] == 'off'
|
|
2060
|
+
out << "#{red}STOPPED#{return_color}"
|
|
2061
|
+
else
|
|
2062
|
+
out << "#{white}#{server['powerState'].to_s.upcase}#{return_color}"
|
|
2063
|
+
end
|
|
2064
|
+
else
|
|
2065
|
+
out = format_server_status(server, return_color)
|
|
2066
|
+
end
|
|
1903
2067
|
out
|
|
1904
2068
|
end
|
|
2069
|
+
|
|
1905
2070
|
|
|
1906
2071
|
def make_managed_option_types(connected=true)
|
|
1907
2072
|
[
|
|
@@ -19,7 +19,7 @@ class Morpheus::Cli::Instances
|
|
|
19
19
|
:history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details},
|
|
20
20
|
:stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
|
|
21
21
|
:backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
|
|
22
|
-
:security_groups, :apply_security_groups, :run_workflow, :import_snapshot,
|
|
22
|
+
:security_groups, :apply_security_groups, :run_workflow, :import_snapshot, :snapshots,
|
|
23
23
|
:console, :status_check, {:containers => :list_containers},
|
|
24
24
|
:scaling, {:'scaling-update' => :scaling_update},
|
|
25
25
|
:wiki, :update_wiki,
|
|
@@ -92,11 +92,28 @@ class Morpheus::Cli::Instances
|
|
|
92
92
|
opts.on('--pending-removal-only', "Only instances pending removal.") do
|
|
93
93
|
options[:deleted] = true
|
|
94
94
|
end
|
|
95
|
+
opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
|
|
96
|
+
val.split(",").each do |k|
|
|
97
|
+
options[:labels] ||= []
|
|
98
|
+
options[:labels] << k.strip
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
|
|
102
|
+
val.split(",").each do |value_pair|
|
|
103
|
+
k,v = value_pair.strip.split("=")
|
|
104
|
+
options[:tags] ||= {}
|
|
105
|
+
options[:tags][k] ||= []
|
|
106
|
+
options[:tags][k] << (v || '')
|
|
107
|
+
end
|
|
108
|
+
end
|
|
95
109
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
|
96
110
|
opts.footer = "List instances."
|
|
97
111
|
end
|
|
98
112
|
optparse.parse!(args)
|
|
99
|
-
verify_args!(args:args,
|
|
113
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
|
114
|
+
if args.count > 0
|
|
115
|
+
options[:phrase] = args.join(" ")
|
|
116
|
+
end
|
|
100
117
|
connect(options)
|
|
101
118
|
begin
|
|
102
119
|
params.merge!(parse_list_options(options))
|
|
@@ -129,7 +146,13 @@ class Morpheus::Cli::Instances
|
|
|
129
146
|
|
|
130
147
|
params['showDeleted'] = true if options[:showDeleted]
|
|
131
148
|
params['deleted'] = true if options[:deleted]
|
|
132
|
-
|
|
149
|
+
params['labels'] = options[:labels] if options[:labels]
|
|
150
|
+
if options[:tags]
|
|
151
|
+
options[:tags].each do |k,v|
|
|
152
|
+
params['tags.' + k] = v
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
133
156
|
@instances_interface.setopts(options)
|
|
134
157
|
if options[:dry_run]
|
|
135
158
|
print_dry_run @instances_interface.dry.list(params)
|
|
@@ -344,18 +367,16 @@ class Morpheus::Cli::Instances
|
|
|
344
367
|
opts.on("--environment ENV", String, "Environment code") do |val|
|
|
345
368
|
options[:environment] = val.to_s
|
|
346
369
|
end
|
|
347
|
-
opts.on('--
|
|
370
|
+
opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
348
371
|
options[:metadata] = val
|
|
349
372
|
end
|
|
350
|
-
opts.on('--
|
|
351
|
-
|
|
352
|
-
options[:tags] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
|
373
|
+
opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
374
|
+
options[:metadata] = val
|
|
353
375
|
end
|
|
354
|
-
opts.
|
|
355
|
-
|
|
356
|
-
options[:
|
|
376
|
+
opts.add_hidden_option('--metadata')
|
|
377
|
+
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
378
|
+
options[:labels] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
|
357
379
|
end
|
|
358
|
-
opts.add_hidden_option('--tags')
|
|
359
380
|
opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
|
|
360
381
|
options[:copies] = val.to_i
|
|
361
382
|
end
|
|
@@ -525,18 +546,17 @@ class Morpheus::Cli::Instances
|
|
|
525
546
|
opts.on('--group GROUP', String, "Group Name or ID") do |val|
|
|
526
547
|
options[:group] = val
|
|
527
548
|
end
|
|
528
|
-
opts.on('--
|
|
549
|
+
opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
529
550
|
options[:metadata] = val
|
|
530
551
|
end
|
|
531
|
-
opts.on('--
|
|
532
|
-
|
|
533
|
-
params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
|
552
|
+
opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
553
|
+
options[:metadata] = val
|
|
534
554
|
end
|
|
535
|
-
opts.
|
|
536
|
-
|
|
555
|
+
opts.add_hidden_option('--metadata')
|
|
556
|
+
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
557
|
+
# todo switch this from 'tags' to 'labels'
|
|
537
558
|
params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
|
538
559
|
end
|
|
539
|
-
opts.add_hidden_option('--tags')
|
|
540
560
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
|
541
561
|
params['powerScheduleType'] = val == "null" ? nil : val
|
|
542
562
|
end
|
|
@@ -607,6 +627,9 @@ class Morpheus::Cli::Instances
|
|
|
607
627
|
metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
|
|
608
628
|
metadata_list = metadata_list.collect do |it|
|
|
609
629
|
metadata_pair = it.split(":")
|
|
630
|
+
if metadata_pair.size == 1 && it.include?("=")
|
|
631
|
+
metadata_pair = it.split("=")
|
|
632
|
+
end
|
|
610
633
|
row = {}
|
|
611
634
|
row['name'] = metadata_pair[0].to_s.strip
|
|
612
635
|
row['value'] = metadata_pair[1].to_s.strip
|
|
@@ -1148,6 +1171,9 @@ class Morpheus::Cli::Instances
|
|
|
1148
1171
|
opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
|
|
1149
1172
|
options[:include_scaling] = true
|
|
1150
1173
|
end
|
|
1174
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
|
1175
|
+
options[:include_costs] = true
|
|
1176
|
+
end
|
|
1151
1177
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
|
1152
1178
|
options[:refresh_until_status] ||= "running,failed"
|
|
1153
1179
|
if !val.to_s.empty?
|
|
@@ -1249,6 +1275,8 @@ class Morpheus::Cli::Instances
|
|
|
1249
1275
|
"Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
|
|
1250
1276
|
"Version" => lambda {|it| it['instanceVersion'] },
|
|
1251
1277
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
|
1278
|
+
# "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1279
|
+
# "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1252
1280
|
"Environment" => 'instanceContext',
|
|
1253
1281
|
"Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
|
|
1254
1282
|
"Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
|
@@ -1304,6 +1332,16 @@ class Morpheus::Cli::Instances
|
|
|
1304
1332
|
print_h2 "Instance Usage", options
|
|
1305
1333
|
print_stats_usage(stats)
|
|
1306
1334
|
end
|
|
1335
|
+
|
|
1336
|
+
if options[:include_costs]
|
|
1337
|
+
print_h2 "Instance Cost"
|
|
1338
|
+
cost_columns = {
|
|
1339
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1340
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1341
|
+
}
|
|
1342
|
+
print_description_list(cost_columns, instance)
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1307
1345
|
print reset, "\n"
|
|
1308
1346
|
|
|
1309
1347
|
# if options[:include_lb]
|
|
@@ -2880,6 +2918,52 @@ class Morpheus::Cli::Instances
|
|
|
2880
2918
|
end
|
|
2881
2919
|
end
|
|
2882
2920
|
|
|
2921
|
+
def snapshots(args)
|
|
2922
|
+
options = {}
|
|
2923
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
2924
|
+
opts.banner = subcommand_usage("[instance]")
|
|
2925
|
+
# no pagination yet
|
|
2926
|
+
# build_standard_list_options(opts, options)
|
|
2927
|
+
build_standard_get_options(opts, options)
|
|
2928
|
+
end
|
|
2929
|
+
optparse.parse!(args)
|
|
2930
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
2931
|
+
connect(options)
|
|
2932
|
+
begin
|
|
2933
|
+
instance = find_instance_by_name_or_id(args[0])
|
|
2934
|
+
params = {}
|
|
2935
|
+
@instances_interface.setopts(options)
|
|
2936
|
+
if options[:dry_run]
|
|
2937
|
+
print_dry_run @instances_interface.dry.snapshots(instance['id'], params)
|
|
2938
|
+
return
|
|
2939
|
+
end
|
|
2940
|
+
json_response = @instances_interface.snapshots(instance['id'], params)
|
|
2941
|
+
snapshots = json_response['snapshots']
|
|
2942
|
+
render_response(json_response, options, 'snapshots') do
|
|
2943
|
+
print_h1 "Snapshots: #{instance['name']} (#{instance['instanceType']['name']})", [], options
|
|
2944
|
+
if snapshots.empty?
|
|
2945
|
+
print cyan,"No snapshots found",reset,"\n"
|
|
2946
|
+
else
|
|
2947
|
+
snapshot_column_definitions = {
|
|
2948
|
+
"ID" => lambda {|it| it['id'] },
|
|
2949
|
+
"Name" => lambda {|it| it['name'] },
|
|
2950
|
+
"Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
|
|
2951
|
+
"Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
|
|
2952
|
+
"Status" => lambda {|it| format_snapshot_status(it) }
|
|
2953
|
+
}
|
|
2954
|
+
print cyan
|
|
2955
|
+
print as_pretty_table(snapshots, snapshot_column_definitions.upcase_keys!, options)
|
|
2956
|
+
print_results_pagination({size: snapshots.size, total: snapshots.size})
|
|
2957
|
+
end
|
|
2958
|
+
print reset, "\n"
|
|
2959
|
+
end
|
|
2960
|
+
return 0
|
|
2961
|
+
rescue RestClient::Exception => e
|
|
2962
|
+
print_rest_exception(e, options)
|
|
2963
|
+
exit 1
|
|
2964
|
+
end
|
|
2965
|
+
end
|
|
2966
|
+
|
|
2883
2967
|
def import_snapshot(args)
|
|
2884
2968
|
options = {}
|
|
2885
2969
|
query_params = {}
|
|
@@ -4006,19 +4090,4 @@ private
|
|
|
4006
4090
|
}
|
|
4007
4091
|
end
|
|
4008
4092
|
|
|
4009
|
-
def format_app_deploy_status(status, return_color=cyan)
|
|
4010
|
-
out = ""
|
|
4011
|
-
s = status.to_s.downcase
|
|
4012
|
-
if s == 'deployed'
|
|
4013
|
-
out << "#{green}#{s.upcase}#{return_color}"
|
|
4014
|
-
elsif s == 'open' || s == 'archived' || s == 'committed'
|
|
4015
|
-
out << "#{cyan}#{s.upcase}#{return_color}"
|
|
4016
|
-
elsif s == 'failed'
|
|
4017
|
-
out << "#{red}#{s.upcase}#{return_color}"
|
|
4018
|
-
else
|
|
4019
|
-
out << "#{yellow}#{s.upcase}#{return_color}"
|
|
4020
|
-
end
|
|
4021
|
-
out
|
|
4022
|
-
end
|
|
4023
|
-
|
|
4024
4093
|
end
|