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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Dockerfile +1 -1
- data/README.md +57 -4
- data/Rakefile +9 -0
- data/bin/morpheus +4 -4
- data/lib/morpheus/api/api_client.rb +20 -2
- data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
- data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
- data/lib/morpheus/api/archive_files_interface.rb +3 -3
- data/lib/morpheus/api/clients_interface.rb +2 -2
- data/lib/morpheus/api/clusters_interface.rb +8 -1
- data/lib/morpheus/api/containers_interface.rb +29 -16
- data/lib/morpheus/api/custom_instance_types_interface.rb +0 -2
- data/lib/morpheus/api/cypher_interface.rb +1 -2
- data/lib/morpheus/api/doc_interface.rb +8 -6
- data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
- data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
- data/lib/morpheus/api/health_interface.rb +1 -1
- data/lib/morpheus/api/image_builder_interface.rb +3 -3
- data/lib/morpheus/api/instances_interface.rb +25 -0
- data/lib/morpheus/api/logs_interface.rb +2 -4
- data/lib/morpheus/api/monitoring_interface.rb +6 -6
- data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
- data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
- data/lib/morpheus/api/packages_interface.rb +1 -1
- data/lib/morpheus/api/reports_interface.rb +1 -1
- data/lib/morpheus/api/servers_interface.rb +9 -1
- data/lib/morpheus/api/storage_providers_interface.rb +2 -2
- data/lib/morpheus/api/virtual_images_interface.rb +1 -1
- data/lib/morpheus/api.rb +2 -0
- data/lib/morpheus/benchmarking.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +79 -37
- data/lib/morpheus/cli/cli_registry.rb +19 -10
- data/lib/morpheus/cli/commands/access_token_command.rb +1 -1
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/archives_command.rb +25 -33
- data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/blueprints_command.rb +10 -21
- data/lib/morpheus/cli/commands/boot_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/cat_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +18 -13
- data/lib/morpheus/cli/commands/clouds.rb +3 -3
- data/lib/morpheus/cli/commands/clusters.rb +154 -3
- data/lib/morpheus/cli/commands/containers_command.rb +398 -253
- data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
- data/lib/morpheus/cli/commands/deployments.rb +1 -1
- data/lib/morpheus/cli/commands/deploys.rb +9 -9
- data/lib/morpheus/cli/commands/doc.rb +15 -16
- data/lib/morpheus/cli/commands/execution_request_command.rb +2 -2
- data/lib/morpheus/cli/commands/file_copy_request_command.rb +5 -5
- data/lib/morpheus/cli/commands/groups.rb +2 -2
- data/lib/morpheus/cli/commands/guidance_command.rb +2 -2
- data/lib/morpheus/cli/commands/guidance_settings.rb +148 -0
- data/lib/morpheus/cli/commands/health_command.rb +4 -4
- data/lib/morpheus/cli/commands/hosts.rb +43 -5
- data/lib/morpheus/cli/commands/image_builder_command.rb +1 -1
- data/lib/morpheus/cli/commands/instances.rb +419 -148
- data/lib/morpheus/cli/commands/integrations_command.rb +22 -20
- data/lib/morpheus/cli/commands/key_pairs.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -3
- data/lib/morpheus/cli/commands/library_spec_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/login.rb +1 -1
- data/lib/morpheus/cli/commands/man_command.rb +32 -18
- data/lib/morpheus/cli/commands/monitoring_settings.rb +228 -0
- data/lib/morpheus/cli/commands/network_server_groups_command.rb +222 -0
- data/lib/morpheus/cli/commands/packages_command.rb +11 -11
- data/lib/morpheus/cli/commands/plugins.rb +1 -1
- data/lib/morpheus/cli/commands/policies_command.rb +4 -4
- data/lib/morpheus/cli/commands/preseed_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/remote.rb +1 -1
- data/lib/morpheus/cli/commands/reports_command.rb +13 -3
- data/lib/morpheus/cli/commands/security_groups.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +40 -62
- data/lib/morpheus/cli/commands/snapshots.rb +3 -5
- data/lib/morpheus/cli/commands/source_command.rb +8 -16
- data/lib/morpheus/cli/commands/storage_providers_command.rb +7 -7
- data/lib/morpheus/cli/commands/tasks.rb +2 -2
- data/lib/morpheus/cli/commands/vdi_pools_command.rb +6 -6
- data/lib/morpheus/cli/commands/view.rb +5 -1
- data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +5 -5
- data/lib/morpheus/cli/commands/whoami.rb +2 -2
- data/lib/morpheus/cli/credentials.rb +30 -8
- data/lib/morpheus/cli/dot_file.rb +8 -15
- data/lib/morpheus/cli/error_handler.rb +16 -0
- data/lib/morpheus/cli/errors.rb +8 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +17 -13
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
- data/lib/morpheus/cli/mixins/rest_command.rb +23 -19
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +47 -24
- data/lib/morpheus/cli/option_parser.rb +5 -1
- data/lib/morpheus/cli/option_types.rb +59 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +26 -16
- data/lib/morpheus/ext/rest_client.rb +3 -2
- data/lib/morpheus/ext/string.rb +6 -4
- data/lib/morpheus/formatters.rb +1 -1
- data/lib/morpheus/logging.rb +4 -4
- data/lib/morpheus/morpkg.rb +4 -4
- data/lib/morpheus/rest_client.rb +2 -2
- data/lib/morpheus/routes.rb +41 -9
- data/lib/morpheus/terminal.rb +65 -16
- data/lib/morpheus.rb +1 -1
- data/morpheus-cli.gemspec +1 -0
- data/test/api/containers_interface_test.rb +68 -0
- data/test/api/doc_interface_test.rb +35 -0
- data/test/api/instances_interface_test.rb +22 -0
- data/test/api/whoami_interface_test.rb +14 -0
- data/test/cli/access_token_test.rb +36 -0
- data/test/cli/auth_test.rb +82 -0
- data/test/cli/cli_test.rb +48 -0
- data/test/cli/containers_test.rb +92 -0
- data/test/cli/doc_test.rb +35 -0
- data/test/cli/help_test.rb +25 -0
- data/test/cli/instances_test.rb +36 -0
- data/test/cli/man_test.rb +14 -0
- data/test/cli/remote_test.rb +89 -0
- data/test/cli/roles_test.rb +34 -0
- data/test/cli/shell_test.rb +81 -0
- data/test/cli/version_test.rb +23 -0
- data/test/cli/view_test.rb +55 -0
- data/test/cli/whoami_test.rb +17 -0
- data/test/morpheus_test.rb +16 -0
- data/test/test_case.rb +338 -0
- data/test/test_config.rb +137 -0
- data/test/test_data_helper.rb +97 -0
- 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.
|
|
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[:
|
|
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[:
|
|
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 =
|
|
1069
|
-
if
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
val.
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
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
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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 #
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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://
|
|
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
|
-
|
|
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
|