morpheus-cli 5.5.2.2 → 5.5.3.1

Sign up to get free protection for your applications and to get access to all the features.
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