loom-core 0.0.1
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 +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +99 -0
- data/Guardfile +54 -0
- data/Rakefile +6 -0
- data/bin/loom +185 -0
- data/lib/env/development.rb +1 -0
- data/lib/loom.rb +44 -0
- data/lib/loom/all.rb +20 -0
- data/lib/loom/config.rb +106 -0
- data/lib/loom/core_ext.rb +37 -0
- data/lib/loom/dsl.rb +60 -0
- data/lib/loom/facts.rb +13 -0
- data/lib/loom/facts/all.rb +2 -0
- data/lib/loom/facts/fact_file_provider.rb +86 -0
- data/lib/loom/facts/fact_set.rb +138 -0
- data/lib/loom/host_spec.rb +32 -0
- data/lib/loom/inventory.rb +124 -0
- data/lib/loom/logger.rb +141 -0
- data/lib/loom/method_signature.rb +174 -0
- data/lib/loom/mods.rb +4 -0
- data/lib/loom/mods/action_proxy.rb +105 -0
- data/lib/loom/mods/all.rb +3 -0
- data/lib/loom/mods/mod_loader.rb +80 -0
- data/lib/loom/mods/module.rb +113 -0
- data/lib/loom/pattern.rb +15 -0
- data/lib/loom/pattern/all.rb +7 -0
- data/lib/loom/pattern/definition_context.rb +74 -0
- data/lib/loom/pattern/dsl.rb +176 -0
- data/lib/loom/pattern/hook.rb +28 -0
- data/lib/loom/pattern/loader.rb +48 -0
- data/lib/loom/pattern/reference.rb +71 -0
- data/lib/loom/pattern/reference_set.rb +169 -0
- data/lib/loom/pattern/result_reporter.rb +77 -0
- data/lib/loom/runner.rb +209 -0
- data/lib/loom/shell.rb +12 -0
- data/lib/loom/shell/all.rb +10 -0
- data/lib/loom/shell/api.rb +48 -0
- data/lib/loom/shell/cmd_result.rb +33 -0
- data/lib/loom/shell/cmd_wrapper.rb +164 -0
- data/lib/loom/shell/core.rb +226 -0
- data/lib/loom/shell/harness_blob.rb +26 -0
- data/lib/loom/shell/harness_command_builder.rb +50 -0
- data/lib/loom/shell/session.rb +25 -0
- data/lib/loom/trap.rb +44 -0
- data/lib/loom/version.rb +3 -0
- data/lib/loomext/all.rb +4 -0
- data/lib/loomext/corefacts.rb +6 -0
- data/lib/loomext/corefacts/all.rb +8 -0
- data/lib/loomext/corefacts/facter_provider.rb +24 -0
- data/lib/loomext/coremods.rb +5 -0
- data/lib/loomext/coremods/all.rb +13 -0
- data/lib/loomext/coremods/exec.rb +50 -0
- data/lib/loomext/coremods/files.rb +104 -0
- data/lib/loomext/coremods/net.rb +33 -0
- data/lib/loomext/coremods/package/adapter.rb +100 -0
- data/lib/loomext/coremods/package/package.rb +62 -0
- data/lib/loomext/coremods/user.rb +82 -0
- data/lib/loomext/coremods/vm.rb +0 -0
- data/lib/loomext/coremods/vm/all.rb +6 -0
- data/lib/loomext/coremods/vm/vbox.rb +84 -0
- data/loom.gemspec +39 -0
- data/loom/inventory.yml +13 -0
- data/scripts/harness.sh +242 -0
- data/spec/loom/host_spec_spec.rb +101 -0
- data/spec/loom/inventory_spec.rb +154 -0
- data/spec/loom/method_signature_spec.rb +275 -0
- data/spec/loom/pattern/dsl_spec.rb +207 -0
- data/spec/loom/shell/cmd_wrapper_spec.rb +239 -0
- data/spec/loom/shell/harness_blob_spec.rb +42 -0
- data/spec/loom/shell/harness_command_builder_spec.rb +36 -0
- data/spec/runloom.sh +35 -0
- data/spec/scripts/harness_spec.rb +385 -0
- data/spec/spec_helper.rb +94 -0
- data/spec/test.loom +370 -0
- data/spec/test_loom_spec.rb +57 -0
- metadata +287 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
describe Loom::Shell::HarnessCommandBuilder do
|
2
|
+
|
3
|
+
let(:cmd) do
|
4
|
+
<<CMD
|
5
|
+
cd /tmp
|
6
|
+
pwd
|
7
|
+
CMD
|
8
|
+
end
|
9
|
+
let(:harness_blob) { Loom::Shell::HarnessBlob.new cmd }
|
10
|
+
|
11
|
+
subject { Loom::Shell::HarnessCommandBuilder.new harness_blob }
|
12
|
+
|
13
|
+
context "#run" do
|
14
|
+
it "builds run commands for the harness" do
|
15
|
+
expected_cmd = [
|
16
|
+
"./scripts/harness.sh",
|
17
|
+
"--run 2>/dev/null",
|
18
|
+
"-",
|
19
|
+
harness_blob.checksum,
|
20
|
+
"--cmd_shell /bin/dash",
|
21
|
+
"--record_file /opt/loom/commands",
|
22
|
+
"<<'[\\w]+'\n"
|
23
|
+
].join " "
|
24
|
+
|
25
|
+
expected_cmd << harness_blob.encoded_script + "\n[\\w]+"
|
26
|
+
|
27
|
+
expect(subject.run_cmd).to match /^#{expected_cmd}/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "is shell executable" do
|
31
|
+
result = %x{#{subject.run_cmd}}
|
32
|
+
expect(result).to eq "/tmp\n"
|
33
|
+
expect($?.exitstatus).to be 0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/runloom.sh
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
spec_file="spec/test.loom"
|
4
|
+
all_patterns=$(bin/loom patterns --print \
|
5
|
+
-t \
|
6
|
+
-l ${spec_file})
|
7
|
+
|
8
|
+
addl_args="${@}"
|
9
|
+
|
10
|
+
bin/loom weave ${all_patterns} \
|
11
|
+
-t \
|
12
|
+
-l ${spec_file} \
|
13
|
+
-X log_level=info \
|
14
|
+
-H vm0.local \
|
15
|
+
-X sshkit_log_level=warn \
|
16
|
+
-X log_device=stderr \
|
17
|
+
-X run_failure_strategy=cowboy \
|
18
|
+
${addl_args}
|
19
|
+
rc=$?
|
20
|
+
|
21
|
+
# expect exit code 104 (100 for patterns execution error + # expected failures):
|
22
|
+
# exec:fail_soft
|
23
|
+
# exec:fail_hard
|
24
|
+
# exec:timeout_fail
|
25
|
+
# net:check_net_fail
|
26
|
+
|
27
|
+
if [ "${rc}" = "104" ]; then
|
28
|
+
# runall.sh exits succesfully on this failure because we expect
|
29
|
+
# the "fail" patterns to fail
|
30
|
+
echo "success with exit code ${rc}"
|
31
|
+
exit 0
|
32
|
+
else
|
33
|
+
echo "failed with exit code ${rc}"
|
34
|
+
exit $rc
|
35
|
+
fi
|
@@ -0,0 +1,385 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
describe 'loom harness script' do
|
5
|
+
|
6
|
+
HARNESS = "./scripts/harness.sh"
|
7
|
+
|
8
|
+
# Set debug_script to true in a context to see STDERR debugging.
|
9
|
+
let(:debug_script) { false }
|
10
|
+
|
11
|
+
def run_script(cmd, *args, stdin: nil, harness_shell: :bash)
|
12
|
+
stderr_redirect = debug_script ? "" : "2>/dev/null"
|
13
|
+
cmd = if stdin
|
14
|
+
stdin = stdin.rstrip + "\n"
|
15
|
+
heredoc = "<<'SH_EOS'\n#{stdin}\nSH_EOS"
|
16
|
+
"#{HARNESS} #{cmd} - #{args.join " "} #{heredoc}"
|
17
|
+
else
|
18
|
+
"#{HARNESS} #{cmd} #{args.join " "}"
|
19
|
+
end
|
20
|
+
|
21
|
+
harness_cmd = "(#{harness_shell} -) #{stderr_redirect} " +
|
22
|
+
"<<'HARNESS_EOS'\n#{cmd}\nHARNESS_EOS"
|
23
|
+
if debug_script
|
24
|
+
puts "[harness-cmd]$ #{harness_cmd}"
|
25
|
+
end
|
26
|
+
|
27
|
+
%x{#{harness_cmd}}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:cmd) { 'echo hi there | (echo "from subshell"; cat);' }
|
31
|
+
let(:quoted_cmd) { "'#{cmd}'" }
|
32
|
+
|
33
|
+
# TODO: This is actually the base64 of `cmd` + a trailing newline. I'm
|
34
|
+
# not sure whether it should be trimmed first or not.
|
35
|
+
let(:base64) do
|
36
|
+
"ZWNobyBoaSB0aGVyZSB8IChlY2hvICJmcm9tIHN1YnNoZWxsIjsgY2F0KTsK"
|
37
|
+
end
|
38
|
+
|
39
|
+
# TODO: This is actually the checksum of `base64` + a trailing newline. I'm
|
40
|
+
# not sure whether it should be trimmed first or not.
|
41
|
+
let(:base64_checksum) { "18e75ac603d7cf76db5a841157a3871c5d53f217" }
|
42
|
+
let(:expected_output) do
|
43
|
+
<<EOS
|
44
|
+
from subshell
|
45
|
+
hi there
|
46
|
+
EOS
|
47
|
+
end
|
48
|
+
|
49
|
+
context "--print_base64" do
|
50
|
+
|
51
|
+
it "encodes commands from args" do
|
52
|
+
result = run_script :"--print_base64", quoted_cmd
|
53
|
+
expect(result).to eq base64
|
54
|
+
expect($?.exitstatus).to be 0
|
55
|
+
end
|
56
|
+
|
57
|
+
it "encodes commands from STDIN" do
|
58
|
+
result = run_script :"--print_base64", :stdin => cmd
|
59
|
+
expect(result).to eq base64
|
60
|
+
expect($?.exitstatus).to be 0
|
61
|
+
end
|
62
|
+
|
63
|
+
context "multiline strings" do
|
64
|
+
it "encodes newlines" do
|
65
|
+
cmd = <<EOS
|
66
|
+
cd /tmp
|
67
|
+
pwd
|
68
|
+
EOS
|
69
|
+
result = run_script :"--print_base64", :stdin => cmd
|
70
|
+
expect(result).to eq "Y2QgL3RtcApwd2QK"
|
71
|
+
expect(Base64.decode64 result).to eq cmd
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "trailing whitespace" do
|
76
|
+
|
77
|
+
it "ignores trailing newlines" do
|
78
|
+
cmd = "pwd"
|
79
|
+
|
80
|
+
3.times do |i|
|
81
|
+
append_str = "\n" * i
|
82
|
+
|
83
|
+
nl_cmd_string = cmd + append_str
|
84
|
+
stdin_result = run_script :"--print_base64", :stdin => nl_cmd_string
|
85
|
+
argv_result = run_script :"--print_base64", "\"#{nl_cmd_string}\""
|
86
|
+
|
87
|
+
expect(stdin_result).to eq "cHdkCg=="
|
88
|
+
expect(argv_result).to eq "cHdkCg=="
|
89
|
+
|
90
|
+
expect(Base64.decode64 argv_result).to eq "pwd\n"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "--print_checksum" do
|
97
|
+
|
98
|
+
it "fails if arg is not a base64 blob" do
|
99
|
+
result = run_script :"--print_checksum", :stdin => "this is not base64"
|
100
|
+
expect($?.exitstatus).to eq 9
|
101
|
+
end
|
102
|
+
|
103
|
+
it "prints the sha1 checksum from args" do
|
104
|
+
result = run_script :"--print_checksum", base64
|
105
|
+
expect(result).to eq base64_checksum
|
106
|
+
expect($?.exitstatus).to eq 0
|
107
|
+
end
|
108
|
+
|
109
|
+
it "prints the sha1 checksum from STDIN" do
|
110
|
+
result = run_script :"--print_checksum", :stdin => base64
|
111
|
+
expect(result).to eq base64_checksum
|
112
|
+
expect($?.exitstatus).to eq 0
|
113
|
+
end
|
114
|
+
|
115
|
+
it "is resilient to trailing whitespace" do
|
116
|
+
result1 = run_script :"--print_checksum", base64 + "\n\n"
|
117
|
+
expect(result1).to eq base64_checksum
|
118
|
+
expect($?.exitstatus).to eq 0
|
119
|
+
|
120
|
+
result2 = run_script :"--print_checksum", :stdin => base64 + "\n\n\n"
|
121
|
+
expect(result2).to eq base64_checksum
|
122
|
+
expect($?.exitstatus).to eq 0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "--check" do
|
127
|
+
|
128
|
+
context "errors" do
|
129
|
+
|
130
|
+
it "if less than 2 args are passed" do
|
131
|
+
result = run_script :"--check", "only1arg"
|
132
|
+
expect($?.exitstatus).to eq 2
|
133
|
+
|
134
|
+
result = run_script :"--check"
|
135
|
+
expect($?.exitstatus).to eq 2
|
136
|
+
end
|
137
|
+
|
138
|
+
it "fails for a invalid base64" do
|
139
|
+
result = run_script :"--check", "not-base-64", base64_checksum
|
140
|
+
expect($?.exitstatus).to eq 9
|
141
|
+
end
|
142
|
+
|
143
|
+
it "fails for a bad checksum" do
|
144
|
+
result = run_script :"--check", base64, "not-a-checksum"
|
145
|
+
expect($?.exitstatus).to eq 8
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "from args" do
|
150
|
+
|
151
|
+
it "succeeds if the sha1 checksum matches" do
|
152
|
+
result = run_script :"--check", base64, base64_checksum
|
153
|
+
expect($?.exitstatus).to eq 0
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "--run" do
|
159
|
+
|
160
|
+
context "errors" do
|
161
|
+
|
162
|
+
it "if less than 2 args are passed" do
|
163
|
+
result = run_script :"--run", "only1arg"
|
164
|
+
expect($?.exitstatus).to eq 2
|
165
|
+
|
166
|
+
result = run_script :"--run"
|
167
|
+
expect($?.exitstatus).to eq 2
|
168
|
+
end
|
169
|
+
|
170
|
+
it "fails for a invalid base64" do
|
171
|
+
result = run_script :"--run", "not-base-64", base64_checksum
|
172
|
+
expect($?.exitstatus).to eq 9
|
173
|
+
end
|
174
|
+
|
175
|
+
it "fails for a bad checksum" do
|
176
|
+
result = run_script :"--run", base64, "not-a-checksum"
|
177
|
+
expect($?.exitstatus).to eq 8
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "record file" do
|
182
|
+
|
183
|
+
let(:record_file) { "/tmp/harness.cmds" }
|
184
|
+
|
185
|
+
after(:example) do
|
186
|
+
File.delete record_file
|
187
|
+
end
|
188
|
+
|
189
|
+
it "stores the executed command history" do
|
190
|
+
result = run_script :"--run", base64, base64_checksum,
|
191
|
+
"--record_file #{record_file}"
|
192
|
+
expect(result).to eq expected_output
|
193
|
+
expect(File.read(record_file).strip).to eq cmd
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "runs valid commands" do
|
198
|
+
|
199
|
+
it "from args" do
|
200
|
+
result = run_script :"--run", base64, base64_checksum
|
201
|
+
expect(result).to eq expected_output
|
202
|
+
expect($?.exitstatus).to eq 0
|
203
|
+
end
|
204
|
+
|
205
|
+
it "from STDIN" do
|
206
|
+
result = run_script :"--run", base64_checksum, :stdin => base64
|
207
|
+
expect(result).to eq expected_output
|
208
|
+
expect($?.exitstatus).to eq 0
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "runs in harness shell" do
|
213
|
+
|
214
|
+
it "bash" do
|
215
|
+
result = run_script :"--run", base64_checksum, {
|
216
|
+
:stdin => base64,
|
217
|
+
:harness_shell => "bash"
|
218
|
+
}
|
219
|
+
expect(result).to eq expected_output
|
220
|
+
expect($?.exitstatus).to eq 0
|
221
|
+
end
|
222
|
+
|
223
|
+
it "bash --posix" do
|
224
|
+
result = run_script :"--run", base64_checksum, {
|
225
|
+
:stdin => base64,
|
226
|
+
:harness_shell => "bash --posix"
|
227
|
+
}
|
228
|
+
expect(result).to eq expected_output
|
229
|
+
expect($?.exitstatus).to eq 0
|
230
|
+
end
|
231
|
+
|
232
|
+
context "dash" do
|
233
|
+
|
234
|
+
it "from args" do
|
235
|
+
result = run_script :"--run", base64, base64_checksum, {
|
236
|
+
:harness_shell => "/bin/dash"
|
237
|
+
}
|
238
|
+
expect(result).to eq expected_output
|
239
|
+
expect($?.exitstatus).to eq 0
|
240
|
+
end
|
241
|
+
|
242
|
+
it "from STDIN" do
|
243
|
+
result = run_script :"--run", base64_checksum, {
|
244
|
+
:stdin => base64,
|
245
|
+
:harness_shell => "/bin/dash"
|
246
|
+
}
|
247
|
+
expect(result).to eq expected_output
|
248
|
+
expect($?.exitstatus).to eq 0
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context "run in command shell" do
|
254
|
+
|
255
|
+
let(:cmd) do
|
256
|
+
<<SH_EOS
|
257
|
+
# The cmd_shell Test
|
258
|
+
echo $0
|
259
|
+
|
260
|
+
# CD Test
|
261
|
+
cd /tmp
|
262
|
+
pwd
|
263
|
+
|
264
|
+
# The subshell tests
|
265
|
+
echo "piped to cat" | (
|
266
|
+
echo from a subshell
|
267
|
+
cat
|
268
|
+
)
|
269
|
+
(
|
270
|
+
exec 2>&1
|
271
|
+
echo "out to err and back to out" 1>&2
|
272
|
+
)
|
273
|
+
|
274
|
+
# The sudo test
|
275
|
+
sudo -u $(whoami) whoami
|
276
|
+
|
277
|
+
# Variable expansion
|
278
|
+
foo=bar
|
279
|
+
echo "I am FOO: ${foo}"
|
280
|
+
|
281
|
+
# Subshell variable expansion
|
282
|
+
(
|
283
|
+
echo "I am subshell FOO: ${foo}"
|
284
|
+
foo=baz
|
285
|
+
echo "I am subshell FOO2: ${foo}"
|
286
|
+
)
|
287
|
+
|
288
|
+
# The ulimit test
|
289
|
+
tmp_file=$(mktemp)
|
290
|
+
(
|
291
|
+
ulimit -f 0
|
292
|
+
echo "this will blow up w/ signal SIGXFSZ" > $tmp_file
|
293
|
+
)
|
294
|
+
echo $? # expect exit 153 (signal 25 + 128), SIGXFSZ
|
295
|
+
rm $tmp_file
|
296
|
+
|
297
|
+
SH_EOS
|
298
|
+
end
|
299
|
+
|
300
|
+
let(:whoami) { %x{whoami}.strip }
|
301
|
+
let(:expected_output) do
|
302
|
+
<<EOS
|
303
|
+
%s
|
304
|
+
/tmp
|
305
|
+
from a subshell
|
306
|
+
piped to cat
|
307
|
+
out to err and back to out
|
308
|
+
#{whoami}
|
309
|
+
I am FOO: bar
|
310
|
+
I am subshell FOO: bar
|
311
|
+
I am subshell FOO2: baz
|
312
|
+
153
|
313
|
+
EOS
|
314
|
+
end
|
315
|
+
|
316
|
+
let(:base64) { run_script :"--print_base64", :stdin => cmd }
|
317
|
+
let(:base64_checksum) { run_script :"--print_checksum", :stdin => base64 }
|
318
|
+
|
319
|
+
context "bash" do
|
320
|
+
|
321
|
+
it "from STDIN" do
|
322
|
+
result = run_script :"--run", base64_checksum,
|
323
|
+
"--cmd_shell /bin/bash", :stdin => base64
|
324
|
+
expect($?.exitstatus).to eq 0
|
325
|
+
|
326
|
+
expected_output_for_shell = expected_output % "/bin/bash"
|
327
|
+
expect(result).to eq expected_output_for_shell
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context "bash --posix" do
|
332
|
+
|
333
|
+
it "from STDIN" do
|
334
|
+
result = run_script :"--run", base64_checksum,
|
335
|
+
"--cmd_shell '/bin/bash --posix'", :stdin => base64
|
336
|
+
expect($?.exitstatus).to eq 0
|
337
|
+
|
338
|
+
expected_output_for_shell = expected_output % "/bin/bash"
|
339
|
+
expect(result).to eq expected_output_for_shell
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context "dash" do
|
344
|
+
|
345
|
+
it "from STDIN" do
|
346
|
+
result = run_script :"--run", base64_checksum,
|
347
|
+
"--cmd_shell /bin/dash", :stdin => base64
|
348
|
+
expect($?.exitstatus).to eq 0
|
349
|
+
|
350
|
+
expected_output_for_shell = expected_output % "/bin/dash"
|
351
|
+
expect(result).to eq expected_output_for_shell
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
context "return codes" do
|
357
|
+
|
358
|
+
def run(cmd)
|
359
|
+
base64 = run_script :"--print_base64", :stdin => cmd
|
360
|
+
base64_checksum = run_script :"--print_checksum", :stdin => base64
|
361
|
+
run_script :"--run", base64_checksum,
|
362
|
+
"--cmd_shell /bin/dash", :stdin => base64
|
363
|
+
end
|
364
|
+
|
365
|
+
it "returns 0 on success" do
|
366
|
+
run "true"
|
367
|
+
expect($?.exitstatus).to be 0
|
368
|
+
end
|
369
|
+
|
370
|
+
it "returns 'exitcode' on failure" do
|
371
|
+
run "exit 123"
|
372
|
+
expect($?.exitstatus).to be 123
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context "usage error" do
|
378
|
+
|
379
|
+
it "prints a usage message" do
|
380
|
+
result = run_script nil
|
381
|
+
expect(result).to match /^Usages:.*/i
|
382
|
+
expect($?.exitstatus).to be 1
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|