morpheus-cli 5.5.2.2 → 5.5.3.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Dockerfile +1 -1
  4. data/README.md +57 -4
  5. data/Rakefile +9 -0
  6. data/bin/morpheus +4 -4
  7. data/lib/morpheus/api/api_client.rb +20 -2
  8. data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
  9. data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
  10. data/lib/morpheus/api/archive_files_interface.rb +3 -3
  11. data/lib/morpheus/api/clients_interface.rb +2 -2
  12. data/lib/morpheus/api/clusters_interface.rb +8 -1
  13. data/lib/morpheus/api/containers_interface.rb +29 -16
  14. data/lib/morpheus/api/custom_instance_types_interface.rb +0 -2
  15. data/lib/morpheus/api/cypher_interface.rb +1 -2
  16. data/lib/morpheus/api/doc_interface.rb +8 -6
  17. data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
  18. data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
  19. data/lib/morpheus/api/health_interface.rb +1 -1
  20. data/lib/morpheus/api/image_builder_interface.rb +3 -3
  21. data/lib/morpheus/api/instances_interface.rb +25 -0
  22. data/lib/morpheus/api/logs_interface.rb +2 -4
  23. data/lib/morpheus/api/monitoring_interface.rb +6 -6
  24. data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
  25. data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
  26. data/lib/morpheus/api/packages_interface.rb +1 -1
  27. data/lib/morpheus/api/reports_interface.rb +1 -1
  28. data/lib/morpheus/api/servers_interface.rb +9 -1
  29. data/lib/morpheus/api/storage_providers_interface.rb +2 -2
  30. data/lib/morpheus/api/virtual_images_interface.rb +1 -1
  31. data/lib/morpheus/api.rb +2 -0
  32. data/lib/morpheus/benchmarking.rb +1 -1
  33. data/lib/morpheus/cli/cli_command.rb +79 -37
  34. data/lib/morpheus/cli/cli_registry.rb +19 -10
  35. data/lib/morpheus/cli/commands/access_token_command.rb +1 -1
  36. data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
  37. data/lib/morpheus/cli/commands/apps.rb +1 -1
  38. data/lib/morpheus/cli/commands/archives_command.rb +25 -33
  39. data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
  40. data/lib/morpheus/cli/commands/blueprints_command.rb +10 -21
  41. data/lib/morpheus/cli/commands/boot_scripts_command.rb +2 -2
  42. data/lib/morpheus/cli/commands/cat_command.rb +1 -1
  43. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +18 -13
  44. data/lib/morpheus/cli/commands/clouds.rb +3 -3
  45. data/lib/morpheus/cli/commands/clusters.rb +154 -3
  46. data/lib/morpheus/cli/commands/containers_command.rb +398 -253
  47. data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
  48. data/lib/morpheus/cli/commands/deployments.rb +1 -1
  49. data/lib/morpheus/cli/commands/deploys.rb +9 -9
  50. data/lib/morpheus/cli/commands/doc.rb +15 -16
  51. data/lib/morpheus/cli/commands/execution_request_command.rb +2 -2
  52. data/lib/morpheus/cli/commands/file_copy_request_command.rb +5 -5
  53. data/lib/morpheus/cli/commands/groups.rb +2 -2
  54. data/lib/morpheus/cli/commands/guidance_command.rb +2 -2
  55. data/lib/morpheus/cli/commands/guidance_settings.rb +148 -0
  56. data/lib/morpheus/cli/commands/health_command.rb +4 -4
  57. data/lib/morpheus/cli/commands/hosts.rb +43 -5
  58. data/lib/morpheus/cli/commands/image_builder_command.rb +1 -1
  59. data/lib/morpheus/cli/commands/instances.rb +419 -148
  60. data/lib/morpheus/cli/commands/integrations_command.rb +22 -20
  61. data/lib/morpheus/cli/commands/key_pairs.rb +2 -2
  62. data/lib/morpheus/cli/commands/library_container_scripts_command.rb +2 -2
  63. data/lib/morpheus/cli/commands/library_container_templates_command.rb +2 -2
  64. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -3
  65. data/lib/morpheus/cli/commands/library_spec_templates_command.rb +2 -2
  66. data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
  67. data/lib/morpheus/cli/commands/login.rb +1 -1
  68. data/lib/morpheus/cli/commands/man_command.rb +32 -18
  69. data/lib/morpheus/cli/commands/monitoring_settings.rb +228 -0
  70. data/lib/morpheus/cli/commands/network_server_groups_command.rb +222 -0
  71. data/lib/morpheus/cli/commands/packages_command.rb +11 -11
  72. data/lib/morpheus/cli/commands/plugins.rb +1 -1
  73. data/lib/morpheus/cli/commands/policies_command.rb +4 -4
  74. data/lib/morpheus/cli/commands/preseed_scripts_command.rb +2 -2
  75. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
  76. data/lib/morpheus/cli/commands/remote.rb +1 -1
  77. data/lib/morpheus/cli/commands/reports_command.rb +13 -3
  78. data/lib/morpheus/cli/commands/security_groups.rb +1 -1
  79. data/lib/morpheus/cli/commands/shell.rb +40 -62
  80. data/lib/morpheus/cli/commands/snapshots.rb +3 -5
  81. data/lib/morpheus/cli/commands/source_command.rb +8 -16
  82. data/lib/morpheus/cli/commands/storage_providers_command.rb +7 -7
  83. data/lib/morpheus/cli/commands/tasks.rb +2 -2
  84. data/lib/morpheus/cli/commands/vdi_pools_command.rb +6 -6
  85. data/lib/morpheus/cli/commands/view.rb +5 -1
  86. data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +5 -5
  87. data/lib/morpheus/cli/commands/whoami.rb +2 -2
  88. data/lib/morpheus/cli/credentials.rb +30 -8
  89. data/lib/morpheus/cli/dot_file.rb +8 -15
  90. data/lib/morpheus/cli/error_handler.rb +16 -0
  91. data/lib/morpheus/cli/errors.rb +8 -1
  92. data/lib/morpheus/cli/mixins/print_helper.rb +17 -13
  93. data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
  94. data/lib/morpheus/cli/mixins/rest_command.rb +23 -19
  95. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +47 -24
  96. data/lib/morpheus/cli/option_parser.rb +5 -1
  97. data/lib/morpheus/cli/option_types.rb +59 -12
  98. data/lib/morpheus/cli/version.rb +1 -1
  99. data/lib/morpheus/cli.rb +26 -16
  100. data/lib/morpheus/ext/rest_client.rb +3 -2
  101. data/lib/morpheus/ext/string.rb +6 -4
  102. data/lib/morpheus/formatters.rb +1 -1
  103. data/lib/morpheus/logging.rb +4 -4
  104. data/lib/morpheus/morpkg.rb +4 -4
  105. data/lib/morpheus/rest_client.rb +2 -2
  106. data/lib/morpheus/routes.rb +41 -9
  107. data/lib/morpheus/terminal.rb +65 -16
  108. data/lib/morpheus.rb +1 -1
  109. data/morpheus-cli.gemspec +1 -0
  110. data/test/api/containers_interface_test.rb +68 -0
  111. data/test/api/doc_interface_test.rb +35 -0
  112. data/test/api/instances_interface_test.rb +22 -0
  113. data/test/api/whoami_interface_test.rb +14 -0
  114. data/test/cli/access_token_test.rb +36 -0
  115. data/test/cli/auth_test.rb +82 -0
  116. data/test/cli/cli_test.rb +48 -0
  117. data/test/cli/containers_test.rb +92 -0
  118. data/test/cli/doc_test.rb +35 -0
  119. data/test/cli/help_test.rb +25 -0
  120. data/test/cli/instances_test.rb +36 -0
  121. data/test/cli/man_test.rb +14 -0
  122. data/test/cli/remote_test.rb +89 -0
  123. data/test/cli/roles_test.rb +34 -0
  124. data/test/cli/shell_test.rb +81 -0
  125. data/test/cli/version_test.rb +23 -0
  126. data/test/cli/view_test.rb +55 -0
  127. data/test/cli/whoami_test.rb +17 -0
  128. data/test/morpheus_test.rb +16 -0
  129. data/test/test_case.rb +338 -0
  130. data/test/test_config.rb +137 -0
  131. data/test/test_data_helper.rb +97 -0
  132. metadata +67 -3
@@ -0,0 +1,7 @@
1
+ require 'morpheus/api/secondary_rest_interface'
2
+
3
+ class Morpheus::NetworkServerGroupsInterface < Morpheus::SecondaryRestInterface
4
+ def base_path(network_server_id)
5
+ "/api/networks/servers/#{network_server_id}/groups"
6
+ end
7
+ end
@@ -79,7 +79,7 @@ class Morpheus::PackagesInterface < Morpheus::APIClient
79
79
  headers = { params: params, authorization: "Bearer #{@access_token}" }
80
80
  opts = {method: :post, url: url, headers: headers}
81
81
  # execute(opts, {parse_json: false})
82
- if Dir.exists?(outfile)
82
+ if Dir.exist?(outfile)
83
83
  raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
84
84
  end
85
85
  # if @verify_ssl == false
@@ -44,7 +44,7 @@ class Morpheus::ReportsInterface < Morpheus::APIClient
44
44
  headers = { params: params, authorization: "Bearer #{@access_token}" }
45
45
  opts = {method: :get, url: url, headers: headers, timeout: 172800}
46
46
  # execute(opts, {parse_json: false})
47
- if Dir.exists?(outfile)
47
+ if Dir.exist?(outfile)
48
48
  raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
49
49
  end
50
50
  # if @verify_ssl == false
@@ -55,6 +55,14 @@ class Morpheus::ServersInterface < Morpheus::APIClient
55
55
  execute(opts)
56
56
  end
57
57
 
58
+ def restart(serverId,payload = {}, params = {})
59
+ url = "#{@base_url}/api/servers/#{serverId}/restart"
60
+
61
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
62
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
63
+ execute(opts)
64
+ end
65
+
58
66
  def make_managed(serverId,payload = {})
59
67
  url = "#{@base_url}/api/servers/#{serverId}/install-agent"
60
68
  #url = "#{@base_url}/api/servers/#{serverId}/make-managed" # added in 4.1
@@ -176,7 +184,7 @@ class Morpheus::ServersInterface < Morpheus::APIClient
176
184
  execute(opts)
177
185
  end
178
186
 
179
- def update_network_label(network_id, server_id, payload)
187
+ def update_network_label(network_id, server_id, payload)
180
188
  url = "#{@base_url}/api/servers/#{server_id}/networkInterfaces/#{network_id}"
181
189
  headers = {authorization: "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
182
190
  opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
@@ -96,7 +96,7 @@ class Morpheus::StorageProvidersInterface < Morpheus::APIClient
96
96
  headers = { params: params, authorization: "Bearer #{@access_token}" }
97
97
  opts = {method: :get, url: url, headers: headers}
98
98
  # execute(opts, false)
99
- if Dir.exists?(outfile)
99
+ if Dir.exist?(outfile)
100
100
  raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
101
101
  end
102
102
  # if @verify_ssl == false
@@ -125,7 +125,7 @@ class Morpheus::StorageProvidersInterface < Morpheus::APIClient
125
125
  headers = { params: params, authorization: "Bearer #{@access_token}" }
126
126
  opts = {method: :get, url: url, headers: headers}
127
127
  # execute(opts, false)
128
- if Dir.exists?(outfile)
128
+ if Dir.exist?(outfile)
129
129
  raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
130
130
  end
131
131
  # if @verify_ssl == false
@@ -81,7 +81,7 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
81
81
  # opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
82
82
  end
83
83
 
84
- start_time = Time.now
84
+ # start_time = Time.now
85
85
  query_params = headers.delete(:params) || {}
86
86
  file_size = image_file.size
87
87
  if File.blockdev?(image_file)
data/lib/morpheus/api.rb CHANGED
@@ -7,4 +7,6 @@ require 'morpheus/formatters'
7
7
 
8
8
  # load interfaces
9
9
  require 'morpheus/api/api_client.rb'
10
+ require 'morpheus/api/rest_interface.rb'
11
+ require 'morpheus/api/read_interface.rb'
10
12
  Dir[File.dirname(__FILE__) + "/api/**/*.rb"].each {|file| require file }
@@ -145,7 +145,7 @@ module Morpheus::Benchmarking
145
145
 
146
146
  # finish the current benchmark and optionally print the time taken.
147
147
  def stop_benchmark(exit_code=0, err=nil)
148
- if @benchmark_record
148
+ if defined?(@benchmark_record) && @benchmark_record
149
149
  @benchmark_record.stop(exit_code, err)
150
150
  @last_benchmark_record = @benchmark_record
151
151
  @benchmark_record = nil
@@ -133,10 +133,12 @@ module Morpheus
133
133
  end
134
134
 
135
135
  # this returns all the options passed in by -O, parsed all nicely into objects.
136
- def parse_passed_options(options)
137
- passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
136
+ def parse_passed_options(options, parse_opts={})
137
+ excludes = [parse_opts[:exclude], parse_opts[:excludes]].flatten.compact
138
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) || excludes.include?(k) } : {}
138
139
  return passed_options
139
140
  end
141
+
140
142
  # Appends Array of OptionType definitions to an OptionParser instance
141
143
  # This adds an option like --fieldContext.fieldName="VALUE"
142
144
  # @param opts [OptionParser]
@@ -378,35 +380,53 @@ module Morpheus
378
380
  end
379
381
  options[:options] = custom_options
380
382
  end
381
- opts.on('-P','--prompt', "Always prompts. Use passed options as the default value.") do |val|
383
+ # --always-prompt can be used with for update commands where it normally defaults to --no-prompt
384
+ opts.on('--prompt', "Always prompt for input on every option, even those not prompted for by default.") do
382
385
  options[:always_prompt] = true
383
- options[:options] ||= {}
384
386
  options[:options][:always_prompt] = true
385
387
  end
386
- opts.on('-N','--no-prompt', "Skip prompts. Use default values for all optional fields.") do |val|
388
+ opts.on('-N','--no-prompt', "No prompt, skips all input prompting.") do |val|
387
389
  options[:no_prompt] = true
388
- options[:options] ||= {}
389
- options[:options][:no_prompt] = true
390
- end
391
-
392
- when :prompt
393
- opts.on('-P','--prompt', "Always prompts. Use passed options as the default value.") do |val|
394
- options[:always_prompt] = true
395
- options[:options] ||= {}
396
- options[:options][:always_prompt] = true
397
- end
398
- opts.on('-N','--no-prompt', "Skip prompts. Use default values for all optional fields.") do |val|
399
- options[:no_prompt] = true
400
- options[:options] ||= {}
401
390
  options[:options][:no_prompt] = true
402
391
  end
392
+ # opts.on('--skip-prompt x,y,z', String, "Skip prompt, do not prompt for input of the specified options.") do |val|
393
+ # options[:skip_prompt] ||= []
394
+ # options[:skip_prompt] += parse_array(val)
395
+ # options[:options][:skip_prompt] = options[:skip_prompt]
396
+ # end
397
+ # opts.on('--only-prompt x,y,z', String, "Only prompt for input on the specified options.") do |val|
398
+ # options[:only_prompt] ||= []
399
+ # options[:only_prompt] += parse_array(val)
400
+ # options[:options][:only_prompt] = options[:only_prompt]
401
+ # end
402
+ opts.on('--no-options', String, "No options, skips all option parsing so no options are required and no default values are used.") do
403
+ options[:no_options] = true
404
+ options[:options][:no_options] = options[:no_options]
405
+ end
406
+ opts.on('--skip-options x,y,z', String, "Skip parsing of the specified options so that they are not required and their default value is not used.") do |val|
407
+ options[:skip_options] ||= []
408
+ options[:skip_options] += parse_array(val)
409
+ options[:options][:skip_options] = options[:skip_options]
410
+ end
411
+ # opts.on('--only-options x,y,z', String, "Only parse the specified options and skip all others.") do |val|
412
+ # options[:only_options] ||= []
413
+ # options[:only_options] += parse_array(val)
414
+ # options[:options][:only_options] = options[:only_options]
415
+ # end
416
+
417
+ # hide these while incubating
418
+ opts.add_hidden_option('--skip-prompt')
419
+ opts.add_hidden_option('--only-prompt')
420
+ opts.add_hidden_option('--no-options')
421
+ opts.add_hidden_option('--skip-options')
422
+ opts.add_hidden_option('--only-options')
403
423
 
404
424
  when :payload
405
425
  opts.on('--payload FILE', String, "Payload from a local JSON or YAML file, skip all prompting") do |val|
406
426
  options[:payload_file] = val.to_s
407
427
  begin
408
428
  payload_file = File.expand_path(options[:payload_file])
409
- if !File.exists?(payload_file) || !File.file?(payload_file)
429
+ if !File.exist?(payload_file) || !File.file?(payload_file)
410
430
  raise ::OptionParser::InvalidOption.new("File not found: #{payload_file}")
411
431
  #return false
412
432
  end
@@ -419,10 +439,10 @@ module Morpheus
419
439
  raise ::OptionParser::InvalidOption.new("Failed to parse payload file: #{payload_file} Error: #{ex.message}")
420
440
  end
421
441
  end
422
- opts.on('--payload-dir DIRECTORY', String, "Payload from a local directory containing 1-N JSON or YAML files, skip all prompting") do |val|
442
+ opts.on('--payload-dir DIRECTORY', String, "Payload from a local directory containing 1-N JSON or YAML files, skip all prompting.") do |val|
423
443
  options[:payload_dir] = val.to_s
424
444
  payload_dir = File.expand_path(options[:payload_dir])
425
- if !Dir.exists?(payload_dir) || !File.directory?(payload_dir)
445
+ if !Dir.exist?(payload_dir) || !File.directory?(payload_dir)
426
446
  raise ::OptionParser::InvalidOption.new("Directory not found: #{payload_dir}")
427
447
  end
428
448
  payload = {}
@@ -592,7 +612,7 @@ module Morpheus
592
612
  end unless excludes.include?(:remote_token)
593
613
  opts.on( '--token-file FILE', String, "Token File, read a file containing the access token." ) do |val|
594
614
  token_file = File.expand_path(val)
595
- if !File.exists?(token_file) || !File.file?(token_file)
615
+ if !File.exist?(token_file) || !File.file?(token_file)
596
616
  raise ::OptionParser::InvalidOption.new("File not found: #{token_file}")
597
617
  end
598
618
  options[:remote_token] = File.read(token_file).to_s.split("\n").first.strip
@@ -609,7 +629,7 @@ module Morpheus
609
629
  end
610
630
  opts.on( '--password-file FILE', String, "Password File, read a file containing the password for authentication." ) do |val|
611
631
  password_file = File.expand_path(val)
612
- if !File.exists?(password_file) || !File.file?(password_file)
632
+ if !File.exist?(password_file) || !File.file?(password_file)
613
633
  raise ::OptionParser::InvalidOption.new("File not found: #{password_file}")
614
634
  end
615
635
  file_content = File.read(password_file) #.strip
@@ -914,12 +934,12 @@ module Morpheus
914
934
 
915
935
  opts.on('--hidden-help', "Print help that includes all the hidden options, like this one." ) do
916
936
  puts opts.full_help_message({show_hidden_options:true})
917
- exit # return 0 maybe?
937
+ exit 0 # return 0 maybe?
918
938
  end
919
939
  opts.add_hidden_option('--hidden-help') if opts.is_a?(Morpheus::Cli::OptionParser)
920
940
  opts.on('-h', '--help', "Print this help" ) do
921
941
  puts opts
922
- exit # return 0 maybe?
942
+ exit 0 # return 0 maybe?
923
943
  end
924
944
 
925
945
  opts
@@ -1012,9 +1032,9 @@ module Morpheus
1012
1032
  out << "\n"
1013
1033
  }
1014
1034
  end
1015
- if command_description
1035
+ if command_description && !command_description.to_s.strip.empty?
1016
1036
  out << "\n"
1017
- out << "#{command_description}\n"
1037
+ out << "#{command_description.strip}\n"
1018
1038
  end
1019
1039
  # out << "\n"
1020
1040
  out
@@ -1248,6 +1268,14 @@ module Morpheus
1248
1268
  true
1249
1269
  end
1250
1270
 
1271
+ def confirm(msg, options)
1272
+ options[:yes] or ::Morpheus::Cli::OptionTypes::confirm(msg, options)
1273
+ end
1274
+
1275
+ def confirm!(msg, options)
1276
+ confirm(msg, options) or raise CommandAborted.new("confirmation declined: #{msg}")
1277
+ end
1278
+
1251
1279
  # The default way to build options for the list command
1252
1280
  # @param [OptionParser] opts
1253
1281
  # @param [Hash] options
@@ -1449,11 +1477,11 @@ module Morpheus
1449
1477
  def validate_outfile(outfile, options)
1450
1478
  full_filename = File.expand_path(outfile)
1451
1479
  outdir = File.dirname(full_filename)
1452
- if Dir.exists?(full_filename)
1480
+ if Dir.exist?(full_filename)
1453
1481
  print_red_alert "[local-file] is invalid. It is the name of an existing directory: #{outfile}"
1454
1482
  return false
1455
1483
  end
1456
- if !Dir.exists?(outdir)
1484
+ if !Dir.exist?(outdir)
1457
1485
  if options[:mkdir]
1458
1486
  print cyan,"Creating local directory #{outdir}",reset,"\n"
1459
1487
  FileUtils.mkdir_p(outdir)
@@ -1462,7 +1490,7 @@ module Morpheus
1462
1490
  return false
1463
1491
  end
1464
1492
  end
1465
- if File.exists?(full_filename) && !options[:overwrite]
1493
+ if File.exist?(full_filename) && !options[:overwrite]
1466
1494
  print_red_alert "[local-file] is invalid. File already exists: #{outfile}\nUse -f to overwrite the existing file."
1467
1495
  return false
1468
1496
  end
@@ -1586,7 +1614,16 @@ module Morpheus
1586
1614
  interface_name = "@#{type.pluralize}_interface"
1587
1615
  interface = instance_variable_get(interface_name)
1588
1616
  if interface.nil?
1589
- raise "#{self.class} has not defined interface #{interface_name}"
1617
+ api_client = instance_variable_get("@api_client")
1618
+ if api_client
1619
+ if api_client.respond_to?(type.pluralize)
1620
+ interface = api_client.send(type.pluralize)
1621
+ else
1622
+ raise "@api_client.#{type.pluralize} is not a recognized interface"
1623
+ end
1624
+ else
1625
+ raise "#{self.class} has not defined interface #{interface_name} or @api_client"
1626
+ end
1590
1627
  end
1591
1628
  begin
1592
1629
  json_response = interface.get(*ids)
@@ -1753,6 +1790,9 @@ module Morpheus
1753
1790
 
1754
1791
  module ClassMethods
1755
1792
 
1793
+ # attr_writer :command_name, :command_description, :hidden_command, :default_refresh_interval,
1794
+ # :subcommands, :hidden_subcommands, :default_subcommand, :subcommand_aliases, :subcommand_descriptions
1795
+
1756
1796
  def prog_name
1757
1797
  "morpheus"
1758
1798
  end
@@ -1779,7 +1819,11 @@ module Morpheus
1779
1819
  # alias :command_name= :set_command_name
1780
1820
 
1781
1821
  def hidden_command
1782
- !!@hidden_command
1822
+ defined?(@hidden_command) && @hidden_command == true
1823
+ end
1824
+
1825
+ def hidden_subcommands
1826
+ @hidden_subcommands ||= []
1783
1827
  end
1784
1828
 
1785
1829
  def set_subcommands_hidden(*cmds)
@@ -1791,7 +1835,7 @@ module Morpheus
1791
1835
  end
1792
1836
 
1793
1837
  def command_description
1794
- @command_description
1838
+ @command_description ||= ""
1795
1839
  end
1796
1840
 
1797
1841
  def set_command_description(val)
@@ -1880,10 +1924,8 @@ module Morpheus
1880
1924
 
1881
1925
  def visible_subcommands
1882
1926
  cmds = subcommands.clone
1883
- if @hidden_subcommands && !@hidden_subcommands.empty?
1884
- @hidden_subcommands.each do |hidden_cmd|
1885
- cmds.delete(hidden_cmd.to_s.gsub('_', '-'))
1886
- end
1927
+ hidden_subcommands.each do |hidden_cmd|
1928
+ cmds.delete(hidden_cmd.to_s.gsub('_', '-'))
1887
1929
  end
1888
1930
  cmds
1889
1931
  end
@@ -78,10 +78,17 @@ module Morpheus
78
78
 
79
79
  def exec_command(command_name, args)
80
80
  #puts "exec_command(#{command_name}, #{args})"
81
+ result = nil
81
82
  if has_alias?(command_name)
82
- exec_alias(command_name, args)
83
+ result = exec_alias(command_name, args)
83
84
  elsif has_command?(command_name)
84
- instance.get(command_name).new.handle(args)
85
+ begin
86
+ result = instance.get(command_name).new.handle(args)
87
+ rescue SystemExit => e
88
+ result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(e) # lol
89
+ rescue => e
90
+ result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(e) # lol
91
+ end
85
92
  else
86
93
  # todo: need to just return error instead of raise
87
94
  msg = "'#{command_name}' is not a morpheus command."
@@ -97,8 +104,10 @@ module Morpheus
97
104
  msg += "\t" + suggestion + "\n"
98
105
  end
99
106
  end
100
- raise CommandNotFoundError.new(msg)
107
+ #raise CommandNotFoundError.new(msg)
108
+ result = Morpheus::Cli::ErrorHandler.new(Morpheus::Terminal.instance.stderr).handle_error(CommandNotFoundError.new(msg)) # lol
101
109
  end
110
+ return result
102
111
  end
103
112
 
104
113
  def exec_alias(alias_name, args)
@@ -248,17 +257,17 @@ module Morpheus
248
257
 
249
258
  # parse any object into a command result [exit_code, error]
250
259
  # 0 means success.
251
- # This treats nil, true, or an object success.
252
- # 0 or
253
- # @return [Array] exit_code, error. Success returns [0, nil].
260
+ # This treats nil, true, or an object as success ie. [0, nil]
261
+ # and false is treated as an error [1, error]
262
+ # @return [Array] [exit_code, error]. Success returns [0, nil].
254
263
  def parse_command_result(cmd_result)
255
- exit_code, err = nil, nil
264
+ exit_code, error = nil, nil
256
265
  if cmd_result.is_a?(Array)
257
266
  exit_code = cmd_result[0] || 0
258
- err = cmd_result[1]
267
+ error = cmd_result[1]
259
268
  elsif cmd_result.is_a?(Hash)
260
269
  exit_code = cmd_result[:exit_code] || 0
261
- err = cmd_result[:error] || cmd_result[:err]
270
+ error = cmd_result[:error] || cmd_result[:err]
262
271
  elsif cmd_result == nil || cmd_result == true
263
272
  exit_code = 0
264
273
  elsif cmd_result == false
@@ -279,7 +288,7 @@ module Morpheus
279
288
  exit_code = 0
280
289
  end
281
290
  end
282
- return exit_code, err
291
+ return exit_code, error
283
292
  end
284
293
 
285
294
  def cached_command_list
@@ -116,7 +116,7 @@ class Morpheus::Cli::AccessTokenCommand
116
116
  end
117
117
  opts.on( '--token-file FILE', String, "Refresh Token File, read a file containing the refresh token." ) do |val|
118
118
  token_file = File.expand_path(val)
119
- if !File.exists?(token_file) || !File.file?(token_file)
119
+ if !File.exist?(token_file) || !File.file?(token_file)
120
120
  raise ::OptionParser::InvalidOption.new("File not found: #{token_file}")
121
121
  end
122
122
  options[:refresh_token] = File.read(token_file).to_s.split("\n").first.strip
@@ -6,7 +6,7 @@ class Morpheus::Cli::ApplianceSettingsCommand
6
6
 
7
7
  set_command_name :'appliance-settings'
8
8
 
9
- register_subcommands :get, :update
9
+ register_subcommands :get, :update, :toggle_maintenance, :'reindex'
10
10
 
11
11
  set_default_subcommand :get
12
12
 
@@ -103,7 +103,7 @@ class Morpheus::Cli::ApplianceSettingsCommand
103
103
  print cyan
104
104
  print enabled_zone_types.collect {|it| it['name']}.join(', ')
105
105
  end
106
- print reset "\n"
106
+ print reset, "\n"
107
107
  return 0
108
108
  rescue RestClient::Exception => e
109
109
  print_rest_exception(e, options)
@@ -307,6 +307,61 @@ class Morpheus::Cli::ApplianceSettingsCommand
307
307
  end
308
308
  end
309
309
 
310
+ def toggle_maintenance(args)
311
+ params = {}
312
+ options = {}
313
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
314
+ opts.banner = opts.banner = subcommand_usage()
315
+ opts.on("--enabled [on|off]", String, "Enabled (on) or Disabled (off)") do |val|
316
+ params['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
317
+ end
318
+ build_standard_update_options(opts, options, [:auto_confirm], [:payload, :options])
319
+ opts.footer = "Toggle maintenance mode."
320
+ end
321
+ optparse.parse!(args)
322
+ connect(options)
323
+ verify_args!(args:args, optparse:optparse, count:0)
324
+ if params['enabled'].nil?
325
+ confirm!("Are you sure you would like to toggle maintenance mode?", options)
326
+ else
327
+ confirm!("Are you sure you would like to toggle maintenance mode: #{params['enabled'] ? 'on' : 'off'}?", options)
328
+ end
329
+ @appliance_settings_interface.setopts(options)
330
+ if options[:dry_run]
331
+ print_dry_run @appliance_settings_interface.dry.maintenance(params)
332
+ return
333
+ end
334
+ json_response = @appliance_settings_interface.maintenance(params)
335
+ render_response(json_response, options) do
336
+ print_green_success "Toggled maintenance mode: '#{params['enabled'] ? 'on' : 'off'}'"
337
+ end
338
+ return 0, nil
339
+ end
340
+
341
+ def reindex(args)
342
+ params = {}
343
+ options = {}
344
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
345
+ opts.banner = opts.banner = subcommand_usage()
346
+ build_standard_update_options(opts, options, [:auto_confirm], [:payload, :options])
347
+ opts.footer = "Reindex all search data."
348
+ end
349
+ optparse.parse!(args)
350
+ connect(options)
351
+ verify_args!(args:args, optparse:optparse, count:0)
352
+ confirm!("Are you sure you would like reindex all search data?", options)
353
+ @appliance_settings_interface.setopts(options)
354
+ if options[:dry_run]
355
+ print_dry_run @appliance_settings_interface.dry.reindex(params)
356
+ return
357
+ end
358
+ json_response = @appliance_settings_interface.reindex(params)
359
+ render_response(json_response, options) do
360
+ print_green_success "Reindexing all search data..."
361
+ end
362
+ return 0, nil
363
+ end
364
+
310
365
  private
311
366
 
312
367
  def format_days(days)
@@ -2260,7 +2260,7 @@ EOT
2260
2260
  build_option_type_options(opts, options, update_wiki_page_option_types)
2261
2261
  opts.on('--file FILE', "File containing the wiki content. This can be used instead of --content") do |filename|
2262
2262
  full_filename = File.expand_path(filename)
2263
- if File.exists?(full_filename)
2263
+ if File.exist?(full_filename)
2264
2264
  params['content'] = File.read(full_filename)
2265
2265
  else
2266
2266
  print_red_alert "File not found: #{full_filename}"