morpheus-cli 4.2.18 → 5.0.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 +14 -0
- data/lib/morpheus/api/billing_interface.rb +33 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
- data/lib/morpheus/api/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- data/lib/morpheus/cli.rb +2 -2
- 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/blueprints_command.rb +27 -61
- 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 +30 -15
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/commands/standard/curl_command.rb +23 -7
- 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/deployments.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +30 -2
- data/lib/morpheus/cli/instances.rb +19 -1
- data/lib/morpheus/cli/invoices_command.rb +8 -9
- data/lib/morpheus/cli/jobs_command.rb +30 -8
- 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/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 +0 -1
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -0
- data/lib/morpheus/cli/network_pools_command.rb +14 -6
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
- data/lib/morpheus/cli/remote.rb +0 -2
- data/lib/morpheus/cli/roles.rb +305 -3
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/tasks.rb +24 -10
- data/lib/morpheus/cli/tenants_command.rb +1 -1
- data/lib/morpheus/cli/usage_command.rb +150 -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/workflows.rb +12 -9
- data/lib/morpheus/formatters.rb +26 -5
- metadata +8 -2
@@ -194,7 +194,7 @@ module Morpheus
|
|
194
194
|
if option_type['placeHolder']
|
195
195
|
value_label = option_type['placeHolder']
|
196
196
|
elsif option_type['type'] == 'checkbox'
|
197
|
-
value_label = 'on|off' # or.. true|false
|
197
|
+
value_label = '[on|off]' # or.. true|false
|
198
198
|
elsif option_type['type'] == 'number'
|
199
199
|
value_label = 'NUMBER'
|
200
200
|
elsif option_type['type'] == 'multiSelect'
|
@@ -204,12 +204,16 @@ module Morpheus
|
|
204
204
|
# elsif option['type'] == 'select'
|
205
205
|
end
|
206
206
|
opts.on("--#{full_field_name} #{value_label}", String, description) do |val|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
207
|
+
if option_type['type'] == 'checkbox'
|
208
|
+
val = (val.to_s != 'false' && val.to_s != 'off')
|
209
|
+
else
|
210
|
+
# attempt to parse JSON, this allows blank arrays for multiSelect like --tenants []
|
211
|
+
if (val.to_s[0] == '{' && val.to_s[-1] == '}') || (val.to_s[0] == '[' && val.to_s[-1] == ']')
|
212
|
+
begin
|
213
|
+
val = JSON.parse(val)
|
214
|
+
rescue
|
215
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
|
216
|
+
end
|
213
217
|
end
|
214
218
|
end
|
215
219
|
cur_namespace = custom_options
|
@@ -489,13 +493,17 @@ module Morpheus
|
|
489
493
|
|
490
494
|
when :query, :query_filters
|
491
495
|
# arbitrary query parameters in the format -Q "category=web&phrase=nginx"
|
496
|
+
# or pass it many times like -Q foo=bar -Q hello=world
|
492
497
|
opts.on( '-Q', '--query PARAMS', "Query parameters. PARAMS format is 'foo=bar&category=web'" ) do |val|
|
493
|
-
options[:query_filters_raw]
|
494
|
-
|
495
|
-
|
498
|
+
if options[:query_filters_raw] && !options[:query_filters_raw].empty?
|
499
|
+
options[:query_filters_raw] += ("&" + val)
|
500
|
+
else
|
501
|
+
options[:query_filters_raw] = val
|
502
|
+
end
|
503
|
+
options[:query_filters] ||= {}
|
496
504
|
val.split('&').each do |filter|
|
497
505
|
k, v = filter.split('=')
|
498
|
-
# allow
|
506
|
+
# allow woot:true instead of woot=true
|
499
507
|
if (k.include?(":") && v == nil)
|
500
508
|
k, v = k.split(":")
|
501
509
|
end
|
@@ -524,6 +532,12 @@ module Morpheus
|
|
524
532
|
end
|
525
533
|
end
|
526
534
|
|
535
|
+
when :find_by_name
|
536
|
+
opts.on('--find-by-name', "Always treat the identifier argument as a name, never an ID. Useful for specifying names that look like numbers. eg. '1234'" ) do
|
537
|
+
options[:find_by_name] = true
|
538
|
+
end
|
539
|
+
# opts.add_hidden_option('--find-by-name') if opts.is_a?(Morpheus::Cli::OptionParser)
|
540
|
+
|
527
541
|
when :remote
|
528
542
|
opts.on( '-r', '--remote REMOTE', "Remote name. The current remote is used by default." ) do |val|
|
529
543
|
options[:remote] = val
|
@@ -1237,17 +1251,18 @@ module Morpheus
|
|
1237
1251
|
end
|
1238
1252
|
end
|
1239
1253
|
if options[:outfile]
|
1254
|
+
full_outfile = File.expand_path(options[:outfile])
|
1240
1255
|
if output
|
1241
1256
|
print_to_file(output, options[:outfile], options[:overwrite])
|
1242
|
-
print "#{cyan}Wrote output to file #{options[:outfile]} (#{File.size(
|
1257
|
+
print "#{cyan}Wrote output to file #{options[:outfile]} (#{File.size(full_outfile)} B)\n" unless options[:quiet]
|
1243
1258
|
else
|
1244
1259
|
# uhhh ok lets try this
|
1245
|
-
Morpheus::Logging::DarkPrinter.puts "using experimental feature: --
|
1260
|
+
Morpheus::Logging::DarkPrinter.puts "using experimental feature: --out without a common format like json, yml or csv" if Morpheus::Logging.debug?
|
1246
1261
|
result = with_stdout_to_file(options[:outfile], options[:overwrite], 'w+', &block)
|
1247
|
-
|
1248
|
-
if result
|
1262
|
+
if result && result != 0
|
1249
1263
|
return result
|
1250
1264
|
end
|
1265
|
+
print "#{cyan}Wrote output to file #{options[:outfile]} (#{File.size(full_outfile)} B)\n" unless options[:quiet]
|
1251
1266
|
return 0, nil
|
1252
1267
|
end
|
1253
1268
|
else
|
@@ -326,6 +326,9 @@ class Morpheus::Cli::CloudResourcePoolsCommand
|
|
326
326
|
opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
|
327
327
|
options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
328
328
|
end
|
329
|
+
opts.on('--default-pool [on|off]', String, "Set resource pool as the default") do |val|
|
330
|
+
options['defaultPool'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
331
|
+
end
|
329
332
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
330
333
|
opts.footer = "Update a resource pool." + "\n" +
|
331
334
|
"[cloud] is required. This is the name or id of the cloud."
|
@@ -437,6 +440,11 @@ class Morpheus::Cli::CloudResourcePoolsCommand
|
|
437
440
|
else
|
438
441
|
payload['resourcePool']['active'] = true
|
439
442
|
end
|
443
|
+
|
444
|
+
# Default
|
445
|
+
if options['defaultPool'] != nil
|
446
|
+
payload['resourcePool']['defaultPool'] = options['defaultPool']
|
447
|
+
end
|
440
448
|
|
441
449
|
# Visibility
|
442
450
|
if options['visibility'] != nil
|
@@ -552,6 +560,9 @@ class Morpheus::Cli::CloudResourcePoolsCommand
|
|
552
560
|
opts.on('--active [on|off]', String, "Can be used to disable a resource pool") do |val|
|
553
561
|
options['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
554
562
|
end
|
563
|
+
opts.on('--default-pool [on|off]', String, "Set resource pool as the default") do |val|
|
564
|
+
options['defaultPool'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
565
|
+
end
|
555
566
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
556
567
|
opts.footer = "Update a resource pool." + "\n" +
|
557
568
|
"[cloud] is required. This is the name or id of the cloud." + "\n"
|
@@ -641,6 +652,11 @@ class Morpheus::Cli::CloudResourcePoolsCommand
|
|
641
652
|
if options['active'] != nil
|
642
653
|
payload['resourcePool']['active'] = options['active']
|
643
654
|
end
|
655
|
+
|
656
|
+
# Default
|
657
|
+
if options['defaultPool'] != nil
|
658
|
+
payload['resourcePool']['defaultPool'] = options['defaultPool']
|
659
|
+
end
|
644
660
|
|
645
661
|
# Visibility
|
646
662
|
if options['visibility'] != nil
|
data/lib/morpheus/cli/clouds.rb
CHANGED
@@ -46,11 +46,15 @@ class Morpheus::Cli::Clouds
|
|
46
46
|
opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
|
47
47
|
options[:zone_type] = val
|
48
48
|
end
|
49
|
-
|
49
|
+
build_standard_list_options(opts, options)
|
50
50
|
opts.footer = "List clouds."
|
51
51
|
end
|
52
52
|
optparse.parse!(args)
|
53
53
|
connect(options)
|
54
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
55
|
+
if args.count > 0
|
56
|
+
options[:phrase] = args.join(" ")
|
57
|
+
end
|
54
58
|
begin
|
55
59
|
if options[:zone_type]
|
56
60
|
cloud_type = cloud_type_for_name(options[:zone_type])
|
@@ -71,15 +75,7 @@ class Morpheus::Cli::Clouds
|
|
71
75
|
end
|
72
76
|
|
73
77
|
json_response = @clouds_interface.list(params)
|
74
|
-
|
75
|
-
puts as_json(json_response, options, "zones")
|
76
|
-
return 0
|
77
|
-
elsif options[:yaml]
|
78
|
-
puts as_yaml(json_response, options, "zones")
|
79
|
-
return 0
|
80
|
-
elsif options[:csv]
|
81
|
-
puts records_as_csv(json_response['zones'], options)
|
82
|
-
else
|
78
|
+
render_response(json_response, options, 'zones') do
|
83
79
|
clouds = json_response['zones']
|
84
80
|
title = "Morpheus Clouds"
|
85
81
|
subtitles = []
|
@@ -99,6 +95,7 @@ class Morpheus::Cli::Clouds
|
|
99
95
|
end
|
100
96
|
print reset,"\n"
|
101
97
|
end
|
98
|
+
return 0, nil
|
102
99
|
rescue RestClient::Exception => e
|
103
100
|
print_rest_exception(e, options)
|
104
101
|
exit 1
|
@@ -9,15 +9,20 @@ class Morpheus::Cli::CurlCommand
|
|
9
9
|
set_command_hidden
|
10
10
|
|
11
11
|
def handle(args)
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
# support syntax for arbitrary curl args after " -- "
|
13
|
+
# eg. curl /api/instances -- -ksv
|
14
|
+
split_index = args.index("--")
|
15
|
+
curl_args = []
|
16
|
+
if split_index
|
17
|
+
if args.length > (split_index + 1)
|
18
|
+
curl_args = args[(split_index + 1)..-1]
|
19
|
+
end
|
20
|
+
args = args[0..(split_index - 1)]
|
21
|
+
end
|
15
22
|
curl_method = nil
|
16
23
|
curl_data = nil
|
17
24
|
curl_verbsose = false
|
18
25
|
show_progress = false
|
19
|
-
# puts "args is : #{args}"
|
20
|
-
# puts "curl_args is : #{curl_args}"
|
21
26
|
options = {}
|
22
27
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
23
28
|
opts.banner = "Usage: morpheus curl [path] -- [*args]"
|
@@ -98,16 +103,27 @@ EOT
|
|
98
103
|
end
|
99
104
|
curl_cmd << " \"#{url}\""
|
100
105
|
if @access_token
|
101
|
-
|
106
|
+
if !(options[:headers] && options[:headers]['Authorization'])
|
107
|
+
curl_cmd << " -H \"Authorization: Bearer #{@access_token}\""
|
108
|
+
end
|
102
109
|
end
|
103
110
|
if curl_data
|
104
111
|
#todo: curl_data.gsub("'","\\'")
|
105
112
|
curl_cmd << " --data '#{curl_data}'"
|
113
|
+
if api_path !~ /^\/?oauth/
|
114
|
+
if !(options[:headers] && options[:headers]['Content-Type'])
|
115
|
+
curl_cmd << " -H \"Content-Type: application/json\""
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if options[:headers]
|
120
|
+
options[:headers].each do |k,v|
|
121
|
+
curl_cmd << " -H \"#{k}: #{v}\""
|
122
|
+
end
|
106
123
|
end
|
107
124
|
if !curl_args.empty?
|
108
125
|
curl_cmd << " " + curl_args.join(' ')
|
109
126
|
end
|
110
|
-
|
111
127
|
# Morpheus::Logging::DarkPrinter.puts "#{curl_cmd}" if Morpheus::Logging.debug?
|
112
128
|
curl_cmd_str = options[:scrub] ? Morpheus::Logging.scrub_message(curl_cmd) : curl_cmd
|
113
129
|
|
@@ -14,7 +14,7 @@ class Morpheus::Cli::SourceCommand
|
|
14
14
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
15
15
|
opts.banner = "Usage: morpheus #{command_name} [file] [file2]"
|
16
16
|
build_common_options(opts, options, [])
|
17
|
-
opts.footer = "This will execute a file
|
17
|
+
opts.footer = "This will execute a file as a script where each line is a morpheus command or expression."
|
18
18
|
end
|
19
19
|
optparse.parse!(args)
|
20
20
|
if args.count < 1
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# This is for use in dotfile scripts and the shell..
|
5
|
+
class Morpheus::Cli::UpdateCommand
|
6
|
+
include Morpheus::Cli::CliCommand
|
7
|
+
set_command_name :update
|
8
|
+
|
9
|
+
def handle(args)
|
10
|
+
options = {}
|
11
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
12
|
+
opts.banner = "Usage: morpheus #{command_name}"
|
13
|
+
opts.on( '-f', '--force', "Force Update, executes update even if latest version is already installed." ) do
|
14
|
+
options[:force] = true
|
15
|
+
end
|
16
|
+
build_common_options(opts, options, [:dry_run, :quiet])
|
17
|
+
opts.footer = "This will update the morpheus command line interface to the latest version.\nThis is done by executing the system command: `gem update #{morpheus_gem_name}`"
|
18
|
+
end
|
19
|
+
optparse.parse!(args)
|
20
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
21
|
+
|
22
|
+
current_version = Morpheus::Cli::VERSION
|
23
|
+
latest_version = get_latest_version()
|
24
|
+
latest_version = latest_version
|
25
|
+
|
26
|
+
if current_version == latest_version && !options[:force]
|
27
|
+
unless options[:quiet]
|
28
|
+
print cyan, "The latest version is already installed. (#{latest_version})", "\n", reset
|
29
|
+
end
|
30
|
+
return 0, nil
|
31
|
+
end
|
32
|
+
|
33
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to update the #{morpheus_gem_name} gem from version #{current_version} to version #{latest_version}?")
|
34
|
+
return 9, "aborted command"
|
35
|
+
end
|
36
|
+
|
37
|
+
gem_update_command = "gem update #{morpheus_gem_name}"
|
38
|
+
|
39
|
+
if options[:dry_run]
|
40
|
+
unless options[:quiet]
|
41
|
+
print "\n"
|
42
|
+
print "#{cyan}#{bold}#{dark}COMMAND#{reset}\n"
|
43
|
+
puts gem_update_command
|
44
|
+
print "\n", reset
|
45
|
+
end
|
46
|
+
return 0, nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# ok, update it
|
50
|
+
if options[:quiet]
|
51
|
+
system(gem_update_command)
|
52
|
+
else
|
53
|
+
`#{gem_update_command}`
|
54
|
+
end
|
55
|
+
|
56
|
+
if $?.success?
|
57
|
+
return 0, nil
|
58
|
+
else
|
59
|
+
return $?.exitstatus, "update failed"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def morpheus_gem_name
|
67
|
+
'morpheus-cli'
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_latest_version
|
71
|
+
result = HTTP.get("https://rubygems.org/api/v1/gems/#{morpheus_gem_name}.json")
|
72
|
+
json_response = JSON.parse(result.body)
|
73
|
+
json_response["version"]
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -35,6 +35,9 @@ class Morpheus::Cli::ContainersCommand
|
|
35
35
|
opts.on( nil, '--actions', "Display Available Actions" ) do
|
36
36
|
options[:include_available_actions] = true
|
37
37
|
end
|
38
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
39
|
+
options[:include_costs] = true
|
40
|
+
end
|
38
41
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
39
42
|
options[:refresh_until_status] ||= "running,failed"
|
40
43
|
if !val.to_s.empty?
|
@@ -99,6 +102,8 @@ class Morpheus::Cli::ContainersCommand
|
|
99
102
|
"Name" => lambda {|it| it['server'] ? it['server']['name'] : '(no server)' }, # there is a server.displayName too?
|
100
103
|
"Type" => lambda {|it| it['containerType'] ? it['containerType']['name'] : '' },
|
101
104
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
105
|
+
# "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
106
|
+
# "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
102
107
|
"Instance" => lambda {|it| it['instance'] ? it['instance']['name'] : '' },
|
103
108
|
"Host" => lambda {|it| it['server'] ? it['server']['name'] : '' },
|
104
109
|
"Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
|
@@ -133,6 +138,15 @@ class Morpheus::Cli::ContainersCommand
|
|
133
138
|
end
|
134
139
|
end
|
135
140
|
|
141
|
+
if options[:include_costs]
|
142
|
+
print_h2 "Container Cost"
|
143
|
+
cost_columns = {
|
144
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
145
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
146
|
+
}
|
147
|
+
print_description_list(cost_columns, container)
|
148
|
+
end
|
149
|
+
|
136
150
|
print reset, "\n"
|
137
151
|
|
138
152
|
# refresh until a status is reached
|
@@ -388,7 +388,7 @@ EOT
|
|
388
388
|
deployment = find_deployment_by_name_or_id(args[0])
|
389
389
|
return 1 if deployment.nil?
|
390
390
|
else
|
391
|
-
deployment_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'deploymentId', 'fieldLabel' => 'Deployment', 'type' => 'select', 'required' => true, 'description' => 'Deployment to add version to', 'optionSource' => lambda {
|
391
|
+
deployment_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'deploymentId', 'fieldLabel' => 'Deployment', 'type' => 'select', 'required' => true, 'description' => 'Deployment to add version to', 'optionSource' => lambda { |api_client, api_params|
|
392
392
|
@deployments_interface.list(max:10000)['deployments'].collect {|it|
|
393
393
|
{'name' => it['name'], 'value' => it['id']}
|
394
394
|
}
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -119,6 +119,10 @@ class Morpheus::Cli::Hosts
|
|
119
119
|
end
|
120
120
|
optparse.parse!(args)
|
121
121
|
connect(options)
|
122
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
123
|
+
if args.count > 0
|
124
|
+
options[:phrase] = args.join(" ")
|
125
|
+
end
|
122
126
|
begin
|
123
127
|
params.merge!(parse_list_options(options))
|
124
128
|
account = nil
|
@@ -392,6 +396,9 @@ class Morpheus::Cli::Hosts
|
|
392
396
|
options = {}
|
393
397
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
394
398
|
opts.banner = subcommand_usage("[name]")
|
399
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
400
|
+
options[:include_costs] = true
|
401
|
+
end
|
395
402
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is provisioned,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
396
403
|
options[:refresh_until_status] ||= "provisioned,failed"
|
397
404
|
if !val.to_s.empty?
|
@@ -453,7 +460,7 @@ class Morpheus::Cli::Hosts
|
|
453
460
|
title = "Host Details"
|
454
461
|
print_h1 title, [], options
|
455
462
|
print cyan
|
456
|
-
|
463
|
+
server_columns = {
|
457
464
|
"ID" => 'id',
|
458
465
|
"Name" => 'name',
|
459
466
|
"Description" => 'description',
|
@@ -463,12 +470,23 @@ class Morpheus::Cli::Hosts
|
|
463
470
|
"Type" => lambda {|it| it['computeServerType'] ? it['computeServerType']['name'] : 'unmanaged' },
|
464
471
|
"Platform" => lambda {|it| it['serverOs'] ? it['serverOs']['name'].upcase : 'N/A' },
|
465
472
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
473
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
474
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
466
475
|
"Agent" => lambda {|it| it['agentInstalled'] ? "#{server['agentVersion'] || ''} updated at #{format_local_dt(server['lastAgentUpdate'])}" : '(not installed)' },
|
467
476
|
"Status" => lambda {|it| format_server_status(it) },
|
468
477
|
"Nodes" => lambda {|it| it['containers'] ? it['containers'].size : 0 },
|
469
478
|
"Power" => lambda {|it| format_server_power_state(it) },
|
470
|
-
}
|
479
|
+
}
|
471
480
|
|
481
|
+
if server['hourlyCost'].to_f == 0
|
482
|
+
server_columns.delete("Cost")
|
483
|
+
end
|
484
|
+
if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
|
485
|
+
server_columns.delete("Price")
|
486
|
+
end
|
487
|
+
|
488
|
+
print_description_list(server_columns, server)
|
489
|
+
|
472
490
|
if server['statusMessage']
|
473
491
|
print_h2 "Status Message", options
|
474
492
|
if server['status'] == 'failed'
|
@@ -485,6 +503,16 @@ class Morpheus::Cli::Hosts
|
|
485
503
|
|
486
504
|
print_h2 "Host Usage", options
|
487
505
|
print_stats_usage(stats)
|
506
|
+
|
507
|
+
if options[:include_costs]
|
508
|
+
print_h2 "Host Cost"
|
509
|
+
cost_columns = {
|
510
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
511
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
512
|
+
}
|
513
|
+
print_description_list(cost_columns, server)
|
514
|
+
end
|
515
|
+
|
488
516
|
print reset, "\n"
|
489
517
|
|
490
518
|
|
@@ -96,7 +96,10 @@ class Morpheus::Cli::Instances
|
|
96
96
|
opts.footer = "List instances."
|
97
97
|
end
|
98
98
|
optparse.parse!(args)
|
99
|
-
verify_args!(args:args,
|
99
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
100
|
+
if args.count > 0
|
101
|
+
options[:phrase] = args.join(" ")
|
102
|
+
end
|
100
103
|
connect(options)
|
101
104
|
begin
|
102
105
|
params.merge!(parse_list_options(options))
|
@@ -1148,6 +1151,9 @@ class Morpheus::Cli::Instances
|
|
1148
1151
|
opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
|
1149
1152
|
options[:include_scaling] = true
|
1150
1153
|
end
|
1154
|
+
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
1155
|
+
options[:include_costs] = true
|
1156
|
+
end
|
1151
1157
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
1152
1158
|
options[:refresh_until_status] ||= "running,failed"
|
1153
1159
|
if !val.to_s.empty?
|
@@ -1249,6 +1255,8 @@ class Morpheus::Cli::Instances
|
|
1249
1255
|
"Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
|
1250
1256
|
"Version" => lambda {|it| it['instanceVersion'] },
|
1251
1257
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
1258
|
+
# "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
1259
|
+
# "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
1252
1260
|
"Environment" => 'instanceContext',
|
1253
1261
|
"Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
|
1254
1262
|
"Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
@@ -1304,6 +1312,16 @@ class Morpheus::Cli::Instances
|
|
1304
1312
|
print_h2 "Instance Usage", options
|
1305
1313
|
print_stats_usage(stats)
|
1306
1314
|
end
|
1315
|
+
|
1316
|
+
if options[:include_costs]
|
1317
|
+
print_h2 "Instance Cost"
|
1318
|
+
cost_columns = {
|
1319
|
+
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
1320
|
+
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
1321
|
+
}
|
1322
|
+
print_description_list(cost_columns, instance)
|
1323
|
+
end
|
1324
|
+
|
1307
1325
|
print reset, "\n"
|
1308
1326
|
|
1309
1327
|
# if options[:include_lb]
|