opswalrus 1.0.39 → 1.0.41
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -3
- data/lib/opswalrus/app.rb +31 -24
- data/lib/opswalrus/bootstrap.sh +3 -2
- data/lib/opswalrus/cli.rb +11 -18
- data/lib/opswalrus/host.rb +59 -32
- data/lib/opswalrus/hosts_file.rb +3 -6
- data/lib/opswalrus/interaction_handlers.rb +0 -3
- data/lib/opswalrus/local_non_blocking_backend.rb +2 -2
- data/lib/opswalrus/local_pty_backend.rb +1 -1
- data/lib/opswalrus/operation_runner.rb +3 -5
- data/lib/opswalrus/ops_file.rb +2 -3
- data/lib/opswalrus/ops_file_script.rb +1 -11
- data/lib/opswalrus/ops_file_script_dsl.rb +67 -43
- data/lib/opswalrus/runtime_environment.rb +12 -19
- data/lib/opswalrus/sshkit_ext.rb +10 -4
- data/lib/opswalrus/version.rb +1 -1
- data/lib/opswalrus/walrus_lang.rb +0 -1
- data/opswalrus.gemspec +0 -1
- data/vms/web-ubuntu/Vagrantfile +13 -7
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e253e6b949d98e3d7deea0044949e94f5e308a2258412cc8667c7af2fe059f9
|
4
|
+
data.tar.gz: 91c12649f126a65c780111fde50cac4d9be674a32ea85d7771df681741ce1ef7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 694d15c5c835df26743fc1ebcae8e8f0a6a517aad301b73780298590f9c3b3834c731e12363321eff5c7c04c14ed8e9206869d6d8a7c1a32e767eb1a093a6505
|
7
|
+
data.tar.gz: 57a5a9fe9f55cab60fb9fbb104b5e6b7c588ee0308c06ed63ac90996328a8f515e9512a6d746a5d943652fceea2804c6ed40e4063f7fe96863d4c762785cc404
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
opswalrus (1.0.
|
5
|
-
amazing_print (~> 1.5)
|
4
|
+
opswalrus (1.0.41)
|
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
|
148
|
+
def info(*args)
|
148
149
|
@logger.info(*args)
|
149
150
|
end
|
150
|
-
alias_method :
|
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
|
-
|
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
|
-
|
235
|
-
|
236
|
-
puts exit_status
|
245
|
+
debug "Op exit_status"
|
246
|
+
debug exit_status
|
237
247
|
|
238
|
-
|
239
|
-
|
240
|
-
end
|
248
|
+
debug "Op output"
|
249
|
+
debug JSON.pretty_generate(result.value)
|
241
250
|
|
242
|
-
|
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
|
data/lib/opswalrus/bootstrap.sh
CHANGED
@@ -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"
|
@@ -26,8 +27,8 @@ if [ -x $RTX ]; then
|
|
26
27
|
|
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_CMD install opswalrus
|
30
|
+
gem 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
|
-
|
26
|
-
|
27
|
-
|
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
|
34
|
-
switch
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/opswalrus/host.rb
CHANGED
@@ -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,57 +169,83 @@ module OpsWalrus
|
|
170
169
|
|
171
170
|
#cmd = Shellwords.escape(cmd)
|
172
171
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
187
|
-
|
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
|
-
|
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
|
-
|
199
|
-
|
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
|
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
|
-
"#{
|
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
|
-
|
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)
|
@@ -391,13 +416,15 @@ module OpsWalrus
|
|
391
416
|
|
392
417
|
def execute(*args, input: nil)
|
393
418
|
@runtime_env.handle_input(input, ssh_password) do |interaction_handler|
|
394
|
-
@sshkit_backend.capture(*args, interaction_handler: interaction_handler, verbosity:
|
419
|
+
# @sshkit_backend.capture(*args, interaction_handler: interaction_handler, verbosity: SSHKit.config.output_verbosity)
|
420
|
+
@sshkit_backend.capture(*args, interaction_handler: interaction_handler)
|
395
421
|
end
|
396
422
|
end
|
397
423
|
|
398
424
|
def execute_cmd(*args, input: nil)
|
399
425
|
@runtime_env.handle_input(input, ssh_password) do |interaction_handler|
|
400
|
-
@sshkit_backend.execute_cmd(*args, interaction_handler: interaction_handler, verbosity:
|
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)
|
401
428
|
end
|
402
429
|
end
|
403
430
|
|
data/lib/opswalrus/hosts_file.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
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
|
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}"
|
data/lib/opswalrus/ops_file.rb
CHANGED
@@ -47,8 +47,7 @@ module OpsWalrus
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def lazy_load_file
|
50
|
-
|
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
|
-
|
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
|
-
#
|
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,8 +134,6 @@ 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)
|
@@ -167,14 +165,6 @@ module OpsWalrus
|
|
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
|
@@ -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
|
-
|
77
|
-
|
77
|
+
App.instance.error "[!] Command failed:"
|
78
|
+
App.instance.error e.message
|
78
79
|
rescue Net::SSH::ConnectionTimeout
|
79
|
-
|
80
|
+
App.instance.error "[!] The host '#{host}' not alive!"
|
80
81
|
rescue Net::SSH::Timeout
|
81
|
-
|
82
|
+
App.instance.error "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
|
82
83
|
rescue Errno::ECONNREFUSED
|
83
|
-
|
84
|
+
App.instance.error "[!] Incorrect port #{port} for #{host}"
|
84
85
|
rescue Net::SSH::HostKeyMismatch => e
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
90
|
+
App.instance.error "Wrong Password: #{host} | #{user}:#{password}"
|
90
91
|
rescue Net::SSH::Authentication::DisallowedMethod
|
91
|
-
|
92
|
+
App.instance.error "[!] The host '#{host}' doesn't accept password authentication method."
|
92
93
|
rescue Errno::EHOSTUNREACH => e
|
93
|
-
|
94
|
+
App.instance.error "[!] The host '#{host}' is unreachable"
|
94
95
|
rescue => e
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
@@ -124,28 +125,28 @@ module OpsWalrus
|
|
124
125
|
|
125
126
|
retval
|
126
127
|
rescue SSHKit::Command::Failed => e
|
127
|
-
|
128
|
-
|
128
|
+
App.instance.error "[!] Command failed:"
|
129
|
+
App.instance.error e.message
|
129
130
|
rescue Net::SSH::ConnectionTimeout
|
130
|
-
|
131
|
+
App.instance.error "[!] The host '#{host}' not alive!"
|
131
132
|
rescue Net::SSH::Timeout
|
132
|
-
|
133
|
+
App.instance.error "[!] The host '#{host}' disconnected/timeouted unexpectedly!"
|
133
134
|
rescue Errno::ECONNREFUSED
|
134
|
-
|
135
|
+
App.instance.error "[!] Incorrect port #{port} for #{host}"
|
135
136
|
rescue Net::SSH::HostKeyMismatch => e
|
136
|
-
|
137
|
-
|
138
|
-
|
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}\"`"
|
139
140
|
rescue Net::SSH::AuthenticationFailed
|
140
|
-
|
141
|
+
App.instance.error "Wrong Password: #{host} | #{user}:#{password}"
|
141
142
|
rescue Net::SSH::Authentication::DisallowedMethod
|
142
|
-
|
143
|
+
App.instance.error "[!] The host '#{host}' doesn't accept password authentication method."
|
143
144
|
rescue Errno::EHOSTUNREACH => e
|
144
|
-
|
145
|
+
App.instance.error "[!] The host '#{host}' is unreachable"
|
145
146
|
rescue => e
|
146
|
-
|
147
|
-
|
148
|
-
|
147
|
+
App.instance.error e.class
|
148
|
+
App.instance.error e.message
|
149
|
+
App.instance.error e.backtrace.join("\n")
|
149
150
|
ensure
|
150
151
|
host.clear_ssh_session
|
151
152
|
end
|
@@ -182,7 +183,6 @@ module OpsWalrus
|
|
182
183
|
package_reference = ops_file.package_file&.dependency(local_package_name)
|
183
184
|
raise Error, "Unknown package reference: #{local_package_name}" unless package_reference
|
184
185
|
import_reference = PackageDependencyReference.new(local_package_name, package_reference)
|
185
|
-
# puts "import: #{import_reference.inspect}"
|
186
186
|
namespace_or_ops_file = @runtime_env.resolve_import_reference(ops_file, import_reference)
|
187
187
|
raise SymbolResolutionError, "Import reference '#{import_reference.summary}' not in load path for #{ops_file.ops_file_path}" unless namespace_or_ops_file
|
188
188
|
invocation_context = LocalImportInvocationContext.new(@runtime_env, namespace_or_ops_file)
|
@@ -223,7 +223,7 @@ module OpsWalrus
|
|
223
223
|
end
|
224
224
|
|
225
225
|
# returns the tuple: [stdout, stderr, exit_status]
|
226
|
-
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)
|
227
227
|
# description = nil
|
228
228
|
|
229
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
|
@@ -250,31 +250,55 @@ module OpsWalrus
|
|
250
250
|
|
251
251
|
#cmd = Shellwords.escape(cmd)
|
252
252
|
|
253
|
-
|
253
|
+
cmd_id = Random.uuid.split('-').first
|
254
254
|
|
255
|
-
if App.instance.report_mode?
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
261
264
|
|
262
265
|
return unless cmd && !cmd.strip.empty?
|
263
266
|
|
264
|
-
|
267
|
+
t1 = Time.now
|
268
|
+
out, err, exit_status = if App.instance.dry_run?
|
265
269
|
["", "", 0]
|
266
270
|
else
|
267
271
|
sshkit_cmd = @runtime_env.handle_input(input) do |interaction_handler|
|
268
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
|
269
|
-
backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity:
|
273
|
+
# backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: SSHKit.config.output_verbosity)
|
274
|
+
backend.execute_cmd(cmd, interaction_handler: interaction_handler)
|
270
275
|
end
|
271
276
|
[sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
|
272
277
|
end
|
273
|
-
|
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
|
+
|
274
299
|
|
275
|
-
|
276
|
-
|
277
|
-
# end
|
300
|
+
[out, err, exit_status]
|
301
|
+
end
|
278
302
|
|
279
303
|
end
|
280
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
|
-
#
|
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
|
-
#
|
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.
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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
|
data/lib/opswalrus/sshkit_ext.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
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)
|
data/lib/opswalrus/version.rb
CHANGED
@@ -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"
|
data/vms/web-ubuntu/Vagrantfile
CHANGED
@@ -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"
|
24
|
-
|
25
|
-
|
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
|
-
|
28
|
-
|
29
|
+
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
|
30
|
+
sudo systemctl restart sshd
|
29
31
|
|
30
|
-
|
31
|
-
|
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.
|
4
|
+
version: 1.0.41
|
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-
|
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
|