opswalrus 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/build.ops +20 -0
- data/lib/opswalrus/app.rb +2 -15
- data/lib/opswalrus/host.rb +23 -10
- data/lib/opswalrus/interaction_handlers.rb +85 -0
- data/lib/opswalrus/local_pty_backend.rb +12 -2
- data/lib/opswalrus/ops_file_script.rb +23 -14
- data/lib/opswalrus/runtime_environment.rb +19 -0
- data/lib/opswalrus/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0c1c00f88ff00a4f7eb735a634ea35e1e8818b44fffdccea7a2347bac78e199
|
|
4
|
+
data.tar.gz: fe54254076c753cfeaf26906fa0f7475bd11807c0ac70d4067da03653b0f774c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28244a51a465941731663e9db3901049d36d1fa385a16b4c5ed9254c31fa62ca44012c2d776ef5b6d1d06906c012802b1352e166d72d28b3ec0aa6f9e27073f5
|
|
7
|
+
data.tar.gz: 39ccb70ca9dc5b2ecf67b1ab29adb7ccc79cb43ad57d256be0deb68b49909bc4c5cd4ddc2871e68aeeb374ed3d0202c365094536e7933f61c3ecf700a2178076
|
data/Gemfile.lock
CHANGED
data/build.ops
CHANGED
|
@@ -7,6 +7,8 @@ imports:
|
|
|
7
7
|
|
|
8
8
|
version = params.version
|
|
9
9
|
|
|
10
|
+
exit 1, "version parameter must be specified" unless version
|
|
11
|
+
|
|
10
12
|
template = <<TEMPLATE
|
|
11
13
|
module OpsWalrus
|
|
12
14
|
VERSION = "{{ version }}"
|
|
@@ -17,4 +19,22 @@ puts "Write version.rb for version #{version}"
|
|
|
17
19
|
core.template.write(path: "./lib/opswalrus/version.rb", template: template, variables: {version: version})
|
|
18
20
|
|
|
19
21
|
sh("Build gem") { 'gem build opswalrus.gemspec' }
|
|
22
|
+
bw_status_output = sh("Check whether Bitwarden is locked or not") { 'bw status' }
|
|
23
|
+
# the status command currently exhibits an error in which it emits 'mac failed.' some number of times, so we need to filter that out
|
|
24
|
+
# see:
|
|
25
|
+
# - https://community.bitwarden.com/t/what-does-mac-failed-mean-exactly/29208
|
|
26
|
+
# - https://github.com/bitwarden/cli/issues/88
|
|
27
|
+
# - https://github.com/vwxyzjn/portwarden/issues/22
|
|
28
|
+
# ❯ bw status
|
|
29
|
+
# mac failed.
|
|
30
|
+
# {"serverUrl":"...","lastSync":"2023-08-17T19:14:09.384Z","userEmail":"...","userId":"...","status":"locked"}
|
|
31
|
+
bw_status_output = bw_status_output.gsub('mac failed.', '').strip
|
|
32
|
+
bw_status_json = bw_status_output.parse_json
|
|
33
|
+
|
|
34
|
+
if bw_status_json['status'] != 'unlocked'
|
|
35
|
+
exit 0, "Bitwarden is not unlocked. Please unlock bitwarden with: bw unlock"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
totp = sh("Get Rubygems OTP") { 'bw get totp Rubygems' }
|
|
39
|
+
sh("Push gem", input: {"You have enabled multi-factor authentication. Please enter OTP code." => "#{totp}\n"}) { 'gem push opswalrus-{{ version }}.gem' }
|
|
20
40
|
sh("Build docker image") { 'docker build -t opswalrus/ops:{{ version }} .' }
|
data/lib/opswalrus/app.rb
CHANGED
|
@@ -7,6 +7,7 @@ require "socket"
|
|
|
7
7
|
require "stringio"
|
|
8
8
|
require "yaml"
|
|
9
9
|
require "pathname"
|
|
10
|
+
require_relative "patches"
|
|
10
11
|
require_relative "git"
|
|
11
12
|
require_relative "host"
|
|
12
13
|
require_relative "hosts_file"
|
|
@@ -14,21 +15,6 @@ require_relative "operation_runner"
|
|
|
14
15
|
require_relative "bundler"
|
|
15
16
|
require_relative "package_file"
|
|
16
17
|
|
|
17
|
-
class String
|
|
18
|
-
def escape_single_quotes
|
|
19
|
-
gsub("'"){"\\'"}
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def to_pathname
|
|
23
|
-
Pathname.new(self)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class Pathname
|
|
28
|
-
def to_pathname
|
|
29
|
-
self
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
18
|
|
|
33
19
|
module OpsWalrus
|
|
34
20
|
class Error < StandardError
|
|
@@ -131,6 +117,7 @@ module OpsWalrus
|
|
|
131
117
|
def prompt_sudo_password
|
|
132
118
|
password = IO::console.getpass(LOCAL_SUDO_PASSWORD_PROMPT)
|
|
133
119
|
set_sudo_password(password)
|
|
120
|
+
# puts "sudo password = |#{password}|"
|
|
134
121
|
nil
|
|
135
122
|
end
|
|
136
123
|
|
data/lib/opswalrus/host.rb
CHANGED
|
@@ -7,18 +7,18 @@ module OpsWalrus
|
|
|
7
7
|
|
|
8
8
|
module HostDSL
|
|
9
9
|
# returns the stdout from the command
|
|
10
|
-
def sh(desc_or_cmd = nil, cmd = nil,
|
|
11
|
-
out, err, status = *shell!(desc_or_cmd, cmd, block,
|
|
10
|
+
def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
|
11
|
+
out, err, status = *shell!(desc_or_cmd, cmd, block, input: input)
|
|
12
12
|
out
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# returns the tuple: [stdout, stderr, exit_status]
|
|
16
|
-
def shell(desc_or_cmd = nil, cmd = nil,
|
|
17
|
-
shell!(desc_or_cmd, cmd, block,
|
|
16
|
+
def shell(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
|
17
|
+
shell!(desc_or_cmd, cmd, block, input: input)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# returns the tuple: [stdout, stderr, exit_status]
|
|
21
|
-
def shell!(desc_or_cmd = nil, cmd = nil, block = nil,
|
|
21
|
+
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
|
|
22
22
|
# description = nil
|
|
23
23
|
|
|
24
24
|
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
|
|
@@ -45,7 +45,7 @@ module OpsWalrus
|
|
|
45
45
|
# puts "shell: #{cmd.inspect}"
|
|
46
46
|
# puts "sudo_password: #{sudo_password}"
|
|
47
47
|
|
|
48
|
-
sshkit_cmd = execute_cmd(cmd)
|
|
48
|
+
sshkit_cmd = execute_cmd(cmd, input: input)
|
|
49
49
|
|
|
50
50
|
[sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
|
|
51
51
|
end
|
|
@@ -203,6 +203,10 @@ module OpsWalrus
|
|
|
203
203
|
})
|
|
204
204
|
end
|
|
205
205
|
|
|
206
|
+
def set_runtime_env(runtime_env)
|
|
207
|
+
@runtime_env = runtime_env
|
|
208
|
+
end
|
|
209
|
+
|
|
206
210
|
def set_ssh_session_connection(sshkit_backend)
|
|
207
211
|
@sshkit_backend = sshkit_backend
|
|
208
212
|
end
|
|
@@ -212,18 +216,27 @@ module OpsWalrus
|
|
|
212
216
|
end
|
|
213
217
|
|
|
214
218
|
def clear_ssh_session
|
|
219
|
+
@runtime_env = nil
|
|
215
220
|
@sshkit_backend = nil
|
|
216
221
|
@tmp_bundle_root_dir = nil
|
|
217
222
|
end
|
|
218
223
|
|
|
219
|
-
def execute(*args)
|
|
224
|
+
def execute(*args, input: nil)
|
|
220
225
|
# puts "interaction handler responds with: #{ssh_password}"
|
|
221
|
-
@sshkit_backend.capture(*args, interaction_handler: SudoPasswordMapper.new(ssh_password).interaction_handler, verbosity: :info)
|
|
226
|
+
# @sshkit_backend.capture(*args, interaction_handler: SudoPasswordMapper.new(ssh_password).interaction_handler, verbosity: :info)
|
|
222
227
|
# @sshkit_backend.capture(*args, interaction_handler: SudoPromptInteractionHandler.new, verbosity: :info)
|
|
228
|
+
|
|
229
|
+
@runtime_env.handle_input(input, ssh_password) do |interaction_handler|
|
|
230
|
+
@sshkit_backend.capture(*args, interaction_handler: interaction_handler, verbosity: :info)
|
|
231
|
+
end
|
|
232
|
+
|
|
223
233
|
end
|
|
224
234
|
|
|
225
|
-
def execute_cmd(*args)
|
|
226
|
-
@sshkit_backend.execute_cmd(*args, interaction_handler: SudoPasswordMapper.new(ssh_password).interaction_handler, verbosity: :info)
|
|
235
|
+
def execute_cmd(*args, input: nil)
|
|
236
|
+
# @sshkit_backend.execute_cmd(*args, interaction_handler: SudoPasswordMapper.new(ssh_password).interaction_handler, verbosity: :info)
|
|
237
|
+
@runtime_env.handle_input(input, ssh_password) do |interaction_handler|
|
|
238
|
+
@sshkit_backend.execute_cmd(*args, interaction_handler: interaction_handler, verbosity: :info)
|
|
239
|
+
end
|
|
227
240
|
end
|
|
228
241
|
|
|
229
242
|
def upload(local_path_or_io, remote_path)
|
|
@@ -2,6 +2,91 @@ require 'sshkit'
|
|
|
2
2
|
|
|
3
3
|
module OpsWalrus
|
|
4
4
|
|
|
5
|
+
class ScopedMappingInteractionHandler
|
|
6
|
+
attr_accessor :input_mappings # Hash[ String | Regex => String ]
|
|
7
|
+
|
|
8
|
+
def initialize(mapping, log_level = nil)
|
|
9
|
+
@log_level = log_level
|
|
10
|
+
@input_mappings = mapping
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# temporarily adds a sudo password mapping to the interaction handler while the given block is being evaluated
|
|
14
|
+
# when the given block returns, then the temporary mapping is removed from the interaction handler
|
|
15
|
+
# def with_sudo_password(password, &block)
|
|
16
|
+
# with_mapping({
|
|
17
|
+
# /\[sudo\] password for .*?:\s*/ => "#{password}\n",
|
|
18
|
+
# App::LOCAL_SUDO_PASSWORD_PROMPT => "#{password}\n",
|
|
19
|
+
# # /\s+/ => nil, # unnecessary
|
|
20
|
+
# }, &block)
|
|
21
|
+
# end
|
|
22
|
+
|
|
23
|
+
# sudo_password : String
|
|
24
|
+
def mapping_for_sudo_password(sudo_password)
|
|
25
|
+
{
|
|
26
|
+
/\[sudo\] password for .*?:\s*/ => "#{sudo_password}\n",
|
|
27
|
+
App::LOCAL_SUDO_PASSWORD_PROMPT => "#{sudo_password}\n",
|
|
28
|
+
# /\s+/ => nil, # unnecessary
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# temporarily adds the specified input mapping to the interaction handler while the given block is being evaluated
|
|
33
|
+
# when the given block returns, then the temporary mapping is removed from the interaction handler
|
|
34
|
+
#
|
|
35
|
+
# mapping : Hash[ String | Regex => String ]
|
|
36
|
+
def with_mapping(mapping, sudo_password = nil)
|
|
37
|
+
mapping ||= {}
|
|
38
|
+
|
|
39
|
+
raise ArgumentError.new("mapping must be a Hash") unless mapping.is_a?(Hash)
|
|
40
|
+
|
|
41
|
+
if sudo_password
|
|
42
|
+
mapping.merge!(mapping_for_sudo_password(sudo_password))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if mapping.empty?
|
|
46
|
+
yield self
|
|
47
|
+
else
|
|
48
|
+
yield ScopedMappingInteractionHandler.new(@input_mappings.merge(mapping), @log_level)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# adds the specified input mapping to the interaction handler
|
|
53
|
+
#
|
|
54
|
+
# mapping : Hash[ String | Regex => String ]
|
|
55
|
+
def add_mapping(mapping)
|
|
56
|
+
@input_mappings.merge!(mapping)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def on_data(_command, stream_name, data, channel)
|
|
60
|
+
log("Looking up response for #{stream_name} message #{data.inspect}")
|
|
61
|
+
|
|
62
|
+
response_data = begin
|
|
63
|
+
first_matching_key_value_pair = @input_mappings.find {|k, _v| k === data }
|
|
64
|
+
first_matching_key_value_pair&.last
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if response_data.nil?
|
|
68
|
+
log("Unable to find interaction handler mapping for #{stream_name}: #{data.inspect} so no response was sent")
|
|
69
|
+
else
|
|
70
|
+
log("Sending #{response_data.inspect}")
|
|
71
|
+
if channel.respond_to?(:send_data) # Net SSH Channel
|
|
72
|
+
channel.send_data(response_data)
|
|
73
|
+
elsif channel.respond_to?(:write) # Local IO
|
|
74
|
+
channel.write(response_data)
|
|
75
|
+
else
|
|
76
|
+
raise "Unable to write response data to channel #{channel.inspect} - does not support '#send_data' or '#write'"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def log(message)
|
|
84
|
+
# puts message
|
|
85
|
+
SSHKit.config.output.send(@log_level, message) unless @log_level.nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
5
90
|
class PasswdInteractionHandler
|
|
6
91
|
def on_data(command, stream_name, data, channel)
|
|
7
92
|
# puts data
|
|
@@ -16,12 +16,16 @@ module SSHKit
|
|
|
16
16
|
cmd.started = Time.now
|
|
17
17
|
PTY.spawn(cmd.to_command) do |stdout, stdin, pid|
|
|
18
18
|
stdout_thread = Thread.new do
|
|
19
|
+
# debug_log = StringIO.new
|
|
19
20
|
buffer = ""
|
|
20
21
|
partial_buffer = ""
|
|
21
22
|
while !stdout.closed?
|
|
23
|
+
# debug_log.puts "!!!\nbuffer=#{buffer}|EOL|\npartial=#{partial_buffer}|EOL|"
|
|
22
24
|
# puts "9" * 80
|
|
23
25
|
begin
|
|
24
|
-
|
|
26
|
+
# partial_buffer = ""
|
|
27
|
+
# stdout.read_nonblock(4096, partial_buffer)
|
|
28
|
+
partial_buffer = stdout.read_nonblock(4096)
|
|
25
29
|
buffer << partial_buffer
|
|
26
30
|
# puts "nonblocking1. buffer=#{buffer} partial_buffer=#{partial_buffer}"
|
|
27
31
|
buffer = handle_data_for_stdout(output, cmd, buffer, stdin, false)
|
|
@@ -48,6 +52,10 @@ module SSHKit
|
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
# puts "end!"
|
|
55
|
+
# debug_log.puts "!!!\nbuffer=#{buffer}|EOL|\npartial=#{partial_buffer}|EOL|"
|
|
56
|
+
|
|
57
|
+
# puts "*" * 80
|
|
58
|
+
# puts debug_log.string
|
|
51
59
|
|
|
52
60
|
end
|
|
53
61
|
stdout_thread.join
|
|
@@ -59,12 +67,14 @@ module SSHKit
|
|
|
59
67
|
|
|
60
68
|
# returns [complete lines, new buffer]
|
|
61
69
|
def split_buffer(buffer)
|
|
62
|
-
lines = buffer.split(/(\r\n)
|
|
70
|
+
lines = buffer.split(/(\r\n)|\r|\n/)
|
|
63
71
|
buffer = lines.pop
|
|
64
72
|
[lines, buffer]
|
|
65
73
|
end
|
|
66
74
|
|
|
67
75
|
def handle_data_for_stdout(output, cmd, buffer, stdin, is_blocked)
|
|
76
|
+
# puts "handling data for stdout: #{buffer}"
|
|
77
|
+
|
|
68
78
|
# we're blocked on reading, so let's process the buffer
|
|
69
79
|
lines, buffer = split_buffer(buffer)
|
|
70
80
|
lines.each do |line|
|
|
@@ -121,13 +121,15 @@ module OpsWalrus
|
|
|
121
121
|
# bootstrap_shell_script = BootstrapLinuxHostShellScript
|
|
122
122
|
# on sshkit_hosts do |sshkit_host|
|
|
123
123
|
SSHKit::Coordinator.new(sshkit_hosts).each(in: kwargs[:in] || :parallel) do |sshkit_host|
|
|
124
|
-
host = sshkit_host_to_ops_host_map[sshkit_host]
|
|
125
124
|
|
|
125
|
+
# in this context, self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
|
|
126
|
+
|
|
127
|
+
host = sshkit_host_to_ops_host_map[sshkit_host]
|
|
126
128
|
# puts "#{host.alias} / #{host}:"
|
|
127
129
|
|
|
128
130
|
begin
|
|
129
|
-
|
|
130
|
-
host.set_ssh_session_connection(self)
|
|
131
|
+
host.set_runtime_env(runtime_env)
|
|
132
|
+
host.set_ssh_session_connection(self) # self is an instance of one of the subclasses of SSHKit::Backend::Abstract, e.g. SSHKit::Backend::Netssh
|
|
131
133
|
|
|
132
134
|
# copy over bootstrap shell script
|
|
133
135
|
# io = StringIO.new(bootstrap_shell_script)
|
|
@@ -199,11 +201,14 @@ module OpsWalrus
|
|
|
199
201
|
@runtime_env.app.inventory(tags)
|
|
200
202
|
end
|
|
201
203
|
|
|
202
|
-
def exit(exit_status)
|
|
204
|
+
def exit(exit_status, message = nil)
|
|
205
|
+
if message
|
|
206
|
+
puts message
|
|
207
|
+
end
|
|
203
208
|
result = if exit_status == 0
|
|
204
|
-
Success.new(nil)
|
|
209
|
+
Invocation::Success.new(nil)
|
|
205
210
|
else
|
|
206
|
-
Error.new(nil, exit_status)
|
|
211
|
+
Invocation::Error.new(nil, exit_status)
|
|
207
212
|
end
|
|
208
213
|
throw :exit_now, result
|
|
209
214
|
end
|
|
@@ -240,18 +245,18 @@ module OpsWalrus
|
|
|
240
245
|
end
|
|
241
246
|
|
|
242
247
|
# returns the stdout from the command
|
|
243
|
-
def sh(desc_or_cmd = nil, cmd = nil,
|
|
244
|
-
out, err, status = *shell!(desc_or_cmd, cmd, block,
|
|
248
|
+
def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
|
249
|
+
out, err, status = *shell!(desc_or_cmd, cmd, block, input: input)
|
|
245
250
|
out
|
|
246
251
|
end
|
|
247
252
|
|
|
248
253
|
# returns the tuple: [stdout, stderr, exit_status]
|
|
249
|
-
def shell(desc_or_cmd = nil, cmd = nil,
|
|
250
|
-
shell!(desc_or_cmd, cmd, block,
|
|
254
|
+
def shell(desc_or_cmd = nil, cmd = nil, input: nil, &block)
|
|
255
|
+
shell!(desc_or_cmd, cmd, block, input: input)
|
|
251
256
|
end
|
|
252
257
|
|
|
253
258
|
# returns the tuple: [stdout, stderr, exit_status]
|
|
254
|
-
def shell!(desc_or_cmd = nil, cmd = nil, block = nil,
|
|
259
|
+
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
|
|
255
260
|
# description = nil
|
|
256
261
|
|
|
257
262
|
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
|
|
@@ -272,8 +277,8 @@ module OpsWalrus
|
|
|
272
277
|
|
|
273
278
|
return unless cmd && !cmd.strip.empty?
|
|
274
279
|
|
|
275
|
-
sudo_password = @runtime_env.sudo_password
|
|
276
|
-
sudo_password &&= sudo_password.gsub(/\n+$/,'') # remove trailing newlines from sudo_password
|
|
280
|
+
# sudo_password = @runtime_env.sudo_password
|
|
281
|
+
# sudo_password &&= sudo_password.gsub(/\n+$/,'') # remove trailing newlines from sudo_password
|
|
277
282
|
|
|
278
283
|
# puts "shell: #{cmd}"
|
|
279
284
|
# puts "shell: #{cmd.inspect}"
|
|
@@ -281,10 +286,14 @@ module OpsWalrus
|
|
|
281
286
|
|
|
282
287
|
# sshkit_cmd = SSHKit::Backend::LocalNonBlocking.new {
|
|
283
288
|
# sshkit_cmd = SSHKit::Backend::LocalPty.new {
|
|
284
|
-
sshkit_cmd = backend.execute_cmd(cmd, interaction_handler: SudoPasswordMapper.new(sudo_password).interaction_handler, verbosity: :info)
|
|
289
|
+
# sshkit_cmd = backend.execute_cmd(cmd, interaction_handler: SudoPasswordMapper.new(sudo_password).interaction_handler, verbosity: :info)
|
|
285
290
|
# execute_cmd(cmd, interaction_handler: SudoPromptInteractionHandler.new, verbosity: :info)
|
|
286
291
|
# }.run
|
|
287
292
|
|
|
293
|
+
sshkit_cmd = @runtime_env.handle_input(input) do |interaction_handler|
|
|
294
|
+
backend.execute_cmd(cmd, interaction_handler: interaction_handler, verbosity: :info)
|
|
295
|
+
end
|
|
296
|
+
|
|
288
297
|
[sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status]
|
|
289
298
|
end
|
|
290
299
|
|
|
@@ -3,6 +3,7 @@ require 'shellwords'
|
|
|
3
3
|
require 'socket'
|
|
4
4
|
require 'sshkit'
|
|
5
5
|
|
|
6
|
+
require_relative 'interaction_handlers'
|
|
6
7
|
require_relative 'traversable'
|
|
7
8
|
require_relative 'walrus_lang'
|
|
8
9
|
|
|
@@ -196,9 +197,27 @@ module OpsWalrus
|
|
|
196
197
|
@bundle_load_path = LoadPath.new(self, @app.bundle_dir)
|
|
197
198
|
@app_load_path = LoadPath.new(self, @app.pwd)
|
|
198
199
|
|
|
200
|
+
@interaction_handler = ScopedMappingInteractionHandler.new({
|
|
201
|
+
/\[sudo\] password for .*?:\s*/ => "#{sudo_password}\n",
|
|
202
|
+
})
|
|
203
|
+
|
|
199
204
|
configure_sshkit
|
|
200
205
|
end
|
|
201
206
|
|
|
207
|
+
# def with_sudo_password(password, &block)
|
|
208
|
+
# @interaction_handler.with_sudo_password(password, &block)
|
|
209
|
+
# end
|
|
210
|
+
|
|
211
|
+
# input_mapping : Hash[ String | Regex => String ]
|
|
212
|
+
# sudo_password : String
|
|
213
|
+
def handle_input(input_mapping, sudo_password = nil, &block)
|
|
214
|
+
@interaction_handler.with_mapping(input_mapping, sudo_password, &block)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# def handle_input_with_sudo_password(input_mapping, password, &block)
|
|
218
|
+
# @interaction_handler.with_mapping(input_mapping, password, &block)
|
|
219
|
+
# end
|
|
220
|
+
|
|
202
221
|
# configure sshkit globally
|
|
203
222
|
def configure_sshkit
|
|
204
223
|
SSHKit.config.use_format :blackhole
|
data/lib/opswalrus/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.7
|
|
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-08-
|
|
11
|
+
date: 2023-08-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: citrus
|