morpheus-cli 3.3.2.2 → 3.3.2.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.
@@ -151,7 +151,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
151
151
 
152
152
  def add(args)
153
153
  options = {}
154
- params = {'scriptType' => 'bash', 'scriptPhase' => 'postProvision'}
154
+ params = {'scriptType' => 'bash', 'scriptPhase' => 'provision'}
155
155
  optparse = Morpheus::Cli::OptionParser.new do |opts|
156
156
  opts.banner = subcommand_usage("[name]")
157
157
  opts.on('--name VALUE', String, "Name") do |val|
@@ -160,7 +160,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
160
160
  opts.on('--type [bash|powershell]', String, "Script Type. Default is 'bash'") do |val|
161
161
  params['scriptType'] = val
162
162
  end
163
- opts.on('--phase [start|stop|postProvision]', String, "Script Phase. Default is 'postProvision'") do |val|
163
+ opts.on('--phase [provision|start|stop]', String, "Script Phase. Default is 'provision'") do |val|
164
164
  params['scriptPhase'] = val
165
165
  end
166
166
  opts.on('--category VALUE', String, "Category") do |val|
@@ -169,7 +169,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
169
169
  opts.on('--script TEXT', String, "Contents of the script.") do |val|
170
170
  params['script'] = val
171
171
  end
172
- opts.on('--file FILE', "File containing the script. This can be used instead --script" ) do |filename|
172
+ opts.on('--file FILE', "File containing the script. This can be used instead of --script" ) do |filename|
173
173
  full_filename = File.expand_path(filename)
174
174
  if File.exists?(full_filename)
175
175
  params['script'] = File.read(full_filename)
@@ -257,7 +257,7 @@ class Morpheus::Cli::LibraryContainerScriptsCommand
257
257
  opts.on('--script TEXT', String, "Contents of the script.") do |val|
258
258
  params['script'] = val
259
259
  end
260
- opts.on('--file FILE', "File containing the script. This can be used instead --script" ) do |filename|
260
+ opts.on('--file FILE', "File containing the script. This can be used instead of --script" ) do |filename|
261
261
  full_filename = File.expand_path(filename)
262
262
  if File.exists?(full_filename)
263
263
  params['script'] = File.read(full_filename)
@@ -188,7 +188,7 @@ class Morpheus::Cli::LibraryContainerTemplatesCommand
188
188
  opts.on('--template TEXT', String, "Contents of the template.") do |val|
189
189
  params['template'] = val
190
190
  end
191
- opts.on('--file FILE', "File containing the template. This can be used instead --template" ) do |filename|
191
+ opts.on('--file FILE', "File containing the template. This can be used instead of --template" ) do |filename|
192
192
  full_filename = File.expand_path(filename)
193
193
  if File.exists?(full_filename)
194
194
  params['template'] = File.read(full_filename)
@@ -283,7 +283,7 @@ class Morpheus::Cli::LibraryContainerTemplatesCommand
283
283
  opts.on('--template TEXT', String, "Contents of the template.") do |val|
284
284
  params['template'] = val
285
285
  end
286
- opts.on('--file FILE', "File containing the template. This can be used instead --template" ) do |filename|
286
+ opts.on('--file FILE', "File containing the template. This can be used instead of --template" ) do |filename|
287
287
  full_filename = File.expand_path(filename)
288
288
  if File.exists?(full_filename)
289
289
  params['template'] = File.read(full_filename)
@@ -78,7 +78,7 @@ class Morpheus::Cli::Login
78
78
  # recalcuate echo vars
79
79
  Morpheus::Cli::Echo.recalculate_variable_map()
80
80
  # recalculate shell prompt after this change
81
- if Morpheus::Cli::Shell.instance
81
+ if Morpheus::Cli::Shell.has_instance?
82
82
  Morpheus::Cli::Shell.instance.reinitialize()
83
83
  end
84
84
 
@@ -63,7 +63,7 @@ class Morpheus::Cli::Logout
63
63
  # recalcuate echo vars
64
64
  Morpheus::Cli::Echo.recalculate_variable_map()
65
65
  # recalculate shell prompt after this change
66
- if Morpheus::Cli::Shell.instance
66
+ if Morpheus::Cli::Shell.has_instance?
67
67
  Morpheus::Cli::Shell.instance.reinitialize()
68
68
  end
69
69
  return 0
@@ -111,13 +111,8 @@ EOT
111
111
  def system_command_available?(cmd)
112
112
  has_it = false
113
113
  begin
114
- cmd = cmd.strip
115
- if cmd.include?(';') ||
116
- cmd =~ /^rm/ || cmd.strip =~ /^mv/ || cmd.strip =~ /^passwd/ ||
117
- cmd.include?("/rm") || cmd.include?("/mv") || cmd.include?("/passwd")
118
- raise_command_error "The specified system command '#{cmd}' is invalid."
119
- end
120
- system("which #{cmd} > /dev/null 2>&1")
114
+ cmd = cmd.strip.gsub("'",'')
115
+ system("which '#{cmd}' > /dev/null 2>&1")
121
116
  has_it = $?.success?
122
117
  rescue => e
123
118
  raise e
@@ -8,7 +8,10 @@ module Morpheus
8
8
  class Morpheus::Cli::OptionParser < OptionParser
9
9
 
10
10
  attr_accessor :footer
11
-
11
+
12
+ # Array of option names to keep out of help message
13
+ attr_accessor :hidden_options
14
+
12
15
  alias :original_to_s :to_s
13
16
 
14
17
  def to_s
@@ -23,7 +26,19 @@ module Morpheus
23
26
  end
24
27
  if !self.to_a.empty?
25
28
  #out << "Options:\n"
26
- out << summarize().join("")
29
+ # the default way..
30
+ # out << summarize().join("")
31
+
32
+ # super hacky, should be examining the option, not the fully formatted description
33
+ my_summaries = summarize()
34
+ summarize().each do |opt_description|
35
+ is_hidden = (@hidden_options || []).find { |hidden_switch|
36
+ opt_description.include?("--#{hidden_switch}")
37
+ }
38
+ if !is_hidden
39
+ out << opt_description
40
+ end
41
+ end
27
42
  end
28
43
  if footer
29
44
  # nice_footer = footer.split("\n").collect {|line| "#{summary_indent}#{line}" }.join("\n")
@@ -35,6 +50,17 @@ module Morpheus
35
50
  out
36
51
  end
37
52
 
53
+ def add_hidden_option(opt_name)
54
+ opt_array = [opt_name].flatten.compact
55
+ @hidden_options ||= []
56
+ opt_array.each do |val|
57
+ if !@hidden_options.include?(val)
58
+ @hidden_options << val
59
+ end
60
+ end
61
+ @hidden_options
62
+ end
63
+
38
64
  end
39
65
 
40
66
  end
@@ -113,7 +113,9 @@ class Morpheus::Cli::PowerSchedulingCommand
113
113
  end
114
114
 
115
115
  def _get(id, options)
116
-
116
+ options ||= {}
117
+ options[:max_servers] ||= 10
118
+ options[:max_instances] ||= 10
117
119
  begin
118
120
  schedule = find_schedule_by_name_or_id(id)
119
121
  if schedule.nil?
@@ -168,23 +170,20 @@ class Morpheus::Cli::PowerSchedulingCommand
168
170
  # print cyan,"No instances",reset,"\n"
169
171
  else
170
172
  print_h2 "Instances (#{instances.size})"
171
- print as_pretty_table(instances.first(options[:max_instances]), [:id, :name])
172
- if instances.size > options[:max_instances]
173
- print_results_pagination({'meta'=>{'total'=>instances.size,'size'=>options[:max_instances]}}, {:label => "instance in schedule", :n_label => "instances in schedule"})
174
- #print cyan, "(and #{instances.size - options[:max_instances]} more...)\n"
175
- end
173
+ instance_rows = instances.first(options[:max_instances])
174
+ print as_pretty_table(instance_rows, [:id, :name])
175
+ print_results_pagination({'meta'=>{'total'=>instances.size,'size'=>instance_rows.size,'max'=>options[:max_servers],'offset'=>0}}, {:label => "instance in schedule", :n_label => "instances in schedule"})
176
176
  end
177
177
 
178
178
  ## Hosts
179
179
  if servers.size == 0
180
180
  # print cyan,"No hosts",reset,"\n"
181
181
  else
182
+ options[:max_servers] ||= 10
182
183
  print_h2 "Hosts (#{servers.size})"
183
- print as_pretty_table(servers.first(options[:max_servers]), [:id, :name])
184
- if servers.size > options[:max_servers]
185
- print_results_pagination({'meta'=>{'total'=>servers.size,'size'=>options[:max_servers]}}, {:label => "host in schedule", :n_label => "hosts in schedule"})
186
- #print cyan, "(and #{servers.size - options[:max_servers]} more...)\n"
187
- end
184
+ server_rows = servers.first(options[:max_servers])
185
+ print as_pretty_table(server_rows, [:id, :name])
186
+ print_results_pagination({'meta'=>{'total'=>servers.size,'size'=>server_rows.size,'max'=>options[:max_servers],'offset'=>0}}, {:label => "host in schedule", :n_label => "hosts in schedule"})
188
187
  end
189
188
 
190
189
  print reset,"\n"
@@ -226,7 +225,7 @@ class Morpheus::Cli::PowerSchedulingCommand
226
225
  end
227
226
  end
228
227
  opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
229
- options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
228
+ params['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
230
229
  end
231
230
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
232
231
  opts.footer = "Create a new power schedule." + "\n" +
@@ -305,7 +304,7 @@ class Morpheus::Cli::PowerSchedulingCommand
305
304
  end
306
305
  end
307
306
  opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
308
- options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
307
+ params['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
309
308
  end
310
309
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
311
310
  opts.footer = "Update a power schedule." + "\n" +
@@ -558,7 +558,7 @@ EOT
558
558
  # recalcuate echo vars
559
559
  Morpheus::Cli::Echo.recalculate_variable_map()
560
560
  # recalculate shell prompt after this change
561
- if Morpheus::Cli::Shell.instance
561
+ if Morpheus::Cli::Shell.has_instance?
562
562
  Morpheus::Cli::Shell.instance.reinitialize()
563
563
  end
564
564
  return 0, nil
@@ -600,7 +600,7 @@ EOT
600
600
  # recalcuate echo vars
601
601
  Morpheus::Cli::Echo.recalculate_variable_map()
602
602
  # recalculate shell prompt after this change
603
- if Morpheus::Cli::Shell.instance
603
+ if Morpheus::Cli::Shell.has_instance?
604
604
  Morpheus::Cli::Shell.instance.reinitialize()
605
605
  end
606
606
 
@@ -630,7 +630,7 @@ EOT
630
630
  # recalcuate echo vars
631
631
  Morpheus::Cli::Echo.recalculate_variable_map()
632
632
  # recalculate shell prompt after this change
633
- if Morpheus::Cli::Shell.instance
633
+ if Morpheus::Cli::Shell.has_instance?
634
634
  Morpheus::Cli::Shell.instance.reinitialize()
635
635
  end
636
636
  return true
@@ -16,6 +16,10 @@ class Morpheus::Cli::Shell
16
16
 
17
17
  @@instance = nil
18
18
 
19
+ def self.has_instance?
20
+ defined?(@@instance) && @@instance
21
+ end
22
+
19
23
  def self.instance
20
24
  @@instance ||= reload_instance
21
25
  end
@@ -108,12 +112,55 @@ class Morpheus::Cli::Shell
108
112
  usage = "Usage: morpheus #{command_name}"
109
113
  optparse = OptionParser.new do|opts|
110
114
  opts.banner = usage
115
+ # change to a temporary home directory, delete it afterwards.
116
+ opts.on('-e','--exec COMMAND', "Execute the provided morpheus commands and exit.") do |val|
117
+ @execute_mode = true
118
+ @execute_mode_command = val
119
+ end
111
120
  opts.on('--norc','--norc', "Do not read and execute the personal initialization script .morpheusrc") do
112
121
  @norc = true
113
122
  end
114
123
  opts.on('-I','--insecure', "Allow for insecure HTTPS communication i.e. bad SSL certificate") do |val|
115
124
  @@insecure = true
116
125
  Morpheus::RestClient.enable_ssl_verification = false
126
+ end
127
+ opts.on('-Z','--incognito', "Incognito mode. Use a temporary shell, no saved credentials and no history.") do
128
+ @incognito_mode = true
129
+ #@norc = true # perhaps?
130
+ tmpdir = ENV['MORPHEUS_CLI_TMPDIR'] || ENV['TMPDIR'] || ENV['TMP']
131
+ if !tmpdir
132
+ puts_error "Temporary directory not found. Use environment variable MORPHEUS_CLI_TMPDIR or TMPDIR or TMP"
133
+ end
134
+ @original_home_directory = my_terminal.home_directory
135
+ @temporary_home_directory = File.join(tmpdir, "morpheus-temp-shell-#{rand().to_s[2..7]}")
136
+ # change to a temporary home directory
137
+ Morpheus::Logging::DarkPrinter.puts "incognito mode" if Morpheus::Logging.debug?
138
+ Morpheus::Logging::DarkPrinter.puts "temporary home directory is #{@temporary_home_directory}" if Morpheus::Logging.debug?
139
+ my_terminal.set_home_directory(@temporary_home_directory)
140
+ # wow..this already has cached list of Remote.appliances
141
+ # this is kinda nice though..keep it for now,
142
+ #Morpheus::Cli::Remote.load_appliance_file
143
+
144
+ Morpheus::Cli::Remote.appliances.each do |app_name, app|
145
+ #app[:username] = "(anonymous)"
146
+ #app[:status] = "fresh"
147
+ app[:authenticated] = false
148
+ app.delete(:username)
149
+ app.delete(:last_login_at)
150
+ app.delete(:last_logout_at)
151
+ app.delete(:last_success_at)
152
+ app.delete(:last_check)
153
+ app.delete(:username)
154
+ app.delete(:error)
155
+ #app[:error] = "ho ho ho"
156
+ end
157
+
158
+ # Morpheus::Cli::Remote.save_appliances(new_remote_config)
159
+
160
+ # Morpheus::Cli::Remote.clear_active_appliance
161
+ # Morpheus::Cli::Credentials.clear_saved_credentials(@appliance_name)
162
+ # Morpheus::Cli::Credentials.load_saved_credentials
163
+ # Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).load_saved_credentials()
117
164
  end
118
165
  opts.on('-C','--nocolor', "Disable ANSI coloring") do
119
166
  Term::ANSIColor::coloring = false
@@ -146,18 +193,63 @@ class Morpheus::Cli::Shell
146
193
  # recalculate_prompt()
147
194
  # recalculate_auto_complete_commands()
148
195
 
149
- exit = false
150
- while !exit do
151
- Readline.completion_append_character = " "
152
- Readline.completion_proc = @auto_complete
153
- Readline.basic_word_break_characters = ""
154
- #Readline.basic_word_break_characters = "\t\n\"\‘`@$><=;|&{( "
155
- input = Readline.readline(@calculated_prompt, true).to_s
156
- input = input.strip
157
-
158
- execute_commands(input)
196
+ result = nil
197
+ if @execute_mode_command
198
+ # execute a single command and exit
199
+ result = execute_commands(@execute_mode_command)
200
+ else
201
+ # interactive prompt
202
+ result = 0
203
+ @exit_now_please = false
204
+ while !@exit_now_please do
205
+ Readline.completion_append_character = " "
206
+ Readline.completion_proc = @auto_complete
207
+ Readline.basic_word_break_characters = ""
208
+ #Readline.basic_word_break_characters = "\t\n\"\‘`@$><=;|&{( "
209
+ input = Readline.readline(@calculated_prompt, true).to_s
210
+ input = input.strip
211
+
212
+ result = execute_commands(input)
213
+ end
159
214
  end
160
215
 
216
+ # incognito mode, cover our tracks
217
+ if @temporary_home_directory
218
+ if @temporary_home_directory.include?("morpheus-temp-shell")
219
+ begin
220
+ FileUtils.remove_dir(@temporary_home_directory, true)
221
+ Morpheus::Logging::DarkPrinter.puts "cleaning up temporary home directory #{@temporary_home_directory}" if Morpheus::Logging.debug?
222
+ rescue
223
+ end
224
+ end
225
+ @temporary_home_directory = nil
226
+ if @original_home_directory
227
+ my_terminal.set_home_directory(@original_home_directory)
228
+ end
229
+ @original_home_directory = nil
230
+ end
231
+
232
+ return result
233
+ end
234
+
235
+ # return exitstatus integer for a given command result
236
+ #todo: clean up CliCommand return values, handle a few diff types for now
237
+ def parse_result_exitstatus(result)
238
+ exit_code, err = 0, nil
239
+ if result.is_a?(Array) # exit_code, err
240
+ exit_code = result[0].to_i
241
+ err = result[1]
242
+ elsif result == nil || result == true || result == 0
243
+ exit_code = 0
244
+ elsif result == false
245
+ exit_code = 1
246
+ # elsif result.is_a?(Integer)
247
+ # exit_code = result.to_i
248
+ else
249
+ exit_code = result.to_i
250
+ end
251
+ # return exit_code, err
252
+ return exit_code
161
253
  end
162
254
 
163
255
  # same as Terminal instance
@@ -198,12 +290,12 @@ class Morpheus::Cli::Shell
198
290
  if flow_cmd == '&&'
199
291
  # AND operator
200
292
  current_operator = flow_cmd
201
- if previous_command_result.to_i != 0
293
+ if parse_result_exitstatus(previous_command_result) != 0
202
294
  still_executing = false
203
295
  end
204
296
  elsif flow_cmd == '||' # or with previous command
205
297
  current_operator = flow_cmd
206
- if previous_command_result.to_i == 0
298
+ if parse_result_exitstatus(previous_command_result) == 0
207
299
  still_executing = false
208
300
  end
209
301
  elsif flow_cmd == '|' # or with previous command
@@ -282,7 +374,9 @@ class Morpheus::Cli::Shell
282
374
  if input == 'exit'
283
375
  #print cyan,"Goodbye\n",reset
284
376
  @history_logger.info "exit" if @history_logger
285
- exit 0
377
+ @exit_now_please = true
378
+ return 0
379
+ #exit 0
286
380
  elsif input == 'help'
287
381
 
288
382
  #print_h1 "Morpheus Shell Help", [], white
@@ -356,44 +450,44 @@ class Morpheus::Cli::Shell
356
450
  @history_logger = load_history_logger
357
451
  puts "history cleared!"
358
452
  return 0
359
- elsif input == "edit rc"
360
- fn = Morpheus::Cli::DotFile.morpheusrc_filename
361
- editor = ENV['EDITOR'] # || 'nano'
362
- if !editor
363
- puts "You have no EDITOR defined. Use 'export EDITOR=emacs'"
364
- #puts "Trying nano..."
365
- #editor = "nano"
366
- end
367
- system("which #{editor} > /dev/null 2>&1")
368
- has_editor = $?.success?
369
- if has_editor
370
- puts "opening #{fn} for editing with #{editor} ..."
371
- system("#{editor} #{fn}")
372
- puts "Use 'reload' to re-execute your startup script #{File.basename(fn)}"
373
- else
374
- puts_error2 Morpheus::Terminal.angry_prompt
375
- puts_error "The defined EDITOR '#{editor}' was not found on your system."
376
- end
377
- return 0 # $?
378
- elsif input == "edit profile"
379
- fn = Morpheus::Cli::DotFile.morpheus_profile_filename
380
- editor = ENV['EDITOR'] # || 'nano'
381
- if !editor
382
- puts "You have no EDITOR defined. Use 'export EDITOR=emacs'."
383
- #puts "Trying nano..."
384
- #editor = "nano"
385
- end
386
- system("which #{editor} > /dev/null 2>&1")
387
- has_editor = $?.success?
388
- if has_editor
389
- puts "opening #{fn} for editing with #{editor} ..."
390
- `#{editor} #{fn}`
391
- puts "Use 'reload' to re-execute your startup script #{File.basename(fn)}"
392
- else
393
- puts_error Morpheus::Terminal.angry_prompt
394
- puts_error "The defined EDITOR '#{editor}' was not found on your system."
395
- end
396
- return 0 # $?
453
+ # elsif input == "edit rc"
454
+ # fn = Morpheus::Cli::DotFile.morpheusrc_filename
455
+ # editor = ENV['EDITOR'] # || 'nano'
456
+ # if !editor
457
+ # puts "You have no EDITOR defined. Use 'export EDITOR=emacs'"
458
+ # #puts "Trying nano..."
459
+ # #editor = "nano"
460
+ # end
461
+ # system("which #{editor} > /dev/null 2>&1")
462
+ # has_editor = $?.success?
463
+ # if has_editor
464
+ # puts "opening #{fn} for editing with #{editor} ..."
465
+ # system("#{editor} #{fn}")
466
+ # puts "Use 'reload' to re-execute your startup script #{File.basename(fn)}"
467
+ # else
468
+ # puts_error2 Morpheus::Terminal.angry_prompt
469
+ # puts_error "The defined EDITOR '#{editor}' was not found on your system."
470
+ # end
471
+ # return 0 # $?
472
+ # elsif input == "edit profile"
473
+ # fn = Morpheus::Cli::DotFile.morpheus_profile_filename
474
+ # editor = ENV['EDITOR'] # || 'nano'
475
+ # if !editor
476
+ # puts "You have no EDITOR defined. Use 'export EDITOR=emacs'."
477
+ # #puts "Trying nano..."
478
+ # #editor = "nano"
479
+ # end
480
+ # system("which #{editor} > /dev/null 2>&1")
481
+ # has_editor = $?.success?
482
+ # if has_editor
483
+ # puts "opening #{fn} for editing with #{editor} ..."
484
+ # `#{editor} #{fn}`
485
+ # puts "Use 'reload' to re-execute your startup script #{File.basename(fn)}"
486
+ # else
487
+ # puts_error Morpheus::Terminal.angry_prompt
488
+ # puts_error "The defined EDITOR '#{editor}' was not found on your system."
489
+ # end
490
+ # return 0 # $?
397
491
  elsif input == 'reload' || input == 'reload!'
398
492
  # raise RestartShellPlease
399
493
  #log_history_command(input)
@@ -497,7 +591,7 @@ class Morpheus::Cli::Shell
497
591
  ::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
498
592
  @return_to_log_level = nil
499
593
  end
500
-
594
+
501
595
  # commands should be a number or nil (treated as 0)
502
596
  if cmd_result == true
503
597
  cmd_result = 0