opswalrus 1.0.52 → 1.0.53
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +73 -1
- data/lib/opswalrus/_run_remote.ops +12 -0
- data/lib/opswalrus/app.rb +46 -24
- data/lib/opswalrus/cli.rb +25 -30
- data/lib/opswalrus/host.rb +58 -44
- data/lib/opswalrus/interaction_handlers.rb +2 -4
- data/lib/opswalrus/operation_runner.rb +6 -6
- data/lib/opswalrus/ops_file_script_dsl.rb +44 -28
- data/lib/opswalrus/patches.rb +2 -0
- data/lib/opswalrus/version.rb +1 -1
- data/opswalrus.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 007f1ac465143fdd629539509b94a8bf7230b034817526d1265768f97eae0786
|
4
|
+
data.tar.gz: 9d0cc607ce7c9fcd06d9e402254b3eb5a75a68687a1ee485aa915b3cd488e2b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83b67721de074efa3ad368ed21ec469d40928351c4ccc6f32d530e3bbda2cdd81b62f2b72692a4796b74d1efb7bbbfa31721db0eefb93864069dc277f8aa66fe
|
7
|
+
data.tar.gz: b54d628df099de1f4c2eea591b86449b5fd254d495ccae38f89dd95f5d1137171aaf9e6c1bd2023613f1c33561b5e49bd12d5696d6bc197bc065ead0a79aed1d
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
opswalrus (1.0.
|
4
|
+
opswalrus (1.0.53)
|
5
|
+
activesupport (~> 7.0)
|
5
6
|
bcrypt_pbkdf (~> 1.1)
|
6
7
|
binding_of_caller (~> 1.0)
|
7
8
|
citrus (~> 3.0)
|
@@ -17,28 +18,61 @@ PATH
|
|
17
18
|
GEM
|
18
19
|
remote: https://rubygems.org/
|
19
20
|
specs:
|
21
|
+
activesupport (7.0.8)
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
|
+
i18n (>= 1.6, < 2)
|
24
|
+
minitest (>= 5.1)
|
25
|
+
tzinfo (~> 2.0)
|
20
26
|
addressable (2.8.5)
|
21
27
|
public_suffix (>= 2.0.2, < 6.0)
|
28
|
+
ast (2.4.2)
|
29
|
+
backport (1.2.0)
|
30
|
+
base64 (0.1.1)
|
22
31
|
bcrypt_pbkdf (1.1.0)
|
32
|
+
benchmark (0.2.1)
|
23
33
|
binding_of_caller (1.0.0)
|
24
34
|
debug_inspector (>= 0.0.1)
|
25
35
|
citrus (3.0.2)
|
26
36
|
concurrent-ruby (1.2.2)
|
27
37
|
debug_inspector (1.1.0)
|
28
38
|
diff-lcs (1.5.0)
|
39
|
+
e2mmap (0.1.0)
|
29
40
|
ed25519 (1.3.0)
|
30
41
|
git (1.18.0)
|
31
42
|
addressable (~> 2.8)
|
32
43
|
rchardet (~> 1.8)
|
33
44
|
gli (2.21.1)
|
45
|
+
i18n (1.14.1)
|
46
|
+
concurrent-ruby (~> 1.0)
|
47
|
+
jaro_winkler (1.5.6)
|
48
|
+
json (2.6.3)
|
49
|
+
kramdown (2.4.0)
|
50
|
+
rexml
|
51
|
+
kramdown-parser-gfm (1.1.0)
|
52
|
+
kramdown (~> 2.0)
|
53
|
+
language_server-protocol (3.17.0.3)
|
54
|
+
minitest (5.20.0)
|
34
55
|
net-scp (4.0.0)
|
35
56
|
net-ssh (>= 2.6.5, < 8.0.0)
|
36
57
|
net-ssh (7.2.0)
|
58
|
+
nokogiri (1.15.4-x86_64-linux)
|
59
|
+
racc (~> 1.4)
|
60
|
+
parallel (1.23.0)
|
61
|
+
parser (3.2.2.3)
|
62
|
+
ast (~> 2.4.1)
|
63
|
+
racc
|
37
64
|
pastel (0.8.0)
|
38
65
|
tty-color (~> 0.5)
|
39
66
|
public_suffix (5.0.3)
|
67
|
+
racc (1.7.1)
|
68
|
+
rainbow (3.1.1)
|
40
69
|
rake (13.0.6)
|
70
|
+
rbs (2.8.4)
|
41
71
|
rchardet (1.8.0)
|
72
|
+
regexp_parser (2.8.1)
|
73
|
+
reverse_markdown (2.1.1)
|
74
|
+
nokogiri
|
75
|
+
rexml (3.2.6)
|
42
76
|
rspec (3.12.0)
|
43
77
|
rspec-core (~> 3.12.0)
|
44
78
|
rspec-expectations (~> 3.12.0)
|
@@ -52,12 +86,45 @@ GEM
|
|
52
86
|
diff-lcs (>= 1.2.0, < 2.0)
|
53
87
|
rspec-support (~> 3.12.0)
|
54
88
|
rspec-support (3.12.1)
|
89
|
+
rubocop (1.56.3)
|
90
|
+
base64 (~> 0.1.1)
|
91
|
+
json (~> 2.3)
|
92
|
+
language_server-protocol (>= 3.17.0)
|
93
|
+
parallel (~> 1.10)
|
94
|
+
parser (>= 3.2.2.3)
|
95
|
+
rainbow (>= 2.2.2, < 4.0)
|
96
|
+
regexp_parser (>= 1.8, < 3.0)
|
97
|
+
rexml (>= 3.2.5, < 4.0)
|
98
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
99
|
+
ruby-progressbar (~> 1.7)
|
100
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
101
|
+
rubocop-ast (1.29.0)
|
102
|
+
parser (>= 3.2.1.0)
|
103
|
+
ruby-progressbar (1.13.0)
|
55
104
|
rubyzip (2.3.2)
|
56
105
|
semantic_logger (4.14.0)
|
57
106
|
concurrent-ruby (~> 1.0)
|
107
|
+
solargraph (0.49.0)
|
108
|
+
backport (~> 1.2)
|
109
|
+
benchmark
|
110
|
+
bundler (~> 2.0)
|
111
|
+
diff-lcs (~> 1.4)
|
112
|
+
e2mmap
|
113
|
+
jaro_winkler (~> 1.5)
|
114
|
+
kramdown (~> 2.3)
|
115
|
+
kramdown-parser-gfm (~> 1.1)
|
116
|
+
parser (~> 3.0)
|
117
|
+
rbs (~> 2.0)
|
118
|
+
reverse_markdown (~> 2.0)
|
119
|
+
rubocop (~> 1.38)
|
120
|
+
thor (~> 1.0)
|
121
|
+
tilt (~> 2.0)
|
122
|
+
yard (~> 0.9, >= 0.9.24)
|
58
123
|
sshkit (1.21.5)
|
59
124
|
net-scp (>= 1.1.2)
|
60
125
|
net-ssh (>= 2.8.0)
|
126
|
+
thor (1.2.2)
|
127
|
+
tilt (2.3.0)
|
61
128
|
tty-color (0.6.0)
|
62
129
|
tty-cursor (0.7.1)
|
63
130
|
tty-editor (0.7.0)
|
@@ -70,7 +137,11 @@ GEM
|
|
70
137
|
tty-screen (~> 0.8)
|
71
138
|
wisper (~> 2.0)
|
72
139
|
tty-screen (0.8.1)
|
140
|
+
tzinfo (2.0.6)
|
141
|
+
concurrent-ruby (~> 1.0)
|
142
|
+
unicode-display_width (2.4.2)
|
73
143
|
wisper (2.0.1)
|
144
|
+
yard (0.9.34)
|
74
145
|
|
75
146
|
PLATFORMS
|
76
147
|
x86_64-linux
|
@@ -79,6 +150,7 @@ DEPENDENCIES
|
|
79
150
|
opswalrus!
|
80
151
|
rake (~> 13.0)
|
81
152
|
rspec (~> 3.0)
|
153
|
+
solargraph
|
82
154
|
|
83
155
|
BUNDLED WITH
|
84
156
|
2.4.10
|
@@ -0,0 +1,12 @@
|
|
1
|
+
params:
|
2
|
+
ops_file: OpsFile
|
3
|
+
operation_kv_args: array string
|
4
|
+
...
|
5
|
+
ssh in: :sequence do
|
6
|
+
# ssh_noprep do
|
7
|
+
puts params.stringify_keys!
|
8
|
+
desc "Running `#{params.ops_file.ops_file_path} #{params.operation_kv_args.join(' ')}` on #{to_s} (alias=#{self.alias})"
|
9
|
+
# run_ops(ops_command, ops_command_options = nil, command_arguments, in_bundle_root_dir: true, ops_prompt_for_sudo_password: false)
|
10
|
+
puts self.inspect
|
11
|
+
self._invoke_remote(params.ops_file, *params.operation_kv_args)
|
12
|
+
end
|
data/lib/opswalrus/app.rb
CHANGED
@@ -38,11 +38,11 @@ module OpsWalrus
|
|
38
38
|
attr_reader :identity_file_paths
|
39
39
|
|
40
40
|
def initialize(pwd = Dir.pwd)
|
41
|
-
SemanticLogger.default_level = :
|
41
|
+
SemanticLogger.default_level = :warn
|
42
42
|
# SemanticLogger.add_appender(file_name: 'development.log', formatter: :color) # Log to a file, and use the colorized formatter
|
43
43
|
SemanticLogger.add_appender(io: $stdout, formatter: :color) # Log errors and above to standard error:
|
44
44
|
@logger = SemanticLogger[OpsWalrus] # Logger.new($stdout, level: Logger::INFO)
|
45
|
-
@logger.level = :
|
45
|
+
@logger.level = :warn # :trace or 'trace'
|
46
46
|
|
47
47
|
# @logger.warn Style.yellow("warn"), foo: "bar", baz: {qux: "quux"}
|
48
48
|
# @logger.info Style.yellow("info"), foo: "bar", baz: {qux: "quux"}
|
@@ -216,18 +216,22 @@ module OpsWalrus
|
|
216
216
|
end
|
217
217
|
|
218
218
|
def bootstrap()
|
219
|
-
|
220
|
-
bootstrap_ops_file = OpsFile.new(self, __FILE__.to_pathname.dirname.join("_bootstrap.ops"))
|
221
|
-
op = OperationRunner.new(self, bootstrap_ops_file)
|
222
|
-
op.run([], params_json_hash: @params)
|
219
|
+
run_internal("_bootstrap.ops")
|
223
220
|
end
|
224
221
|
|
225
222
|
def shell(command)
|
223
|
+
run_internal("_shell.ops", {"command" => command})
|
224
|
+
end
|
225
|
+
|
226
|
+
def reboot()
|
227
|
+
run_internal("_reboot.ops")
|
228
|
+
end
|
229
|
+
|
230
|
+
def run_internal(ops_file_name, params = @params)
|
226
231
|
set_pwd(__FILE__.to_pathname.dirname)
|
227
|
-
|
228
|
-
op = OperationRunner.new(self,
|
229
|
-
|
230
|
-
result = op.run([], params_json_hash: {"command" => command})
|
232
|
+
internal_ops_file = OpsFile.new(self, __FILE__.to_pathname.dirname.join(ops_file_name))
|
233
|
+
op = OperationRunner.new(self, internal_ops_file)
|
234
|
+
result = op.run([], params_json_hash: params)
|
231
235
|
puts "result class=#{result.class}"
|
232
236
|
exit_status = result.exit_status
|
233
237
|
stdout = JSON.pretty_generate(result.value)
|
@@ -243,27 +247,45 @@ module OpsWalrus
|
|
243
247
|
1
|
244
248
|
end
|
245
249
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
250
|
+
# package_operation_and_args is of the form ["github.com/davidkellis/my-package/sub-package1", "operation1", "arg1:val1", "arg2:val2", "arg3:val3"]
|
251
|
+
# if the first argument is the path to a .ops file, then treat it as a local path, and add the containing package
|
252
|
+
# to the load path
|
253
|
+
# otherwise, copy the
|
254
|
+
# returns the exit status code that the script should terminate with
|
255
|
+
def run_remote(package_operation_and_args, update_bundle: false)
|
256
|
+
return 0 if package_operation_and_args.empty?
|
257
|
+
|
258
|
+
ops_file_path, operation_kv_args, tmp_bundle_root_dir = get_entry_point_ops_file_and_args(package_operation_and_args)
|
259
|
+
|
260
|
+
ops_file = load_entry_point_ops_file(ops_file_path, tmp_bundle_root_dir)
|
261
|
+
|
262
|
+
bundler.update if update_bundle
|
263
|
+
|
264
|
+
debug "Running: #{ops_file.ops_file_path}"
|
265
|
+
|
266
|
+
internal_ops_file = OpsFile.new(self, __FILE__.to_pathname.dirname.join("_run_remote.ops"))
|
267
|
+
|
268
|
+
op = OperationRunner.new(self, internal_ops_file)
|
269
|
+
result = op.run([], params_json_hash: {ops_file: ops_file, operation_kv_args: operation_kv_args})
|
252
270
|
exit_status = result.exit_status
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
271
|
+
|
272
|
+
debug "Op exit_status"
|
273
|
+
debug exit_status
|
274
|
+
|
275
|
+
debug "Op output"
|
276
|
+
debug JSON.pretty_generate(result.value)
|
277
|
+
|
278
|
+
puts JSON.pretty_generate(result.value)
|
279
|
+
|
260
280
|
exit_status
|
261
281
|
rescue Error => e
|
262
282
|
puts "Error: #{e.message}"
|
263
283
|
1
|
284
|
+
ensure
|
285
|
+
FileUtils.remove_entry(tmp_bundle_root_dir) if tmp_bundle_root_dir
|
264
286
|
end
|
265
287
|
|
266
|
-
#
|
288
|
+
# package_operation_and_args is of the form ["github.com/davidkellis/my-package/sub-package1", "operation1", "arg1:val1", "arg2:val2", "arg3:val3"]
|
267
289
|
# if the first argument is the path to a .ops file, then treat it as a local path, and add the containing package
|
268
290
|
# to the load path
|
269
291
|
# otherwise, copy the
|
data/lib/opswalrus/cli.rb
CHANGED
@@ -30,13 +30,11 @@ module OpsWalrus
|
|
30
30
|
|
31
31
|
program_desc 'ops is an operation runner'
|
32
32
|
|
33
|
-
switch
|
34
|
-
switch :
|
35
|
-
switch :
|
33
|
+
switch :loud, desc: "Verbose output"
|
34
|
+
switch :louder, desc: "Debug output"
|
35
|
+
switch :loudest, desc: "Trace output"
|
36
36
|
|
37
|
-
switch :
|
38
|
-
switch :dryrun, desc: "Perform a dry run"
|
39
|
-
switch :dry_run, desc: "Perform a dry run"
|
37
|
+
switch :dry, desc: "Perform a dry run"
|
40
38
|
|
41
39
|
flag [:h, :hosts], multiple: true, desc: "Specify the hosts.yaml file"
|
42
40
|
flag [:t, :tags], multiple: true, desc: "Specify a set of tags to filter the hosts by"
|
@@ -61,7 +59,7 @@ module OpsWalrus
|
|
61
59
|
hosts = global_options[:hosts]
|
62
60
|
tags = global_options[:tags]
|
63
61
|
|
64
|
-
$app.set_log_level(global_options[:
|
62
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
65
63
|
|
66
64
|
$app.report_inventory(hosts, tags: tags)
|
67
65
|
end
|
@@ -123,12 +121,10 @@ module OpsWalrus
|
|
123
121
|
long_desc 'Bootstrap a set of hotss to run opswalrus: install dependencies, ruby, opswalrus gem'
|
124
122
|
command :bootstrap do |c|
|
125
123
|
# dry run
|
126
|
-
c.switch :
|
127
|
-
c.switch :dryrun, desc: "Perform a dry run"
|
128
|
-
c.switch :dry_run, desc: "Perform a dry run"
|
124
|
+
c.switch :dry, desc: "Perform a dry run"
|
129
125
|
|
130
126
|
c.action do |global_options, options, args|
|
131
|
-
$app.set_log_level(global_options[:
|
127
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
132
128
|
|
133
129
|
hosts = global_options[:hosts]
|
134
130
|
$app.set_inventory_hosts(hosts)
|
@@ -141,7 +137,7 @@ module OpsWalrus
|
|
141
137
|
|
142
138
|
$app.set_identity_files(id_files)
|
143
139
|
|
144
|
-
dry_run = [:
|
140
|
+
dry_run = global_options[:dry] || options[:dry]
|
145
141
|
$app.dry_run! if dry_run
|
146
142
|
|
147
143
|
$app.bootstrap()
|
@@ -155,12 +151,10 @@ module OpsWalrus
|
|
155
151
|
c.flag [:u, :user], desc: "Specify the user that the operation will run as"
|
156
152
|
|
157
153
|
# dry run
|
158
|
-
c.switch :
|
159
|
-
c.switch :dryrun, desc: "Perform a dry run"
|
160
|
-
c.switch :dry_run, desc: "Perform a dry run"
|
154
|
+
c.switch :dry, desc: "Perform a dry run"
|
161
155
|
|
162
156
|
c.action do |global_options, options, args|
|
163
|
-
$app.set_log_level(global_options[:
|
157
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
164
158
|
|
165
159
|
hosts = global_options[:hosts]
|
166
160
|
$app.set_inventory_hosts(hosts)
|
@@ -176,7 +170,7 @@ module OpsWalrus
|
|
176
170
|
|
177
171
|
$app.set_identity_files(id_files)
|
178
172
|
|
179
|
-
dry_run = [:
|
173
|
+
dry_run = global_options[:dry] || options[:dry]
|
180
174
|
$app.dry_run! if dry_run
|
181
175
|
|
182
176
|
if options[:pass]
|
@@ -193,12 +187,10 @@ module OpsWalrus
|
|
193
187
|
long_desc 'Reboot one or more remote hosts'
|
194
188
|
command :reboot do |c|
|
195
189
|
# dry run
|
196
|
-
c.switch :
|
197
|
-
c.switch :dryrun, desc: "Perform a dry run"
|
198
|
-
c.switch :dry_run, desc: "Perform a dry run"
|
190
|
+
c.switch :dry, desc: "Perform a dry run"
|
199
191
|
|
200
192
|
c.action do |global_options, options, args|
|
201
|
-
$app.set_log_level(global_options[:
|
193
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
202
194
|
|
203
195
|
hosts = global_options[:hosts]
|
204
196
|
$app.set_inventory_hosts(hosts)
|
@@ -211,7 +203,7 @@ module OpsWalrus
|
|
211
203
|
|
212
204
|
$app.set_identity_files(id_files)
|
213
205
|
|
214
|
-
dry_run = [:
|
206
|
+
dry_run = global_options[:dry] || options[:dry]
|
215
207
|
$app.dry_run! if dry_run
|
216
208
|
|
217
209
|
exit_status = $app.reboot()
|
@@ -227,17 +219,16 @@ module OpsWalrus
|
|
227
219
|
c.switch [:b, :bundle], desc: "Update bundle prior to running the specified operation"
|
228
220
|
c.switch :pass, desc: "Prompt for a sudo password"
|
229
221
|
c.switch :script, desc: "Script mode"
|
222
|
+
c.switch [:r, :remote], desc: "Run the operation on the remote hosts"
|
230
223
|
|
231
224
|
c.flag [:u, :user], desc: "Specify the user that the operation will run as"
|
232
225
|
c.flag [:p, :params], desc: "Either specify a file that contains JSON OR specify a JSON encoded string. In both cases, the JSON represents the runtime arguments (i.e. the params) for the operation. The JSON string must conform to the params schema for the operation being run."
|
233
226
|
|
234
227
|
# dry run
|
235
|
-
c.switch :
|
236
|
-
c.switch :dryrun, desc: "Perform a dry run"
|
237
|
-
c.switch :dry_run, desc: "Perform a dry run"
|
228
|
+
c.switch :dry, desc: "Perform a dry run"
|
238
229
|
|
239
230
|
c.action do |global_options, options, args|
|
240
|
-
$app.set_log_level(global_options[:
|
231
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
241
232
|
|
242
233
|
hosts = global_options[:hosts]
|
243
234
|
$app.set_inventory_hosts(hosts)
|
@@ -256,7 +247,7 @@ module OpsWalrus
|
|
256
247
|
|
257
248
|
$app.set_identity_files(id_files)
|
258
249
|
|
259
|
-
dry_run = [:
|
250
|
+
dry_run = global_options[:dry] || options[:dry]
|
260
251
|
$app.dry_run! if dry_run
|
261
252
|
|
262
253
|
if options[:pass]
|
@@ -267,7 +258,11 @@ module OpsWalrus
|
|
267
258
|
$app.script_mode!
|
268
259
|
end
|
269
260
|
|
270
|
-
exit_status =
|
261
|
+
exit_status = if options[:remote]
|
262
|
+
$app.run_remote(args, update_bundle: options[:bundle])
|
263
|
+
else
|
264
|
+
$app.run(args, update_bundle: options[:bundle])
|
265
|
+
end
|
271
266
|
|
272
267
|
exit_now!("error", exit_status) unless exit_status == 0
|
273
268
|
end
|
@@ -281,7 +276,7 @@ module OpsWalrus
|
|
281
276
|
long_desc 'Download and bundle the latest versions of dependencies for the current package'
|
282
277
|
c.command :update do |update|
|
283
278
|
update.action do |global_options, options, args|
|
284
|
-
$app.set_log_level(global_options[:
|
279
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
285
280
|
|
286
281
|
$app.bundle_update
|
287
282
|
end
|
@@ -301,7 +296,7 @@ module OpsWalrus
|
|
301
296
|
unzip.flag [:o, :output], desc: "Specify the output directory"
|
302
297
|
|
303
298
|
unzip.action do |global_options, options, args|
|
304
|
-
$app.set_log_level(global_options[:
|
299
|
+
$app.set_log_level(global_options[:loudest] && :trace || global_options[:louder] && :debug || global_options[:loud] && :info || :warn)
|
305
300
|
|
306
301
|
output_dir = options[:output]
|
307
302
|
zip_file_path = args.first
|
data/lib/opswalrus/host.rb
CHANGED
@@ -81,6 +81,13 @@ module OpsWalrus
|
|
81
81
|
@_host.to_s
|
82
82
|
end
|
83
83
|
|
84
|
+
def _invoke_remote(ops_file, *args, **kwargs)
|
85
|
+
puts "boom"
|
86
|
+
is_invocation_a_call_to_package_in_bundle_dir = true
|
87
|
+
invocation_context = RemoteImportInvocationContext.new(@runtime_env, self, ops_file, is_invocation_a_call_to_package_in_bundle_dir, ops_prompt_for_sudo_password: !!ssh_password)
|
88
|
+
invocation_context._invoke(*args, **kwargs)
|
89
|
+
end
|
90
|
+
|
84
91
|
# returns [stdout, stderr, exit_status]
|
85
92
|
def _bootstrap_host(print_report = true)
|
86
93
|
# copy over bootstrap shell script
|
@@ -119,7 +126,7 @@ module OpsWalrus
|
|
119
126
|
raise Error, "Unable to upload ops bundle to remote host" unless upload_success
|
120
127
|
|
121
128
|
stdout, _stderr, exit_status = @_host.run_ops(:bundle, "unzip tmpops.zip", in_bundle_root_dir: false)
|
122
|
-
raise Error, "Unable to unzip ops bundle on remote host" unless exit_status == 0
|
129
|
+
raise Error, "Unable to unzip ops bundle on remote host: #{stdout}" unless exit_status == 0
|
123
130
|
tmp_bundle_root_dir = stdout.strip
|
124
131
|
@_host.set_ssh_session_tmp_bundle_root_dir(tmp_bundle_root_dir)
|
125
132
|
|
@@ -168,7 +175,8 @@ module OpsWalrus
|
|
168
175
|
# while trying to reconnect, we expect the following exceptions:
|
169
176
|
# 1. Net::SSH::Disconnect < Net::SSH::Exception with message: "connection closed by remote host"
|
170
177
|
# 2. Errno::ECONNRESET < SystemCallError with message: "Connection reset by peer"
|
171
|
-
|
178
|
+
# 3. Errno::ECONNREFUSED < SystemCallError with message: "Connection refused - connect(2) for 192.168.56.10:22"
|
179
|
+
rescue Net::SSH::Disconnect, Errno::ECONNRESET, Errno::ECONNREFUSED => e
|
172
180
|
# noop; we expect these while we're trying to reconnect
|
173
181
|
rescue => e
|
174
182
|
puts "#{e.class} < #{e.class.superclass}"
|
@@ -214,7 +222,7 @@ module OpsWalrus
|
|
214
222
|
end
|
215
223
|
|
216
224
|
# returns the tuple: [stdout, stderr, exit_status]
|
217
|
-
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil,
|
225
|
+
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, ops_prompt_for_sudo_password: false)
|
218
226
|
# description = nil
|
219
227
|
|
220
228
|
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
|
@@ -241,28 +249,24 @@ module OpsWalrus
|
|
241
249
|
#cmd = Shellwords.escape(cmd)
|
242
250
|
|
243
251
|
cmd_id = Random.uuid.split('-').first
|
244
|
-
# if App.instance.report_mode?
|
245
252
|
output_block = StringIO.open do |io|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
+
if App.instance.info? # this is true if log_level is trace, debug, info
|
254
|
+
io.print Style.blue(host)
|
255
|
+
io.print " (#{Style.blue(self.alias)})" if self.alias
|
256
|
+
io.print " | #{Style.magenta(description)}" if description
|
257
|
+
io.puts
|
258
|
+
io.print Style.yellow(cmd_id)
|
259
|
+
io.print Style.green.bold(" > ")
|
260
|
+
io.puts Style.yellow(cmd)
|
261
|
+
elsif App.instance.warn? && description
|
262
|
+
io.print Style.blue(host)
|
263
|
+
io.print " (#{Style.blue(self.alias)})" if self.alias
|
264
|
+
io.print " | #{Style.magenta(description)}" if description
|
265
|
+
io.puts
|
266
|
+
end
|
253
267
|
io.string
|
254
268
|
end
|
255
|
-
puts output_block
|
256
|
-
|
257
|
-
# puts Style.green("*" * 80)
|
258
|
-
# if self.alias
|
259
|
-
# print "[#{Style.blue(self.alias)} | #{Style.blue(host)}] "
|
260
|
-
# else
|
261
|
-
# print "[#{Style.blue(host)}] "
|
262
|
-
# end
|
263
|
-
# print "#{description}: " if description
|
264
|
-
# puts Style.yellow("[#{cmd_id}] #{cmd}")
|
265
|
-
# end
|
269
|
+
puts output_block unless output_block.empty?
|
266
270
|
|
267
271
|
return unless cmd && !cmd.strip.empty?
|
268
272
|
|
@@ -277,27 +281,37 @@ module OpsWalrus
|
|
277
281
|
seconds = t2 - t1
|
278
282
|
|
279
283
|
output_block = StringIO.open do |io|
|
280
|
-
if App.instance.info?
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
284
|
+
if App.instance.info? # this is true if log_level is trace, debug, info
|
285
|
+
if App.instance.trace?
|
286
|
+
io.puts Style.cyan(out)
|
287
|
+
io.puts Style.red(err)
|
288
|
+
elsif App.instance.debug?
|
289
|
+
io.puts Style.cyan(out)
|
290
|
+
io.puts Style.red(err)
|
291
|
+
elsif App.instance.info?
|
292
|
+
# io.puts Style.cyan(out)
|
293
|
+
# io.puts Style.red(err)
|
294
|
+
end
|
295
|
+
io.print Style.yellow(cmd_id)
|
296
|
+
io.print Style.blue(" | Finished in #{seconds} seconds with exit status ")
|
297
|
+
if exit_status == 0
|
298
|
+
io.puts Style.green("#{exit_status} (success)")
|
299
|
+
else
|
300
|
+
io.puts Style.red("#{exit_status} (failure)")
|
301
|
+
end
|
302
|
+
io.puts Style.green("*" * 80)
|
303
|
+
elsif App.instance.warn? && description
|
304
|
+
io.print Style.blue(" | Finished in #{seconds} seconds with exit status ")
|
305
|
+
if exit_status == 0
|
306
|
+
io.puts Style.green("#{exit_status} (success)")
|
307
|
+
else
|
308
|
+
io.puts Style.red("#{exit_status} (failure)")
|
309
|
+
end
|
310
|
+
io.puts Style.green("*" * 80)
|
296
311
|
end
|
297
|
-
io.puts Style.green("*" * 80)
|
298
312
|
io.string
|
299
313
|
end
|
300
|
-
puts output_block
|
314
|
+
puts output_block unless output_block.empty?
|
301
315
|
|
302
316
|
[out, err, exit_status]
|
303
317
|
end
|
@@ -313,18 +327,18 @@ module OpsWalrus
|
|
313
327
|
# cmd = "OPS_GEM=\"#{OPS_GEM}\" OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}'; $OPS_GEM exec --conservative -g opswalrus ops"
|
314
328
|
cmd = "OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}' eval #{OPS_CMD}"
|
315
329
|
if App.instance.trace?
|
316
|
-
cmd << " --
|
330
|
+
cmd << " --loudest"
|
317
331
|
elsif App.instance.debug?
|
318
|
-
cmd << " --
|
332
|
+
cmd << " --louder"
|
319
333
|
elsif App.instance.info?
|
320
|
-
cmd << " --
|
334
|
+
cmd << " --loud"
|
321
335
|
end
|
322
336
|
cmd << " #{ops_command.to_s}"
|
323
337
|
cmd << " #{ops_command_options.to_s}" if ops_command_options
|
324
338
|
cmd << " #{@tmp_bundle_root_dir}" if in_bundle_root_dir
|
325
339
|
cmd << " #{command_arguments}" unless command_arguments.empty?
|
326
340
|
|
327
|
-
shell!(cmd,
|
341
|
+
shell!(cmd, ops_prompt_for_sudo_password: ops_prompt_for_sudo_password)
|
328
342
|
end
|
329
343
|
|
330
344
|
def desc(msg)
|
@@ -8,9 +8,7 @@ module OpsWalrus
|
|
8
8
|
|
9
9
|
attr_accessor :input_mappings # Hash[ String | Regex => String ]
|
10
10
|
|
11
|
-
|
12
|
-
def initialize(mapping, log_level = nil)
|
13
|
-
@log_level = log_level
|
11
|
+
def initialize(mapping)
|
14
12
|
@input_mappings = mapping
|
15
13
|
end
|
16
14
|
|
@@ -63,7 +61,7 @@ module OpsWalrus
|
|
63
61
|
if new_mapping.empty? || new_mapping == @input_mappings
|
64
62
|
yield self
|
65
63
|
else
|
66
|
-
yield ScopedMappingInteractionHandler.new(new_mapping
|
64
|
+
yield ScopedMappingInteractionHandler.new(new_mapping)
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
@@ -110,12 +110,12 @@ module OpsWalrus
|
|
110
110
|
Invocation::Error.new(e)
|
111
111
|
end
|
112
112
|
|
113
|
-
if result.failure?
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
end
|
113
|
+
# if result.failure?
|
114
|
+
# App.instance.debug "Ops script error details:"
|
115
|
+
# App.instance.debug "Error: #{result.value}"
|
116
|
+
# App.instance.debug "Status code: #{result.exit_status}"
|
117
|
+
# App.instance.debug @entry_point_ops_file.script.to_s
|
118
|
+
# end
|
119
119
|
|
120
120
|
result
|
121
121
|
end
|
@@ -263,7 +263,7 @@ module OpsWalrus
|
|
263
263
|
end
|
264
264
|
|
265
265
|
# returns the tuple: [stdout, stderr, exit_status]
|
266
|
-
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil
|
266
|
+
def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil)
|
267
267
|
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
|
268
268
|
|
269
269
|
description = desc_or_cmd if cmd || block
|
@@ -285,7 +285,7 @@ module OpsWalrus
|
|
285
285
|
end
|
286
286
|
#cmd = Shellwords.escape(cmd)
|
287
287
|
|
288
|
-
report_on(@runtime_env.local_hostname, description, cmd
|
288
|
+
report_on(@runtime_env.local_hostname, description, cmd) do
|
289
289
|
if App.instance.dry_run?
|
290
290
|
["", "", 0]
|
291
291
|
else
|
@@ -300,19 +300,25 @@ module OpsWalrus
|
|
300
300
|
end
|
301
301
|
end
|
302
302
|
|
303
|
-
def report_on(hostname, description = nil, cmd
|
303
|
+
def report_on(hostname, description = nil, cmd)
|
304
304
|
cmd_id = Random.uuid.split('-').first
|
305
305
|
|
306
306
|
output_block = StringIO.open do |io|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
307
|
+
if App.instance.info? # this is true if log_level is trace, debug, info
|
308
|
+
io.print Style.blue(hostname)
|
309
|
+
io.print " | #{Style.magenta(description)}" if description
|
310
|
+
io.puts
|
311
|
+
io.print Style.yellow(cmd_id)
|
312
|
+
io.print Style.green.bold(" > ")
|
313
|
+
io.puts Style.yellow(cmd)
|
314
|
+
elsif App.instance.warn? && description
|
315
|
+
io.print Style.blue(hostname)
|
316
|
+
io.print " | #{Style.magenta(description)}" if description
|
317
|
+
io.puts
|
318
|
+
end
|
313
319
|
io.string
|
314
320
|
end
|
315
|
-
puts output_block
|
321
|
+
puts output_block unless output_block.empty?
|
316
322
|
|
317
323
|
t1 = Time.now
|
318
324
|
out, err, exit_status = yield
|
@@ -320,27 +326,37 @@ module OpsWalrus
|
|
320
326
|
seconds = t2 - t1
|
321
327
|
|
322
328
|
output_block = StringIO.open do |io|
|
323
|
-
if App.instance.info?
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
329
|
+
if App.instance.info? # this is true if log_level is trace, debug, info
|
330
|
+
if App.instance.trace?
|
331
|
+
io.puts Style.cyan(out)
|
332
|
+
io.puts Style.red(err)
|
333
|
+
elsif App.instance.debug?
|
334
|
+
io.puts Style.cyan(out)
|
335
|
+
io.puts Style.red(err)
|
336
|
+
elsif App.instance.info?
|
337
|
+
# io.puts Style.cyan(out)
|
338
|
+
# io.puts Style.red(err)
|
339
|
+
end
|
340
|
+
io.print Style.yellow(cmd_id)
|
341
|
+
io.print Style.blue(" | Finished in #{seconds} seconds with exit status ")
|
342
|
+
if exit_status == 0
|
343
|
+
io.puts Style.green("#{exit_status} (success)")
|
344
|
+
else
|
345
|
+
io.puts Style.red("#{exit_status} (failure)")
|
346
|
+
end
|
347
|
+
io.puts Style.green("*" * 80)
|
348
|
+
elsif App.instance.warn? && description
|
349
|
+
io.print Style.blue(" | Finished in #{seconds} seconds with exit status ")
|
350
|
+
if exit_status == 0
|
351
|
+
io.puts Style.green("#{exit_status} (success)")
|
352
|
+
else
|
353
|
+
io.puts Style.red("#{exit_status} (failure)")
|
354
|
+
end
|
355
|
+
io.puts Style.green("*" * 80)
|
339
356
|
end
|
340
|
-
io.puts Style.green("*" * 80)
|
341
357
|
io.string
|
342
358
|
end
|
343
|
-
puts output_block
|
359
|
+
puts output_block unless output_block.empty?
|
344
360
|
|
345
361
|
[out, err, exit_status]
|
346
362
|
end
|
data/lib/opswalrus/patches.rb
CHANGED
data/lib/opswalrus/version.rb
CHANGED
data/opswalrus.gemspec
CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.require_paths = ["lib"]
|
33
33
|
|
34
34
|
# gem dependencies
|
35
|
+
spec.add_dependency "activesupport", "~> 7.0"
|
35
36
|
spec.add_dependency "binding_of_caller", "~> 1.0"
|
36
37
|
spec.add_dependency "citrus", "~> 3.0"
|
37
38
|
spec.add_dependency "gli", "~> 2.21"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
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.53
|
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-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: binding_of_caller
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,6 +200,7 @@ files:
|
|
186
200
|
- lib/opswalrus.rb
|
187
201
|
- lib/opswalrus/_bootstrap.ops
|
188
202
|
- lib/opswalrus/_reboot.ops
|
203
|
+
- lib/opswalrus/_run_remote.ops
|
189
204
|
- lib/opswalrus/_shell.ops
|
190
205
|
- lib/opswalrus/app.rb
|
191
206
|
- lib/opswalrus/bootstrap.sh
|