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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +4 -0
  4. data/lib/morpheus/api/clusters_interface.rb +12 -0
  5. data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
  6. data/lib/morpheus/api/prices_interface.rb +6 -0
  7. data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
  8. data/lib/morpheus/cli/cli_command.rb +55 -23
  9. data/lib/morpheus/cli/commands/apps.rb +2 -2
  10. data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
  11. data/lib/morpheus/cli/commands/clouds.rb +61 -31
  12. data/lib/morpheus/cli/commands/clusters.rb +66 -5
  13. data/lib/morpheus/cli/commands/cypher_command.rb +22 -23
  14. data/lib/morpheus/cli/commands/hosts.rb +5 -1
  15. data/lib/morpheus/cli/commands/instances.rb +12 -12
  16. data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
  17. data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
  18. data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
  19. data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
  20. data/lib/morpheus/cli/commands/library_option_lists_command.rb +18 -8
  21. data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
  22. data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
  23. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
  24. data/lib/morpheus/cli/commands/prices_command.rb +25 -11
  25. data/lib/morpheus/cli/commands/roles.rb +475 -70
  26. data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
  27. data/lib/morpheus/cli/commands/tasks.rb +64 -22
  28. data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
  29. data/lib/morpheus/cli/commands/users.rb +10 -10
  30. data/lib/morpheus/cli/commands/view.rb +1 -0
  31. data/lib/morpheus/cli/commands/workflows.rb +21 -14
  32. data/lib/morpheus/cli/error_handler.rb +13 -4
  33. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  34. data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
  35. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
  36. data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
  37. data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
  38. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -3
  39. data/lib/morpheus/cli/mixins/rest_command.rb +41 -14
  40. data/lib/morpheus/cli/option_types.rb +69 -13
  41. data/lib/morpheus/cli/version.rb +1 -1
  42. data/lib/morpheus/logging.rb +6 -8
  43. data/lib/morpheus/routes.rb +3 -5
  44. 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
- print_green_success "Cluster #{cluster['name']} is being removed..."
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
- print_green_success "Added worker to cluster #{cluster['name']}"
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
- print_green_success "Worker #{worker['name']} is being removed from cluster #{cluster['name']}..."
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
- puts_error "Cypher data not found in response"
189
- return 1
190
- end
191
- description_cols = {
192
- #"ID" => 'id',
193
- "Key" => lambda {|it| it["itemKey"] },
194
- "TTL" => lambda {|it|
195
- format_expiration_ttl(it["expireDate"])
196
- },
197
- # "Type" => lambda {|it|
198
- # data_type
199
- # },
200
- "Expiration" => lambda {|it|
201
- format_expiration_date(it["expireDate"])
202
- },
203
- # "Date Created" => lambda {|it| format_local_dt(it["dateCreated"]) },
204
- "Last Updated" => lambda {|it| format_local_dt(it["lastUpdated"]) },
205
- "Last Accessed" => lambda {|it| format_local_dt(it["lastAccessed"]) }
206
- }
207
- if cypher_item["expireDate"].nil?
208
- description_cols.delete("Expires")
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
- print_green_success "Host #{server['name']} is being removed..."
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, :plan, :apply, :state
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
- 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
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 = 15
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| format_status(job['lastResult']) },
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
- build_common_options(opts, options, [:json, :dry_run, :remote])
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
- build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
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
- if args.count > 1
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
- if options[:json]
430
- puts as_json(json_response, options)
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
- build_common_options(opts, options, [:options, :payload, :list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
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
- if args.count != 1
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
- if options[:json]
614
- puts as_json(json_response, options)
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
- build_common_options(opts, options, [:json, :dry_run, :remote])
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
- if args.count != 1
694
- raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
695
- return 1
696
- end
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.on('-D', '--details [on|off]', String, "Can be used to enable / disable execution details. Default is on") do |val|
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
- begin
809
- @jobs_interface.setopts(options)
810
-
811
- if options[:dry_run]
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
- build_common_options(opts, options, [:json, :dry_run, :remote])
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