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.
- 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
@@ -110,6 +110,13 @@ class Morpheus::Cli::Shell
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def handle(args)
|
113
|
+
@clean_shell_mode = false
|
114
|
+
@execute_mode = false
|
115
|
+
@execute_mode_command = nil
|
116
|
+
@norc = false
|
117
|
+
@temporary_shell_mode = false
|
118
|
+
@temporary_home_directory = nil
|
119
|
+
@original_home_directory = nil
|
113
120
|
usage = "Usage: morpheus #{command_name}"
|
114
121
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
115
122
|
opts.banner = usage
|
@@ -159,9 +166,7 @@ class Morpheus::Cli::Shell
|
|
159
166
|
@parent_shell_directories ||= []
|
160
167
|
@parent_shell_directories << my_terminal.home_directory
|
161
168
|
@previous_home_directory = @parent_shell_directories.last
|
162
|
-
|
163
|
-
@original_home_directory = @previous_home_directory
|
164
|
-
end
|
169
|
+
@original_home_directory ||= @previous_home_directory
|
165
170
|
|
166
171
|
#@norc = true # perhaps?
|
167
172
|
# instead of using TMPDIR, create tmp shell directory inside $MORPHEUS_CLI_HOME/tmp
|
@@ -171,18 +176,18 @@ class Morpheus::Cli::Shell
|
|
171
176
|
if !tmpdir
|
172
177
|
tmpdir = File.join(@original_home_directory, "tmp")
|
173
178
|
end
|
174
|
-
if !File.
|
179
|
+
if !File.exist?(tmpdir)
|
175
180
|
# Morpheus::Logging::DarkPrinter.puts "creating tmpdir #{tmpdir}" if Morpheus::Logging.debug?
|
176
181
|
FileUtils.mkdir_p(tmpdir)
|
177
182
|
end
|
178
183
|
# this won't not happen since we mkdir above
|
179
|
-
if !File.
|
184
|
+
if !File.exist?(tmpdir)
|
180
185
|
raise_command_error "Temporary directory not found. Use environment variable MORPHEUS_CLI_TMPDIR"
|
181
186
|
end
|
182
187
|
# change to a temporary home directory
|
183
188
|
@temporary_home_directory = File.join(tmpdir, "tmpshell-#{rand().to_s[2..7]}")
|
184
189
|
|
185
|
-
#if !File.
|
190
|
+
#if !File.exist?(@temporary_home_directory)
|
186
191
|
Morpheus::Logging::DarkPrinter.puts "starting temporary shell at #{@temporary_home_directory}" if Morpheus::Logging.debug?
|
187
192
|
FileUtils.mkdir_p(@temporary_home_directory)
|
188
193
|
# end
|
@@ -209,21 +214,21 @@ class Morpheus::Cli::Shell
|
|
209
214
|
# not just in shell
|
210
215
|
# .morpheus_profile has aliases
|
211
216
|
# this has already been loaded, probably should reload it...
|
212
|
-
if File.
|
217
|
+
if File.exist?(File.join(@previous_home_directory, ".morpheus_profile"))
|
213
218
|
FileUtils.cp(File.join(@previous_home_directory, ".morpheus_profile"), File.join(@temporary_home_directory, ".morpheus_profile"))
|
214
219
|
end
|
215
220
|
if @norc != true
|
216
|
-
if File.
|
221
|
+
if File.exist?(File.join(@previous_home_directory, ".morpheusrc"))
|
217
222
|
FileUtils.cp(File.join(@previous_home_directory, ".morpheusrc"), File.join(@temporary_home_directory, ".morpheusrc"))
|
218
223
|
end
|
219
224
|
end
|
220
|
-
if File.
|
225
|
+
if File.exist?(File.join(@previous_home_directory, "appliances"))
|
221
226
|
FileUtils.cp(File.join(@previous_home_directory, "appliances"), File.join(@temporary_home_directory, "appliances"))
|
222
227
|
end
|
223
|
-
if File.
|
228
|
+
if File.exist?(File.join(@previous_home_directory, "credentials"))
|
224
229
|
FileUtils.cp(File.join(@previous_home_directory, "credentials"), File.join(@temporary_home_directory, "credentials"))
|
225
230
|
end
|
226
|
-
if File.
|
231
|
+
if File.exist?(File.join(@previous_home_directory, "groups"))
|
227
232
|
FileUtils.cp(File.join(@previous_home_directory, "groups"), File.join(@temporary_home_directory, "groups"))
|
228
233
|
end
|
229
234
|
# stay logged in
|
@@ -258,7 +263,7 @@ class Morpheus::Cli::Shell
|
|
258
263
|
|
259
264
|
# execute startup script
|
260
265
|
if !@norc
|
261
|
-
if File.
|
266
|
+
if File.exist?(Morpheus::Cli::DotFile.morpheusrc_filename)
|
262
267
|
@history_logger.info("load source #{Morpheus::Cli::DotFile.morpheusrc_filename}") if @history_logger
|
263
268
|
Morpheus::Cli::DotFile.new(Morpheus::Cli::DotFile.morpheusrc_filename).execute()
|
264
269
|
end
|
@@ -277,6 +282,8 @@ class Morpheus::Cli::Shell
|
|
277
282
|
result = 0
|
278
283
|
@exit_now_please = false
|
279
284
|
while !@exit_now_please do
|
285
|
+
#Readline.input = my_terminal.stdin
|
286
|
+
#Readline.input = $stdin
|
280
287
|
Readline.completion_append_character = " "
|
281
288
|
Readline.completion_proc = @auto_complete
|
282
289
|
Readline.basic_word_break_characters = ""
|
@@ -335,7 +342,6 @@ class Morpheus::Cli::Shell
|
|
335
342
|
if input[0..(prog_name.size)] == "#{prog_name} "
|
336
343
|
input = input[(prog_name.size + 1)..-1] || ""
|
337
344
|
end
|
338
|
-
|
339
345
|
if !input.empty?
|
340
346
|
|
341
347
|
if input == 'exit'
|
@@ -372,7 +378,7 @@ class Morpheus::Cli::Shell
|
|
372
378
|
out << "\t#{cmd.to_s}\n"
|
373
379
|
}
|
374
380
|
out << "\n"
|
375
|
-
out << "For more information, see https://
|
381
|
+
out << "For more information, see https://clidocs.morpheusdata.com"
|
376
382
|
out << "\n"
|
377
383
|
print out
|
378
384
|
return 0
|
@@ -386,12 +392,12 @@ class Morpheus::Cli::Shell
|
|
386
392
|
# clear registry
|
387
393
|
Morpheus::Cli::CliRegistry.instance.flush
|
388
394
|
# reload code
|
389
|
-
Morpheus::Cli.
|
395
|
+
Morpheus::Cli.reload!
|
390
396
|
# execute startup scripts
|
391
|
-
if File.
|
397
|
+
if File.exist?(Morpheus::Cli::DotFile.morpheus_profile_filename)
|
392
398
|
Morpheus::Cli::DotFile.new(Morpheus::Cli::DotFile.morpheus_profile_filename).execute()
|
393
399
|
end
|
394
|
-
if File.
|
400
|
+
if File.exist?(Morpheus::Cli::DotFile.morpheusrc_filename)
|
395
401
|
Morpheus::Cli::DotFile.new(Morpheus::Cli::DotFile.morpheusrc_filename).execute()
|
396
402
|
end
|
397
403
|
# recalculate shell environment
|
@@ -486,7 +492,11 @@ class Morpheus::Cli::Shell
|
|
486
492
|
rescue SystemExit => cmdexit
|
487
493
|
# nothing to do, assume the command that exited printed an error already
|
488
494
|
# print "\n"
|
489
|
-
|
495
|
+
if cmdexit.success?
|
496
|
+
exit_code, err = cmdexit.status, nil
|
497
|
+
else
|
498
|
+
exit_code, err = cmdexit.status, "Command exited early."
|
499
|
+
end
|
490
500
|
rescue => e
|
491
501
|
# some other type of failure..
|
492
502
|
@history_logger.error "#{e.message}" if @history_logger
|
@@ -514,6 +524,7 @@ class Morpheus::Cli::Shell
|
|
514
524
|
|
515
525
|
end
|
516
526
|
|
527
|
+
# wha this?
|
517
528
|
def get_prompt
|
518
529
|
|
519
530
|
# print cyan,"morpheus > ",reset
|
@@ -538,10 +549,10 @@ class Morpheus::Cli::Shell
|
|
538
549
|
|
539
550
|
def load_history_logger
|
540
551
|
file_path = history_file_path
|
541
|
-
if !Dir.
|
552
|
+
if !Dir.exist?(File.dirname(file_path))
|
542
553
|
FileUtils.mkdir_p(File.dirname(file_path))
|
543
554
|
end
|
544
|
-
if !File.
|
555
|
+
if !File.exist?(file_path)
|
545
556
|
FileUtils.touch(file_path)
|
546
557
|
FileUtils.chmod(0600, file_path)
|
547
558
|
end
|
@@ -561,7 +572,13 @@ class Morpheus::Cli::Shell
|
|
561
572
|
|
562
573
|
begin
|
563
574
|
file_path = history_file_path
|
564
|
-
|
575
|
+
# if !Dir.exist?(File.dirname(file_path))
|
576
|
+
# FileUtils.mkdir_p(File.dirname(file_path))
|
577
|
+
# end
|
578
|
+
# if !File.exist?(file_path)
|
579
|
+
# FileUtils.touch(file_path)
|
580
|
+
# FileUtils.chmod(0600, file_path)
|
581
|
+
# end
|
565
582
|
|
566
583
|
File.open(file_path).each_line do |line|
|
567
584
|
# this is pretty goofy, but this looks for the format: (cmd $command_number) $command_string
|
@@ -578,7 +595,7 @@ class Morpheus::Cli::Shell
|
|
578
595
|
# for Ctrl+R history searching
|
579
596
|
Readline::HISTORY << cmd
|
580
597
|
end
|
581
|
-
end
|
598
|
+
end unless !File.exist?(file_path)
|
582
599
|
rescue => e
|
583
600
|
# raise e
|
584
601
|
puts_error "failed to load history from log: #{e}"
|
@@ -587,45 +604,6 @@ class Morpheus::Cli::Shell
|
|
587
604
|
return @history
|
588
605
|
end
|
589
606
|
|
590
|
-
# remove this..
|
591
|
-
def _old_load_history_from_log_file(n_commands=1000)
|
592
|
-
@history ||= {}
|
593
|
-
@last_command_number ||= 0
|
594
|
-
|
595
|
-
begin
|
596
|
-
if Gem.win_platform?
|
597
|
-
return @history
|
598
|
-
end
|
599
|
-
file_path = history_file_path
|
600
|
-
FileUtils.mkdir_p(File.dirname(file_path))
|
601
|
-
# grab extra lines because not all log entries are commands
|
602
|
-
n_lines = n_commands + 500
|
603
|
-
history_lines = `tail -n #{n_lines} #{file_path}`.split(/\n/)
|
604
|
-
command_lines = history_lines.select do |line|
|
605
|
-
line.match(/\(cmd (\d+)\) (.+)/)
|
606
|
-
end
|
607
|
-
command_lines = command_lines.last(n_commands)
|
608
|
-
command_lines.each do |line|
|
609
|
-
matches = line.match(/\(cmd (\d+)\) (.+)/)
|
610
|
-
if matches && matches.size == 3
|
611
|
-
cmd_number = matches[1].to_i
|
612
|
-
cmd = matches[2]
|
613
|
-
|
614
|
-
@last_command_number = cmd_number
|
615
|
-
@history[@last_command_number] = cmd
|
616
|
-
|
617
|
-
# for Ctrl+R history searching
|
618
|
-
Readline::HISTORY << cmd
|
619
|
-
end
|
620
|
-
end
|
621
|
-
rescue => e
|
622
|
-
# raise e
|
623
|
-
# puts "failed to load history from log"
|
624
|
-
@history = {}
|
625
|
-
end
|
626
|
-
return @history
|
627
|
-
end
|
628
|
-
|
629
607
|
def log_history_command(cmd)
|
630
608
|
load_history_from_log_file if !@history
|
631
609
|
#todo: a fast log_history_command, that doesnt need to load the file..
|
@@ -745,7 +723,7 @@ class Morpheus::Cli::Shell
|
|
745
723
|
def flush_history(n=nil)
|
746
724
|
# todo: support only flushing last n commands
|
747
725
|
file_path = history_file_path
|
748
|
-
if File.
|
726
|
+
if File.exist?(file_path)
|
749
727
|
File.truncate(file_path, 0)
|
750
728
|
end
|
751
729
|
@history = {}
|
@@ -24,7 +24,7 @@ class Morpheus::Cli::Snapshots
|
|
24
24
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
25
25
|
opts.banner = subcommand_usage("[id]")
|
26
26
|
opts.footer = "Get Snapshot details." + "\n" +
|
27
|
-
"[
|
27
|
+
"[id] is required. This is the id of the snapshot."
|
28
28
|
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
29
29
|
end
|
30
30
|
optparse.parse!(args)
|
@@ -96,14 +96,12 @@ class Morpheus::Cli::Snapshots
|
|
96
96
|
|
97
97
|
def remove(args)
|
98
98
|
options = {}
|
99
|
-
instance = nil
|
100
99
|
snapshot_id = nil
|
101
|
-
|
102
100
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
103
|
-
opts.banner = subcommand_usage("[
|
101
|
+
opts.banner = subcommand_usage("[id]")
|
104
102
|
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
105
103
|
opts.footer = "Remove/Delete a snapshot." + "\n" +
|
106
|
-
"[
|
104
|
+
"[id] is required. This is the id of the snapshot to delete."
|
107
105
|
end
|
108
106
|
|
109
107
|
optparse.parse!(args)
|
@@ -7,7 +7,6 @@ class Morpheus::Cli::SourceCommand
|
|
7
7
|
set_command_hidden
|
8
8
|
|
9
9
|
def handle(args)
|
10
|
-
append_newline = true
|
11
10
|
options = {}
|
12
11
|
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
13
12
|
opts.banner = "Usage: morpheus #{command_name} [file] [file2]"
|
@@ -15,24 +14,17 @@ class Morpheus::Cli::SourceCommand
|
|
15
14
|
opts.footer = "This will execute a file as a script where each line is a morpheus command or expression."
|
16
15
|
end
|
17
16
|
optparse.parse!(args)
|
18
|
-
|
19
|
-
|
20
|
-
return false # exit 1
|
21
|
-
end
|
22
|
-
|
17
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
18
|
+
exit_code, err = 0, nil
|
23
19
|
source_files = args
|
20
|
+
bad_files = source_files.select { |source_file| !File.exist?(File.expand_path(source_file)) }
|
21
|
+
if !bad_files.empty?
|
22
|
+
raise_command_error("source file(s) not found: #{bad_files.join(', ')}")
|
23
|
+
end
|
24
24
|
source_files.each do |source_file|
|
25
|
-
|
26
|
-
source_file = File.expand_path(source_file)
|
27
|
-
if File.exists?(source_file)
|
28
|
-
cmd_results = Morpheus::Cli::DotFile.new(source_file).execute()
|
29
|
-
else
|
30
|
-
print_red_alert "file not found: '#{source_file}'"
|
31
|
-
# return false
|
32
|
-
end
|
25
|
+
Morpheus::Cli::DotFile.new(File.expand_path(source_file)).execute()
|
33
26
|
end
|
34
|
-
|
35
|
-
return true
|
27
|
+
return exit_code, err
|
36
28
|
end
|
37
29
|
|
38
30
|
end
|
@@ -794,7 +794,7 @@ class Morpheus::Cli::StorageProvidersCommand
|
|
794
794
|
puts_error "#{command_name} missing argument: [local-file]\n#{optparse}"
|
795
795
|
return 1
|
796
796
|
end
|
797
|
-
if !File.
|
797
|
+
if !File.exist?(local_file_path)
|
798
798
|
print_error Morpheus::Terminal.angry_prompt
|
799
799
|
puts_error "#{command_name} bad argument: [local-file]\nFile '#{local_file_path}' was not found.\n#{optparse}"
|
800
800
|
return 1
|
@@ -918,7 +918,7 @@ class Morpheus::Cli::StorageProvidersCommand
|
|
918
918
|
else
|
919
919
|
|
920
920
|
# upload file
|
921
|
-
if !File.
|
921
|
+
if !File.exist?(local_file_path) && !File.file?(local_file_path)
|
922
922
|
print_error Morpheus::Terminal.angry_prompt
|
923
923
|
puts_error "#{command_name} bad argument: [local-file]\nFile '#{local_file_path}' was not found.\n#{optparse}"
|
924
924
|
return 1
|
@@ -1016,15 +1016,15 @@ class Morpheus::Cli::StorageProvidersCommand
|
|
1016
1016
|
|
1017
1017
|
file_path = file_path.squeeze('/')
|
1018
1018
|
outfile = File.expand_path(outfile)
|
1019
|
-
if Dir.
|
1019
|
+
if Dir.exist?(outfile)
|
1020
1020
|
outfile = File.join(outfile, File.basename(file_path))
|
1021
1021
|
end
|
1022
|
-
if Dir.
|
1022
|
+
if Dir.exist?(outfile)
|
1023
1023
|
print_red_alert "[local-file] is invalid. It is the name of an existing directory: #{outfile}"
|
1024
1024
|
return 1
|
1025
1025
|
end
|
1026
1026
|
destination_dir = File.dirname(outfile)
|
1027
|
-
if !Dir.
|
1027
|
+
if !Dir.exist?(destination_dir)
|
1028
1028
|
if do_mkdir
|
1029
1029
|
print cyan,"Creating local directory #{destination_dir}",reset,"\n"
|
1030
1030
|
FileUtils.mkdir_p(destination_dir)
|
@@ -1033,7 +1033,7 @@ class Morpheus::Cli::StorageProvidersCommand
|
|
1033
1033
|
return 1
|
1034
1034
|
end
|
1035
1035
|
end
|
1036
|
-
if File.
|
1036
|
+
if File.exist?(outfile)
|
1037
1037
|
if do_overwrite
|
1038
1038
|
# uhh need to be careful wih the passed filepath here..
|
1039
1039
|
# don't delete, just overwrite.
|
@@ -1069,7 +1069,7 @@ class Morpheus::Cli::StorageProvidersCommand
|
|
1069
1069
|
print red + "ERROR" + reset + " HTTP #{http_response.code}" + "\n"
|
1070
1070
|
end
|
1071
1071
|
# F it, just remove a bad result
|
1072
|
-
if File.
|
1072
|
+
if File.exist?(outfile) && File.file?(outfile)
|
1073
1073
|
Morpheus::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if Morpheus::Logging.debug?
|
1074
1074
|
File.delete(outfile)
|
1075
1075
|
end
|
@@ -290,7 +290,7 @@ class Morpheus::Cli::Tasks
|
|
290
290
|
opts.on('--file FILE', "File containing the task script. This can be used instead of --content" ) do |filename|
|
291
291
|
file_params['sourceType'] = 'local' if file_params['sourceType'].nil?
|
292
292
|
full_filename = File.expand_path(filename)
|
293
|
-
if File.
|
293
|
+
if File.exist?(full_filename)
|
294
294
|
file_params['content'] = File.read(full_filename)
|
295
295
|
else
|
296
296
|
print_red_alert "File not found: #{full_filename}"
|
@@ -673,7 +673,7 @@ class Morpheus::Cli::Tasks
|
|
673
673
|
opts.on('--file FILE', "File containing the task script. This can be used instead of --content" ) do |filename|
|
674
674
|
file_params['sourceType'] = 'local' if file_params['sourceType'].nil?
|
675
675
|
full_filename = File.expand_path(filename)
|
676
|
-
if File.
|
676
|
+
if File.exist?(full_filename)
|
677
677
|
file_params['content'] = File.read(full_filename)
|
678
678
|
else
|
679
679
|
print_red_alert "File not found: #{full_filename}"
|
@@ -184,7 +184,7 @@ EOT
|
|
184
184
|
options[:config_file] = val.to_s
|
185
185
|
file_content = nil
|
186
186
|
full_filename = File.expand_path(options[:config_file])
|
187
|
-
if File.
|
187
|
+
if File.exist?(full_filename)
|
188
188
|
file_content = File.read(full_filename)
|
189
189
|
else
|
190
190
|
print_red_alert "File not found: #{full_filename}"
|
@@ -194,7 +194,7 @@ EOT
|
|
194
194
|
config_map = parse_result[:data]
|
195
195
|
if config_map.nil?
|
196
196
|
# todo: bubble up JSON.parse error message
|
197
|
-
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:
|
197
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
|
198
198
|
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
199
199
|
else
|
200
200
|
params['config'] = config_map
|
@@ -244,7 +244,7 @@ EOT
|
|
244
244
|
config_map = parse_result[:data]
|
245
245
|
if config_map.nil?
|
246
246
|
# todo: bubble up JSON.parse error message
|
247
|
-
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:
|
247
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
|
248
248
|
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
249
249
|
else
|
250
250
|
params['config'] = config_map
|
@@ -290,7 +290,7 @@ EOT
|
|
290
290
|
options[:config_file] = val.to_s
|
291
291
|
file_content = nil
|
292
292
|
full_filename = File.expand_path(options[:config_file])
|
293
|
-
if File.
|
293
|
+
if File.exist?(full_filename)
|
294
294
|
file_content = File.read(full_filename)
|
295
295
|
else
|
296
296
|
print_red_alert "File not found: #{full_filename}"
|
@@ -300,7 +300,7 @@ EOT
|
|
300
300
|
config_map = parse_result[:data]
|
301
301
|
if config_map.nil?
|
302
302
|
# todo: bubble up JSON.parse error message
|
303
|
-
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:
|
303
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
|
304
304
|
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
305
305
|
else
|
306
306
|
params['config'] = config_map
|
@@ -345,7 +345,7 @@ EOT
|
|
345
345
|
config_map = parse_result[:data]
|
346
346
|
if config_map.nil?
|
347
347
|
# todo: bubble up JSON.parse error message
|
348
|
-
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:
|
348
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:error]}"
|
349
349
|
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
350
350
|
else
|
351
351
|
params['config'] = config_map
|
@@ -17,9 +17,13 @@ class Morpheus::Cli::View
|
|
17
17
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
18
18
|
opts.banner = subcommand_usage("[path] [id]")
|
19
19
|
# debate: should login using /login/ouath-redirect
|
20
|
-
opts.on('-
|
20
|
+
opts.on('-l', '--login', "Login with the CLI access token before loading the path." ) do
|
21
21
|
options[:login] = true
|
22
22
|
end
|
23
|
+
opts.on('-L', '--old-login', "Alias for -l, --login" ) do
|
24
|
+
options[:login] = true
|
25
|
+
end
|
26
|
+
opts.add_hidden_option('-L, --old-login')
|
23
27
|
opts.on('--absolute', "Absolute path, do not search for a matching route to use") do
|
24
28
|
options[:absolute_path] = true
|
25
29
|
end
|
@@ -137,7 +137,7 @@ class Morpheus::Cli::WhitelabelSettingsCommand
|
|
137
137
|
print cyan
|
138
138
|
print options[:details] ? content : truncate_string(content, trunc_len), "\n"
|
139
139
|
end
|
140
|
-
print reset "\n"
|
140
|
+
print reset, "\n"
|
141
141
|
return 0
|
142
142
|
rescue RestClient::Exception => e
|
143
143
|
print_rest_exception(e, options)
|
@@ -596,11 +596,11 @@ class Morpheus::Cli::WhitelabelSettingsCommand
|
|
596
596
|
outfile = File.expand_path(args[1])
|
597
597
|
outdir = File.dirname(outfile)
|
598
598
|
|
599
|
-
if Dir.
|
599
|
+
if Dir.exist?(outfile)
|
600
600
|
print_red_alert "[local-file] is invalid. It is the name of an existing directory: #{outfile}"
|
601
601
|
return 1
|
602
602
|
end
|
603
|
-
if !Dir.
|
603
|
+
if !Dir.exist?(outdir)
|
604
604
|
if options[:mkdir]
|
605
605
|
print cyan,"Creating local directory #{outdir}",reset,"\n"
|
606
606
|
FileUtils.mkdir_p(outdir)
|
@@ -609,7 +609,7 @@ class Morpheus::Cli::WhitelabelSettingsCommand
|
|
609
609
|
return 1
|
610
610
|
end
|
611
611
|
end
|
612
|
-
if File.
|
612
|
+
if File.exist?(outfile) && !options[:overwrite]
|
613
613
|
print_red_alert "[local-file] is invalid. File already exists: #{outfile}\nUse -f to overwrite the existing file."
|
614
614
|
return 1
|
615
615
|
end
|
@@ -636,7 +636,7 @@ class Morpheus::Cli::WhitelabelSettingsCommand
|
|
636
636
|
if !options[:quiet]
|
637
637
|
print red + "ERROR" + reset + " HTTP #{http_response.code}" + "\n"
|
638
638
|
end
|
639
|
-
if File.
|
639
|
+
if File.exist?(outfile) && File.file?(outfile)
|
640
640
|
Morpheus::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if Morpheus::Logging.debug?
|
641
641
|
File.delete(outfile)
|
642
642
|
end
|
@@ -92,7 +92,7 @@ EOT
|
|
92
92
|
# no permissions, or even name stored atm, we should start storing that.
|
93
93
|
# then we can start checking permissions nd restricting command visibility.
|
94
94
|
whoami_response = {
|
95
|
-
"user"
|
95
|
+
"user" => {
|
96
96
|
"username" => @remote_appliance ? @remote_appliance[:username] : nil
|
97
97
|
},
|
98
98
|
# "isMasterAccount" => true,
|
@@ -263,7 +263,7 @@ EOT
|
|
263
263
|
|
264
264
|
def save_whoami_file(appliance_name, user_id, json_response)
|
265
265
|
fn = File.join(whoami_file_path, appliance_name.to_s, user_id.to_s + ".json")
|
266
|
-
if !Dir.
|
266
|
+
if !Dir.exist?(File.dirname(fn))
|
267
267
|
FileUtils.mkdir_p(File.dirname(fn))
|
268
268
|
end
|
269
269
|
Morpheus::Logging::DarkPrinter.puts "writing file #{fn}" if Morpheus::Logging.debug?
|
@@ -112,16 +112,38 @@ module Morpheus
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
if username.empty?
|
115
|
-
print "Username: #{required_blue_prompt} "
|
116
|
-
username = $stdin.gets.chomp!
|
115
|
+
# print "Username: #{required_blue_prompt} "
|
116
|
+
# username = $stdin.gets.chomp!
|
117
|
+
Readline.completion_append_character = ""
|
118
|
+
Readline.basic_word_break_characters = ''
|
119
|
+
Readline.completion_proc = nil
|
120
|
+
username = Readline.readline("Username: #{required_blue_prompt} ", false).to_s.chomp
|
117
121
|
else
|
118
122
|
print "Username: #{required_blue_prompt} #{username}\n"
|
119
123
|
end
|
120
124
|
if password.empty?
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
+
# readline is still echoing secret with 'NUL:'' so just use $stdin on windows for now
|
126
|
+
if Morpheus::Cli.windows?
|
127
|
+
print "Password: #{required_blue_prompt} "
|
128
|
+
# this should be my_terminal.stdin instead of STDIN and $stdin
|
129
|
+
password = $stdin.noecho(&:gets).chomp!
|
130
|
+
print "\n"
|
131
|
+
else
|
132
|
+
|
133
|
+
Readline.completion_append_character = ""
|
134
|
+
Readline.basic_word_break_characters = ''
|
135
|
+
Readline.completion_proc = nil
|
136
|
+
# needs to work like $stdin.noecho
|
137
|
+
Readline.pre_input_hook = lambda {
|
138
|
+
Readline.output = File.open('/dev/null', 'w')
|
139
|
+
#Readline.output = File.open(Morpheus::Cli.windows? ? 'NUL:' : '/dev/null', 'w')
|
140
|
+
#$stdout = File.open(Morpheus::Cli.windows? ? 'NUL:' : '/dev/null', 'w')
|
141
|
+
}
|
142
|
+
password = Readline.readline("Password: #{required_blue_prompt} ", false).to_s.chomp
|
143
|
+
Readline.pre_input_hook = nil
|
144
|
+
Readline.output = Morpheus::Terminal.instance.stdout #my_terminal.stdout
|
145
|
+
print "\n"
|
146
|
+
end
|
125
147
|
else
|
126
148
|
print "Password: #{required_blue_prompt} \n"
|
127
149
|
end
|
@@ -396,7 +418,7 @@ module Morpheus
|
|
396
418
|
credential_map.delete(appliance_name.to_sym)
|
397
419
|
begin
|
398
420
|
fn = credentials_file_path
|
399
|
-
if !Dir.
|
421
|
+
if !Dir.exist?(File.dirname(fn))
|
400
422
|
FileUtils.mkdir_p(File.dirname(fn))
|
401
423
|
end
|
402
424
|
#Morpheus::Logging::DarkPrinter.puts "adding credentials for #{appliance_name} to #{fn}" if Morpheus::Logging.debug?
|
@@ -433,7 +455,7 @@ module Morpheus
|
|
433
455
|
credential_map.delete(appliance_name.to_sym)
|
434
456
|
begin
|
435
457
|
fn = credentials_file_path
|
436
|
-
if !Dir.
|
458
|
+
if !Dir.exist?(File.dirname(fn))
|
437
459
|
FileUtils.mkdir_p(File.dirname(fn))
|
438
460
|
end
|
439
461
|
#Morpheus::Logging::DarkPrinter.puts "renaming credentials from #{appliance_name} to #{new_appliance_name}" if Morpheus::Logging.debug?
|
@@ -32,13 +32,10 @@ class Morpheus::Cli::DotFile
|
|
32
32
|
end
|
33
33
|
|
34
34
|
# execute this file as a morpheus shell script
|
35
|
-
#
|
36
|
-
# Default is false, keep going...
|
37
|
-
# @block [Proc] if a block is given, each command in the file will be yielded to it
|
38
|
-
# The default is executes the command with the CliRegistry.exec(cmd, args)
|
35
|
+
# executes each line in the file as a morpheus expression, ignores empty lines and comments '#'
|
39
36
|
# @return [Array] exit codes of all the commands that were run.
|
40
|
-
def execute(
|
41
|
-
if !File.
|
37
|
+
def execute()
|
38
|
+
if !File.exist?(@filename)
|
42
39
|
print "#{Term::ANSIColor.red}source file not found: #{@filename}#{Term::ANSIColor.reset}\n" # if Morpheus::Logging.debug?
|
43
40
|
else
|
44
41
|
Morpheus::Logging::DarkPrinter.puts "executing source file #{@filename}" if Morpheus::Logging.debug?
|
@@ -70,11 +67,7 @@ class Morpheus::Cli::DotFile
|
|
70
67
|
puts "#{red} source file: #{@filename}, line: #{line_num}, command: #{line}, error: #{err}#{reset}"
|
71
68
|
cmd_result = false
|
72
69
|
end
|
73
|
-
|
74
|
-
if stop_on_failure
|
75
|
-
return cmd_results
|
76
|
-
end
|
77
|
-
end
|
70
|
+
cmd_results << cmd_result
|
78
71
|
end
|
79
72
|
return cmd_results
|
80
73
|
end
|
@@ -89,10 +82,10 @@ class Morpheus::Cli::DotFile
|
|
89
82
|
print "#{Term::ANSIColor.dark}Skipping source file save because filename has not been set#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
|
90
83
|
return false
|
91
84
|
end
|
92
|
-
if !Dir.
|
85
|
+
if !Dir.exist?(File.dirname(@filename))
|
93
86
|
FileUtils.mkdir_p(File.dirname(@filename))
|
94
87
|
end
|
95
|
-
if !File.
|
88
|
+
if !File.exist?(@filename)
|
96
89
|
print "#{Term::ANSIColor.dark}Initializing source file #{@filename}#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
|
97
90
|
FileUtils.touch(@filename)
|
98
91
|
else
|
@@ -158,10 +151,10 @@ class Morpheus::Cli::DotFile
|
|
158
151
|
print "#{Term::ANSIColor.dark}Skipping source file save because filename has not been set#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
|
159
152
|
return false
|
160
153
|
end
|
161
|
-
if !Dir.
|
154
|
+
if !Dir.exist?(File.dirname(@filename))
|
162
155
|
FileUtils.mkdir_p(File.dirname(@filename))
|
163
156
|
end
|
164
|
-
if !File.
|
157
|
+
if !File.exist?(@filename)
|
165
158
|
print "#{Term::ANSIColor.dark}Initializing source file #{@filename}#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
|
166
159
|
FileUtils.touch(@filename)
|
167
160
|
else
|
@@ -25,6 +25,16 @@ class Morpheus::Cli::ErrorHandler
|
|
25
25
|
#@stderr.puts "#{dark}Handling error #{err.class} - #{err}#{reset}"
|
26
26
|
|
27
27
|
case (err)
|
28
|
+
when SystemExit
|
29
|
+
# nothing to do, assume the command that exited printed an error already
|
30
|
+
# print "\n"
|
31
|
+
cmdexit = err
|
32
|
+
if cmdexit.success?
|
33
|
+
exit_code, err = 0, nil
|
34
|
+
else
|
35
|
+
exit_code, err = cmdexit.status, "Command exited with status: #{cmdexit.status}"
|
36
|
+
end
|
37
|
+
return exit_code, err
|
28
38
|
# when Morpheus::Cli::CommandNotFoundError
|
29
39
|
# puts_angry_error err.message
|
30
40
|
# @stderr.puts "Try help to see a list of available commands"
|
@@ -32,6 +42,12 @@ class Morpheus::Cli::ErrorHandler
|
|
32
42
|
# if err.exit_code
|
33
43
|
# exit_code = err.exit_code
|
34
44
|
# end
|
45
|
+
when Morpheus::Cli::CommandAborted
|
46
|
+
# user declined a confirmation prompt, do not print anything and exit 9
|
47
|
+
do_print_stacktrace = false
|
48
|
+
exit_code = err.exit_code if err.exit_code
|
49
|
+
# err = err.message
|
50
|
+
return
|
35
51
|
when ::OptionParser::InvalidOption, ::OptionParser::AmbiguousOption,
|
36
52
|
::OptionParser::MissingArgument, ::OptionParser::InvalidArgument,
|
37
53
|
::OptionParser::NeedlessArgument
|