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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/backup_service_types_interface.rb +9 -0
  5. data/lib/morpheus/api/backup_services_interface.rb +9 -0
  6. data/lib/morpheus/api/clusters_interface.rb +12 -0
  7. data/lib/morpheus/api/network_pool_servers_interface.rb +7 -0
  8. data/lib/morpheus/api/prices_interface.rb +6 -0
  9. data/lib/morpheus/api/scale_thresholds_interface.rb +9 -0
  10. data/lib/morpheus/cli/cli_command.rb +55 -23
  11. data/lib/morpheus/cli/commands/apps.rb +1 -1
  12. data/lib/morpheus/cli/commands/backup_services_command.rb +44 -0
  13. data/lib/morpheus/cli/commands/cloud_resource_pools_command.rb +33 -2
  14. data/lib/morpheus/cli/commands/clouds.rb +67 -31
  15. data/lib/morpheus/cli/commands/clusters.rb +66 -5
  16. data/lib/morpheus/cli/commands/cypher_command.rb +22 -23
  17. data/lib/morpheus/cli/commands/hosts.rb +5 -1
  18. data/lib/morpheus/cli/commands/instances.rb +11 -11
  19. data/lib/morpheus/cli/commands/integrations_command.rb +1 -1
  20. data/lib/morpheus/cli/commands/invoices_command.rb +8 -1
  21. data/lib/morpheus/cli/commands/jobs_command.rb +45 -225
  22. data/lib/morpheus/cli/commands/library_container_types_command.rb +52 -3
  23. data/lib/morpheus/cli/commands/library_option_lists_command.rb +18 -8
  24. data/lib/morpheus/cli/commands/library_option_types_command.rb +56 -62
  25. data/lib/morpheus/cli/commands/load_balancers.rb +11 -19
  26. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +5 -2
  27. data/lib/morpheus/cli/commands/prices_command.rb +25 -11
  28. data/lib/morpheus/cli/commands/roles.rb +475 -70
  29. data/lib/morpheus/cli/commands/scale_thresholds.rb +103 -0
  30. data/lib/morpheus/cli/commands/tasks.rb +64 -22
  31. data/lib/morpheus/cli/commands/user_sources_command.rb +107 -39
  32. data/lib/morpheus/cli/commands/users.rb +10 -10
  33. data/lib/morpheus/cli/commands/view.rb +1 -0
  34. data/lib/morpheus/cli/commands/workflows.rb +21 -14
  35. data/lib/morpheus/cli/error_handler.rb +13 -4
  36. data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
  37. data/lib/morpheus/cli/mixins/execution_request_helper.rb +1 -1
  38. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +3 -3
  39. data/lib/morpheus/cli/mixins/jobs_helper.rb +173 -0
  40. data/lib/morpheus/cli/mixins/print_helper.rb +120 -38
  41. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -3
  42. data/lib/morpheus/cli/mixins/rest_command.rb +58 -15
  43. data/lib/morpheus/cli/option_types.rb +69 -13
  44. data/lib/morpheus/cli/version.rb +1 -1
  45. data/lib/morpheus/logging.rb +6 -8
  46. data/lib/morpheus/routes.rb +3 -5
  47. 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
- 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
@@ -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