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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +14 -0
  4. data/lib/morpheus/api/billing_interface.rb +33 -0
  5. data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
  6. data/lib/morpheus/api/rest_interface.rb +0 -6
  7. data/lib/morpheus/api/roles_interface.rb +14 -0
  8. data/lib/morpheus/cli.rb +2 -2
  9. data/lib/morpheus/cli/apps.rb +3 -4
  10. data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
  11. data/lib/morpheus/cli/backups_command.rb +3 -0
  12. data/lib/morpheus/cli/blueprints_command.rb +27 -61
  13. data/lib/morpheus/cli/budgets_command.rb +4 -4
  14. data/lib/morpheus/cli/catalog_command.rb +507 -0
  15. data/lib/morpheus/cli/cli_command.rb +30 -15
  16. data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
  17. data/lib/morpheus/cli/clouds.rb +7 -10
  18. data/lib/morpheus/cli/commands/standard/curl_command.rb +23 -7
  19. data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
  20. data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
  21. data/lib/morpheus/cli/containers_command.rb +14 -0
  22. data/lib/morpheus/cli/deployments.rb +1 -1
  23. data/lib/morpheus/cli/hosts.rb +30 -2
  24. data/lib/morpheus/cli/instances.rb +19 -1
  25. data/lib/morpheus/cli/invoices_command.rb +8 -9
  26. data/lib/morpheus/cli/jobs_command.rb +30 -8
  27. data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
  28. data/lib/morpheus/cli/library_option_lists_command.rb +14 -6
  29. data/lib/morpheus/cli/mixins/accounts_helper.rb +7 -6
  30. data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
  31. data/lib/morpheus/cli/mixins/catalog_helper.rb +66 -0
  32. data/lib/morpheus/cli/mixins/deployments_helper.rb +0 -1
  33. data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
  34. data/lib/morpheus/cli/mixins/print_helper.rb +46 -0
  35. data/lib/morpheus/cli/network_pools_command.rb +14 -6
  36. data/lib/morpheus/cli/ping.rb +0 -1
  37. data/lib/morpheus/cli/projects_command.rb +7 -7
  38. data/lib/morpheus/cli/provisioning_licenses_command.rb +2 -2
  39. data/lib/morpheus/cli/remote.rb +0 -2
  40. data/lib/morpheus/cli/roles.rb +305 -3
  41. data/lib/morpheus/cli/service_plans_command.rb +2 -2
  42. data/lib/morpheus/cli/storage_providers_command.rb +40 -56
  43. data/lib/morpheus/cli/tasks.rb +24 -10
  44. data/lib/morpheus/cli/tenants_command.rb +1 -1
  45. data/lib/morpheus/cli/usage_command.rb +150 -0
  46. data/lib/morpheus/cli/user_settings_command.rb +1 -0
  47. data/lib/morpheus/cli/users.rb +12 -1
  48. data/lib/morpheus/cli/version.rb +1 -1
  49. data/lib/morpheus/cli/workflows.rb +12 -9
  50. data/lib/morpheus/formatters.rb +26 -5
  51. 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
- # attempt to parse JSON, this allows blank arrays for multiSelect like --tenants []
208
- if (val.to_s[0] == '{' && val.to_s[-1] == '}') || (val.to_s[0] == '[' && val.to_s[-1] == ']')
209
- begin
210
- val = JSON.parse(val)
211
- rescue
212
- Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
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] = val
494
- options[:query_filters] = {}
495
- # todo: smarter parsing
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 "woot:true instead of woot=true"
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(options[:outfile])} B)\n" unless options[:quiet]
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: --outfile without a common format like json, yml or csv" if Morpheus::Logging.debug?
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
- print "#{cyan}Wrote output to file #{options[:outfile]} (#{File.size(options[:outfile])} B)\n" unless options[:quiet]
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
@@ -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
- build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
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
- if options[:json]
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
- split_args = args.join(" ").split(" -- ")
13
- args = split_args[0].split(" ")
14
- curl_args = split_args[1] ? split_args[1].split(" ") : []
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
- curl_cmd << " -H \"Authorization: Bearer #{@access_token}\""
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, treatin it as a script of morpheus commands"
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
  }
@@ -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
- print_description_list({
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
- }, server)
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, count:0, optparse:optparse)
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]