morpheus-cli 4.2.16 → 4.2.21
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/README.md +8 -6
- data/lib/morpheus/api/api_client.rb +32 -14
- data/lib/morpheus/api/auth_interface.rb +4 -2
- data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
- data/lib/morpheus/api/backups_interface.rb +16 -0
- data/lib/morpheus/api/deploy_interface.rb +25 -56
- data/lib/morpheus/api/deployments_interface.rb +44 -55
- data/lib/morpheus/api/doc_interface.rb +57 -0
- data/lib/morpheus/api/instances_interface.rb +5 -0
- data/lib/morpheus/api/rest_interface.rb +40 -0
- data/lib/morpheus/api/user_sources_interface.rb +0 -15
- data/lib/morpheus/api/users_interface.rb +2 -3
- data/lib/morpheus/benchmarking.rb +2 -2
- data/lib/morpheus/cli.rb +4 -1
- data/lib/morpheus/cli/access_token_command.rb +27 -10
- data/lib/morpheus/cli/apps.rb +21 -15
- data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
- data/lib/morpheus/cli/backups_command.rb +271 -0
- data/lib/morpheus/cli/blueprints_command.rb +27 -61
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/budgets_command.rb +4 -4
- data/lib/morpheus/cli/cli_command.rb +99 -41
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +16 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/clusters.rb +0 -18
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +7 -7
- data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
- data/lib/morpheus/cli/credentials.rb +13 -9
- data/lib/morpheus/cli/deploy.rb +374 -0
- data/lib/morpheus/cli/deployments.rb +521 -197
- data/lib/morpheus/cli/deploys.rb +271 -126
- data/lib/morpheus/cli/doc.rb +182 -0
- data/lib/morpheus/cli/error_handler.rb +23 -8
- data/lib/morpheus/cli/errors.rb +3 -2
- data/lib/morpheus/cli/image_builder_command.rb +2 -2
- data/lib/morpheus/cli/instances.rb +136 -17
- data/lib/morpheus/cli/invoices_command.rb +59 -47
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_instance_types_command.rb +17 -3
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/login.rb +9 -3
- data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
- data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
- data/lib/morpheus/cli/network_routers_command.rb +1 -1
- data/lib/morpheus/cli/option_parser.rb +48 -5
- data/lib/morpheus/cli/option_types.rb +1 -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 +3 -2
- data/lib/morpheus/cli/roles.rb +49 -92
- data/lib/morpheus/cli/security_groups.rb +7 -1
- data/lib/morpheus/cli/service_plans_command.rb +10 -10
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +7 -6
- data/lib/morpheus/cli/subnets_command.rb +1 -1
- data/lib/morpheus/cli/tasks.rb +24 -10
- data/lib/morpheus/cli/tenants_command.rb +133 -163
- data/lib/morpheus/cli/user_groups_command.rb +20 -65
- data/lib/morpheus/cli/user_settings_command.rb +115 -13
- data/lib/morpheus/cli/user_sources_command.rb +57 -24
- data/lib/morpheus/cli/users.rb +210 -186
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
- data/lib/morpheus/cli/whoami.rb +113 -6
- data/lib/morpheus/cli/workflows.rb +11 -8
- data/lib/morpheus/ext/hash.rb +21 -0
- data/lib/morpheus/terminal.rb +1 -0
- metadata +12 -3
- data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -31,18 +31,31 @@ class Morpheus::Cli::ErrorHandler
|
|
31
31
|
# raise err
|
32
32
|
# @stderr.puts "#{red}#{err.message}#{reset}"
|
33
33
|
puts_angry_error err.message
|
34
|
-
@stderr.puts
|
34
|
+
@stderr.puts err.optparse.banner if err.optparse && err.optparse.banner
|
35
|
+
@stderr.puts "Try --help for more usage information"
|
35
36
|
do_print_stacktrace = false
|
36
37
|
# exit_code = 127
|
37
|
-
|
38
|
+
when Morpheus::Cli::CommandArgumentsError
|
39
|
+
puts_angry_error err.message
|
40
|
+
@stderr.puts err.optparse.banner if err.optparse && err.optparse.banner
|
41
|
+
@stderr.puts "Try --help for more usage information"
|
42
|
+
do_print_stacktrace = false
|
43
|
+
if err.exit_code
|
44
|
+
exit_code = err.exit_code
|
45
|
+
end
|
46
|
+
|
38
47
|
when Morpheus::Cli::CommandError
|
39
|
-
#
|
40
|
-
#
|
48
|
+
# this should probably always print the whole thing as red, but just does the first line for now.
|
49
|
+
# until verify_args! replaces raise_command_error where the full parser help is in the error message..
|
41
50
|
message_lines = err.message.split(/\r?\n/)
|
42
51
|
first_line = message_lines.shift
|
43
52
|
puts_angry_error first_line
|
44
|
-
|
45
|
-
|
53
|
+
if !message_lines.empty?
|
54
|
+
@stderr.puts message_lines.join("\n") unless message_lines.empty?
|
55
|
+
else
|
56
|
+
@stderr.puts err.optparse.banner if err.optparse && err.optparse.banner && message_lines.empty?
|
57
|
+
@stderr.puts "Try --help for more usage information"
|
58
|
+
end
|
46
59
|
do_print_stacktrace = false
|
47
60
|
if err.exit_code
|
48
61
|
exit_code = err.exit_code
|
@@ -82,7 +95,7 @@ class Morpheus::Cli::ErrorHandler
|
|
82
95
|
@stderr.puts err.to_s
|
83
96
|
end
|
84
97
|
else
|
85
|
-
@stderr.puts "Use --debug for more information."
|
98
|
+
@stderr.puts "Use -V or --debug for more verbose debugging information."
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
@@ -127,6 +140,8 @@ class Morpheus::Cli::ErrorHandler
|
|
127
140
|
begin
|
128
141
|
print_rest_errors(JSON.parse(err.response.to_s), options)
|
129
142
|
rescue TypeError, JSON::ParserError => ex
|
143
|
+
# not json, just 404
|
144
|
+
@stderr.print red, "Error Communicating with the remote appliance. #{e}", reset, "\n"
|
130
145
|
end
|
131
146
|
else
|
132
147
|
@stderr.print red, "Error Communicating with the remote appliance. #{e}", reset, "\n"
|
@@ -145,7 +160,7 @@ class Morpheus::Cli::ErrorHandler
|
|
145
160
|
@stderr.print reset
|
146
161
|
end
|
147
162
|
else
|
148
|
-
@stderr.puts "Use --debug for more information."
|
163
|
+
@stderr.puts "Use -V or --debug for more verbose debugging information."
|
149
164
|
end
|
150
165
|
end
|
151
166
|
else
|
data/lib/morpheus/cli/errors.rb
CHANGED
@@ -3,7 +3,7 @@ module Morpheus::Cli
|
|
3
3
|
# A standard error to raise in your CliCommand classes.
|
4
4
|
class CommandError < StandardError
|
5
5
|
|
6
|
-
attr_reader :args, :exit_code
|
6
|
+
attr_reader :args, :optparse, :exit_code
|
7
7
|
|
8
8
|
def initialize(msg, args=[], optparse=nil, exit_code=nil)
|
9
9
|
@args = args
|
@@ -11,6 +11,7 @@ module Morpheus::Cli
|
|
11
11
|
@exit_code = exit_code # || 1
|
12
12
|
super(msg)
|
13
13
|
end
|
14
|
+
|
14
15
|
end
|
15
16
|
|
16
17
|
# An error indicating the command was not recoginzed
|
@@ -24,7 +25,7 @@ module Morpheus::Cli
|
|
24
25
|
|
25
26
|
# An error for wrong number of arguments
|
26
27
|
# could use ::OptionParser::MissingArgument, ::OptionParser::NeedlessArgument
|
27
|
-
# maybe return an error code
|
28
|
+
# maybe return an error code other than 1?
|
28
29
|
class CommandArgumentsError < CommandError
|
29
30
|
|
30
31
|
def initialize(msg, args=[], optparse=nil, exit_code=nil)
|
@@ -518,7 +518,7 @@ class Morpheus::Cli::ImageBuilderCommand
|
|
518
518
|
opts.on( '-K', '--keep-virtual-images', "Preserve associated virtual images" ) do
|
519
519
|
query_params['keepVirtualImages'] = 'on'
|
520
520
|
end
|
521
|
-
build_common_options(opts, options, [:
|
521
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
522
522
|
end
|
523
523
|
optparse.parse!(args)
|
524
524
|
|
@@ -565,7 +565,7 @@ class Morpheus::Cli::ImageBuilderCommand
|
|
565
565
|
query_params = {}
|
566
566
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
567
567
|
opts.banner = subcommand_usage("[image-build]")
|
568
|
-
build_common_options(opts, options, [:
|
568
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
569
569
|
end
|
570
570
|
optparse.parse!(args)
|
571
571
|
|
@@ -9,14 +9,22 @@ class Morpheus::Cli::Instances
|
|
9
9
|
include Morpheus::Cli::AccountsHelper # needed? replace with OptionSourceHelper
|
10
10
|
include Morpheus::Cli::OptionSourceHelper
|
11
11
|
include Morpheus::Cli::ProvisioningHelper
|
12
|
+
include Morpheus::Cli::DeploymentsHelper
|
12
13
|
include Morpheus::Cli::ProcessesHelper
|
13
14
|
include Morpheus::Cli::LogsHelper
|
14
15
|
|
15
16
|
set_command_name :instances
|
16
17
|
set_command_description "View and manage instances."
|
17
|
-
register_subcommands :list, :count, :get, :view, :add, :update, :remove, :cancel_removal, :logs,
|
18
|
-
|
19
|
-
|
18
|
+
register_subcommands :list, :count, :get, :view, :add, :update, :remove, :cancel_removal, :logs,
|
19
|
+
:history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details},
|
20
|
+
:stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
|
21
|
+
:backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
|
22
|
+
:security_groups, :apply_security_groups, :run_workflow, :import_snapshot,
|
23
|
+
:console, :status_check, {:containers => :list_containers},
|
24
|
+
:scaling, {:'scaling-update' => :scaling_update},
|
25
|
+
:wiki, :update_wiki,
|
26
|
+
{:exec => :execution_request},
|
27
|
+
:deploys
|
20
28
|
#register_subcommands :firewall_disable, :firewall_enable
|
21
29
|
# register_subcommands {:'lb-update' => :load_balancer_update}
|
22
30
|
alias_subcommand :details, :get
|
@@ -43,6 +51,8 @@ class Morpheus::Cli::Instances
|
|
43
51
|
@options_interface = @api_client.options
|
44
52
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
45
53
|
@execution_request_interface = @api_client.execution_request
|
54
|
+
@deploy_interface = @api_client.deploy
|
55
|
+
@deployments_interface = @api_client.deployments
|
46
56
|
end
|
47
57
|
|
48
58
|
def handle(args)
|
@@ -546,18 +556,12 @@ class Morpheus::Cli::Instances
|
|
546
556
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
547
557
|
end
|
548
558
|
optparse.parse!(args)
|
549
|
-
|
550
|
-
puts optparse
|
551
|
-
exit 1
|
552
|
-
end
|
559
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
553
560
|
connect(options)
|
554
561
|
|
555
562
|
begin
|
556
563
|
instance = find_instance_by_name_or_id(args[0])
|
557
564
|
return 1 if instance.nil?
|
558
|
-
new_group = nil
|
559
|
-
|
560
|
-
|
561
565
|
if options[:payload]
|
562
566
|
payload = options[:payload]
|
563
567
|
end
|
@@ -579,10 +583,40 @@ class Morpheus::Cli::Instances
|
|
579
583
|
params['ownerId'] = owner_id
|
580
584
|
#payload['createdById'] = options[:owner].to_i # pre 4.2.1 api
|
581
585
|
end
|
582
|
-
if
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
+
if options[:group]
|
587
|
+
group = find_group_by_name_or_id_for_provisioning(options[:group])
|
588
|
+
if group.nil?
|
589
|
+
return 1, "group not found"
|
590
|
+
end
|
591
|
+
payload['instance']['site'] = {'id' => group['id']}
|
592
|
+
end
|
593
|
+
# metadata tags
|
594
|
+
# if options[:options]['metadata'].is_a?(Array) && !options[:metadata]
|
595
|
+
# options[:metadata] = options[:options]['metadata']
|
596
|
+
# end
|
597
|
+
if options[:metadata]
|
598
|
+
metadata = []
|
599
|
+
if options[:metadata] == "[]" || options[:metadata] == "null"
|
600
|
+
payload['instance']['metadata'] = []
|
601
|
+
elsif options[:metadata].is_a?(Array)
|
602
|
+
payload['instance']['metadata'] = options[:metadata]
|
603
|
+
else
|
604
|
+
# parse string into format name:value, name:value
|
605
|
+
# merge IDs from current metadata
|
606
|
+
# todo: should allow quoted semicolons..
|
607
|
+
metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
|
608
|
+
metadata_list = metadata_list.collect do |it|
|
609
|
+
metadata_pair = it.split(":")
|
610
|
+
row = {}
|
611
|
+
row['name'] = metadata_pair[0].to_s.strip
|
612
|
+
row['value'] = metadata_pair[1].to_s.strip
|
613
|
+
row
|
614
|
+
end
|
615
|
+
payload['instance']['metadata'] = metadata_list
|
616
|
+
end
|
617
|
+
end
|
618
|
+
if payload['instance'].empty? && params.empty? && options[:owner].nil?
|
619
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
586
620
|
end
|
587
621
|
if !params.empty?
|
588
622
|
payload['instance'].deep_merge!(params)
|
@@ -1218,7 +1252,6 @@ class Morpheus::Cli::Instances
|
|
1218
1252
|
"Environment" => 'instanceContext',
|
1219
1253
|
"Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
|
1220
1254
|
"Metadata" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
1221
|
-
"Power Schedule" => lambda {|it| (it['powerSchedule'] && it['powerSchedule']['type']) ? it['powerSchedule']['type']['name'] : '' },
|
1222
1255
|
"Owner" => lambda {|it|
|
1223
1256
|
if it['owner']
|
1224
1257
|
(it['owner']['username'] || it['owner']['id'])
|
@@ -1228,13 +1261,20 @@ class Morpheus::Cli::Instances
|
|
1228
1261
|
},
|
1229
1262
|
#"Tenant" => lambda {|it| it['tenant'] ? it['tenant']['name'] : '' },
|
1230
1263
|
"Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
1264
|
+
# "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
1265
|
+
"Power Schedule" => lambda {|it| (it['powerSchedule'] && it['powerSchedule']['type']) ? it['powerSchedule']['type']['name'] : '' },
|
1266
|
+
"Last Deployment" => lambda {|it| (it['lastDeploy'] ? "#{it['lastDeploy']['deployment']['name']} #{it['lastDeploy']['deploymentVersion']['userVersion']} at #{format_local_dt it['lastDeploy']['deployDate']}" : nil) rescue "" },
|
1267
|
+
"Expire Date" => lambda {|it| it['expireDate'] ? format_local_dt(it['expireDate']) : '' },
|
1268
|
+
"Shutdown Date" => lambda {|it| it['shutdownDate'] ? format_local_dt(it['shutdownDate']) : '' },
|
1231
1269
|
"Nodes" => lambda {|it| it['containers'] ? it['containers'].count : 0 },
|
1232
1270
|
"Connection" => lambda {|it| format_instance_connection_string(it) },
|
1233
1271
|
"Status" => lambda {|it| format_instance_status(it) }
|
1234
1272
|
}
|
1235
|
-
|
1273
|
+
description_cols.delete("Power Schedule") if instance['powerSchedule'].nil?
|
1274
|
+
description_cols.delete("Expire Date") if instance['expireDate'].nil?
|
1275
|
+
description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
|
1236
1276
|
description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
|
1237
|
-
|
1277
|
+
description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
|
1238
1278
|
print_description_list(description_cols, instance)
|
1239
1279
|
|
1240
1280
|
if instance['statusMessage']
|
@@ -3606,6 +3646,60 @@ class Morpheus::Cli::Instances
|
|
3606
3646
|
end
|
3607
3647
|
end
|
3608
3648
|
|
3649
|
+
def deploys(args)
|
3650
|
+
params = {}
|
3651
|
+
options = {}
|
3652
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3653
|
+
opts.banner = subcommand_usage("[instance] [search]")
|
3654
|
+
build_standard_list_options(opts, options)
|
3655
|
+
opts.footer = <<-EOT
|
3656
|
+
List deployments for an instance.
|
3657
|
+
[instance] is required. This is the name or id of an instance
|
3658
|
+
[search] is optional. Filters on deployment version identifier
|
3659
|
+
EOT
|
3660
|
+
end
|
3661
|
+
optparse.parse!(args)
|
3662
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
3663
|
+
connect(options)
|
3664
|
+
if args.count > 1
|
3665
|
+
options[:phrase] = args.join(" ")
|
3666
|
+
end
|
3667
|
+
params.merge!(parse_list_options(options))
|
3668
|
+
instance = find_instance_by_name_or_id(args[0])
|
3669
|
+
return 1 if instance.nil?
|
3670
|
+
# @deploy_interface.setopts(options)
|
3671
|
+
# if options[:dry_run]
|
3672
|
+
# print_dry_run @deploy_interface.dry.list(instance['id'], params)
|
3673
|
+
# return
|
3674
|
+
# end
|
3675
|
+
# json_response = @deploy_interface.list(instance['id'], params)
|
3676
|
+
|
3677
|
+
@instances_interface.setopts(options)
|
3678
|
+
if options[:dry_run]
|
3679
|
+
print_dry_run @instances_interface.dry.deploys(instance['id'], params)
|
3680
|
+
return
|
3681
|
+
end
|
3682
|
+
json_response = @instances_interface.deploys(instance['id'], params)
|
3683
|
+
|
3684
|
+
app_deploys = json_response['appDeploys']
|
3685
|
+
render_response(json_response, options, 'appDeploys') do
|
3686
|
+
print_h1 "Instance Deploys", ["#{instance['name']}"] + parse_list_subtitles(options), options
|
3687
|
+
if app_deploys.empty?
|
3688
|
+
print cyan,"No deployments found.",reset,"\n"
|
3689
|
+
else
|
3690
|
+
print as_pretty_table(app_deploys, app_deploy_column_definitions.upcase_keys!, options)
|
3691
|
+
if json_response['meta']
|
3692
|
+
print_results_pagination(json_response)
|
3693
|
+
else
|
3694
|
+
print_results_pagination({size:app_deploys.size,total:app_deploys.size.to_i})
|
3695
|
+
end
|
3696
|
+
|
3697
|
+
end
|
3698
|
+
print reset,"\n"
|
3699
|
+
end
|
3700
|
+
return 0
|
3701
|
+
end
|
3702
|
+
|
3609
3703
|
private
|
3610
3704
|
|
3611
3705
|
def find_zone_by_name_or_id(group_id, val)
|
@@ -3902,4 +3996,29 @@ private
|
|
3902
3996
|
]
|
3903
3997
|
end
|
3904
3998
|
|
3999
|
+
def app_deploy_column_definitions
|
4000
|
+
{
|
4001
|
+
"ID" => 'id',
|
4002
|
+
"Deployment" => lambda {|it| it['deployment']['name'] rescue '' },
|
4003
|
+
"Version" => lambda {|it| (it['deploymentVersion']['userVersion'] || it['deploymentVersion']['version']) rescue '' },
|
4004
|
+
"Deploy Date" => lambda {|it| format_local_dt(it['deployDate']) },
|
4005
|
+
"Status" => lambda {|it| format_app_deploy_status(it['status']) },
|
4006
|
+
}
|
4007
|
+
end
|
4008
|
+
|
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
|
+
|
3905
4024
|
end
|
@@ -25,6 +25,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
25
25
|
options = {}
|
26
26
|
params = {}
|
27
27
|
ref_ids = []
|
28
|
+
query_tags = {}
|
28
29
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
29
30
|
opts.banner = subcommand_usage()
|
30
31
|
opts.on('-a', '--all', "Display all details, costs and prices." ) do
|
@@ -34,16 +35,16 @@ class Morpheus::Cli::InvoicesCommand
|
|
34
35
|
options[:show_prices] = true
|
35
36
|
# options[:show_raw_data] = true
|
36
37
|
end
|
37
|
-
opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network,
|
38
|
+
opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network, Extra" ) do
|
38
39
|
options[:show_estimates] = true
|
39
40
|
end
|
40
|
-
# opts.on('--costs', '--costs', "Display all costs: Compute, Storage, Network,
|
41
|
+
# opts.on('--costs', '--costs', "Display all costs: Compute, Storage, Network, Extra" ) do
|
41
42
|
# options[:show_costs] = true
|
42
43
|
# end
|
43
|
-
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network,
|
44
|
+
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network, Extra" ) do
|
44
45
|
options[:show_prices] = true
|
45
46
|
end
|
46
|
-
opts.on('--type TYPE',
|
47
|
+
opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
|
47
48
|
params['refType'] ||= []
|
48
49
|
values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
|
49
50
|
values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
|
@@ -105,6 +106,11 @@ class Morpheus::Cli::InvoicesCommand
|
|
105
106
|
opts.on('--tenant ID', String, "View invoices for a tenant. Default is your own account.") do |val|
|
106
107
|
params['accountId'] = val
|
107
108
|
end
|
109
|
+
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
110
|
+
k,v = val.split("=")
|
111
|
+
query_tags[k] ||= []
|
112
|
+
query_tags[k] << v
|
113
|
+
end
|
108
114
|
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
109
115
|
options[:show_raw_data] = true
|
110
116
|
end
|
@@ -163,6 +169,11 @@ class Morpheus::Cli::InvoicesCommand
|
|
163
169
|
end
|
164
170
|
params['rawData'] = true if options[:show_raw_data]
|
165
171
|
params['refId'] = ref_ids unless ref_ids.empty?
|
172
|
+
if query_tags && !query_tags.empty?
|
173
|
+
query_tags.each do |k,v|
|
174
|
+
params['tags.' + k] = v
|
175
|
+
end
|
176
|
+
end
|
166
177
|
@invoices_interface.setopts(options)
|
167
178
|
if options[:dry_run]
|
168
179
|
print_dry_run @invoices_interface.dry.list(params)
|
@@ -182,9 +193,8 @@ class Morpheus::Cli::InvoicesCommand
|
|
182
193
|
subtitles += parse_list_subtitles(options)
|
183
194
|
print_h1 title, subtitles
|
184
195
|
if invoices.empty?
|
185
|
-
|
186
|
-
|
187
|
-
end
|
196
|
+
print cyan,"No invoices found.",reset,"\n"
|
197
|
+
print reset,"\n"
|
188
198
|
else
|
189
199
|
# current_date = Time.now
|
190
200
|
# current_period = "#{current_date.year}#{current_date.month.to_s.rjust(2, '0')}"
|
@@ -216,7 +226,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
216
226
|
# {"MEMORY" => lambda {|it| format_money(it['memoryCost']) } },
|
217
227
|
{"STORAGE" => lambda {|it| format_money(it['storageCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
218
228
|
{"NETWORK" => lambda {|it| format_money(it['networkCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
219
|
-
{"
|
229
|
+
{"EXTRA" => lambda {|it| format_money(it['extraCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
220
230
|
{"MTD" => lambda {|it| format_money(it['runningCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
221
231
|
{"TOTAL" => lambda {|it|
|
222
232
|
format_money(it['totalCost'], 'usd', {sigdig:options[:sigdig]}) + ((it['totalCost'].to_f > 0 && it['totalCost'] != it['runningCost']) ? " (Projected)" : "")
|
@@ -229,7 +239,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
229
239
|
# {"MEMORY PRICE" => lambda {|it| format_money(it['memoryPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
230
240
|
{"STORAGE PRICE" => lambda {|it| format_money(it['storagePrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
231
241
|
{"NETWORK PRICE" => lambda {|it| format_money(it['networkPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
232
|
-
{"
|
242
|
+
{"EXTRA PRICE" => lambda {|it| format_money(it['extraPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
233
243
|
{"MTD PRICE" => lambda {|it| format_money(it['runningPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
234
244
|
{"TOTAL PRICE" => lambda {|it|
|
235
245
|
format_money(it['totalPrice'], 'usd', {sigdig:options[:sigdig]}) + ((it['totalCost'].to_f > 0 && it['totalCost'] != it['runningCost']) ? " (Projected)" : "")
|
@@ -242,7 +252,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
242
252
|
# {"MEMORY EST." => lambda {|it| format_money(it['estimatedMemoryCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
243
253
|
{"STORAGE EST." => lambda {|it| format_money(it['estimatedStorageCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
244
254
|
{"NETWORK EST." => lambda {|it| format_money(it['estimatedNetworkCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
245
|
-
{"
|
255
|
+
{"EXTRA EST." => lambda {|it| format_money(it['estimatedExtraCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
246
256
|
{"MTD EST." => lambda {|it| format_money(it['estimatedRunningCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
247
257
|
{"TOTAL EST." => lambda {|it|
|
248
258
|
format_money(it['estimatedTotalCost'], 'usd', {sigdig:options[:sigdig]}) + ((it['estimatedTotalCost'].to_f > 0 && it['estimatedTotalCost'] != it['estimatedRunningCost']) ? " (Projected)" : "")
|
@@ -253,6 +263,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
253
263
|
{"ESTIMATE" => lambda {|it| format_boolean(it['estimate']) } },
|
254
264
|
{"ACTIVE" => lambda {|it| format_boolean(it['active']) } },
|
255
265
|
{"ITEMS" => lambda {|it| it['lineItems'].size rescue '' } },
|
266
|
+
{"TAGS" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
|
256
267
|
]
|
257
268
|
if show_projects
|
258
269
|
columns += [
|
@@ -273,40 +284,23 @@ class Morpheus::Cli::InvoicesCommand
|
|
273
284
|
print_results_pagination(json_response, {:label => "invoice", :n_label => "invoices"})
|
274
285
|
end
|
275
286
|
|
276
|
-
if options[:show_invoice_totals]
|
277
|
-
invoice_totals = json_response['invoiceTotals']
|
278
|
-
print_h2 "Line Item Totals" unless options[:totals_only]
|
279
|
-
invoice_totals_columns = [
|
280
|
-
{"Invoices" => lambda {|it| format_number(json_response['meta']['total']) rescue '' } },
|
281
|
-
{"Compute" => lambda {|it| format_money(it['actualComputeCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
282
|
-
{"Storage" => lambda {|it| format_money(it['actualStorageCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
283
|
-
{"Network" => lambda {|it| format_money(it['actualNetworkCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
284
|
-
{"Extra" => lambda {|it| format_money(it['actualExtraCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
285
|
-
] + (options[:show_prices] ? [
|
286
|
-
{"Compute Price" => lambda {|it| format_money(it['actualComputePrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
287
|
-
{"Storage Price" => lambda {|it| format_money(it['actualStoragePrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
288
|
-
{"Network Price" => lambda {|it| format_money(it['actualNetworkPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
289
|
-
{"Extra Price" => lambda {|it| format_money(it['actualExtraPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
290
|
-
] : [])
|
291
|
-
print_description_list(invoice_totals_columns, line_item_totals)
|
292
|
-
end
|
293
287
|
if options[:show_invoice_totals]
|
294
288
|
invoice_totals = json_response['invoiceTotals']
|
295
289
|
print_h2 "Invoice Totals (#{format_number(json_response['meta']['total']) rescue ''})"
|
296
290
|
|
297
291
|
if invoice_totals
|
298
292
|
cost_rows = [
|
299
|
-
{label: 'Cost', compute: invoice_totals['actualComputeCost'], memory: invoice_totals['actualMemoryCost'], storage: invoice_totals['actualStorageCost'], network: invoice_totals['actualNetworkCost'], license: invoice_totals['actualLicenseCost'], extra: invoice_totals['actualExtraCost'], running: invoice_totals['actualRunningCost'], total: invoice_totals['actualTotalCost']},
|
293
|
+
{label: 'Cost'.upcase, compute: invoice_totals['actualComputeCost'], memory: invoice_totals['actualMemoryCost'], storage: invoice_totals['actualStorageCost'], network: invoice_totals['actualNetworkCost'], license: invoice_totals['actualLicenseCost'], extra: invoice_totals['actualExtraCost'], running: invoice_totals['actualRunningCost'], total: invoice_totals['actualTotalCost']},
|
300
294
|
]
|
301
295
|
if options[:show_prices]
|
302
296
|
cost_rows += [
|
303
|
-
{label: 'Price', compute: invoice_totals['actualComputePrice'], memory: invoice_totals['actualMemoryPrice'], storage: invoice_totals['actualStoragePrice'], network: invoice_totals['actualNetworkPrice'], license: invoice_totals['actualLicensePrice'], extra: invoice_totals['actualExtraPrice'], running: invoice_totals['actualRunningPrice'], total: invoice_totals['actualTotalPrice']},
|
297
|
+
{label: 'Price'.upcase, compute: invoice_totals['actualComputePrice'], memory: invoice_totals['actualMemoryPrice'], storage: invoice_totals['actualStoragePrice'], network: invoice_totals['actualNetworkPrice'], license: invoice_totals['actualLicensePrice'], extra: invoice_totals['actualExtraPrice'], running: invoice_totals['actualRunningPrice'], total: invoice_totals['actualTotalPrice']},
|
304
298
|
]
|
305
299
|
end
|
306
300
|
if options[:show_estimates]
|
307
301
|
cost_rows += [
|
308
|
-
{label: '
|
309
|
-
{label: '
|
302
|
+
{label: 'Metered Cost'.upcase, compute: invoice_totals['estimatedComputeCost'], memory: invoice_totals['estimatedMemoryCost'], storage: invoice_totals['estimatedStorageCost'], network: invoice_totals['estimatedNetworkCost'], license: invoice_totals['estimatedLicenseCost'], extra: invoice_totals['estimatedExtraCost'], running: invoice_totals['estimatedRunningCost'], total: invoice_totals['estimatedTotalCost']},
|
303
|
+
{label: 'Metered Price'.upcase, compute: invoice_totals['estimatedComputePrice'], memory: invoice_totals['estimatedMemoryPrice'], storage: invoice_totals['estimatedStoragePrice'], network: invoice_totals['estimatedNetworkPrice'], license: invoice_totals['estimatedLicensePrice'], extra: invoice_totals['estimatedExtraPrice'], running: invoice_totals['estimatedRunningPrice'], total: invoice_totals['estimatedTotalPrice']},
|
310
304
|
]
|
311
305
|
end
|
312
306
|
cost_columns = {
|
@@ -316,8 +310,8 @@ class Morpheus::Cli::InvoicesCommand
|
|
316
310
|
"Storage".upcase => lambda {|it| format_money(it[:storage], 'usd', {sigdig:options[:sigdig]}) },
|
317
311
|
"Network".upcase => lambda {|it| format_money(it[:network], 'usd', {sigdig:options[:sigdig]}) },
|
318
312
|
"License".upcase => lambda {|it| format_money(it[:license], 'usd', {sigdig:options[:sigdig]}) },
|
319
|
-
"
|
320
|
-
"MTD" => lambda {|it| format_money(it[:running], 'usd', {sigdig:options[:sigdig]}) },
|
313
|
+
"Extra".upcase => lambda {|it| format_money(it[:extra], 'usd', {sigdig:options[:sigdig]}) },
|
314
|
+
"MTD".upcase => lambda {|it| format_money(it[:running], 'usd', {sigdig:options[:sigdig]}) },
|
321
315
|
"Total".upcase => lambda {|it|
|
322
316
|
format_money(it[:total], 'usd', {sigdig:options[:sigdig]}) + ((it[:total].to_f > 0 && it[:total] != it[:running]) ? " (Projected)" : "")
|
323
317
|
},
|
@@ -330,7 +324,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
330
324
|
cost_columns.delete("License".upcase)
|
331
325
|
end
|
332
326
|
if cost_rows.sum { |it| it[:extra].to_f } == 0
|
333
|
-
cost_columns.delete("
|
327
|
+
cost_columns.delete("Extra".upcase)
|
334
328
|
end
|
335
329
|
print as_pretty_table(cost_rows, cost_columns, options)
|
336
330
|
else
|
@@ -338,8 +332,8 @@ class Morpheus::Cli::InvoicesCommand
|
|
338
332
|
print yellow, "No invoice totals data", reset, "\n"
|
339
333
|
end
|
340
334
|
end
|
335
|
+
print reset,"\n"
|
341
336
|
end
|
342
|
-
print reset,"\n"
|
343
337
|
return 0, nil
|
344
338
|
end
|
345
339
|
end
|
@@ -355,10 +349,10 @@ class Morpheus::Cli::InvoicesCommand
|
|
355
349
|
# options[:show_raw_data] = true
|
356
350
|
options[:max_line_items] = 10000
|
357
351
|
end
|
358
|
-
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network,
|
352
|
+
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network, Extra" ) do
|
359
353
|
options[:show_prices] = true
|
360
354
|
end
|
361
|
-
opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network,
|
355
|
+
opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network, Extra" ) do
|
362
356
|
options[:show_estimates] = true
|
363
357
|
end
|
364
358
|
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
@@ -415,6 +409,7 @@ EOT
|
|
415
409
|
"Type" => lambda {|it| format_invoice_ref_type(it) },
|
416
410
|
"Ref ID" => lambda {|it| it['refId'] },
|
417
411
|
"Ref Name" => lambda {|it| it['refName'] },
|
412
|
+
"Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
|
418
413
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
419
414
|
"Power State" => lambda {|it| format_server_power_state(it) },
|
420
415
|
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
@@ -428,6 +423,7 @@ EOT
|
|
428
423
|
"Ref Start" => lambda {|it| format_dt(it['refStart']) },
|
429
424
|
"Ref End" => lambda {|it| format_dt(it['refEnd']) },
|
430
425
|
"Items" => lambda {|it| it['lineItems'].size rescue '' },
|
426
|
+
"Tags" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
431
427
|
"Project ID" => lambda {|it| it['project'] ? it['project']['id'] : '' },
|
432
428
|
"Project Name" => lambda {|it| it['project'] ? it['project']['name'] : '' },
|
433
429
|
"Project Tags" => lambda {|it| it['project'] ? format_metadata(it['project']['tags']) : '' },
|
@@ -443,6 +439,9 @@ EOT
|
|
443
439
|
description_cols.delete("Project Name")
|
444
440
|
description_cols.delete("Project Tags")
|
445
441
|
end
|
442
|
+
if invoice['metadata'].nil? || invoice['metadata'].empty?
|
443
|
+
description_cols.delete("Tags")
|
444
|
+
end
|
446
445
|
if !['ComputeServer','Instance','Container'].include?(invoice['refType'])
|
447
446
|
description_cols.delete("Power State")
|
448
447
|
end
|
@@ -455,7 +454,7 @@ EOT
|
|
455
454
|
"Storage" => lambda {|it| format_money(it['storageCost'], 'usd', {sigdig:options[:sigdig]}) },
|
456
455
|
"Network" => lambda {|it| format_money(it['networkCost'], 'usd', {sigdig:options[:sigdig]}) },
|
457
456
|
"License" => lambda {|it| format_money(it['licenseCost'], 'usd', {sigdig:options[:sigdig]}) },
|
458
|
-
"
|
457
|
+
"Extra" => lambda {|it| format_money(it['extraCost'], 'usd', {sigdig:options[:sigdig]}) },
|
459
458
|
"Running" => lambda {|it| format_money(it['runningCost'], 'usd', {sigdig:options[:sigdig]}) },
|
460
459
|
"Total Cost" => lambda {|it| format_money(it['totalCost'], 'usd', {sigdig:options[:sigdig]}) },
|
461
460
|
}
|
@@ -468,7 +467,7 @@ EOT
|
|
468
467
|
"Storage" => lambda {|it| format_money(it['storagePrice'], 'usd', {sigdig:options[:sigdig]}) },
|
469
468
|
"Network" => lambda {|it| format_money(it['networkPrice'], 'usd', {sigdig:options[:sigdig]}) },
|
470
469
|
"License" => lambda {|it| format_money(it['licensePrice'], 'usd', {sigdig:options[:sigdig]}) },
|
471
|
-
"
|
470
|
+
"Extra" => lambda {|it| format_money(it['extraPrice'], 'usd', {sigdig:options[:sigdig]}) },
|
472
471
|
"Running" => lambda {|it| format_money(it['runningPrice'], 'usd', {sigdig:options[:sigdig]}) },
|
473
472
|
"Total Price" => lambda {|it| format_money(it['totalPrice'], 'usd', {sigdig:options[:sigdig]}) },
|
474
473
|
}
|
@@ -495,6 +494,7 @@ EOT
|
|
495
494
|
{"USAGE CATEGORY" => lambda {|it| it['usageCategory'] } },
|
496
495
|
{"USAGE" => lambda {|it| it['itemUsage'] } },
|
497
496
|
{"RATE" => lambda {|it| it['itemRate'] } },
|
497
|
+
{"UNIT" => lambda {|it| it['rateUnit'] } },
|
498
498
|
{"COST" => lambda {|it| format_money(it['itemCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
499
499
|
{"PRICE" => lambda {|it| format_money(it['itemPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|
500
500
|
#{"TAX" => lambda {|it| format_money(it['itemTax'], 'usd', {sigdig:options[:sigdig]}) } },
|
@@ -533,8 +533,8 @@ EOT
|
|
533
533
|
end
|
534
534
|
if options[:show_estimates]
|
535
535
|
cost_rows += [
|
536
|
-
{label: '
|
537
|
-
{label: '
|
536
|
+
{label: 'Metered Cost'.upcase, compute: invoice['estimatedComputeCost'], memory: invoice['estimatedMemoryCost'], storage: invoice['estimatedStorageCost'], network: invoice['estimatedNetworkCost'], license: invoice['estimatedLicenseCost'], extra: invoice['estimatedExtraCost'], running: invoice['estimatedRunningCost'], total: invoice['estimatedTotalCost']},
|
537
|
+
{label: 'Metered Price'.upcase, compute: invoice['estimatedComputePrice'], memory: invoice['estimatedMemoryPrice'], storage: invoice['estimatedStoragePrice'], network: invoice['estimatedNetworkPrice'], license: invoice['estimatedLicensePrice'], extra: invoice['estimatedExtraPrice'], running: invoice['estimatedRunningPrice'], total: invoice['estimatedTotalPrice']},
|
538
538
|
]
|
539
539
|
end
|
540
540
|
cost_columns = {
|
@@ -544,7 +544,7 @@ EOT
|
|
544
544
|
"Storage".upcase => lambda {|it| format_money(it[:storage], 'usd', {sigdig:options[:sigdig]}) },
|
545
545
|
"Network".upcase => lambda {|it| format_money(it[:network], 'usd', {sigdig:options[:sigdig]}) },
|
546
546
|
"License".upcase => lambda {|it| format_money(it[:license], 'usd', {sigdig:options[:sigdig]}) },
|
547
|
-
"
|
547
|
+
"Extra".upcase => lambda {|it| format_money(it[:extra], 'usd', {sigdig:options[:sigdig]}) },
|
548
548
|
"MTD" => lambda {|it| format_money(it[:running], 'usd', {sigdig:options[:sigdig]}) },
|
549
549
|
"Total".upcase => lambda {|it|
|
550
550
|
format_money(it[:total], 'usd', {sigdig:options[:sigdig]}) + ((it[:total].to_f > 0 && it[:total] != it[:running]) ? " (Projected)" : "")
|
@@ -558,7 +558,7 @@ EOT
|
|
558
558
|
cost_columns.delete("License".upcase)
|
559
559
|
end
|
560
560
|
if cost_rows.sum { |it| it[:extra].to_f } == 0
|
561
|
-
cost_columns.delete("
|
561
|
+
cost_columns.delete("Extra".upcase)
|
562
562
|
end
|
563
563
|
print as_pretty_table(cost_rows, cost_columns, options)
|
564
564
|
|
@@ -656,6 +656,7 @@ EOT
|
|
656
656
|
options = {}
|
657
657
|
params = {}
|
658
658
|
ref_ids = []
|
659
|
+
query_tags = {}
|
659
660
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
660
661
|
opts.banner = subcommand_usage()
|
661
662
|
opts.on('-a', '--all', "Display all details, costs and prices." ) do
|
@@ -664,13 +665,13 @@ EOT
|
|
664
665
|
options[:show_prices] = true
|
665
666
|
# options[:show_raw_data] = true
|
666
667
|
end
|
667
|
-
# opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Storage, Network,
|
668
|
+
# opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Storage, Network, Extra" ) do
|
668
669
|
# options[:show_actual_costs] = true
|
669
670
|
# end
|
670
|
-
# opts.on('--costs', '--costs', "Display all costs: Compute, Storage, Network,
|
671
|
+
# opts.on('--costs', '--costs', "Display all costs: Compute, Storage, Network, Extra" ) do
|
671
672
|
# options[:show_costs] = true
|
672
673
|
# end
|
673
|
-
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network,
|
674
|
+
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network, Extra" ) do
|
674
675
|
options[:show_prices] = true
|
675
676
|
end
|
676
677
|
opts.on('--invoice-id ID', String, "Filter by Invoice ID") do |val|
|
@@ -681,7 +682,7 @@ EOT
|
|
681
682
|
params['externalId'] ||= []
|
682
683
|
params['externalId'] << val
|
683
684
|
end
|
684
|
-
opts.on('--type TYPE',
|
685
|
+
opts.on('-t', '--type TYPE', "Filter by Ref Type eg. ComputeSite (Group), ComputeZone (Cloud), ComputeServer (Host), Instance, Container, User") do |val|
|
685
686
|
params['refType'] ||= []
|
686
687
|
values = val.split(",").collect {|it| it.strip }.select {|it| it != "" }
|
687
688
|
values.each { |it| params['refType'] << parse_invoice_ref_type(it) }
|
@@ -743,6 +744,11 @@ EOT
|
|
743
744
|
opts.on('--tenant ID', String, "View invoice line items for a tenant. Default is your own account.") do |val|
|
744
745
|
params['accountId'] = val
|
745
746
|
end
|
747
|
+
# opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
748
|
+
# k,v = val.split("=")
|
749
|
+
# query_tags[k] ||= []
|
750
|
+
# query_tags[k] << v
|
751
|
+
# end
|
746
752
|
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
747
753
|
options[:show_raw_data] = true
|
748
754
|
end
|
@@ -802,6 +808,11 @@ EOT
|
|
802
808
|
end
|
803
809
|
params['rawData'] = true if options[:show_raw_data]
|
804
810
|
params['refId'] = ref_ids unless ref_ids.empty?
|
811
|
+
if query_tags && !query_tags.empty?
|
812
|
+
query_tags.each do |k,v|
|
813
|
+
params['tags.' + k] = v
|
814
|
+
end
|
815
|
+
end
|
805
816
|
@invoice_line_items_interface.setopts(options)
|
806
817
|
if options[:dry_run]
|
807
818
|
print_dry_run @invoice_line_items_interface.dry.list(params)
|
@@ -838,6 +849,7 @@ EOT
|
|
838
849
|
{"USAGE CATEGORY" => lambda {|it| it['usageCategory'] } },
|
839
850
|
{"USAGE" => lambda {|it| it['itemUsage'] } },
|
840
851
|
{"RATE" => lambda {|it| it['itemRate'] } },
|
852
|
+
{"UNIT" => lambda {|it| it['rateUnit'] } },
|
841
853
|
{"COST" => lambda {|it| format_money(it['itemCost'], 'usd', {sigdig:options[:sigdig]}) } },
|
842
854
|
] + (options[:show_prices] ? [
|
843
855
|
{"PRICE" => lambda {|it| format_money(it['itemPrice'], 'usd', {sigdig:options[:sigdig]}) } },
|