morpheus-cli 5.2.1 → 5.3.0
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 +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
|