morpheus-cli 5.2.1 → 5.3.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/README.md +3 -3
- data/lib/morpheus/api/instances_interface.rb +21 -0
- data/lib/morpheus/api/invoices_interface.rb +12 -3
- data/lib/morpheus/cli/activity_command.rb +7 -4
- data/lib/morpheus/cli/backup_jobs_command.rb +1 -1
- data/lib/morpheus/cli/backups_command.rb +2 -3
- data/lib/morpheus/cli/budgets_command.rb +389 -319
- data/lib/morpheus/cli/cli_command.rb +19 -9
- data/lib/morpheus/cli/commands/standard/curl_command.rb +25 -10
- data/lib/morpheus/cli/commands/standard/history_command.rb +6 -2
- data/lib/morpheus/cli/dashboard_command.rb +260 -20
- data/lib/morpheus/cli/execution_request_command.rb +15 -5
- data/lib/morpheus/cli/hosts.rb +12 -0
- data/lib/morpheus/cli/instances.rb +116 -2
- data/lib/morpheus/cli/invoices_command.rb +89 -95
- data/lib/morpheus/cli/jobs_command.rb +94 -92
- data/lib/morpheus/cli/library_option_types_command.rb +5 -3
- data/lib/morpheus/cli/mixins/print_helper.rb +16 -6
- data/lib/morpheus/cli/projects_command.rb +1 -1
- data/lib/morpheus/cli/remote.rb +2 -1
- data/lib/morpheus/cli/user_sources_command.rb +118 -134
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +21 -11
- metadata +2 -2
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -117,6 +117,12 @@ class Morpheus::Cli::Hosts
|
|
117
117
|
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
118
118
|
options[:account] = val
|
119
119
|
end
|
120
|
+
opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
|
121
|
+
val.split(",").each do |k|
|
122
|
+
options[:labels] ||= []
|
123
|
+
options[:labels] << k.strip
|
124
|
+
end
|
125
|
+
end
|
120
126
|
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
121
127
|
val.split(",").each do |value_pair|
|
122
128
|
k,v = value_pair.strip.split("=")
|
@@ -186,6 +192,7 @@ class Morpheus::Cli::Hosts
|
|
186
192
|
params['clusterId'] = cluster['id']
|
187
193
|
end
|
188
194
|
end
|
195
|
+
params['labels'] = options[:labels] if options[:labels]
|
189
196
|
if options[:tags] && !options[:tags].empty?
|
190
197
|
options[:tags].each do |k,v|
|
191
198
|
params['tags.' + k] = v
|
@@ -542,6 +549,7 @@ class Morpheus::Cli::Hosts
|
|
542
549
|
"Name" => 'name',
|
543
550
|
"Hostname" => 'hostname',
|
544
551
|
"Description" => 'description',
|
552
|
+
"Labels" => lambda {|it| it['labels'] ? it['labels'].join(',') : '' },
|
545
553
|
"Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
|
546
554
|
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
547
555
|
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
@@ -566,6 +574,7 @@ class Morpheus::Cli::Hosts
|
|
566
574
|
# server_columns.delete("Tenant") if multi_tenant != true
|
567
575
|
server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
|
568
576
|
server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
|
577
|
+
server_columns.delete("Labels") if server['labels'].nil? || server['labels'].empty?
|
569
578
|
server_columns.delete("Tags") if tags.nil? || tags.empty?
|
570
579
|
|
571
580
|
print_description_list(server_columns, server)
|
@@ -993,6 +1002,9 @@ class Morpheus::Cli::Hosts
|
|
993
1002
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
994
1003
|
params['powerScheduleType'] = val == "null" ? nil : val
|
995
1004
|
end
|
1005
|
+
opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
1006
|
+
params['labels'] = val.to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
1007
|
+
end
|
996
1008
|
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
997
1009
|
options[:tags] = val
|
998
1010
|
end
|
@@ -19,6 +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
|
+
:lock, :unlock, :clone_image,
|
22
23
|
:security_groups, :apply_security_groups, :run_workflow, :import_snapshot, :snapshot, :snapshots,
|
23
24
|
:console, :status_check, {:containers => :list_containers},
|
24
25
|
:scaling, {:'scaling-update' => :scaling_update},
|
@@ -603,8 +604,8 @@ class Morpheus::Cli::Instances
|
|
603
604
|
opts.on('--group GROUP', String, "Group Name or ID") do |val|
|
604
605
|
options[:group] = val
|
605
606
|
end
|
606
|
-
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
607
|
-
params['labels'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
607
|
+
opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
608
|
+
params['labels'] = val.to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
|
608
609
|
end
|
609
610
|
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
610
611
|
options[:tags] = val
|
@@ -1350,6 +1351,7 @@ class Morpheus::Cli::Instances
|
|
1350
1351
|
"Shutdown Date" => lambda {|it| it['shutdownDate'] ? format_local_dt(it['shutdownDate']) : '' },
|
1351
1352
|
"Nodes" => lambda {|it| it['containers'] ? it['containers'].count : 0 },
|
1352
1353
|
"Connection" => lambda {|it| format_instance_connection_string(it) },
|
1354
|
+
"Locked" => lambda {|it| format_boolean(it['locked']) },
|
1353
1355
|
"Status" => lambda {|it| format_instance_status(it) }
|
1354
1356
|
}
|
1355
1357
|
description_cols.delete("Labels") if labels.nil? || labels.empty?
|
@@ -1359,6 +1361,7 @@ class Morpheus::Cli::Instances
|
|
1359
1361
|
description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
|
1360
1362
|
description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
|
1361
1363
|
description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
|
1364
|
+
description_cols.delete("Locked") if instance['locked'] != true
|
1362
1365
|
#description_cols.delete("Environment") if instance['instanceContext'].nil?
|
1363
1366
|
print_description_list(description_cols, instance)
|
1364
1367
|
|
@@ -3888,6 +3891,117 @@ EOT
|
|
3888
3891
|
return 0
|
3889
3892
|
end
|
3890
3893
|
|
3894
|
+
def clone_image(args)
|
3895
|
+
options = {}
|
3896
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3897
|
+
opts.banner = subcommand_usage("[instance]")
|
3898
|
+
opts.on( '--name VALUE', String, "Image Name (Template Name). Default is server name + timestamp" ) do |val|
|
3899
|
+
options[:options]['templateName'] = val
|
3900
|
+
end
|
3901
|
+
build_standard_update_options(opts, options)
|
3902
|
+
opts.footer = <<-EOT
|
3903
|
+
Clone to image (template) for an instance
|
3904
|
+
[instance] is required. This is the name or id of an instance
|
3905
|
+
EOT
|
3906
|
+
end
|
3907
|
+
optparse.parse!(args)
|
3908
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
3909
|
+
connect(options)
|
3910
|
+
instance = find_instance_by_name_or_id(args[0])
|
3911
|
+
return 1 if instance.nil?
|
3912
|
+
payload = {}
|
3913
|
+
if options[:payload]
|
3914
|
+
payload = options[:payload]
|
3915
|
+
payload.deep_merge!(parse_passed_options(options))
|
3916
|
+
else
|
3917
|
+
payload.deep_merge!(parse_passed_options(options))
|
3918
|
+
if payload['templateName'].nil?
|
3919
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'templateName', 'type' => 'text', 'fieldLabel' => 'Image Name', 'description' => 'Choose a name for the new image template. Default is the server name + timestamp'}], options[:options])
|
3920
|
+
if v_prompt['templateName'].to_s != ''
|
3921
|
+
payload['templateName'] = v_prompt['templateName']
|
3922
|
+
end
|
3923
|
+
end
|
3924
|
+
end
|
3925
|
+
@instances_interface.setopts(options)
|
3926
|
+
if options[:dry_run]
|
3927
|
+
print_dry_run @instances_interface.dry.clone_image(instance['id'], payload)
|
3928
|
+
return
|
3929
|
+
end
|
3930
|
+
json_response = @instances_interface.clone_image(instance['id'], payload)
|
3931
|
+
render_response(json_response, options) do
|
3932
|
+
print_green_success "Clone Image initiated."
|
3933
|
+
end
|
3934
|
+
return 0, nil
|
3935
|
+
end
|
3936
|
+
|
3937
|
+
def lock(args)
|
3938
|
+
options = {}
|
3939
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3940
|
+
opts.banner = subcommand_usage("[instance]")
|
3941
|
+
build_standard_update_options(opts, options)
|
3942
|
+
opts.footer = <<-EOT
|
3943
|
+
Lock an instance
|
3944
|
+
[instance] is required. This is the name or id of an instance
|
3945
|
+
EOT
|
3946
|
+
end
|
3947
|
+
optparse.parse!(args)
|
3948
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
3949
|
+
connect(options)
|
3950
|
+
instance = find_instance_by_name_or_id(args[0])
|
3951
|
+
return 1 if instance.nil?
|
3952
|
+
payload = {}
|
3953
|
+
if options[:payload]
|
3954
|
+
payload = options[:payload]
|
3955
|
+
payload.deep_merge!(parse_passed_options(options))
|
3956
|
+
else
|
3957
|
+
payload.deep_merge!(parse_passed_options(options))
|
3958
|
+
end
|
3959
|
+
@instances_interface.setopts(options)
|
3960
|
+
if options[:dry_run]
|
3961
|
+
print_dry_run @instances_interface.dry.lock(instance['id'], payload)
|
3962
|
+
return
|
3963
|
+
end
|
3964
|
+
json_response = @instances_interface.lock(instance['id'], payload)
|
3965
|
+
render_response(json_response, options) do
|
3966
|
+
print_green_success "Locked instance #{instance['name']}"
|
3967
|
+
end
|
3968
|
+
return 0, nil
|
3969
|
+
end
|
3970
|
+
|
3971
|
+
def unlock(args)
|
3972
|
+
options = {}
|
3973
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3974
|
+
opts.banner = subcommand_usage("[instance]")
|
3975
|
+
build_standard_update_options(opts, options)
|
3976
|
+
opts.footer = <<-EOT
|
3977
|
+
Unlock an instance
|
3978
|
+
[instance] is required. This is the name or id of an instance
|
3979
|
+
EOT
|
3980
|
+
end
|
3981
|
+
optparse.parse!(args)
|
3982
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
3983
|
+
connect(options)
|
3984
|
+
instance = find_instance_by_name_or_id(args[0])
|
3985
|
+
return 1 if instance.nil?
|
3986
|
+
payload = {}
|
3987
|
+
if options[:payload]
|
3988
|
+
payload = options[:payload]
|
3989
|
+
payload.deep_merge!(parse_passed_options(options))
|
3990
|
+
else
|
3991
|
+
payload.deep_merge!(parse_passed_options(options))
|
3992
|
+
end
|
3993
|
+
@instances_interface.setopts(options)
|
3994
|
+
if options[:dry_run]
|
3995
|
+
print_dry_run @instances_interface.dry.unlock(instance['id'], payload)
|
3996
|
+
return
|
3997
|
+
end
|
3998
|
+
json_response = @instances_interface.unlock(instance['id'], payload)
|
3999
|
+
render_response(json_response, options) do
|
4000
|
+
print_green_success "Unlocked instance #{instance['name']}"
|
4001
|
+
end
|
4002
|
+
return 0, nil
|
4003
|
+
end
|
4004
|
+
|
3891
4005
|
private
|
3892
4006
|
|
3893
4007
|
def find_zone_by_name_or_id(group_id, val)
|
@@ -8,7 +8,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
8
8
|
|
9
9
|
set_command_name :'invoices'
|
10
10
|
|
11
|
-
register_subcommands :list, :get, :refresh,
|
11
|
+
register_subcommands :list, :get, :update, :refresh,
|
12
12
|
:list_line_items, :get_line_item
|
13
13
|
|
14
14
|
def connect(opts)
|
@@ -33,7 +33,6 @@ class Morpheus::Cli::InvoicesCommand
|
|
33
33
|
options[:show_estimates] = true
|
34
34
|
# options[:show_costs] = true
|
35
35
|
options[:show_prices] = true
|
36
|
-
# options[:show_raw_data] = true
|
37
36
|
end
|
38
37
|
opts.on('--dates', "Display Ref Start, Ref End, etc.") do |val|
|
39
38
|
options[:show_dates] = true
|
@@ -117,9 +116,6 @@ class Morpheus::Cli::InvoicesCommand
|
|
117
116
|
options[:tags][k] << (v || '')
|
118
117
|
end
|
119
118
|
end
|
120
|
-
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
121
|
-
options[:show_raw_data] = true
|
122
|
-
end
|
123
119
|
opts.on('--totals', "View total costs and prices for all the invoices found.") do |val|
|
124
120
|
params['includeTotals'] = true
|
125
121
|
options[:show_invoice_totals] = true
|
@@ -144,36 +140,35 @@ class Morpheus::Cli::InvoicesCommand
|
|
144
140
|
# construct params
|
145
141
|
params.merge!(parse_list_options(options))
|
146
142
|
if options[:clouds]
|
147
|
-
cloud_ids = parse_cloud_id_list(options[:clouds])
|
143
|
+
cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
|
148
144
|
return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
|
149
145
|
params['zoneId'] = cloud_ids
|
150
146
|
end
|
151
147
|
if options[:groups]
|
152
|
-
group_ids = parse_group_id_list(options[:groups])
|
148
|
+
group_ids = parse_group_id_list(options[:groups], {}, false, true)
|
153
149
|
return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
|
154
150
|
params['siteId'] = group_ids
|
155
151
|
end
|
156
152
|
if options[:instances]
|
157
|
-
instance_ids = parse_instance_id_list(options[:instances])
|
153
|
+
instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
|
158
154
|
return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
|
159
155
|
params['instanceId'] = instance_ids
|
160
156
|
end
|
161
157
|
if options[:servers]
|
162
|
-
server_ids = parse_server_id_list(options[:servers])
|
158
|
+
server_ids = parse_server_id_list(options[:servers], {}, false, true)
|
163
159
|
return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
|
164
160
|
params['serverId'] = server_ids
|
165
161
|
end
|
166
162
|
if options[:users]
|
167
|
-
user_ids = parse_user_id_list(options[:users])
|
163
|
+
user_ids = parse_user_id_list(options[:users], {}, false, true)
|
168
164
|
return 1, "users not found for #{options[:users]}" if user_ids.nil?
|
169
165
|
params['userId'] = user_ids
|
170
166
|
end
|
171
167
|
if options[:projects]
|
172
|
-
project_ids = parse_project_id_list(options[:projects])
|
168
|
+
project_ids = parse_project_id_list(options[:projects], {}, false, true)
|
173
169
|
return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
|
174
170
|
params['projectId'] = project_ids
|
175
171
|
end
|
176
|
-
params['rawData'] = true if options[:show_raw_data]
|
177
172
|
params['refId'] = ref_ids unless ref_ids.empty?
|
178
173
|
if options[:tags] && !options[:tags].empty?
|
179
174
|
options[:tags].each do |k,v|
|
@@ -271,7 +266,7 @@ class Morpheus::Cli::InvoicesCommand
|
|
271
266
|
columns += [
|
272
267
|
{"ESTIMATE" => lambda {|it| format_boolean(it['estimate']) } },
|
273
268
|
{"ACTIVE" => lambda {|it| format_boolean(it['active']) } },
|
274
|
-
{"ITEMS" => lambda {|it| it['lineItems'].size rescue '' } },
|
269
|
+
{"ITEMS" => lambda {|it| (it['lineItemCount'] ? it['lineItemCount'] : it['lineItems'].size) rescue '' } },
|
275
270
|
{"TAGS" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
|
276
271
|
]
|
277
272
|
if show_projects
|
@@ -291,9 +286,6 @@ class Morpheus::Cli::InvoicesCommand
|
|
291
286
|
{"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
|
292
287
|
{"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
|
293
288
|
]
|
294
|
-
if options[:show_raw_data]
|
295
|
-
columns += [{"RAW DATA" => lambda {|it| truncate_string(it['rawData'].to_s, 10) } }]
|
296
|
-
end
|
297
289
|
unless options[:totals_only]
|
298
290
|
print as_pretty_table(invoices, columns, options)
|
299
291
|
print_results_pagination(json_response, {:label => "invoice", :n_label => "invoices"})
|
@@ -361,7 +353,6 @@ class Morpheus::Cli::InvoicesCommand
|
|
361
353
|
options[:show_estimates] = true
|
362
354
|
# options[:show_costs] = true
|
363
355
|
options[:show_prices] = true
|
364
|
-
# options[:show_raw_data] = true
|
365
356
|
options[:max_line_items] = 10000
|
366
357
|
end
|
367
358
|
opts.on('--prices', '--prices', "Display prices: Total, Compute, Storage, Network, Extra" ) do
|
@@ -370,13 +361,6 @@ class Morpheus::Cli::InvoicesCommand
|
|
370
361
|
opts.on('--estimates', '--estimates', "Display all estimated costs, from usage info: Compute, Storage, Network, Extra" ) do
|
371
362
|
options[:show_estimates] = true
|
372
363
|
end
|
373
|
-
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
374
|
-
options[:show_raw_data] = true
|
375
|
-
end
|
376
|
-
opts.on('--pretty-raw-data', '--raw-data', "Display Raw Data that is a bit more pretty") do |val|
|
377
|
-
options[:show_raw_data] = true
|
378
|
-
options[:pretty_json] = true
|
379
|
-
end
|
380
364
|
opts.on('--no-line-items', '--no-line-items', "Do not display line items.") do |val|
|
381
365
|
options[:hide_line_items] = true
|
382
366
|
end
|
@@ -401,9 +385,6 @@ EOT
|
|
401
385
|
|
402
386
|
def _get(id, options)
|
403
387
|
params = {}
|
404
|
-
if options[:show_raw_data]
|
405
|
-
params['rawData'] = true
|
406
|
-
end
|
407
388
|
begin
|
408
389
|
@invoices_interface.setopts(options)
|
409
390
|
if options[:dry_run]
|
@@ -412,6 +393,9 @@ EOT
|
|
412
393
|
end
|
413
394
|
json_response = @invoices_interface.get(id, params)
|
414
395
|
invoice = json_response['invoice']
|
396
|
+
if options[:hide_line_items]
|
397
|
+
json_response['invoice'].delete('lineItems') rescue nil
|
398
|
+
end
|
415
399
|
render_result = render_with_format(json_response, options, 'invoice')
|
416
400
|
return 0 if render_result
|
417
401
|
|
@@ -437,7 +421,7 @@ EOT
|
|
437
421
|
"End" => lambda {|it| format_date(it['endDate']) },
|
438
422
|
"Ref Start" => lambda {|it| format_dt(it['refStart']) },
|
439
423
|
"Ref End" => lambda {|it| format_dt(it['refEnd']) },
|
440
|
-
"Items" => lambda {|it| it['lineItems'].size rescue '' },
|
424
|
+
"Items" => lambda {|it| (it['lineItemCount'] ? it['lineItemCount'] : it['lineItems'].size) rescue '' },
|
441
425
|
"Tags" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
442
426
|
"Project ID" => lambda {|it| it['project'] ? it['project']['id'] : '' },
|
443
427
|
"Project Name" => lambda {|it| it['project'] ? it['project']['name'] : '' },
|
@@ -523,9 +507,6 @@ EOT
|
|
523
507
|
{"CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
|
524
508
|
{"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } }
|
525
509
|
]
|
526
|
-
if options[:show_raw_data]
|
527
|
-
line_items_columns += [{"RAW DATA" => lambda {|it| truncate_string(it['rawData'].to_s, 10) } }]
|
528
|
-
end
|
529
510
|
print_h2 "Line Items"
|
530
511
|
#max_line_items = options[:max_line_items] ? options[:max_line_items].to_i : 5
|
531
512
|
paged_line_items = line_items #.first(max_line_items)
|
@@ -578,10 +559,7 @@ EOT
|
|
578
559
|
end
|
579
560
|
print as_pretty_table(cost_rows, cost_columns, options)
|
580
561
|
|
581
|
-
|
582
|
-
print_h2 "Raw Data"
|
583
|
-
puts as_json(invoice['rawData'], {pretty_json:false}.merge(options))
|
584
|
-
end
|
562
|
+
|
585
563
|
|
586
564
|
print reset,"\n"
|
587
565
|
return 0
|
@@ -591,42 +569,87 @@ EOT
|
|
591
569
|
end
|
592
570
|
end
|
593
571
|
|
594
|
-
def
|
572
|
+
def update(args)
|
595
573
|
options = {}
|
596
574
|
params = {}
|
597
575
|
payload = {}
|
598
576
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
599
|
-
opts.banner = subcommand_usage("[
|
600
|
-
opts.on(
|
601
|
-
|
577
|
+
opts.banner = subcommand_usage("[invoice] [options]")
|
578
|
+
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
579
|
+
options[:tags] = val
|
602
580
|
end
|
603
|
-
opts.on(
|
604
|
-
|
581
|
+
opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
|
582
|
+
options[:add_tags] = val
|
605
583
|
end
|
606
|
-
opts.on(
|
607
|
-
|
584
|
+
opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
|
585
|
+
options[:remove_tags] = val
|
608
586
|
end
|
609
|
-
opts
|
610
|
-
|
587
|
+
build_standard_update_options(opts, options)
|
588
|
+
opts.footer = <<-EOT
|
589
|
+
Update an invoice.
|
590
|
+
[invoice] is required. This is the id of an invoice.
|
591
|
+
EOT
|
592
|
+
end
|
593
|
+
optparse.parse!(args)
|
594
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
595
|
+
connect(options)
|
596
|
+
json_response = @invoices_interface.get(args[0])
|
597
|
+
invoice = json_response['invoice']
|
598
|
+
|
599
|
+
invoice_payload = parse_passed_options(options)
|
600
|
+
if options[:tags]
|
601
|
+
invoice_payload['tags'] = parse_metadata(options[:tags])
|
602
|
+
end
|
603
|
+
if options[:add_tags]
|
604
|
+
invoice_payload['addTags'] = parse_metadata(options[:add_tags])
|
605
|
+
end
|
606
|
+
if options[:remove_tags]
|
607
|
+
invoice_payload['removeTags'] = parse_metadata(options[:remove_tags])
|
608
|
+
end
|
609
|
+
|
610
|
+
payload = {}
|
611
|
+
if options[:payload]
|
612
|
+
payload = options[:payload]
|
613
|
+
payload.deep_merge!({'invoice' => invoice_payload})
|
614
|
+
else
|
615
|
+
payload.deep_merge!({'invoice' => invoice_payload})
|
616
|
+
if invoice_payload.empty?
|
617
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
611
618
|
end
|
612
|
-
|
619
|
+
end
|
620
|
+
@invoices_interface.setopts(options)
|
621
|
+
if options[:dry_run]
|
622
|
+
print_dry_run @invoices_interface.dry.update(invoice['id'], payload)
|
623
|
+
return
|
624
|
+
end
|
625
|
+
json_response = @invoices_interface.update(invoice['id'], payload)
|
626
|
+
invoice = json_response['invoice']
|
627
|
+
render_response(json_response, options, 'invoice') do
|
628
|
+
print_green_success "Updated invoice #{invoice['id']}"
|
629
|
+
return _get(invoice["id"], options)
|
630
|
+
end
|
631
|
+
return 0, nil
|
632
|
+
end
|
633
|
+
|
634
|
+
def refresh(args)
|
635
|
+
options = {}
|
636
|
+
params = {}
|
637
|
+
payload = {}
|
638
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
639
|
+
opts.banner = subcommand_usage("[-c CLOUD]")
|
640
|
+
opts.on( '-c', '--clouds CLOUD', "Specify clouds to refresh costing for." ) do |val|
|
613
641
|
payload[:clouds] ||= []
|
614
642
|
payload[:clouds] << val
|
615
643
|
end
|
616
|
-
opts.on( '--all', "Refresh costing for all clouds." ) do
|
644
|
+
opts.on( '--all', "Refresh costing for all clouds. This can be used instead of --clouds" ) do
|
617
645
|
payload[:all] = true
|
618
646
|
end
|
619
|
-
|
620
|
-
|
621
|
-
|
647
|
+
opts.on( '--date DATE', String, "Date to collect costing for. By default the cost data is collected for the end of the previous job interval (hour or day)." ) do |val|
|
648
|
+
payload[:date] = val.to_s
|
649
|
+
end
|
622
650
|
build_standard_update_options(opts, options, [:query, :auto_confirm])
|
623
651
|
opts.footer = <<-EOT
|
624
|
-
Refresh
|
625
|
-
By default, nothing is changed.
|
626
|
-
Include --daily to regenerate invoice records.
|
627
|
-
Include --costing to refresh actual costing data.
|
628
|
-
Include --current to refresh costing data for the actual current time.
|
629
|
-
To get the latest invoice costing data, include --daily --costing --current --all
|
652
|
+
Refresh invoice costing data for the specified clouds.
|
630
653
|
EOT
|
631
654
|
end
|
632
655
|
optparse.parse!(args)
|
@@ -637,17 +660,11 @@ EOT
|
|
637
660
|
payload = options[:payload]
|
638
661
|
end
|
639
662
|
payload.deep_merge!(parse_passed_options(options))
|
640
|
-
# --clouds
|
663
|
+
# --clouds lookup ID for name
|
641
664
|
if payload[:clouds]
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
else
|
646
|
-
cloud = find_cloud_option(cloud_id)
|
647
|
-
return 1 if cloud.nil?
|
648
|
-
cloud['id']
|
649
|
-
end
|
650
|
-
}
|
665
|
+
cloud_ids = parse_cloud_id_list(payload[:clouds], {}, false, true)
|
666
|
+
return 1, "clouds not found for #{payload[:clouds]}" if cloud_ids.nil?
|
667
|
+
payload[:clouds] = cloud_ids
|
651
668
|
end
|
652
669
|
# are you sure?
|
653
670
|
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to refresh invoices?")
|
@@ -678,7 +695,6 @@ EOT
|
|
678
695
|
options[:show_actual_costs] = true
|
679
696
|
options[:show_costs] = true
|
680
697
|
options[:show_prices] = true
|
681
|
-
# options[:show_raw_data] = true
|
682
698
|
end
|
683
699
|
# opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Storage, Network, Extra" ) do
|
684
700
|
# options[:show_actual_costs] = true
|
@@ -767,9 +783,6 @@ EOT
|
|
767
783
|
options[:tags][k] << (v || '')
|
768
784
|
end
|
769
785
|
end
|
770
|
-
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
771
|
-
options[:show_raw_data] = true
|
772
|
-
end
|
773
786
|
opts.on('--totals', "View total costs and prices for all the invoices found.") do |val|
|
774
787
|
params['includeTotals'] = true
|
775
788
|
options[:show_invoice_totals] = true
|
@@ -795,36 +808,35 @@ EOT
|
|
795
808
|
# construct params
|
796
809
|
params.merge!(parse_list_options(options))
|
797
810
|
if options[:clouds]
|
798
|
-
cloud_ids = parse_cloud_id_list(options[:clouds])
|
811
|
+
cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
|
799
812
|
return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
|
800
813
|
params['zoneId'] = cloud_ids
|
801
814
|
end
|
802
815
|
if options[:groups]
|
803
|
-
group_ids = parse_group_id_list(options[:groups])
|
816
|
+
group_ids = parse_group_id_list(options[:groups], {}, false, true)
|
804
817
|
return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
|
805
818
|
params['siteId'] = group_ids
|
806
819
|
end
|
807
820
|
if options[:instances]
|
808
|
-
instance_ids = parse_instance_id_list(options[:instances])
|
821
|
+
instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
|
809
822
|
return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
|
810
823
|
params['instanceId'] = instance_ids
|
811
824
|
end
|
812
825
|
if options[:servers]
|
813
|
-
server_ids = parse_server_id_list(options[:servers])
|
826
|
+
server_ids = parse_server_id_list(options[:servers], {}, false, true)
|
814
827
|
return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
|
815
828
|
params['serverId'] = server_ids
|
816
829
|
end
|
817
830
|
if options[:users]
|
818
|
-
user_ids = parse_user_id_list(options[:users])
|
831
|
+
user_ids = parse_user_id_list(options[:users], {}, false, true)
|
819
832
|
return 1, "users not found for #{options[:users]}" if user_ids.nil?
|
820
833
|
params['userId'] = user_ids
|
821
834
|
end
|
822
835
|
if options[:projects]
|
823
|
-
project_ids = parse_project_id_list(options[:projects])
|
836
|
+
project_ids = parse_project_id_list(options[:projects], {}, false, true)
|
824
837
|
return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
|
825
838
|
params['projectId'] = project_ids
|
826
839
|
end
|
827
|
-
params['rawData'] = true if options[:show_raw_data]
|
828
840
|
params['refId'] = ref_ids unless ref_ids.empty?
|
829
841
|
if options[:tags] && !options[:tags].empty?
|
830
842
|
options[:tags].each do |k,v|
|
@@ -882,9 +894,6 @@ EOT
|
|
882
894
|
"UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
883
895
|
]
|
884
896
|
|
885
|
-
if options[:show_raw_data]
|
886
|
-
columns += [{"RAW DATA" => lambda {|it| truncate_string(it['rawData'].to_s, 10) } }]
|
887
|
-
end
|
888
897
|
# if options[:show_invoice_totals]
|
889
898
|
# line_item_totals = json_response['lineItemTotals']
|
890
899
|
# if line_item_totals
|
@@ -933,13 +942,6 @@ EOT
|
|
933
942
|
options = {}
|
934
943
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
935
944
|
opts.banner = subcommand_usage("[id]")
|
936
|
-
opts.on('--raw-data', '--raw-data', "Display Raw Data, the cost data from the cloud provider's API.") do |val|
|
937
|
-
options[:show_raw_data] = true
|
938
|
-
end
|
939
|
-
opts.on('--pretty-raw-data', '--raw-data', "Display Raw Data that is a bit more pretty") do |val|
|
940
|
-
options[:show_raw_data] = true
|
941
|
-
options[:pretty_json] = true
|
942
|
-
end
|
943
945
|
opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 2. eg. $3.50") do |val|
|
944
946
|
options[:sigdig] = val.to_i
|
945
947
|
end
|
@@ -961,9 +963,6 @@ EOT
|
|
961
963
|
|
962
964
|
def _get_line_item(id, options)
|
963
965
|
params = {}
|
964
|
-
if options[:show_raw_data]
|
965
|
-
params['rawData'] = true
|
966
|
-
end
|
967
966
|
@invoice_line_items_interface.setopts(options)
|
968
967
|
if options[:dry_run]
|
969
968
|
print_dry_run @invoice_line_items_interface.dry.get(id, params)
|
@@ -1001,11 +1000,6 @@ EOT
|
|
1001
1000
|
}
|
1002
1001
|
print_description_list(description_cols, line_item, options)
|
1003
1002
|
|
1004
|
-
if options[:show_raw_data]
|
1005
|
-
print_h2 "Raw Data"
|
1006
|
-
puts as_json(line_item['rawData'], {pretty_json:false}.merge(options))
|
1007
|
-
end
|
1008
|
-
|
1009
1003
|
print reset,"\n"
|
1010
1004
|
end
|
1011
1005
|
return 0, nil
|