opswalrus 1.0.38 → 1.0.40

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a8829f40ddadca854579786cb5c26aa6d67967afe3805930028cd9d65565267
4
- data.tar.gz: d3bc1e8772b1f52cac6ff4625509eede301cb4cffc686eae9a12f4013d55c412
3
+ metadata.gz: 43969fb5bd89993b9f4fb4c127d8a63f7d074d79d08104609b3a43d4df3f6457
4
+ data.tar.gz: beca6e40dcabbe38815ef6ac2fe6581895ba8ea2dcb27ab314ad22d5ff2d47cd
5
5
  SHA512:
6
- metadata.gz: 14f5e7f7efc6651e506110ccde42a403e9fd69fe0a64d4ca44b4e5622da92900d21a88191437fad7b73fc52e880af02a2ebfc5f3b2035d83c006efd9a86cca13
7
- data.tar.gz: 15149d50ef7c8ae277d2fd8044fc6f096b5472a1b565978231d82568fa3db6b60dfa6c405ba1c5cceb86a415914f2096405e9c32c0ba6692c5fa2b28c023d33f
6
+ metadata.gz: be45244077503ac67da072c8d41cad8800553cb9dc243d49904de29588c20a93317543b3d2d2d97a8c7a74ca0a1abc6c0d2fa5d4187b1fe34d863e1e3e558218
7
+ data.tar.gz: 3cd42b3c126aef7dcec443c7f14fe9ee308da1d153148430b2413fe4166c4a214c43b0e368b485a4b3dd6cddf9c3047f778e55dbd4b99dc79697d75eaf910c72
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- opswalrus (1.0.38)
5
- amazing_print (~> 1.5)
4
+ opswalrus (1.0.40)
6
5
  bcrypt_pbkdf (~> 1.1)
7
6
  binding_of_caller (~> 1.0)
8
7
  citrus (~> 3.0)
@@ -20,7 +19,6 @@ GEM
20
19
  specs:
21
20
  addressable (2.8.5)
22
21
  public_suffix (>= 2.0.2, < 6.0)
23
- amazing_print (1.5.0)
24
22
  bcrypt_pbkdf (1.1.0)
25
23
  binding_of_caller (1.0.0)
26
24
  debug_inspector (>= 0.0.1)
data/lib/opswalrus/app.rb CHANGED
@@ -49,7 +49,6 @@ module OpsWalrus
49
49
  # @logger.debug Style.yellow("debug"), foo: "bar", baz: {qux: "quux"}
50
50
  # @logger.trace Style.yellow("trace"), foo: "bar", baz: {qux: "quux"}
51
51
 
52
- @verbose = false
53
52
  @sudo_user = nil
54
53
  @sudo_password = nil
55
54
  @identity_file_paths = []
@@ -124,38 +123,53 @@ module OpsWalrus
124
123
  @logger.level = log_level
125
124
  end
126
125
 
127
- def verbose?
128
- [:info, :debug, :trace].include? @logger.level
129
- end
130
-
131
- def debug?
132
- [:debug, :trace].include? @logger.level
133
- end
134
-
135
126
  def fatal(*args)
136
127
  @logger.fatal(*args)
137
128
  end
129
+ def fatal?
130
+ @logger.fatal?
131
+ end
138
132
 
139
133
  def error(*args)
140
134
  @logger.error(*args)
141
135
  end
136
+ def error?
137
+ @logger.error?
138
+ end
142
139
 
143
140
  def warn(*args)
144
141
  @logger.warn(*args)
145
142
  end
143
+ alias_method :important, :warn # warn means important
144
+ def warn?
145
+ @logger.warn?
146
+ end
146
147
 
147
- def log(*args)
148
+ def info(*args)
148
149
  @logger.info(*args)
149
150
  end
150
- alias_method :info, :log
151
+ alias_method :log, :info
152
+ def info?
153
+ @logger.info?
154
+ end
151
155
 
152
156
  def debug(*args)
153
157
  @logger.debug(*args)
154
158
  end
159
+ def debug?
160
+ @logger.debug?
161
+ end
155
162
 
156
163
  def trace(*args)
157
164
  @logger.trace(*args)
158
165
  end
166
+ def trace?
167
+ @logger.trace?
168
+ end
169
+
170
+ def verbose?
171
+ info? || debug? || trace?
172
+ end
159
173
 
160
174
  def set_pwd(pwd)
161
175
  @pwd = pwd.to_pathname
@@ -181,7 +195,6 @@ module OpsWalrus
181
195
  def prompt_sudo_password
182
196
  password = IO::console.getpass(LOCAL_SUDO_PASSWORD_PROMPT)
183
197
  set_sudo_password(password)
184
- # puts "sudo password = |#{password}|"
185
198
  nil
186
199
  end
187
200
 
@@ -223,25 +236,19 @@ module OpsWalrus
223
236
 
224
237
  ops_file = load_entry_point_ops_file(ops_file_path, tmp_bundle_root_dir)
225
238
 
226
- if @verbose
227
- puts "Running: #{ops_file.ops_file_path}"
228
- end
239
+ debug "Running: #{ops_file.ops_file_path}"
229
240
 
230
241
  op = OperationRunner.new(self, ops_file)
231
242
  result = op.run(operation_kv_args, params_json_hash: @params)
232
243
  exit_status = result.exit_status
233
244
 
234
- if @verbose
235
- puts "Op exit_status"
236
- puts exit_status
245
+ debug "Op exit_status"
246
+ debug exit_status
237
247
 
238
- puts "Op output"
239
- puts JSON.pretty_generate(result.value)
240
- end
248
+ debug "Op output"
249
+ debug JSON.pretty_generate(result.value)
241
250
 
242
- if script_mode?
243
- puts JSON.pretty_generate(result.value)
244
- end
251
+ puts JSON.pretty_generate(result.value)
245
252
 
246
253
  exit_status
247
254
  ensure
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  export PATH="$HOME/.local/share/rtx/bin:$PATH" # this is key for activating rtx without running `eval "$($RTX activate bash)"`
4
+ # eval "$(rtx activate bash)"
4
5
  RTX="$HOME/.local/share/rtx/bin/rtx"
5
6
  rtx_init() { eval "$($RTX activate bash)"; }
6
7
  # RTX_RUBY="$HOME/.local/share/rtx/bin/rtx x ruby -- ruby"
@@ -27,7 +28,7 @@ if [ -x $RTX ]; then
27
28
  # make sure the latest opswalrus gem is installed
28
29
  # todo: figure out how to install this differently, so that test versions will work
29
30
  # gem install opswalrus
30
- $GEM_CMD install opswalrus
31
+ # $GEM_CMD install opswalrus
31
32
  $RTX reshim
32
33
 
33
34
  exit 0
data/lib/opswalrus/cli.rb CHANGED
@@ -22,19 +22,17 @@ module OpsWalrus
22
22
  on_error do |exception|
23
23
  next(false) if exception.is_a? GLI::CustomExit
24
24
 
25
- puts "catchall exception handler:"
26
- puts exception.message
27
- puts exception.backtrace.join("\n")
25
+ $app.fatal "catchall exception handler:"
26
+ $app.fatal exception.message
27
+ $app.fatal exception.backtrace.join("\n")
28
28
  false # disable built-in exception handling
29
29
  end
30
30
 
31
31
  program_desc 'ops is an operation runner'
32
32
 
33
- desc 'Be verbose'
34
- switch [:v, :verbose]
35
-
36
- desc 'Turn on debug mode'
37
- switch [:d, :debug]
33
+ switch [:v, :verbose], desc: "Verbose output"
34
+ switch :debug, desc: "Debug output"
35
+ switch :trace, desc: "Trace output"
38
36
 
39
37
  switch :noop, desc: "Perform a dry run"
40
38
  switch :dryrun, desc: "Perform a dry run"
@@ -63,8 +61,7 @@ module OpsWalrus
63
61
  hosts = global_options[:hosts]
64
62
  tags = global_options[:tags]
65
63
 
66
- log_level = global_options[:debug] && :trace || global_options[:verbose] && :debug || :info
67
- $app.set_log_level(log_level)
64
+ $app.set_log_level(global_options[:trace] && :trace || global_options[:debug] && :debug || global_options[:verbose] && :info || :warn)
68
65
 
69
66
  $app.report_inventory(hosts, tags: tags)
70
67
  end
@@ -131,8 +128,7 @@ module OpsWalrus
131
128
  c.switch :dry_run, desc: "Perform a dry run"
132
129
 
133
130
  c.action do |global_options, options, args|
134
- log_level = global_options[:debug] && :trace || global_options[:verbose] && :debug || :info
135
- $app.set_log_level(log_level)
131
+ $app.set_log_level(global_options[:trace] && :trace || global_options[:debug] && :debug || global_options[:verbose] && :info || :warn)
136
132
 
137
133
  hosts = global_options[:hosts]
138
134
  tags = global_options[:tags]
@@ -168,8 +164,7 @@ module OpsWalrus
168
164
  c.switch :dry_run, desc: "Perform a dry run"
169
165
 
170
166
  c.action do |global_options, options, args|
171
- log_level = global_options[:debug] && :trace || global_options[:verbose] && :debug || :info
172
- $app.set_log_level(log_level)
167
+ $app.set_log_level(global_options[:trace] && :trace || global_options[:debug] && :debug || global_options[:verbose] && :info || :warn)
173
168
 
174
169
  hosts = global_options[:hosts]
175
170
  $app.set_inventory_hosts(hosts)
@@ -213,8 +208,7 @@ module OpsWalrus
213
208
  long_desc 'Download and bundle the latest versions of dependencies for the current package'
214
209
  c.command :update do |update|
215
210
  update.action do |global_options, options, args|
216
- log_level = global_options[:debug] && :trace || global_options[:verbose] && :debug || :info
217
- $app.set_log_level(log_level)
211
+ $app.set_log_level(global_options[:trace] && :trace || global_options[:debug] && :debug || global_options[:verbose] && :info || :warn)
218
212
 
219
213
  $app.bundle_update
220
214
  end
@@ -234,8 +228,7 @@ module OpsWalrus
234
228
  unzip.flag [:o, :output], desc: "Specify the output directory"
235
229
 
236
230
  unzip.action do |global_options, options, args|
237
- log_level = global_options[:debug] && :trace || global_options[:verbose] && :debug || :info
238
- $app.set_log_level(log_level)
231
+ $app.set_log_level(global_options[:trace] && :trace || global_options[:debug] && :debug || global_options[:verbose] && :info || :warn)
239
232
 
240
233
  output_dir = options[:output]
241
234
  zip_file_path = args.first
@@ -51,7 +51,6 @@ module OpsWalrus
51
51
  sibling_symbol_table |= ops_file.dirname.glob("*").select(&:directory?).map {|dir_path| dir_path.basename.to_s } # Namespaces
52
52
  sibling_symbol_table.each do |symbol_name|
53
53
  unless methods_defined.include? symbol_name
54
- # puts "2. defining: #{symbol_name}(...)"
55
54
  klass.define_method(symbol_name) do |*args, **kwargs, &block|
56
55
  App.instance.trace "resolving implicit import: #{symbol_name}"
57
56
  namespace_or_ops_file = @runtime_env.resolve_sibling_symbol(ops_file, symbol_name)
@@ -144,7 +143,7 @@ module OpsWalrus
144
143
  end
145
144
 
146
145
  # returns the tuple: [stdout, stderr, exit_status]
147
- def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
146
+ def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, log_level: nil)
148
147
  # description = nil
149
148
 
150
149
  return ["", "", 0] if !desc_or_cmd && !cmd && !block # we were told to do nothing; like hitting enter at the bash prompt; we can do nothing successfully
@@ -170,61 +169,95 @@ module OpsWalrus
170
169
 
171
170
  #cmd = Shellwords.escape(cmd)
172
171
 
173
- if App.instance.report_mode?
174
- puts Style.green("*" * 80)
175
- if self.alias
176
- print "[#{Style.blue(self.alias)} | #{Style.blue(host)}] "
177
- else
178
- print "[#{Style.blue(host)}] "
179
- end
180
- print "#{description}: " if description
181
- puts Style.yellow(cmd)
182
- end
172
+ cmd_id = Random.uuid.split('-').first
173
+ # if App.instance.report_mode?
174
+ puts Style.green("*" * 80)
175
+ print Style.blue(host)
176
+ print " (#{Style.blue(self.alias)})" if self.alias
177
+ print " | #{Style.magenta(description)}" if description
178
+ puts
179
+ print Style.yellow(cmd_id)
180
+ print Style.green.bold(" > ")
181
+ puts Style.yellow(cmd)
182
+
183
+ # puts Style.green("*" * 80)
184
+ # if self.alias
185
+ # print "[#{Style.blue(self.alias)} | #{Style.blue(host)}] "
186
+ # else
187
+ # print "[#{Style.blue(host)}] "
188
+ # end
189
+ # print "#{description}: " if description
190
+ # puts Style.yellow("[#{cmd_id}] #{cmd}")
191
+ # end
183
192
 
184
193
  return unless cmd && !cmd.strip.empty?
185
194
 
186
- # puts "shell: #{cmd}"
187
- # puts "shell: #{cmd.inspect}"
188
- # puts "sudo_password: #{sudo_password}"
189
-
190
- if App.instance.dry_run?
195
+ t1 = Time.now
196
+ out, err, exit_status = if App.instance.dry_run?
191
197
  ["", "", 0]
192
198
  else
193
199
  sshkit_cmd = execute_cmd(cmd, input: input)
194
200
  [sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
195
201
  end
196
- end
202
+ t2 = Time.now
203
+ seconds = t2 - t1
204
+
205
+ if App.instance.info? || log_level == :info
206
+ puts Style.cyan(out)
207
+ puts Style.red(err)
208
+ elsif App.instance.debug? || log_level == :debug
209
+ puts Style.cyan(out)
210
+ puts Style.red(err)
211
+ elsif App.instance.trace? || log_level == :trace
212
+ puts Style.cyan(out)
213
+ puts Style.red(err)
214
+ end
215
+ print Style.yellow(cmd_id)
216
+ print Style.blue(" | Finished in #{seconds} seconds with exit status ")
217
+ if exit_status == 0
218
+ puts Style.green("#{exit_status} (#{exit_status == 0 ? 'success' : 'failure'})")
219
+ else
220
+ puts Style.red("#{exit_status} (#{exit_status == 0 ? 'success' : 'failure'})")
221
+ end
197
222
 
198
- # def init_brew
199
- # execute('eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"')
200
- # end
223
+ [out, err, exit_status]
224
+ end
201
225
 
202
226
  # runs the specified ops command with the specified command arguments
203
- def run_ops(ops_command, ops_command_options = nil, command_arguments, in_bundle_root_dir: true, verbose: false)
204
- # e.g. /home/linuxbrew/.linuxbrew/bin/gem exec -g opswalrus ops bundle unzip tmpops.zip
205
- # e.g. /home/linuxbrew/.linuxbrew/bin/gem exec -g opswalrus ops run echo.ops args:foo args:bar
206
-
207
- # cmd = "/home/linuxbrew/.linuxbrew/bin/gem exec -g opswalrus ops"
227
+ def run_ops(ops_command, ops_command_options = nil, command_arguments, in_bundle_root_dir: true)
208
228
  local_hostname_for_remote_host = if self.alias
209
- "#{self.alias} | #{host}"
229
+ "#{host} (#{self.alias})"
210
230
  else
211
231
  host
212
232
  end
213
233
 
214
- # cmd = "OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}'; /home/linuxbrew/.linuxbrew/bin/gem exec --conservative -g opswalrus ops"
215
234
  # cmd = "OPS_GEM=\"#{OPS_GEM}\" OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}'; $OPS_GEM exec --conservative -g opswalrus ops"
216
235
  cmd = "OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}' eval #{OPS_CMD}"
217
- cmd << " -v" if verbose
236
+ if App.instance.info?
237
+ cmd << " --verbose"
238
+ elsif App.instance.debug?
239
+ cmd << " --debug"
240
+ elsif App.instance.trace?
241
+ cmd << " --trace"
242
+ end
218
243
  cmd << " #{ops_command.to_s}"
219
244
  cmd << " #{ops_command_options.to_s}" if ops_command_options
220
245
  cmd << " #{@tmp_bundle_root_dir}" if in_bundle_root_dir
221
246
  cmd << " #{command_arguments}" unless command_arguments.empty?
222
247
 
223
- shell!(cmd)
248
+ shell!(cmd, log_level: :info)
224
249
  end
225
250
 
226
251
  def desc(msg)
227
- puts msg.mustache(1)
252
+ puts msg.mustache(2) # we use two here, because one stack frame accounts for the call from the ops script into HostProxy#desc
253
+ end
254
+
255
+ def env(*args, **kwargs)
256
+ @ops_file_script.env(*args, **kwargs)
257
+ end
258
+
259
+ def params(*args, **kwargs)
260
+ @ops_file_script.params(*args, **kwargs)
228
261
  end
229
262
 
230
263
  def host_prop(name)
@@ -360,6 +393,10 @@ module OpsWalrus
360
393
  @runtime_env = runtime_env
361
394
  end
362
395
 
396
+ def set_ops_file_script(ops_file_script)
397
+ @ops_file_script = ops_file_script
398
+ end
399
+
363
400
  def set_ssh_session_connection(sshkit_backend)
364
401
  @sshkit_backend = sshkit_backend
365
402
  end
@@ -370,6 +407,7 @@ module OpsWalrus
370
407
 
371
408
  def clear_ssh_session
372
409
  @runtime_env = nil
410
+ ops_file_script = nil
373
411
  @sshkit_backend = nil
374
412
  @tmp_bundle_root_dir = nil
375
413
  @tmp_ssh_key_files.each {|tmpfile| tmpfile.close() rescue nil; File.unlink(tmpfile) rescue nil }
@@ -378,13 +416,15 @@ module OpsWalrus
378
416
 
379
417
  def execute(*args, input: nil)
380
418
  @runtime_env.handle_input(input, ssh_password) do |interaction_handler|
381
- @sshkit_backend.capture(*args, interaction_handler: interaction_handler, verbosity: :info)
419
+ # @sshkit_backend.capture(*args, interaction_handler: interaction_handler, verbosity: SSHKit.config.output_verbosity)
420
+ @sshkit_backend.capture(*args, interaction_handler: interaction_handler)
382
421
  end
383
422
  end
384
423
 
385
424
  def execute_cmd(*args, input: nil)
386
425
  @runtime_env.handle_input(input, ssh_password) do |interaction_handler|
387
- @sshkit_backend.execute_cmd(*args, interaction_handler: interaction_handler, verbosity: :info)
426
+ # @sshkit_backend.execute_cmd(*args, interaction_handler: interaction_handler, verbosity: SSHKit.config.output_verbosity)
427
+ @sshkit_backend.execute_cmd(*args, interaction_handler: interaction_handler)
388
428
  end
389
429
  end
390
430
 
@@ -168,20 +168,18 @@ module OpsWalrus
168
168
 
169
169
  def decrypt(decrypted_file_path = nil)
170
170
  decrypted_file_path ||= @hosts_file_path
171
- puts "Decrypting #{@hosts_file_path} -> #{decrypted_file_path}."
171
+ App.instance.debug "Decrypting #{@hosts_file_path} -> #{decrypted_file_path}."
172
172
  raise("Path to age identity not specified") if App.instance.identity_file_paths.empty?
173
173
  decrypt_secrets!
174
174
  File.write(decrypted_file_path, to_yaml)
175
- # puts to_yaml
176
175
  end
177
176
 
178
177
  def encrypt(encrypted_file_path = nil)
179
178
  encrypted_file_path ||= @hosts_file_path
180
- puts "Encrypting #{@hosts_file_path} -> #{encrypted_file_path}."
179
+ App.instance.debug "Encrypting #{@hosts_file_path} -> #{encrypted_file_path}."
181
180
  raise("Path to age identity not specified") if App.instance.identity_file_paths.empty?
182
181
  encrypt_secrets!
183
182
  File.write(encrypted_file_path, to_yaml)
184
- # puts to_yaml
185
183
  end
186
184
  end
187
185
 
@@ -231,7 +229,7 @@ module OpsWalrus
231
229
  when Array
232
230
  ref.map {|audience_id_reference| dereference(audience_id_reference) }.flatten.compact.uniq
233
231
  when Nil
234
- puts "ID #{audience_id_reference} does not appear in the list of known public key identifiers"
232
+ App.instance.warn "ID #{audience_id_reference} does not appear in the list of known public key identifiers"
235
233
  nil
236
234
  else
237
235
  raise "ID reference #{audience_id_reference} corresponds to an unknown type of public key or transitive ID reference: #{ref.inspect}"
@@ -372,7 +370,6 @@ module OpsWalrus
372
370
  # coder.represent_scalar(nil, @public_key)
373
371
 
374
372
  # coder.scalar = @public_key
375
- # puts @ids.inspect
376
373
  single_line_ids = @ids.join(", ")
377
374
  if single_line_ids.size <= 80
378
375
  coder['ids'] = single_line_ids
@@ -85,9 +85,6 @@ module OpsWalrus
85
85
 
86
86
  def debug(message)
87
87
  App.instance.debug(message)
88
- if [:fatal, :error, :warn, :info, :debug, :trace].include? @log_level
89
- SSHKit.config.output.send(@log_level, message)
90
- end
91
88
  end
92
89
 
93
90
  end
@@ -39,7 +39,7 @@ module SSHKit
39
39
  handle_data_for_stdout(output, cmd, buffer, stdin, true)
40
40
  stdout.close
41
41
  rescue => e
42
- puts "closing PTY due to unexpected error: #{e.message}"
42
+ App.instance.error "closing PTY due to unexpected error: #{e.message}"
43
43
  handle_data_for_stdout(output, cmd, buffer, stdin, true)
44
44
  stdout.close
45
45
  # puts e.message
@@ -73,7 +73,7 @@ module SSHKit
73
73
  handle_data_for_stderr(output, cmd, buffer, stdin, true)
74
74
  stderr.close
75
75
  rescue => e
76
- puts "closing PTY due to unexpected error: #{e.message}"
76
+ App.instance.error "closing PTY due to unexpected error: #{e.message}"
77
77
  handle_data_for_stderr(output, cmd, buffer, stdin, true)
78
78
  stderr.close
79
79
  # puts e.message
@@ -44,7 +44,7 @@ module SSHKit
44
44
  handle_data_for_stdout(output, cmd, buffer, stdin, true)
45
45
  stdout.close
46
46
  rescue => e
47
- puts "closing PTY due to unexpected error: #{e.message}"
47
+ App.instance.error "closing PTY due to unexpected error: #{e.message}"
48
48
  handle_data_for_stdout(output, cmd, buffer, stdin, true)
49
49
  stdout.close
50
50
  # puts e.message
@@ -83,10 +83,8 @@ module OpsWalrus
83
83
  def run(runtime_kv_args, params_json_hash: nil)
84
84
  params_hash = build_params_hash(runtime_kv_args, params_json_hash: params_json_hash)
85
85
 
86
- if app.debug?
87
- App.instance.trace "Script:"
88
- App.instance.trace @entry_point_ops_file.script
89
- end
86
+ App.instance.trace "Script:"
87
+ App.instance.trace @entry_point_ops_file.script
90
88
 
91
89
  result = begin
92
90
  # update the bundle for the package
@@ -112,7 +110,7 @@ module OpsWalrus
112
110
  Invocation::Error.new(e)
113
111
  end
114
112
 
115
- if app.debug? && result.failure?
113
+ if result.failure?
116
114
  App.instance.debug "Ops script error details:"
117
115
  App.instance.debug "Error: #{result.value}"
118
116
  App.instance.debug "Status code: #{result.exit_status}"
@@ -47,8 +47,7 @@ module OpsWalrus
47
47
  end
48
48
 
49
49
  def lazy_load_file
50
- # puts "OpsFile#lazy_load_file for #{ops_file_path}"
51
- # puts caller
50
+ App.instance.trace "OpsFile#lazy_load_file for #{@ops_file_path}"
52
51
  yaml, ruby_script = if @ops_file_path.exist?
53
52
  parse(File.read(@ops_file_path))
54
53
  end || ["", ""]
@@ -166,7 +165,7 @@ module OpsWalrus
166
165
  package_uri = import_str
167
166
  if Git.repo?(package_uri) # ops file has imported an ad-hoc git repo
168
167
  destination_package_path = app.bundler.dynamic_package_path_for_git_package(package_uri)
169
- # puts "DynamicPackageImportReference: #{local_name} -> #{destination_package_path}"
168
+ App.instance.trace "DynamicPackageImportReference: #{local_name} -> #{destination_package_path}"
170
169
  return DynamicPackageImportReference.new(local_name, DynamicPackageReference.new(local_name, package_uri, nil))
171
170
  end
172
171
 
@@ -110,7 +110,7 @@ module OpsWalrus
110
110
  sibling_symbol_table_names = Set.new
111
111
  sibling_symbol_table_names |= ops_file.dirname.glob("*.ops").map {|ops_file_path| ops_file_path.basename(".ops").to_s } # OpsFiles
112
112
  sibling_symbol_table_names |= ops_file.dirname.glob("*").select(&:directory?).map {|dir_path| dir_path.basename.to_s } # Namespaces
113
- # puts "sibling_symbol_table_names=#{sibling_symbol_table_names}"
113
+ # App.instance.trace "sibling_symbol_table_names=#{sibling_symbol_table_names}"
114
114
  App.instance.trace "methods_defined=#{methods_defined}"
115
115
  sibling_symbol_table_names.each do |symbol_name|
116
116
  unless methods_defined.include? symbol_name
@@ -134,19 +134,16 @@ module OpsWalrus
134
134
  # - @params
135
135
  # - #host_proxy_class
136
136
  # - #backend
137
- # - #debug?
138
- # - #verbose?
139
137
  # - all the dynamically defined methods in the subclass of Invocation
140
138
  invoke_method_definition = <<~INVOKE_METHOD
141
139
  def _invoke(runtime_env, hashlike_params)
142
140
  @runtime_env = runtime_env
143
141
  @params = InvocationParams.new(hashlike_params)
144
- params = @params
145
142
  #{ruby_script}
146
143
  end
147
144
  INVOKE_METHOD
148
145
 
149
- invoke_method_line_count_prior_to_ruby_script_from_ops_file = 4
146
+ invoke_method_line_count_prior_to_ruby_script_from_ops_file = 3
150
147
  klass.module_eval(invoke_method_definition, ops_file.ops_file_path.to_s, ops_file.script_line_offset - invoke_method_line_count_prior_to_ruby_script_from_ops_file)
151
148
 
152
149
  klass
@@ -161,20 +158,13 @@ module OpsWalrus
161
158
  @ops_file = ops_file
162
159
  @script = ruby_script
163
160
  @runtime_env = nil # this is set at the very first line of #_invoke
161
+ @params = nil # this is set at the very first line of #_invoke
164
162
  end
165
163
 
166
164
  def backend
167
165
  @runtime_env.pty
168
166
  end
169
167
 
170
- def debug?
171
- @runtime_env.debug?
172
- end
173
-
174
- def verbose?
175
- @runtime_env.verbose?
176
- end
177
-
178
168
  def host_proxy_class
179
169
  @ops_file.host_proxy_class
180
170
  end
@@ -184,6 +174,15 @@ module OpsWalrus
184
174
  raise "Not implemented in base class."
185
175
  end
186
176
 
177
+ def params(*keys, default: nil)
178
+ keys = keys.map(&:to_s)
179
+ if keys.empty?
180
+ @params
181
+ else
182
+ @params.dig(*keys) || default
183
+ end
184
+ end
185
+
187
186
  def to_s
188
187
  @script
189
188
  end
@@ -1,5 +1,6 @@
1
1
  require 'shellwords'
2
2
  require 'stringio'
3
+ require 'random/formatter'
3
4
 
4
5
  require 'sshkit'
5
6
  require 'sshkit/dsl'
@@ -73,28 +74,28 @@ module OpsWalrus
73
74
 
74
75
  retval
75
76
  rescue SSHKit::Command::Failed => e
76
- puts "[!] Command failed:"
77
- puts e.message
77
+ App.instance.error "[!] Command failed:"
78
+ App.instance.error e.message
78
79
  rescue Net::SSH::ConnectionTimeout
79
- puts "[!] The host '#{host}' not alive!"
80
+ App.instance.error "[!] The host '#{host}' not alive!"
80
81
  rescue Net::SSH::Timeout
81
- puts "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
82
+ App.instance.error "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
82
83
  rescue Errno::ECONNREFUSED
83
- puts "[!] Incorrect port #{port} for #{host}"
84
+ App.instance.error "[!] Incorrect port #{port} for #{host}"
84
85
  rescue Net::SSH::HostKeyMismatch => e
85
- puts "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
86
- puts e.message
87
- puts "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
86
+ App.instance.error "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
87
+ App.instance.error e.message
88
+ App.instance.error "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
88
89
  rescue Net::SSH::AuthenticationFailed
89
- puts "Wrong Password: #{host} | #{user}:#{password}"
90
+ App.instance.error "Wrong Password: #{host} | #{user}:#{password}"
90
91
  rescue Net::SSH::Authentication::DisallowedMethod
91
- puts "[!] The host '#{host}' doesn't accept password authentication method."
92
+ App.instance.error "[!] The host '#{host}' doesn't accept password authentication method."
92
93
  rescue Errno::EHOSTUNREACH => e
93
- puts "[!] The host '#{host}' is unreachable"
94
+ App.instance.error "[!] The host '#{host}' is unreachable"
94
95
  rescue => e
95
- puts e.class
96
- puts e.message
97
- puts e.backtrace.join("\n")
96
+ App.instance.error e.class
97
+ App.instance.error e.message
98
+ App.instance.error e.backtrace.join("\n")
98
99
  ensure
99
100
  host.clear_ssh_session
100
101
  end
@@ -107,7 +108,7 @@ module OpsWalrus
107
108
  hosts = inventory(*args, **kwargs).map {|host| host_proxy_class.new(runtime_env, host) }
108
109
  sshkit_hosts = hosts.map(&:sshkit_host)
109
110
  sshkit_host_to_ops_host_map = sshkit_hosts.zip(hosts).to_h
110
- local_host = self
111
+ ops_file_script = local_host = self
111
112
  # bootstrap_shell_script = BootstrapLinuxHostShellScript
112
113
  # on sshkit_hosts do |sshkit_host|
113
114
  SSHKit::Coordinator.new(sshkit_hosts).each(in: kwargs[:in] || :parallel) do |sshkit_host|
@@ -116,6 +117,7 @@ module OpsWalrus
116
117
 
117
118
  begin
118
119
  host.set_runtime_env(runtime_env)
120
+ host.set_ops_file_script(ops_file_script)
119
121
  host.set_ssh_session_connection(self) # self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
120
122
 
121
123
  host._bootstrap_host
@@ -123,28 +125,28 @@ module OpsWalrus
123
125
 
124
126
  retval
125
127
  rescue SSHKit::Command::Failed => e
126
- puts "[!] Command failed:"
127
- puts e.message
128
+ App.instance.error "[!] Command failed:"
129
+ App.instance.error e.message
128
130
  rescue Net::SSH::ConnectionTimeout
129
- puts "[!] The host '#{host}' not alive!"
131
+ App.instance.error "[!] The host '#{host}' not alive!"
130
132
  rescue Net::SSH::Timeout
131
- puts "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
133
+ App.instance.error "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
132
134
  rescue Errno::ECONNREFUSED
133
- puts "[!] Incorrect port #{port} for #{host}"
135
+ App.instance.error "[!] Incorrect port #{port} for #{host}"
134
136
  rescue Net::SSH::HostKeyMismatch => e
135
- puts "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
136
- puts e.message
137
- puts "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
137
+ App.instance.error "[!] The host fingerprint does not match the last observed fingerprint for #{host}"
138
+ App.instance.error e.message
139
+ App.instance.error "You might try `ssh-keygen -f ~/.ssh/known_hosts -R \"#{host}\"`"
138
140
  rescue Net::SSH::AuthenticationFailed
139
- puts "Wrong Password: #{host} | #{user}:#{password}"
141
+ App.instance.error "Wrong Password: #{host} | #{user}:#{password}"
140
142
  rescue Net::SSH::Authentication::DisallowedMethod
141
- puts "[!] The host '#{host}' doesn't accept password authentication method."
143
+ App.instance.error "[!] The host '#{host}' doesn't accept password authentication method."
142
144
  rescue Errno::EHOSTUNREACH => e
143
- puts "[!] The host '#{host}' is unreachable"
145
+ App.instance.error "[!] The host '#{host}' is unreachable"
144
146
  rescue => e
145
- puts e.class
146
- puts e.message
147
- puts e.backtrace.join("\n")
147
+ App.instance.error e.class
148
+ App.instance.error e.message
149
+ App.instance.error e.backtrace.join("\n")
148
150
  ensure
149
151
  host.clear_ssh_session
150
152
  end
@@ -172,15 +174,6 @@ module OpsWalrus
172
174
  throw :exit_now, result
173
175
  end
174
176
 
175
- def env(*keys)
176
- keys = keys.map(&:to_s)
177
- if keys.empty?
178
- @runtime_env.env
179
- else
180
- @runtime_env.env.dig(*keys)
181
- end
182
- end
183
-
184
177
  # currently, import may only be used to import a package that is referenced in the script's package file
185
178
  # I may decide to extend this to work with dynamic package references
186
179
  #
@@ -190,7 +183,6 @@ module OpsWalrus
190
183
  package_reference = ops_file.package_file&.dependency(local_package_name)
191
184
  raise Error, "Unknown package reference: #{local_package_name}" unless package_reference
192
185
  import_reference = PackageDependencyReference.new(local_package_name, package_reference)
193
- # puts "import: #{import_reference.inspect}"
194
186
  namespace_or_ops_file = @runtime_env.resolve_import_reference(ops_file, import_reference)
195
187
  raise SymbolResolutionError, "Import reference '#{import_reference.summary}' not in load path for #{ops_file.ops_file_path}" unless namespace_or_ops_file
196
188
  invocation_context = LocalImportInvocationContext.new(@runtime_env, namespace_or_ops_file)
@@ -198,19 +190,19 @@ module OpsWalrus
198
190
  # invocation_context._invoke(*args, **kwargs)
199
191
  end
200
192
 
201
- # def params(*keys, default: nil)
202
- # keys = keys.map(&:to_s)
203
- # if keys.empty?
204
- # @params
205
- # else
206
- # @params.dig(*keys) || default
207
- # end
208
- # end
209
-
210
193
  def desc(msg)
211
194
  puts msg.mustache(1)
212
195
  end
213
196
 
197
+ def env(*keys)
198
+ keys = keys.map(&:to_s)
199
+ if keys.empty?
200
+ @runtime_env.env
201
+ else
202
+ @runtime_env.env.dig(*keys)
203
+ end
204
+ end
205
+
214
206
  # runs the given command
215
207
  # returns the stdout from the command
216
208
  def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block)
@@ -231,7 +223,7 @@ module OpsWalrus
231
223
  end
232
224
 
233
225
  # returns the tuple: [stdout, stderr, exit_status]
234
- def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
226
+ def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, log_level: nil)
235
227
  # description = nil
236
228
 
237
229
  return ["", "", 0] if !desc_or_cmd && !cmd && !block # we were told to do nothing; like hitting enter at the bash prompt; we can do nothing successfully
@@ -258,31 +250,55 @@ module OpsWalrus
258
250
 
259
251
  #cmd = Shellwords.escape(cmd)
260
252
 
261
- # puts "shell! self: #{self.inspect}"
253
+ cmd_id = Random.uuid.split('-').first
262
254
 
263
- if App.instance.report_mode?
264
- puts Style.green("*" * 80)
265
- print "[#{Style.blue(@runtime_env.local_hostname)}] "
266
- print "#{description}: " if description
267
- puts Style.yellow(cmd)
268
- end
255
+ # if App.instance.report_mode?
256
+ puts Style.green("*" * 80)
257
+ print Style.blue(@runtime_env.local_hostname)
258
+ print " | #{Style.magenta(description)}" if description
259
+ puts
260
+ print Style.yellow(cmd_id)
261
+ print Style.green.bold(" > ")
262
+ puts Style.yellow(cmd)
263
+ # end
269
264
 
270
265
  return unless cmd && !cmd.strip.empty?
271
266
 
272
- if App.instance.dry_run?
267
+ t1 = Time.now
268
+ out, err, exit_status = if App.instance.dry_run?
273
269
  ["", "", 0]
274
270
  else
275
271
  sshkit_cmd = @runtime_env.handle_input(input) do |interaction_handler|
276
272
  # self is a Module instance that is serving as the evaluation context in an instance of a subclass of an Invocation; see Invocation#evaluate
277
- backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: :info)
273
+ # backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: SSHKit.config.output_verbosity)
274
+ backend.execute_cmd(cmd, interaction_handler: interaction_handler)
278
275
  end
279
276
  [sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
280
277
  end
281
- end
278
+ t2 = Time.now
279
+ seconds = t2 - t1
280
+
281
+ if App.instance.info? || log_level == :info
282
+ puts Style.cyan(out)
283
+ puts Style.red(err)
284
+ elsif App.instance.debug? || log_level == :debug
285
+ puts Style.cyan(out)
286
+ puts Style.red(err)
287
+ elsif App.instance.trace? || log_level == :trace
288
+ puts Style.cyan(out)
289
+ puts Style.red(err)
290
+ end
291
+ print Style.yellow(cmd_id)
292
+ print Style.blue(" | Finished in #{seconds} seconds with exit status ")
293
+ if exit_status == 0
294
+ puts Style.green("#{exit_status} (#{exit_status == 0 ? 'success' : 'failure'})")
295
+ else
296
+ puts Style.red("#{exit_status} (#{exit_status == 0 ? 'success' : 'failure'})")
297
+ end
298
+
282
299
 
283
- # def init_brew
284
- # execute('eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"')
285
- # end
300
+ [out, err, exit_status]
301
+ end
286
302
 
287
303
  end
288
304
 
@@ -207,12 +207,12 @@ module OpsWalrus
207
207
  def resolve_import_reference(origin_ops_file, import_reference)
208
208
  resolved_namespace_or_ops_file = case import_reference
209
209
  when PackageDependencyReference
210
- # puts "root namespace: #{@root_namespace.symbol_table}"
210
+ # App.instance.trace "root namespace: #{@root_namespace.symbol_table}"
211
211
  @root_namespace.resolve_symbol(import_reference.package_reference.import_resolution_dirname) # returns the Namespace associated with the bundled package import_resolution_dirname (i.e. the local name)
212
212
  when DynamicPackageImportReference
213
213
  dynamic_package_reference = import_reference.package_reference
214
214
  @dynamic_package_additions_memo[dynamic_package_reference] ||= begin
215
- # puts "Downloading dynamic package: #{dynamic_package_reference.inspect}"
215
+ # App.instance.trace "Downloading dynamic package: #{dynamic_package_reference.inspect}"
216
216
  App.instance.debug("Downloading dynamic package: #{dynamic_package_reference}")
217
217
  dynamically_added_package_dir = @runtime_env.app.bundler.download_git_package(dynamic_package_reference.package_uri, dynamic_package_reference.version)
218
218
  dynamically_add_new_package_dir(dynamically_added_package_dir)
@@ -267,15 +267,16 @@ module OpsWalrus
267
267
  SSHKit.config.use_format :blackhole
268
268
  SSHKit.config.output_verbosity = :info
269
269
 
270
- if app.debug?
271
- SSHKit.config.use_format :pretty
272
- # SSHKit.config.use_format :simpletext
273
- SSHKit.config.output_verbosity = :debug
274
- elsif app.verbose?
275
- SSHKit.config.use_format :pretty
276
- # SSHKit.config.use_format :dot
277
- SSHKit.config.output_verbosity = :info
278
- end
270
+ # if app.info?
271
+ # SSHKit.config.use_format :pretty
272
+ # SSHKit.config.output_verbosity = :info
273
+ # elsif app.debug?
274
+ # SSHKit.config.use_format :pretty
275
+ # SSHKit.config.output_verbosity = :debug
276
+ # elsif app.trace?
277
+ # SSHKit.config.use_format :pretty
278
+ # SSHKit.config.output_verbosity = :debug
279
+ # end
279
280
 
280
281
  SSHKit::Backend::Netssh.configure do |ssh|
281
282
  ssh.pty = true # necessary for interaction with sudo on the remote host
@@ -292,14 +293,6 @@ module OpsWalrus
292
293
  SSHKit::Backend::Netssh.pool.idle_timeout = 1 # seconds
293
294
  end
294
295
 
295
- def debug?
296
- @app.debug?
297
- end
298
-
299
- def verbose?
300
- @app.verbose?
301
- end
302
-
303
296
  def local_hostname
304
297
  @app.local_hostname
305
298
  end
@@ -9,10 +9,10 @@ require_relative 'local_pty_backend'
9
9
  module SSHKit
10
10
  module Backend
11
11
  class Abstract
12
- def execute(*args)
13
- options = { raise_on_non_zero_exit: false }.merge(args.extract_options!)
14
- create_command_and_execute(args, options).success?
15
- end
12
+ # def execute(*args)
13
+ # options = { verbosity: :debug, raise_on_non_zero_exit: false }.merge(args.extract_options!)
14
+ # create_command_and_execute(args, options).success?
15
+ # end
16
16
 
17
17
  def execute_cmd(*args)
18
18
  options = { verbosity: :debug, strip: true, raise_on_non_zero_exit: false }.merge(args.extract_options!)
@@ -21,6 +21,12 @@ module SSHKit
21
21
  end
22
22
  end
23
23
 
24
+ # module Formatter
25
+ # class Pretty < Abstract
26
+
27
+ # end
28
+ # end
29
+
24
30
  module Runner
25
31
  class Sequential < Abstract
26
32
  def run_backend(host, &block)
@@ -1,3 +1,3 @@
1
1
  module OpsWalrus
2
- VERSION = "1.0.38"
2
+ VERSION = "1.0.40"
3
3
  end
@@ -99,7 +99,6 @@ end
99
99
  # # m = TemplateLang.parse("abc; {{ 'foo' * bar }} def ")
100
100
  # m = WalrusLang::Parser.parse("abc; {{ 'foo{{1+2}}' * bar }} def {{ 4 * 4 }}; def")
101
101
  # # m = TemplateLang.parse("a{{b{{c}}d}}e{{f}}g{{h{{i{{j{{k{{l}}m{{n}}o}}p}}}}}}")
102
- # # puts m.dump
103
102
  # puts m.render(binding)
104
103
 
105
104
  # puts("abc {{ 1 + 2 }} def".mustache)
data/opswalrus.gemspec CHANGED
@@ -32,7 +32,6 @@ Gem::Specification.new do |spec|
32
32
  spec.require_paths = ["lib"]
33
33
 
34
34
  # gem dependencies
35
- spec.add_dependency "amazing_print", "~> 1.5"
36
35
  spec.add_dependency "binding_of_caller", "~> 1.0"
37
36
  spec.add_dependency "citrus", "~> 3.0"
38
37
  spec.add_dependency "gli", "~> 2.21"
@@ -20,13 +20,19 @@ Vagrant.configure("2") do |config|
20
20
  # Enable provisioning with a shell script. Additional provisioners such as
21
21
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
22
22
  # documentation for more information about their specific syntax and use.
23
- config.vm.provision "shell", inline: <<-SHELL
24
- sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
25
- sudo systemctl restart sshd
23
+ config.vm.provision "shell" do |s|
24
+ ssh_pub_key = File.readlines("#{Dir.home}/.ssh/id_ops.pub").first.strip
25
+ s.inline = <<-SHELL
26
+ echo #{ssh_pub_key} >> /home/vagrant/.ssh/authorized_keys
27
+ echo #{ssh_pub_key} >> /root/.ssh/authorized_keys
26
28
 
27
- # change vagrant user to require sudo password
28
- sudo sed -i 's/vagrant ALL=(ALL) NOPASSWD:ALL/vagrant ALL=(ALL:ALL) ALL/g' /etc/sudoers.d/vagrant
29
+ sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
30
+ sudo systemctl restart sshd
29
31
 
30
- # sudo sh -c 'echo root:foo | chpasswd'
31
- SHELL
32
+ # change vagrant user to require sudo password
33
+ sudo sed -i 's/vagrant ALL=(ALL) NOPASSWD:ALL/vagrant ALL=(ALL:ALL) ALL/g' /etc/sudoers.d/vagrant
34
+
35
+ # sudo sh -c 'echo root:foo | chpasswd'
36
+ SHELL
37
+ end
32
38
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opswalrus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.38
4
+ version: 1.0.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Ellis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2023-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: amazing_print
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.5'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.5'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: binding_of_caller
29
15
  requirement: !ruby/object:Gem::Requirement