morpheus-cli 5.4.5 → 5.5.1
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/lib/morpheus/api/api_client.rb +4 -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 +2 -2
- data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
- data/lib/morpheus/cli/commands/clouds.rb +61 -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 +12 -12
- 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 +41 -14
- 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 +6 -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
|
@@ -25,7 +25,7 @@ class Morpheus::Cli::Instances
|
|
25
25
|
:wiki, :update_wiki,
|
26
26
|
{:exec => :execution_request},
|
27
27
|
:deploys,
|
28
|
-
:refresh, :prepare_apply, :
|
28
|
+
:refresh, :prepare_apply, :apply, :state
|
29
29
|
#register_subcommands :firewall_disable, :firewall_enable
|
30
30
|
# register_subcommands {:'lb-update' => :load_balancer_update}
|
31
31
|
alias_subcommand :details, :get
|
@@ -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
|