loom-core 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +99 -0
  6. data/Guardfile +54 -0
  7. data/Rakefile +6 -0
  8. data/bin/loom +185 -0
  9. data/lib/env/development.rb +1 -0
  10. data/lib/loom.rb +44 -0
  11. data/lib/loom/all.rb +20 -0
  12. data/lib/loom/config.rb +106 -0
  13. data/lib/loom/core_ext.rb +37 -0
  14. data/lib/loom/dsl.rb +60 -0
  15. data/lib/loom/facts.rb +13 -0
  16. data/lib/loom/facts/all.rb +2 -0
  17. data/lib/loom/facts/fact_file_provider.rb +86 -0
  18. data/lib/loom/facts/fact_set.rb +138 -0
  19. data/lib/loom/host_spec.rb +32 -0
  20. data/lib/loom/inventory.rb +124 -0
  21. data/lib/loom/logger.rb +141 -0
  22. data/lib/loom/method_signature.rb +174 -0
  23. data/lib/loom/mods.rb +4 -0
  24. data/lib/loom/mods/action_proxy.rb +105 -0
  25. data/lib/loom/mods/all.rb +3 -0
  26. data/lib/loom/mods/mod_loader.rb +80 -0
  27. data/lib/loom/mods/module.rb +113 -0
  28. data/lib/loom/pattern.rb +15 -0
  29. data/lib/loom/pattern/all.rb +7 -0
  30. data/lib/loom/pattern/definition_context.rb +74 -0
  31. data/lib/loom/pattern/dsl.rb +176 -0
  32. data/lib/loom/pattern/hook.rb +28 -0
  33. data/lib/loom/pattern/loader.rb +48 -0
  34. data/lib/loom/pattern/reference.rb +71 -0
  35. data/lib/loom/pattern/reference_set.rb +169 -0
  36. data/lib/loom/pattern/result_reporter.rb +77 -0
  37. data/lib/loom/runner.rb +209 -0
  38. data/lib/loom/shell.rb +12 -0
  39. data/lib/loom/shell/all.rb +10 -0
  40. data/lib/loom/shell/api.rb +48 -0
  41. data/lib/loom/shell/cmd_result.rb +33 -0
  42. data/lib/loom/shell/cmd_wrapper.rb +164 -0
  43. data/lib/loom/shell/core.rb +226 -0
  44. data/lib/loom/shell/harness_blob.rb +26 -0
  45. data/lib/loom/shell/harness_command_builder.rb +50 -0
  46. data/lib/loom/shell/session.rb +25 -0
  47. data/lib/loom/trap.rb +44 -0
  48. data/lib/loom/version.rb +3 -0
  49. data/lib/loomext/all.rb +4 -0
  50. data/lib/loomext/corefacts.rb +6 -0
  51. data/lib/loomext/corefacts/all.rb +8 -0
  52. data/lib/loomext/corefacts/facter_provider.rb +24 -0
  53. data/lib/loomext/coremods.rb +5 -0
  54. data/lib/loomext/coremods/all.rb +13 -0
  55. data/lib/loomext/coremods/exec.rb +50 -0
  56. data/lib/loomext/coremods/files.rb +104 -0
  57. data/lib/loomext/coremods/net.rb +33 -0
  58. data/lib/loomext/coremods/package/adapter.rb +100 -0
  59. data/lib/loomext/coremods/package/package.rb +62 -0
  60. data/lib/loomext/coremods/user.rb +82 -0
  61. data/lib/loomext/coremods/vm.rb +0 -0
  62. data/lib/loomext/coremods/vm/all.rb +6 -0
  63. data/lib/loomext/coremods/vm/vbox.rb +84 -0
  64. data/loom.gemspec +39 -0
  65. data/loom/inventory.yml +13 -0
  66. data/scripts/harness.sh +242 -0
  67. data/spec/loom/host_spec_spec.rb +101 -0
  68. data/spec/loom/inventory_spec.rb +154 -0
  69. data/spec/loom/method_signature_spec.rb +275 -0
  70. data/spec/loom/pattern/dsl_spec.rb +207 -0
  71. data/spec/loom/shell/cmd_wrapper_spec.rb +239 -0
  72. data/spec/loom/shell/harness_blob_spec.rb +42 -0
  73. data/spec/loom/shell/harness_command_builder_spec.rb +36 -0
  74. data/spec/runloom.sh +35 -0
  75. data/spec/scripts/harness_spec.rb +385 -0
  76. data/spec/spec_helper.rb +94 -0
  77. data/spec/test.loom +370 -0
  78. data/spec/test_loom_spec.rb +57 -0
  79. 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