morpheus-cli 5.5.2.1 → 5.5.3
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 +8 -2
- 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/doc_interface.rb +8 -6
- data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
- 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/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 +69 -36
- 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/apps.rb +1 -1
- data/lib/morpheus/cli/commands/archives_command.rb +25 -33
- 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 +12 -12
- 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/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/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/login.rb +1 -1
- data/lib/morpheus/cli/commands/man_command.rb +32 -18
- 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/remote.rb +1 -1
- data/lib/morpheus/cli/commands/reports_command.rb +3 -3
- data/lib/morpheus/cli/commands/roles.rb +6 -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 +4 -4
- 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/rest_command.rb +18 -18
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +12 -12
- 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/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 +2 -2
- 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 +61 -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
|
|
@@ -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
|
data/lib/morpheus/cli/errors.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Morpheus::Cli
|
|
|
14
14
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
# An error indicating the command was not
|
|
17
|
+
# An error indicating the command was not recognized, assigned exit code 127
|
|
18
18
|
class CommandNotFoundError < CommandError
|
|
19
19
|
|
|
20
20
|
def initialize(msg, args=[], optparse=nil, exit_code=nil)
|
|
@@ -40,7 +40,14 @@ module Morpheus::Cli
|
|
|
40
40
|
def initialize(msg, args=[], optparse=nil, exit_code=nil)
|
|
41
41
|
super(msg, args, optparse, exit_code || 1)
|
|
42
42
|
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# An error indicating the user declined to accept a confirmation prompt, assigned exit code 9
|
|
46
|
+
class CommandAborted < CommandError
|
|
43
47
|
|
|
48
|
+
def initialize(msg, args=[], optparse=nil, exit_code=nil)
|
|
49
|
+
super(msg, args, optparse, exit_code || 9)
|
|
50
|
+
end
|
|
44
51
|
end
|
|
45
52
|
|
|
46
53
|
end
|