morpheus-cli 5.4.5.1 → 5.5.1.1
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/lib/morpheus/api/api_client.rb +12 -0
- data/lib/morpheus/api/backup_service_types_interface.rb +9 -0
- data/lib/morpheus/api/backup_services_interface.rb +9 -0
- data/lib/morpheus/api/clusters_interface.rb +12 -0
- data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
- data/lib/morpheus/api/prices_interface.rb +6 -0
- data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
- data/lib/morpheus/cli/cli_command.rb +55 -23
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/backup_services_command.rb +44 -0
- data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
- data/lib/morpheus/cli/commands/clouds.rb +67 -31
- data/lib/morpheus/cli/commands/clusters.rb +66 -5
- data/lib/morpheus/cli/commands/cypher_command.rb +22 -23
- data/lib/morpheus/cli/commands/hosts.rb +5 -1
- data/lib/morpheus/cli/commands/instances.rb +11 -11
- data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
- data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
- data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
- data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
- data/lib/morpheus/cli/commands/library_option_lists_command.rb +18 -8
- data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
- data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
- data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
- data/lib/morpheus/cli/commands/prices_command.rb +25 -11
- data/lib/morpheus/cli/commands/roles.rb +475 -70
- data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
- data/lib/morpheus/cli/commands/tasks.rb +64 -22
- data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
- data/lib/morpheus/cli/commands/users.rb +10 -10
- data/lib/morpheus/cli/commands/view.rb +1 -0
- data/lib/morpheus/cli/commands/workflows.rb +21 -14
- data/lib/morpheus/cli/error_handler.rb +13 -4
- data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
- data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -3
- data/lib/morpheus/cli/mixins/rest_command.rb +58 -15
- data/lib/morpheus/cli/option_types.rb +69 -13
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/logging.rb +6 -8
- data/lib/morpheus/routes.rb +3 -5
- metadata +9 -4
@@ -10,6 +10,7 @@ class Morpheus::Cli::Clusters
|
|
10
10
|
register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
|
11
11
|
register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
|
12
12
|
register_subcommands :list_masters
|
13
|
+
register_subcommands :upgrade_cluster
|
13
14
|
register_subcommands :list_volumes, :remove_volume
|
14
15
|
register_subcommands :list_namespaces, :get_namespace, :add_namespace, :update_namespace, :remove_namespace
|
15
16
|
register_subcommands :list_containers, :remove_container, :restart_container
|
@@ -69,7 +70,6 @@ class Morpheus::Cli::Clusters
|
|
69
70
|
return
|
70
71
|
end
|
71
72
|
json_response = @clusters_interface.list(params)
|
72
|
-
|
73
73
|
render_result = render_with_format(json_response, options, 'clusters')
|
74
74
|
return 0 if render_result
|
75
75
|
|
@@ -859,7 +859,11 @@ class Morpheus::Cli::Clusters
|
|
859
859
|
print JSON.pretty_generate(json_response)
|
860
860
|
print "\n"
|
861
861
|
elsif !options[:quiet]
|
862
|
-
|
862
|
+
msg = "Cluster #{cluster['name']} is being removed..."
|
863
|
+
if json_response['msg'] != nil && json_response['msg'] != ''
|
864
|
+
msg = json_response['msg']
|
865
|
+
end
|
866
|
+
print_green_success msg
|
863
867
|
#list([])
|
864
868
|
end
|
865
869
|
rescue RestClient::Exception => e
|
@@ -1324,7 +1328,11 @@ class Morpheus::Cli::Clusters
|
|
1324
1328
|
if options[:json]
|
1325
1329
|
puts as_json(json_response)
|
1326
1330
|
elsif json_response['success']
|
1327
|
-
|
1331
|
+
if json_response['msg'] == nil
|
1332
|
+
print_green_success "Added worker to cluster #{cluster['name']}"
|
1333
|
+
else
|
1334
|
+
print_green_success json_response['msg']
|
1335
|
+
end
|
1328
1336
|
#get_args = [json_response["cluster"]["id"]] + (options[:remote] ? ["-r",options[:remote]] : [])
|
1329
1337
|
#get(get_args)
|
1330
1338
|
end
|
@@ -1377,7 +1385,11 @@ class Morpheus::Cli::Clusters
|
|
1377
1385
|
end
|
1378
1386
|
json_response = @clusters_interface.destroy_worker(cluster['id'], worker['id'], params)
|
1379
1387
|
render_response(json_response, options) do
|
1380
|
-
|
1388
|
+
msg = "Worker #{worker['name']} is being removed from cluster #{cluster['name']}..."
|
1389
|
+
if json_response['msg']
|
1390
|
+
msg = json_response['msg']
|
1391
|
+
end
|
1392
|
+
print_green_success msg
|
1381
1393
|
end
|
1382
1394
|
return 0, nil
|
1383
1395
|
end
|
@@ -1518,6 +1530,45 @@ class Morpheus::Cli::Clusters
|
|
1518
1530
|
end
|
1519
1531
|
end
|
1520
1532
|
|
1533
|
+
def upgrade_cluster(args)
|
1534
|
+
params = {}
|
1535
|
+
options = {}
|
1536
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1537
|
+
opts.banner = subcommand_usage("[cluster]")
|
1538
|
+
build_standard_update_options(opts, options)
|
1539
|
+
opts.footer = "Updates kubernetes version (kubectl and kubeadm) of the specified cluster.\n" +
|
1540
|
+
"[cluster] is required. This is the name or id of an existing cluster.\n"
|
1541
|
+
end
|
1542
|
+
optparse.parse!(args)
|
1543
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
1544
|
+
connect(options)
|
1545
|
+
|
1546
|
+
cluster = find_cluster_by_name_or_id(args[0])
|
1547
|
+
return 1 if cluster.nil?
|
1548
|
+
|
1549
|
+
version_options = get_valid_upgrade_versions(cluster['id'])
|
1550
|
+
version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'targetVersion', 'type' => 'select', 'fieldLabel' => 'To Version', 'selectOptions' => version_options, 'required' => true, 'description' => 'Select target version.' }],options[:options],api_client,{})
|
1551
|
+
target_version = version_options.detect{ |element| element['value'] == version_prompt['targetVersion'] }['name']
|
1552
|
+
|
1553
|
+
payload = {}
|
1554
|
+
if options[:payload]
|
1555
|
+
payload = options[:payload]
|
1556
|
+
payload.deep_merge!({'targetVersion' => target_version})
|
1557
|
+
else
|
1558
|
+
payload.deep_merge!({'targetVersion' => target_version})
|
1559
|
+
end
|
1560
|
+
@clusters_interface.setopts(options)
|
1561
|
+
if options[:dry_run]
|
1562
|
+
print_dry_run @clusters_interface.dry.do_cluster_upgrade(cluster['id'], payload)
|
1563
|
+
return
|
1564
|
+
end
|
1565
|
+
json_response = @clusters_interface.do_cluster_upgrade(cluster['id'], payload)
|
1566
|
+
render_response(json_response, options) do
|
1567
|
+
print_green_success "Cluster #{cluster['name']} is being upgraded to #{target_version}..."
|
1568
|
+
end
|
1569
|
+
return 0, nil
|
1570
|
+
end
|
1571
|
+
|
1521
1572
|
def list_volumes(args)
|
1522
1573
|
options = {}
|
1523
1574
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
@@ -3573,6 +3624,7 @@ class Morpheus::Cli::Clusters
|
|
3573
3624
|
rows = clusters.collect do |cluster|
|
3574
3625
|
{
|
3575
3626
|
id: cluster['id'],
|
3627
|
+
display_name: cluster['displayName'],
|
3576
3628
|
name: cluster['name'],
|
3577
3629
|
type: (cluster['type']['name'] rescue ''),
|
3578
3630
|
layout: (cluster['layout']['name'] rescue ''),
|
@@ -3582,7 +3634,7 @@ class Morpheus::Cli::Clusters
|
|
3582
3634
|
}
|
3583
3635
|
end
|
3584
3636
|
columns = [
|
3585
|
-
:id, :name, :type, :layout, :workers, :cloud, :status
|
3637
|
+
:id, :name, :display_name, :type, :layout, :workers, :cloud, :status
|
3586
3638
|
]
|
3587
3639
|
print as_pretty_table(rows, columns, opts)
|
3588
3640
|
end
|
@@ -4107,6 +4159,15 @@ class Morpheus::Cli::Clusters
|
|
4107
4159
|
rtn
|
4108
4160
|
end
|
4109
4161
|
|
4162
|
+
def get_valid_upgrade_versions(cluster_id)
|
4163
|
+
result = @clusters_interface.get_upgrade_versions(cluster_id, {})
|
4164
|
+
rtn = []
|
4165
|
+
if result['versions']
|
4166
|
+
rtn = result['versions'].map.with_index {|value, idx| {'name' => value,'value' => idx}}
|
4167
|
+
end
|
4168
|
+
rtn
|
4169
|
+
end
|
4170
|
+
|
4110
4171
|
def update_wiki_page_option_types
|
4111
4172
|
[
|
4112
4173
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1, 'description' => 'The name of the wiki page for this instance. Default is the instance name.'},
|
@@ -185,30 +185,29 @@ class Morpheus::Cli::CypherCommand
|
|
185
185
|
# This response does contain cypher too though.
|
186
186
|
|
187
187
|
if cypher_item.empty?
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
188
|
+
puts "Cypher item not found in response"
|
189
|
+
else
|
190
|
+
description_cols = {
|
191
|
+
#"ID" => 'id',
|
192
|
+
"Key" => lambda {|it| it["itemKey"] },
|
193
|
+
"TTL" => lambda {|it|
|
194
|
+
format_expiration_ttl(it["expireDate"])
|
195
|
+
},
|
196
|
+
# "Type" => lambda {|it|
|
197
|
+
# data_type
|
198
|
+
# },
|
199
|
+
"Expiration" => lambda {|it|
|
200
|
+
format_expiration_date(it["expireDate"])
|
201
|
+
},
|
202
|
+
# "Date Created" => lambda {|it| format_local_dt(it["dateCreated"]) },
|
203
|
+
"Last Updated" => lambda {|it| format_local_dt(it["lastUpdated"]) },
|
204
|
+
"Last Accessed" => lambda {|it| format_local_dt(it["lastAccessed"]) }
|
205
|
+
}
|
206
|
+
if cypher_item["expireDate"].nil?
|
207
|
+
description_cols.delete("Expires")
|
208
|
+
end
|
209
|
+
print_description_list(description_cols, cypher_item)
|
209
210
|
end
|
210
|
-
print_description_list(description_cols, cypher_item)
|
211
|
-
|
212
211
|
# print_h2 "Value", options
|
213
212
|
# print_h2 "Data", options
|
214
213
|
print_h2 "Data (#{data_type})", options
|
@@ -1118,7 +1118,11 @@ class Morpheus::Cli::Hosts
|
|
1118
1118
|
print JSON.pretty_generate(json_response)
|
1119
1119
|
print "\n"
|
1120
1120
|
elsif !options[:quiet]
|
1121
|
-
|
1121
|
+
if json_response['deleteApprovalRequired'] == true
|
1122
|
+
print_green_success "Delete Request created for Host #{server['name']}"
|
1123
|
+
else
|
1124
|
+
print_green_success "Host #{server['name']} is being removed..."
|
1125
|
+
end
|
1122
1126
|
#list([])
|
1123
1127
|
end
|
1124
1128
|
rescue RestClient::Exception => e
|
@@ -496,15 +496,15 @@ class Morpheus::Cli::Instances
|
|
496
496
|
payload["zoneId"] = cloud["id"]
|
497
497
|
payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
|
498
498
|
end
|
499
|
-
if options[:cloud]
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
end
|
499
|
+
# if options[:cloud]
|
500
|
+
# group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
|
501
|
+
# cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
|
502
|
+
# if cloud.nil?
|
503
|
+
# return 1, "cloud not found by #{options[:cloud]}"
|
504
|
+
# end
|
505
|
+
# payload["zoneId"] = cloud["id"]
|
506
|
+
# payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
|
507
|
+
# end
|
508
508
|
if options[:instance_type_code]
|
509
509
|
# should just use find_instance_type_by_name_or_id
|
510
510
|
# note that the api actually will match name name or code
|
@@ -539,7 +539,7 @@ class Morpheus::Cli::Instances
|
|
539
539
|
end
|
540
540
|
end
|
541
541
|
end
|
542
|
-
|
542
|
+
|
543
543
|
payload['instance'] ||= {}
|
544
544
|
if options[:instance_name]
|
545
545
|
payload['instance']['name'] = options[:instance_name]
|
@@ -4607,7 +4607,7 @@ EOT
|
|
4607
4607
|
end
|
4608
4608
|
|
4609
4609
|
def apply(args)
|
4610
|
-
default_refresh_interval =
|
4610
|
+
default_refresh_interval = 10
|
4611
4611
|
params, payload, options = {}, {}, {}
|
4612
4612
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
4613
4613
|
opts.banner = subcommand_usage("[instance] [options]")
|
@@ -275,7 +275,7 @@ EOT
|
|
275
275
|
opt['fieldContext'] = nil
|
276
276
|
end
|
277
277
|
end
|
278
|
-
config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, options[:params])
|
278
|
+
config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, options[:params], false, true)
|
279
279
|
config_prompt.deep_compact!
|
280
280
|
params.deep_merge!(config_prompt)
|
281
281
|
end
|
@@ -627,6 +627,12 @@ Update an invoice.
|
|
627
627
|
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|
|
628
628
|
payload[:date] = val.to_s
|
629
629
|
end
|
630
|
+
opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. This is an alias for the --date option." ) do |val|
|
631
|
+
payload[:date] = val.to_s
|
632
|
+
end
|
633
|
+
opts.on( '--rebuild', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
|
634
|
+
query_params[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
635
|
+
end
|
630
636
|
build_standard_update_options(opts, options, [:query, :auto_confirm])
|
631
637
|
opts.footer = <<-EOT
|
632
638
|
Refresh invoice costing data for the specified clouds.
|
@@ -674,6 +680,7 @@ EOT
|
|
674
680
|
opts.on('-a', '--all', "Display all details, costs and prices." ) do
|
675
681
|
options[:show_actual_costs] = true
|
676
682
|
options[:show_costs] = true
|
683
|
+
options[:details] = true
|
677
684
|
end
|
678
685
|
# opts.on('--actuals', '--actuals', "Display all actual costs: Compute, Memory, Storage, Network, Extra" ) do
|
679
686
|
# options[:show_actual_costs] = true
|
@@ -861,7 +868,7 @@ EOT
|
|
861
868
|
{"COST" => lambda {|it| format_money(it['itemCost'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
|
862
869
|
{"TAX" => lambda {|it| format_money(it['itemTax'], it['currency'] || 'USD', {sigdig:options[:sigdig]}) } },
|
863
870
|
] : []) + [
|
864
|
-
{"ITEM ID" => lambda {|it| truncate_string_right(it['itemId'], 65) } },
|
871
|
+
{"ITEM ID" => lambda {|it| options[:details] ? it['itemId'] : truncate_string_right(it['itemId'], 65) } },
|
865
872
|
{"ITEM NAME" => lambda {|it| it['itemName'] } },
|
866
873
|
{"ITEM TYPE" => lambda {|it| it['itemType'] } },
|
867
874
|
{"ITEM DESCRIPTION" => lambda {|it| it['itemDescription'] } },
|
@@ -2,6 +2,7 @@ require 'morpheus/cli/cli_command'
|
|
2
2
|
|
3
3
|
class Morpheus::Cli::JobsCommand
|
4
4
|
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::JobsHelper
|
5
6
|
include Morpheus::Cli::AccountsHelper
|
6
7
|
|
7
8
|
set_command_name :'jobs'
|
@@ -90,7 +91,7 @@ class Morpheus::Cli::JobsCommand
|
|
90
91
|
# "Last Updated" => lambda {|job| format_local_dt(job['lastUpdated']) },
|
91
92
|
"Last Run" => lambda {|job| format_local_dt(job['lastRun']) },
|
92
93
|
"Next Run" => lambda {|job| job['enabled'] && job['scheduleMode'] && job['scheduleMode'] != 'manual' ? format_local_dt(job['nextFire']) : '' },
|
93
|
-
"Last Result" => lambda {|job|
|
94
|
+
"Last Result" => lambda {|job| format_job_status(job['lastResult']) },
|
94
95
|
}
|
95
96
|
print as_pretty_table(jobs, columns.upcase_keys!, options)
|
96
97
|
print_results_pagination(json_response)
|
@@ -124,7 +125,7 @@ class Morpheus::Cli::JobsCommand
|
|
124
125
|
options = {}
|
125
126
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
126
127
|
opts.banner = subcommand_usage("[job] [max-exec-count]")
|
127
|
-
|
128
|
+
build_standard_get_options(opts, options)
|
128
129
|
opts.footer = "Get details about a job.\n" +
|
129
130
|
"[job] is required. Job ID or name.\n" +
|
130
131
|
"[max-exec-count] is optional. Specified max # of most recent executions. Defaults is 3"
|
@@ -274,17 +275,13 @@ class Morpheus::Cli::JobsCommand
|
|
274
275
|
options[:schedule] = 'dateTime'
|
275
276
|
params['dateTime'] = val.to_s
|
276
277
|
end
|
277
|
-
|
278
|
+
build_standard_add_options(opts, options)
|
278
279
|
opts.footer = "Create job."
|
279
280
|
end
|
280
281
|
optparse.parse!(args)
|
281
282
|
connect(options)
|
282
|
-
|
283
|
-
raise_command_error "wrong number of arguments, expected 0 or 1 and got (#{args.count}) #{args}\n#{optparse}"
|
284
|
-
return 1
|
285
|
-
end
|
283
|
+
verify_args!(args:args, optparse:optparse, max:1)
|
286
284
|
|
287
|
-
begin
|
288
285
|
if options[:payload]
|
289
286
|
payload = parse_payload(options, 'job')
|
290
287
|
else
|
@@ -425,22 +422,10 @@ class Morpheus::Cli::JobsCommand
|
|
425
422
|
return
|
426
423
|
end
|
427
424
|
json_response = @jobs_interface.create(payload)
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
elsif !options[:quiet]
|
432
|
-
if json_response['success']
|
433
|
-
print_green_success "Job created"
|
434
|
-
_get(json_response['id'], 0, options)
|
435
|
-
else
|
436
|
-
print_red_alert "Error creating job: #{json_response['msg'] || json_response['errors']}"
|
437
|
-
end
|
425
|
+
render_response(json_response, options, 'job') do
|
426
|
+
print_green_success "Job created"
|
427
|
+
_get(json_response['id'], 0, options)
|
438
428
|
end
|
439
|
-
return 0
|
440
|
-
rescue RestClient::Exception => e
|
441
|
-
print_rest_exception(e, options)
|
442
|
-
exit 1
|
443
|
-
end
|
444
429
|
end
|
445
430
|
|
446
431
|
def update(args)
|
@@ -492,18 +477,14 @@ class Morpheus::Cli::JobsCommand
|
|
492
477
|
options[:schedule] = 'dateTime'
|
493
478
|
params['dateTime'] = val.to_s
|
494
479
|
end
|
495
|
-
|
480
|
+
build_standard_update_options(opts, options)
|
496
481
|
opts.footer = "Update job.\n" +
|
497
482
|
"[job] is required. Job ID or name"
|
498
483
|
end
|
499
484
|
optparse.parse!(args)
|
500
485
|
connect(options)
|
501
|
-
|
502
|
-
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
|
503
|
-
return 1
|
504
|
-
end
|
486
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
505
487
|
|
506
|
-
begin
|
507
488
|
job = find_by_name_or_id('job', args[0])
|
508
489
|
|
509
490
|
if job.nil?
|
@@ -609,22 +590,10 @@ class Morpheus::Cli::JobsCommand
|
|
609
590
|
return
|
610
591
|
end
|
611
592
|
json_response = @jobs_interface.update(job['id'], payload)
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
elsif !options[:quiet]
|
616
|
-
if json_response['success']
|
617
|
-
print_green_success "Job updated"
|
618
|
-
_get(job['id'], nil, options)
|
619
|
-
else
|
620
|
-
print_red_alert "Error updating job: #{json_response['msg'] || json_response['errors']}"
|
621
|
-
end
|
593
|
+
render_response(json_response, options, 'job') do
|
594
|
+
print_green_success "Job updated"
|
595
|
+
_get(job['id'], nil, options)
|
622
596
|
end
|
623
|
-
return 0
|
624
|
-
rescue RestClient::Exception => e
|
625
|
-
print_rest_exception(e, options)
|
626
|
-
exit 1
|
627
|
-
end
|
628
597
|
end
|
629
598
|
|
630
599
|
def execute(args)
|
@@ -684,48 +653,31 @@ class Morpheus::Cli::JobsCommand
|
|
684
653
|
params = {}
|
685
654
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
686
655
|
opts.banner = subcommand_usage( "[job]")
|
687
|
-
|
656
|
+
build_standard_remove_options(opts, options)
|
688
657
|
opts.footer = "Remove job.\n" +
|
689
658
|
"[job] is required. Job ID or name"
|
690
659
|
end
|
691
660
|
optparse.parse!(args)
|
692
661
|
connect(options)
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
begin
|
699
|
-
job = find_by_name_or_id('job', args[0])
|
700
|
-
|
701
|
-
if job.nil?
|
702
|
-
print_red_alert "Job #{args[0]} not found"
|
703
|
-
exit 1
|
704
|
-
end
|
705
|
-
|
706
|
-
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the job '#{job['name']}'?", options)
|
707
|
-
return 9, "aborted command"
|
708
|
-
end
|
709
|
-
|
710
|
-
@jobs_interface.setopts(options)
|
711
|
-
if options[:dry_run]
|
712
|
-
print_dry_run @jobs_interface.dry.destroy(job['id'], params)
|
713
|
-
return
|
714
|
-
end
|
715
|
-
|
716
|
-
json_response = @jobs_interface.destroy(job['id'], params)
|
717
|
-
|
718
|
-
if options[:json]
|
719
|
-
print JSON.pretty_generate(json_response)
|
720
|
-
print "\n"
|
721
|
-
elsif !options[:quiet]
|
722
|
-
print_green_success "Job #{job['name']} removed"
|
723
|
-
end
|
724
|
-
return 0
|
725
|
-
rescue RestClient::Exception => e
|
726
|
-
print_rest_exception(e, options)
|
662
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
663
|
+
job = find_by_name_or_id('job', args[0])
|
664
|
+
if job.nil?
|
665
|
+
print_red_alert "Job #{args[0]} not found"
|
727
666
|
exit 1
|
728
667
|
end
|
668
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the job '#{job['name']}'?", options)
|
669
|
+
return 9, "aborted command"
|
670
|
+
end
|
671
|
+
@jobs_interface.setopts(options)
|
672
|
+
if options[:dry_run]
|
673
|
+
print_dry_run @jobs_interface.dry.destroy(job['id'], params)
|
674
|
+
return
|
675
|
+
end
|
676
|
+
json_response = @jobs_interface.destroy(job['id'], params)
|
677
|
+
render_response(json_response, options) do
|
678
|
+
print_green_success "Job #{job['name']} removed"
|
679
|
+
end
|
680
|
+
return 0, nil
|
729
681
|
end
|
730
682
|
|
731
683
|
def list_executions(args)
|
@@ -739,7 +691,7 @@ class Morpheus::Cli::JobsCommand
|
|
739
691
|
opts.on("--internal [true|false]", String, "Filters executions based on internal flag. Internal executions are excluded by default.") do |val|
|
740
692
|
params["internalOnly"] = (val.to_s != "false")
|
741
693
|
end
|
742
|
-
build_standard_list_options(opts, options)
|
694
|
+
build_standard_list_options(opts, options, [:details])
|
743
695
|
opts.footer = "List job executions.\n" +
|
744
696
|
"[job] is optional. Job ID or name to filter executions."
|
745
697
|
|
@@ -792,10 +744,7 @@ class Morpheus::Cli::JobsCommand
|
|
792
744
|
params = {}
|
793
745
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
794
746
|
opts.banner = subcommand_usage("[id]")
|
795
|
-
opts
|
796
|
-
options[:details] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
797
|
-
end
|
798
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
747
|
+
build_standard_get_options(opts, options, [:details])
|
799
748
|
opts.footer = "Get details about a job.\n" +
|
800
749
|
"[id] is required. Job execution ID."
|
801
750
|
end
|
@@ -805,82 +754,17 @@ class Morpheus::Cli::JobsCommand
|
|
805
754
|
end
|
806
755
|
connect(options)
|
807
756
|
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
print_dry_run @jobs_interface.dry.get_execution(args[0], params)
|
813
|
-
return
|
814
|
-
end
|
815
|
-
json_response = @jobs_interface.get_execution(args[0], params)
|
816
|
-
|
817
|
-
render_result = render_with_format(json_response, options, 'jobExecution')
|
818
|
-
return 0 if render_result
|
819
|
-
|
820
|
-
title = "Morpheus Job Execution"
|
821
|
-
subtitles = []
|
822
|
-
subtitles += parse_list_subtitles(options)
|
823
|
-
print_h1 title, subtitles
|
824
|
-
|
825
|
-
exec = json_response['jobExecution']
|
826
|
-
process = exec['process']
|
827
|
-
print cyan
|
828
|
-
description_cols = {
|
829
|
-
"ID" => lambda {|it| it['id'] },
|
830
|
-
"Job" => lambda {|it| it['job'] ? it['job']['name'] : ''},
|
831
|
-
"Job Type" => lambda {|it| it['job'] && it['job']['type'] ? (it['job']['type']['code'] == 'morpheus.workflow' ? 'Workflow' : 'Task') : ''},
|
832
|
-
# "Description" => lambda {|it| it['description'] || (it['job'] ? it['job']['description'] : '') },
|
833
|
-
"Start Date" => lambda {|it| format_local_dt(it['startDate'])},
|
834
|
-
"ETA/Time" => lambda {|it| it['duration'] ? format_human_duration(it['duration'] / 1000.0) : ''},
|
835
|
-
"Status" => lambda {|it| format_status(it['status'])},
|
836
|
-
"Error" => lambda {|it| it['process'] && (it['process']['message'] || it['process']['error']) ? red + (it['process']['message'] || it['process']['error']) + cyan : ''},
|
837
|
-
"Created By" => lambda {|it| it['createdBy'].nil? ? '' : it['createdBy']['displayName'] || it['createdBy']['username']}
|
838
|
-
}
|
839
|
-
description_cols["Process ID"] = lambda {|it| process['id']} if !process.nil?
|
840
|
-
|
841
|
-
print_description_list(description_cols, exec)
|
842
|
-
|
843
|
-
if !process.nil?
|
844
|
-
if options[:details]
|
845
|
-
process_data = get_process_event_data(process)
|
846
|
-
print_h2 "Execution Details"
|
847
|
-
description_cols = {
|
848
|
-
"Process ID" => lambda {|it| it[:id]},
|
849
|
-
"Description" => lambda {|it| it[:description]},
|
850
|
-
"Start Date" => lambda {|it| it[:start_date]},
|
851
|
-
"Created By" => lambda {|it| it[:created_by]},
|
852
|
-
"Duration" => lambda {|it| it[:duration]},
|
853
|
-
"Status" => lambda {|it| it[:status]}
|
854
|
-
}
|
855
|
-
if !options[:details]
|
856
|
-
description_cols["Output"] = lambda {|it| it[:output]} if process_data[:output] && process_data[:output].strip.length > 0
|
857
|
-
description_cols["Error"] = lambda {|it| it[:error]} if process_data[:error] && process_data[:error].strip.length > 0
|
858
|
-
end
|
859
|
-
|
860
|
-
print_description_list(description_cols, process_data)
|
861
|
-
|
862
|
-
if process_data[:output] && process_data[:output].strip.length > 0
|
863
|
-
print_h2 "Output"
|
864
|
-
print process['output']
|
865
|
-
end
|
866
|
-
if process_data[:error] && process_data[:error].strip.length > 0
|
867
|
-
print_h2 "Error"
|
868
|
-
print process['message'] || process['error']
|
869
|
-
print reset,"\n"
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
|
-
if process['events'] && !process['events'].empty?
|
874
|
-
print_h2 "Execution Events"
|
875
|
-
print_process_events(process['events'])
|
876
|
-
end
|
877
|
-
end
|
878
|
-
print reset,"\n"
|
879
|
-
return 0
|
880
|
-
rescue RestClient::Exception => e
|
881
|
-
print_rest_exception(e, options)
|
882
|
-
exit 1
|
757
|
+
@jobs_interface.setopts(options)
|
758
|
+
if options[:dry_run]
|
759
|
+
print_dry_run @jobs_interface.dry.get_execution(args[0], params)
|
760
|
+
return
|
883
761
|
end
|
762
|
+
json_response = @jobs_interface.get_execution(args[0], params)
|
763
|
+
render_response(json_response, options, 'jobExecution') do
|
764
|
+
print_h1 "Morpheus Job Execution", [], options
|
765
|
+
print_job_execution(json_response['jobExecution'], options)
|
766
|
+
end
|
767
|
+
return 0, nil
|
884
768
|
end
|
885
769
|
|
886
770
|
def get_execution_event(args)
|
@@ -888,7 +772,7 @@ class Morpheus::Cli::JobsCommand
|
|
888
772
|
params = {}
|
889
773
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
890
774
|
opts.banner = subcommand_usage("[id] [event]")
|
891
|
-
|
775
|
+
build_standard_get_options(opts, options)
|
892
776
|
opts.footer = "Get details about a job.\n" +
|
893
777
|
"[id] is required. Job execution ID.\n" +
|
894
778
|
"[event] is required. Process event ID."
|
@@ -947,72 +831,8 @@ class Morpheus::Cli::JobsCommand
|
|
947
831
|
|
948
832
|
private
|
949
833
|
|
950
|
-
def get_process_event_data(process_or_event)
|
951
|
-
{
|
952
|
-
id: process_or_event['id'],
|
953
|
-
description: process_or_event['description'] || (process_or_event['refType'] == 'instance' ? process_or_event['displayName'] : (process_or_event['processTypeName'] || '').capitalize),
|
954
|
-
start_date: format_local_dt(process_or_event['startDate']),
|
955
|
-
created_by: process_or_event['createdBy'] ? process_or_event['createdBy']['displayName'] : '',
|
956
|
-
duration: format_human_duration((process_or_event['duration'] || process_or_event['statusEta'] || 0) / 1000.0),
|
957
|
-
status: format_status(process_or_event['status']),
|
958
|
-
error: truncate_string(process_or_event['message'] || process_or_event['error'], 32),
|
959
|
-
output: truncate_string(process_or_event['output'], 32)
|
960
|
-
}
|
961
|
-
end
|
962
|
-
|
963
|
-
# both process and process events
|
964
|
-
def print_process_events(events, options={})
|
965
|
-
print as_pretty_table(events.collect {|it| get_process_event_data(it)}, [:id, :description, :start_date, :created_by, :duration, :status, :error], options)
|
966
|
-
print reset,"\n"
|
967
|
-
end
|
968
|
-
|
969
|
-
def print_job_executions(execs, options={})
|
970
|
-
if execs.empty?
|
971
|
-
print cyan,"No job executions found.",reset,"\n"
|
972
|
-
else
|
973
|
-
rows = execs.collect do |ex|
|
974
|
-
{
|
975
|
-
id: ex['id'],
|
976
|
-
job: ex['job'] ? ex['job']['name'] : '',
|
977
|
-
description: ex['description'] || ex['job'] ? ex['job']['description'] : '',
|
978
|
-
type: ex['job'] && ex['job']['type'] ? (ex['job']['type']['code'] == 'morpheus.workflow' ? 'Workflow' : 'Task') : '',
|
979
|
-
start: format_local_dt(ex['startDate']),
|
980
|
-
duration: ex['duration'] ? format_human_duration(ex['duration'] / 1000.0) : '',
|
981
|
-
status: format_status(ex['status']),
|
982
|
-
error: truncate_string(ex['process'] && (ex['process']['message'] || ex['process']['error']) ? ex['process']['message'] || ex['process']['error'] : '', 32)
|
983
|
-
}
|
984
|
-
end
|
985
|
-
|
986
|
-
columns = [
|
987
|
-
:id, :job, :type, {'START DATE' => :start}, {'ETA/TIME' => :duration}, :status, :error
|
988
|
-
]
|
989
|
-
print as_pretty_table(rows, columns, options)
|
990
|
-
print reset,"\n"
|
991
|
-
end
|
992
|
-
end
|
993
|
-
|
994
|
-
def format_status(status_string, return_color=cyan)
|
995
|
-
out = ""
|
996
|
-
if status_string
|
997
|
-
if ['complete','success', 'successful', 'ok'].include?(status_string)
|
998
|
-
out << "#{green}#{status_string.upcase}"
|
999
|
-
elsif ['error', 'offline', 'failed', 'failure'].include?(status_string)
|
1000
|
-
out << "#{red}#{status_string.upcase}"
|
1001
|
-
else
|
1002
|
-
out << "#{yellow}#{status_string.upcase}"
|
1003
|
-
end
|
1004
|
-
end
|
1005
|
-
out + return_color
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
def find_by_name_or_id(type, val)
|
1009
|
-
interface = instance_variable_get "@#{type}s_interface"
|
1010
|
-
typeCamelCase = type.gsub(/(?:^|_)([a-z])/) do $1.upcase end
|
1011
|
-
typeCamelCase = typeCamelCase[0, 1].downcase + typeCamelCase[1..-1]
|
1012
|
-
(val.to_s =~ /\A\d{1,}\Z/) ? interface.get(val.to_i)[typeCamelCase] : interface.list({'name' => val})["#{typeCamelCase}s"].first
|
1013
|
-
end
|
1014
|
-
|
1015
834
|
def load_job_type_id_by_code(code)
|
1016
835
|
@options_interface.options_for_source('jobTypes', {})['data'].find {|it| it['code'] == code}['value'] rescue nil
|
1017
836
|
end
|
837
|
+
|
1018
838
|
end
|