morpheus-cli 3.3.2.2 → 3.3.2.3

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