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
@@ -760,7 +760,7 @@ EOT
760
760
  options[:config_file] = val.to_s
761
761
  file_content = nil
762
762
  full_filename = File.expand_path(options[:config_file])
763
- if File.exists?(full_filename)
763
+ if File.exist?(full_filename)
764
764
  file_content = File.read(full_filename)
765
765
  else
766
766
  print_red_alert "File not found: #{full_filename}"
@@ -770,7 +770,7 @@ EOT
770
770
  config_map = parse_result[:data]
771
771
  if config_map.nil?
772
772
  # todo: bubble up JSON.parse error message
773
- raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
773
+ raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
774
774
  #raise_command_error "Failed to parse config as valid YAML or JSON."
775
775
  else
776
776
  params['config'] = config_map
@@ -813,7 +813,7 @@ EOT
813
813
  # config_map = parse_result[:data]
814
814
  # if config_map.nil?
815
815
  # # todo: bubble up JSON.parse error message
816
- # raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
816
+ # raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
817
817
  # #raise_command_error "Failed to parse config as valid YAML or JSON."
818
818
  # else
819
819
  # params['config'] = config_map
@@ -1065,26 +1065,28 @@ EOT
1065
1065
  return 1, "integration inventory not found for #{args[1]}" if integration_inventory.nil?
1066
1066
  # construct payload
1067
1067
  object_key = integration_inventory_object_key
1068
- payload = build_payload(options, object_key)
1069
- if options[:tenants]
1070
- #params['tenants'] = options[:tenants]
1071
- params['tenants'] = options[:tenants].collect do |val|
1072
- if val.to_s =~ /\A\d{1,}\Z/
1073
- val.to_i
1074
- else
1075
- # todo: use /api/options/allTenants to avoid permission errors here..
1076
- record = find_by_name_or_id(:account, val)
1077
- if record.nil?
1078
- exit 1 #return 1, "Tenant not found by '#{val}'"
1079
- else
1080
- record['id']
1068
+ payload = parse_payload(options, object_key)
1069
+ if payload.nil?
1070
+ if options[:tenants]
1071
+ #params['tenants'] = options[:tenants]
1072
+ params['tenants'] = options[:tenants].collect do |val|
1073
+ if val.to_s =~ /\A\d{1,}\Z/
1074
+ val.to_i
1075
+ else
1076
+ # todo: use /api/options/allTenants to avoid permission errors here..
1077
+ record = find_by_name_or_id(:account, val)
1078
+ if record.nil?
1079
+ exit 1 #return 1, "Tenant not found by '#{val}'"
1080
+ else
1081
+ record['id']
1082
+ end
1081
1083
  end
1082
1084
  end
1083
1085
  end
1084
- end
1085
- payload.deep_merge!({object_key => params})
1086
- if payload.empty? || payload[object_key].empty?
1087
- raise_command_error "Specify at least one option to update.\n#{optparse}"
1086
+ payload.deep_merge!({object_key => params})
1087
+ if payload.empty? || payload[object_key].empty?
1088
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
1089
+ end
1088
1090
  end
1089
1091
  # make request
1090
1092
  @integrations_interface.setopts(options)
@@ -146,7 +146,7 @@ class Morpheus::Cli::KeyPairs
146
146
  optparse = Morpheus::Cli::OptionParser.new do |opts|
147
147
  opts.banner = subcommand_usage("[name] [options]")
148
148
  opts.on('', '--public-key-file FILENAME', "Public Key File" ) do |filename|
149
- if File.exists?(File.expand_path(filename))
149
+ if File.exist?(File.expand_path(filename))
150
150
  options['publicKey'] = File.read(File.expand_path(filename))
151
151
  options[:options] ||= {}
152
152
  options[:options]['publicKey'] = options['publicKey']
@@ -163,7 +163,7 @@ class Morpheus::Cli::KeyPairs
163
163
  end
164
164
 
165
165
  opts.on('', '--private-key-file FILENAME', "Private Key File" ) do |filename|
166
- if File.exists?(File.expand_path(filename))
166
+ if File.exist?(File.expand_path(filename))
167
167
  options['privateKey'] = File.read(File.expand_path(filename))
168
168
  options[:options] ||= {}
169
169
  options[:options]['privateKey'] = options['privateKey']
@@ -172,7 +172,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
172
172
  end
173
173
  opts.on('--file FILE', "File containing the script. This can be used instead of --script" ) do |filename|
174
174
  full_filename = File.expand_path(filename)
175
- if File.exists?(full_filename)
175
+ if File.exist?(full_filename)
176
176
  params['script'] = File.read(full_filename)
177
177
  else
178
178
  print_red_alert "File not found: #{full_filename}"
@@ -266,7 +266,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
266
266
  end
267
267
  opts.on('--file FILE', "File containing the script. This can be used instead of --script" ) do |filename|
268
268
  full_filename = File.expand_path(filename)
269
- if File.exists?(full_filename)
269
+ if File.exist?(full_filename)
270
270
  params['script'] = File.read(full_filename)
271
271
  else
272
272
  print_red_alert "File not found: #{full_filename}"
@@ -195,7 +195,7 @@ class Morpheus::Cli::LibraryContainerTemplatesCommand
195
195
  end
196
196
  opts.on('--file FILE', "File containing the template. This can be used instead of --template" ) do |filename|
197
197
  full_filename = File.expand_path(filename)
198
- if File.exists?(full_filename)
198
+ if File.exist?(full_filename)
199
199
  params['template'] = File.read(full_filename)
200
200
  else
201
201
  print_red_alert "File not found: #{full_filename}"
@@ -312,7 +312,7 @@ class Morpheus::Cli::LibraryContainerTemplatesCommand
312
312
  end
313
313
  opts.on('--file FILE', "File containing the template. This can be used instead of --template" ) do |filename|
314
314
  full_filename = File.expand_path(filename)
315
- if File.exists?(full_filename)
315
+ if File.exist?(full_filename)
316
316
  params['template'] = File.read(full_filename)
317
317
  else
318
318
  print_red_alert "File not found: #{full_filename}"
@@ -306,7 +306,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
306
306
  params.deep_merge!(v_prompt)
307
307
  if params['logo']
308
308
  filename = File.expand_path(params['logo'])
309
- if !File.exists?(filename)
309
+ if !File.exist?(filename)
310
310
  print_red_alert "File not found: #{filename}"
311
311
  exit 1
312
312
  end
@@ -523,7 +523,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
523
523
  logo_file = 'null' # clear it
524
524
  else
525
525
  filename = File.expand_path(filename)
526
- if !File.exists?(filename)
526
+ if !File.exist?(filename)
527
527
  print_red_alert "File not found: #{filename}"
528
528
  exit 1
529
529
  end
@@ -571,7 +571,7 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
571
571
  dark_logo_file = 'null' # clear it
572
572
  else
573
573
  filename = File.expand_path(filename)
574
- if !File.exists?(filename)
574
+ if !File.exist?(filename)
575
575
  print_red_alert "File not found: #{filename}"
576
576
  exit 1
577
577
  end
@@ -207,7 +207,7 @@ class Morpheus::Cli::LibrarySpecTemplatesCommand
207
207
  opts.on('--file FILE', "File containing the template. This can be used instead of --content" ) do |filename|
208
208
  file_params['sourceType'] = 'local' if file_params['sourceType'].nil?
209
209
  full_filename = File.expand_path(filename)
210
- if File.exists?(full_filename)
210
+ if File.exist?(full_filename)
211
211
  file_params['content'] = File.read(full_filename)
212
212
  else
213
213
  print_red_alert "File not found: #{full_filename}"
@@ -363,7 +363,7 @@ class Morpheus::Cli::LibrarySpecTemplatesCommand
363
363
  opts.on('--file FILE', "File containing the template. This can be used instead of --content" ) do |filename|
364
364
  file_params['sourceType'] = 'local' if file_params['sourceType'].nil?
365
365
  full_filename = File.expand_path(filename)
366
- if File.exists?(full_filename)
366
+ if File.exist?(full_filename)
367
367
  file_params['content'] = File.read(full_filename)
368
368
  else
369
369
  print_red_alert "File not found: #{full_filename}"
@@ -78,7 +78,7 @@ class Morpheus::Cli::LogSettingsCommand
78
78
  print cyan
79
79
  print as_pretty_table(log_settings['integrations'], [:name, :enabled, :host, :port])
80
80
  end
81
- print reset "\n"
81
+ print reset, "\n"
82
82
  return 0
83
83
  rescue RestClient::Exception => e
84
84
  print_rest_exception(e, options)
@@ -33,7 +33,7 @@ class Morpheus::Cli::Login
33
33
  end
34
34
  opts.on( '--password-file FILE', String, "Password File, read a file containing the password." ) do |val|
35
35
  password_file = File.expand_path(val)
36
- if !File.exists?(password_file) || !File.file?(password_file) # check readable too
36
+ if !File.exist?(password_file) || !File.file?(password_file) # check readable too
37
37
  raise ::OptionParser::InvalidOption.new("File not found: #{password_file}")
38
38
  end
39
39
  password = File.read(password_file) #.to_s.split("\n").first.strip
@@ -8,12 +8,24 @@ class Morpheus::Cli::ManCommand
8
8
  # this should be read only anyway...
9
9
  @@default_editor = "less" # ENV['EDITOR']
10
10
 
11
+ def self.man_file_path
12
+ File.join(Morpheus::Cli.home_directory, "CLI-Manual-#{Morpheus::Cli::VERSION}.md")
13
+ end
14
+
11
15
  def handle(args)
12
16
  options = {}
13
17
  regenerate = false
14
- editor = @@default_editor
15
18
  open_as_link = false # true please
16
19
  goto_wiki = false
20
+ editor = @@default_editor
21
+ #todo: windows
22
+ if !$stdin.tty?
23
+ editor = "cat"
24
+ end
25
+ # no editor for windows atm
26
+ if Morpheus::Cli.windows?
27
+ open_as_link = true
28
+ end
17
29
  optparse = Morpheus::Cli::OptionParser.new do|opts|
18
30
  opts.banner = "Usage: morpheus man"
19
31
  opts.on('-w','--wiki', "Open the morpheus-cli wiki instead of the local man page") do
@@ -81,16 +93,16 @@ EOT
81
93
  print_error "#{red}It is the name of an existing directory.#{reset}\n"
82
94
  return 1
83
95
  end
84
- if File.exists?(fn) && options[:overwrite] != true
96
+ if File.exist?(fn) && options[:overwrite] != true
85
97
  print_error "#{red}Output file '#{fn}' already exists.#{reset}\n"
86
98
  print_error "#{red}Use --overwrite to overwrite the existing file.#{reset}\n"
87
99
  return 1
88
100
  end
89
101
  end
90
102
  exit_code, err = 0, nil
91
- if regenerate || !File.exists?(fn)
103
+ if regenerate || !File.exist?(fn)
92
104
  #Morpheus::Logging::DarkPrinter.puts "generating manual #{fn} ..." if Morpheus::Logging.debug? && !options[:quiet]
93
- exit_code, err = Morpheus::Cli::ManCommand.generate_manual(options)
105
+ exit_code, err = generate_manual(options)
94
106
  end
95
107
 
96
108
  if options[:quiet]
@@ -99,7 +111,7 @@ EOT
99
111
 
100
112
  Morpheus::Logging::DarkPrinter.puts "opening manual file #{fn}" if Morpheus::Logging.debug? && !options[:quiet]
101
113
 
102
- if open_as_link # not used atm
114
+ if open_as_link # windows only atm
103
115
  link = "file://#{fn}"
104
116
  if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
105
117
  system "start #{link}"
@@ -142,13 +154,9 @@ EOT
142
154
  return has_it
143
155
  end
144
156
 
145
- def self.man_file_path
146
- File.join(Morpheus::Cli.home_directory, "CLI-Manual-#{Morpheus::Cli::VERSION}.md")
147
- end
148
-
149
157
  # def self.save_manual(fn, content)
150
- # # fn = man_file_path()
151
- # if !Dir.exists?(File.dirname(fn))
158
+ # # fn = Morpheus::Cli::ManCommand.man_file_path
159
+ # if !Dir.exist?(File.dirname(fn))
152
160
  # FileUtils.mkdir_p(File.dirname(fn))
153
161
  # end
154
162
  # Morpheus::Logging::DarkPrinter.puts "saving manual to #{fn}" if Morpheus::Logging.debug?
@@ -156,19 +164,19 @@ EOT
156
164
  # FileUtils.chmod(0600, fn)
157
165
  # end
158
166
 
159
- def self.generate_manual(options={})
167
+ def generate_manual(options={})
160
168
  # todo: use pandoc or something else to convert the CLI-Manual.md to a man page
161
169
  # and install it, so the os command `man morpheus` will work too.
162
- fn = man_file_path()
170
+ fn = Morpheus::Cli::ManCommand.man_file_path
163
171
  if options[:outfile]
164
172
  fn = File.expand_path(options[:outfile])
165
- if File.exists?(fn) && options[:overwrite] != true
173
+ if File.exist?(fn) && options[:overwrite] != true
166
174
  print_error "#{red}Output file '#{options[:outfile]}' already exists.#{reset}\n"
167
175
  print_error "#{red}Use --overwrite to overwrite the existing file.#{reset}\n"
168
176
  return 1, "output file already exists"
169
177
  end
170
178
  end
171
- if !Dir.exists?(File.dirname(fn))
179
+ if !Dir.exist?(File.dirname(fn))
172
180
  FileUtils.mkdir_p(File.dirname(fn))
173
181
  end
174
182
  Morpheus::Logging::DarkPrinter.puts "generating manual #{fn}" if Morpheus::Logging.debug? && !options[:quiet]
@@ -202,7 +210,7 @@ EOT
202
210
 
203
211
  Use the command `#{prog_name} remote add` to connect to your Morpheus appliance.
204
212
 
205
- To learn more, visit https://github.com/gomorpheus/morpheus-cli/wiki/Getting-Started
213
+ To learn more, visit https://clidocs.morpheusdata.com
206
214
 
207
215
  To learn more about the Morpheus Appliance, visit https://www.morpheusdata.com
208
216
 
@@ -254,7 +262,11 @@ EOT
254
262
  The available commands and their options are documented below.
255
263
  ENDTEXT
256
264
 
257
- terminal = Morpheus::Terminal.new($stdin, manpage)
265
+
266
+ #terminal = Morpheus::Terminal.new($stdin, manpage)
267
+ terminal = my_terminal
268
+ terminal.with_stdout(manpage) do
269
+
258
270
  Morpheus::Logging::DarkPrinter.puts "appending command help `#{prog_name} --help`" if Morpheus::Logging.debug? && !options[:quiet]
259
271
 
260
272
  manpage.print "\n"
@@ -406,12 +418,14 @@ echo
406
418
  ```
407
419
 
408
420
  ENDTEXT
421
+
422
+ end # end with_stdout(manpage)
409
423
 
410
424
  ensure
411
425
  manpage.close if manpage
412
426
  # $stdout = previous_stdout if previous_stdout
413
427
  # this is needed to re-establish instance with STDOUT, STDIN
414
- terminal = Morpheus::Terminal.new()
428
+ #terminal = Morpheus::Terminal.new()
415
429
  end
416
430
 
417
431
  return 0, nil
@@ -0,0 +1,228 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::MonitoringSettings
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::AccountsHelper
6
+
7
+ set_command_name :'monitor-settings'
8
+ set_command_description "View and manage monitoring settings"
9
+ register_subcommands :get, :update
10
+
11
+ def connect(opts)
12
+ @api_client = establish_remote_appliance_connection(opts)
13
+ @monitoring_settings_interface = @api_client.monitoring_settings
14
+ @options_interface = @api_client.options
15
+ end
16
+
17
+ def handle(args)
18
+ handle_subcommand(args)
19
+ end
20
+
21
+ def get(args)
22
+ params = {}
23
+ options = {}
24
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
25
+ opts.banner = subcommand_usage()
26
+ build_standard_get_options(opts, options)
27
+ opts.footer = "Get monitoring settings."
28
+ end
29
+ optparse.parse!(args)
30
+ connect(options)
31
+ verify_args!(args:args, optparse:optparse, count:0)
32
+ params.merge!(parse_query_options(options))
33
+ @monitoring_settings_interface.setopts(options)
34
+ if options[:dry_run]
35
+ print_dry_run @monitoring_settings_interface.dry.get(options)
36
+ return
37
+ end
38
+ json_response = @monitoring_settings_interface.get(options)
39
+ render_response(json_response, options, 'monitoringSettings') do
40
+ monitoring_settings = json_response['monitoringSettings']
41
+ service_now_settings = monitoring_settings['serviceNow']
42
+ new_relic_settings = monitoring_settings['newRelic']
43
+ print_h1 "Monitoring Settings"
44
+ print cyan
45
+ description_cols = {
46
+ "Auto Create Checks" => lambda {|it| format_boolean(it['autoManageChecks']) },
47
+ "Availability Time Frame" => lambda {|it| it['availabilityTimeFrame'] ? it['availabilityTimeFrame'].to_s + ' days' : '' },
48
+ "Availability Precision" => lambda {|it| it['availabilityPrecision'] ? it['availabilityPrecision'].to_s : '' },
49
+ "Default Check Interval" => lambda {|it| it['defaultCheckInterval'] ? it['defaultCheckInterval'].to_s + ' minutes' : '' },
50
+ }
51
+ print_description_list(description_cols, monitoring_settings, options)
52
+
53
+ print_h2 "ServiceNow Settings", options.merge(:border_style => :thin)
54
+ description_cols = {
55
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
56
+ "Integration" => lambda {|it| it['integration'] ? it['integration']['name'] : '' },
57
+ "New Incident Action" => lambda {|it| format_service_now_action(it['newIncidentAction']) },
58
+ "Close Incident Action" => lambda {|it| format_service_now_action(it['closeIncidentAction']) },
59
+ "Info Mapping" => lambda {|it| format_service_now_mapping(it['infoMapping']) },
60
+ "Warning Mapping" => lambda {|it| format_service_now_mapping(it['warningMapping']) },
61
+ "Critical Mapping" => lambda {|it| format_service_now_mapping(it['criticalMapping']) },
62
+ }
63
+ print_description_list(description_cols, service_now_settings)
64
+
65
+ print_h2 "New Relic Settings", options.merge(:border_style => :thin)
66
+ description_cols = {
67
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
68
+ "License Key" => lambda {|it| it['licenseKey'] },
69
+ }
70
+ print_description_list(description_cols, new_relic_settings, options)
71
+
72
+ print reset, "\n"
73
+ end
74
+ return 0, nil
75
+ end
76
+
77
+ def update(args)
78
+ params = {}
79
+ options = {}
80
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
81
+ opts.banner = opts.banner = subcommand_usage()
82
+ opts.on('--auto-create-checks [on|off]', String, "Auto Create Checks") do |val|
83
+ params['autoManageChecks'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
84
+ end
85
+ opts.on("--availability-time-frame DAYS", Integer, "Availability Time Frame. The number of days availability should be calculated for. Changes will not take effect until your checks have passed their check interval.") do |val|
86
+ params['availabilityTimeFrame'] = val.to_i
87
+ end
88
+ opts.on("--availability-precision DIGITS", Integer, "Availability Precision. The number of decimal places availability should be displayed in. Can be anywhere between 0 and 5.") do |val|
89
+ params['availabilityPrecision'] = val.to_i
90
+ end
91
+ opts.on("--default-check-interval MINUTES", Integer, "Default Check Interval. The default interval to use when creating new checks. Value is in minutes.") do |val|
92
+ params['defaultCheckInterval'] = val.to_i
93
+ end
94
+ opts.on('--service-now-enabled [on|off]', String, "ServiceNow: Enabled (on) or disabled (off)") do |val|
95
+ params['serviceNow'] ||= {}
96
+ params['serviceNow']['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
97
+ end
98
+ opts.on('--service-now-integration ID', String, "ServiceNow: Integration ID or Name") do |val|
99
+ params['serviceNow'] ||= {}
100
+ params['serviceNow']['integration'] = val # {'id' => val.to_i}
101
+ end
102
+ opts.on("--service-now-new-incident-action create|none", String, "ServiceNow: New Incident Action") do |val|
103
+ # allowed_values = 'create|none'.split('|') #get_service_now_actions().keys
104
+ # if !allowed_values.include?(val)
105
+ # raise ::OptionParser::InvalidOption.new("New Incident Action value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
106
+ # end
107
+ params['serviceNow'] ||= {}
108
+ params['serviceNow']['newIncidentAction'] = val
109
+ end
110
+ opts.on("--service-now-close-incident-action close|activity|none", String, "ServiceNow: Close Incident Action") do |val|
111
+ # allowed_values = 'close|activity|none'.split('|') #get_service_now_mappings().keys
112
+ # if !allowed_values.include?(val)
113
+ # raise ::OptionParser::InvalidOption.new("Close Incident Action value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
114
+ # end
115
+ params['serviceNow'] ||= {}
116
+ params['serviceNow']['closeIncidentAction'] = val
117
+ end
118
+ opts.on("--service-now-info-mapping low|medium|high", String, "ServiceNow: Info Mapping") do |val|
119
+ # allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
120
+ # if !allowed_values.include?(val)
121
+ # raise ::OptionParser::InvalidOption.new("Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
122
+ # end
123
+ params['serviceNow'] ||= {}
124
+ params['serviceNow']['infoMapping'] = val
125
+ end
126
+ opts.on("--service-now-warning-mapping low|medium|high", String, "ServiceNow: Warning Mapping") do |val|
127
+ # allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
128
+ # if !allowed_values.include?(val)
129
+ # raise ::OptionParser::InvalidOption.new("Warning Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
130
+ # end
131
+ params['serviceNow'] ||= {}
132
+ params['serviceNow']['warningMapping'] = val
133
+ end
134
+ opts.on("--service-now-critical-mapping low|medium|high", String, "ServiceNow: Critical Mapping") do |val|
135
+ # allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
136
+ # if !allowed_values.include?(val)
137
+ # raise ::OptionParser::InvalidOption.new("Critical Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
138
+ # end
139
+ params['serviceNow'] ||= {}
140
+ params['serviceNow']['criticalMapping'] = val
141
+ end
142
+ opts.on('--new-relic-enabled [on|off]', String, "New Relic: Enabled (on) or disabled (off)") do |val|
143
+ params['newRelic'] ||= {}
144
+ params['newRelic']['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
145
+ end
146
+ opts.on("--new-relic-license-key [VALUE]", String, "New Relic: License Key") do |val|
147
+ params['newRelic'] ||= {}
148
+ params['newRelic']['licenseKey'] = val
149
+ end
150
+ build_standard_update_options(opts, options)
151
+ opts.footer = "Update monitoring settings."
152
+ end
153
+ optparse.parse!(args)
154
+ connect(options)
155
+ verify_args!(args:args, optparse:optparse, count:0)
156
+ payload = parse_payload(options)
157
+ if !payload
158
+ payload = {}
159
+ payload.deep_merge!({object_key => parse_passed_options(options)}) # inject options passed with -O foo=bar
160
+ if params['serviceNow'] && params['serviceNow']['integration']
161
+ integration = find_by_name_or_id(:integration, params['serviceNow']['integration'])
162
+ if integration.nil?
163
+ exit 1 #return 1, "Integration not found by '#{options[:servicenow_integration]}'"
164
+ else
165
+ if integration['integrationType']['code'] != 'serviceNow'
166
+ raise_command_error "Integration '#{integration['id']}' must be a Service Now integration"
167
+ end
168
+ params['serviceNow'] ||= {}
169
+ params['serviceNow']['integration'] = {'id' => integration['id'].to_i}
170
+ end
171
+ end
172
+ payload.deep_merge!({object_key => params})
173
+ end
174
+ if payload[object_key].empty?
175
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
176
+ end
177
+ @monitoring_settings_interface.setopts(options)
178
+ if options[:dry_run]
179
+ print_dry_run @monitoring_settings_interface.dry.update(payload)
180
+ return
181
+ end
182
+ json_response = @monitoring_settings_interface.update(payload)
183
+ exit_code, err = 0, nil
184
+ render_response(json_response, options, object_key) do
185
+ if json_response['success']
186
+ print_green_success "Updated monitoring settings"
187
+ get([] + (options[:remote] ? ["-r",options[:remote]] : []))
188
+ else
189
+ exit_code, err = 1, "Error updating monitoring settings: #{json_response['msg'] || json_response['errors']}"
190
+ print_rest_errors(json_response)
191
+ end
192
+ end
193
+ return exit_code, err
194
+ end
195
+
196
+ private
197
+
198
+ def get_service_now_actions()
199
+ {
200
+ 'create' => 'Create new incident in ServiceNow',
201
+ 'close' => 'Resolve Incident in ServiceNow',
202
+ 'activity' => 'Add Activity to Incident in ServiceNow',
203
+ 'none' => 'No action',
204
+ }
205
+ end
206
+
207
+ def format_service_now_action(action_value)
208
+ get_service_now_actions()[action_value].to_s
209
+ end
210
+
211
+ def get_service_now_mappings()
212
+ {
213
+ 'low' => 'Low',
214
+ 'medium' => 'Medium',
215
+ 'high' => 'High',
216
+ }
217
+ end
218
+
219
+ def format_service_now_mapping(mapping_value)
220
+ get_service_now_mappings()[mapping_value].to_s
221
+ end
222
+
223
+
224
+ def object_key
225
+ 'monitoringSettings'
226
+ end
227
+
228
+ end