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.
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,94 @@
1
+ Dir.glob('./spec/shared/**/*.rb').each { |f| require f }
2
+ require './lib/loom'
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
7
+ # this file to always be loaded, without a need to explicitly require it in any
8
+ # files.
9
+ #
10
+ # Given that it is always loaded, you are encouraged to keep this file as
11
+ # light-weight as possible. Requiring heavyweight dependencies from this file
12
+ # will add to the boot time of your test suite on EVERY test run, even for an
13
+ # individual file that may not need all of that loaded. Instead, consider making
14
+ # a separate helper file that requires the additional dependencies and performs
15
+ # the additional setup, and require it from the spec files that actually need
16
+ # it.
17
+ #
18
+ # The `.rspec` file also contains a few flags that are not defaults but that
19
+ # users commonly want.
20
+ #
21
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
+ RSpec.configure do |config|
23
+ # rspec-expectations config goes here. You can use an alternate
24
+ # assertion/expectation library such as wrong or the stdlib/minitest
25
+ # assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4. It makes the `description`
28
+ # and `failure_message` of custom matchers include text for helper methods
29
+ # defined using `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double
38
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on
41
+ # a real object. This is generally recommended, and will default to
42
+ # `true` in RSpec 4.
43
+ mocks.verify_partial_doubles = true
44
+ end
45
+
46
+ # The settings below are suggested to provide a good initial experience
47
+ # with RSpec, but feel free to customize to your heart's content.
48
+ =begin
49
+ # These two settings work together to allow you to limit a spec run
50
+ # to individual examples or groups you care about by tagging them with
51
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
52
+ # get run.
53
+ config.filter_run :focus
54
+ config.run_all_when_everything_filtered = true
55
+
56
+ # Limits the available syntax to the non-monkey patched syntax that is
57
+ # recommended. For more details, see:
58
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
59
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
60
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
61
+ config.disable_monkey_patching!
62
+
63
+ # This setting enables warnings. It's recommended, but in some cases may
64
+ # be too noisy due to issues in dependencies.
65
+ config.warnings = true
66
+
67
+ # Many RSpec users commonly either run the entire suite or an individual
68
+ # file, and it's useful to allow more verbose output when running an
69
+ # individual spec file.
70
+ if config.files_to_run.one?
71
+ # Use the documentation formatter for detailed output,
72
+ # unless a formatter has already been configured
73
+ # (e.g. via a command-line flag).
74
+ config.default_formatter = 'doc'
75
+ end
76
+
77
+ # Print the 10 slowest examples and example groups at the
78
+ # end of the spec run, to help surface which specs are running
79
+ # particularly slow.
80
+ config.profile_examples = 10
81
+
82
+ # Run specs in random order to surface order dependencies. If you find an
83
+ # order dependency and want to debug it, you can fix the order by providing
84
+ # the seed, which is printed after each run.
85
+ # --seed 1234
86
+ config.order = :random
87
+
88
+ # Seed global randomization in this process using the `--seed` CLI option.
89
+ # Setting this allows you to use `--seed` to deterministically reproduce
90
+ # test failures related to randomization by passing the same `--seed` value
91
+ # as the one that triggered the failure.
92
+ Kernel.srand config.seed
93
+ =end
94
+ end
data/spec/test.loom ADDED
@@ -0,0 +1,370 @@
1
+ require "loomext/all"
2
+
3
+ desc "Prints some known facts"
4
+ pattern :three_facts do |loom, facts|
5
+ puts "first 3 facts..."
6
+ puts facts.facts.to_a.slice(0, 3).map { |tuple| tuple.join "=" }.join("\n")
7
+ end
8
+
9
+
10
+ desc "Reports `uptime` status"
11
+ pattern :uptime do |loom, facts|
12
+ loom << :uptime
13
+ loom << :hostname
14
+ loom.local << :hostname
15
+ end
16
+ #produces { pkg.installed? :httpd }
17
+
18
+ desc "cd's to the /etc directory and runs `pwd`"
19
+ pattern :cd do |loom, facts|
20
+ loom.cd "/etc" do
21
+ loom << :pwd
22
+ end
23
+ end
24
+
25
+ desc "tests return codes from wrapped commands"
26
+ pattern :wrap_returns do |loom, facts|
27
+ # using loom.time as a proxy for Shell::Core#wrap here
28
+ loom.time do
29
+ raise "wrapped true is not true" unless loom.test :true
30
+ raise "wrapped false is not false" if loom.test :false
31
+ end
32
+ end
33
+
34
+ desc "Tests a condition."
35
+ pattern :test do |loom, facts|
36
+ unless loom.test :false
37
+ loom.x :echo, "i tested false"
38
+ end
39
+
40
+ if loom.test :true
41
+ loom.x :echo, "i tested true"
42
+ end
43
+
44
+ if loom.test :which, "bash"
45
+ loom.x :echo, "has bash"
46
+ end
47
+ end
48
+
49
+ desc "Tests a grep condition."
50
+ pattern :match do |loom, facts|
51
+ if loom.files("/etc/hosts").match? :pattern => "aldsfja;ldjf"
52
+ loom.fail "should not match garbage"
53
+ else
54
+ loom.x :echo, "I didnt match garbage"
55
+ end
56
+
57
+ unless loom.files("/etc/hosts").match? :pattern => "localhost"
58
+ loom.fail "should match localhost"
59
+ else
60
+ loom.x :echo, "I did match my target"
61
+ end
62
+ end
63
+
64
+ desc "Always fails due to return code."
65
+ pattern :fail_soft do |loom, facts|
66
+ unless loom << :false
67
+ loom.x :echo, "i am false"
68
+ end
69
+ end
70
+
71
+ desc "Always fails due to a hard failure"
72
+ pattern :fail_hard do |loom, facts|
73
+ loom.fail "Fail big or not at all"
74
+ end
75
+
76
+ desc "Check timeout commands"
77
+ pattern :timeout_fail do |loom, facts|
78
+ loom.timeout(:timeout => 1) do
79
+ loom.x :sleep, 2
80
+ end
81
+ end
82
+
83
+ desc "Wrapped time commands"
84
+ pattern :time do |loom, facts|
85
+ loom.time do
86
+ loom.x :echo, :hi
87
+ loom.x :sleep, 2
88
+ end
89
+ end
90
+
91
+ module Net
92
+ include Loom::Pattern
93
+
94
+ desc "tests the net package, with_net check"
95
+ pattern :check_net do |loom, facts|
96
+ unless loom.net(check_host: '127.0.0.1').has_net?
97
+ loom.fail 'can not ping localhost'
98
+ end
99
+
100
+ has_local_net = false
101
+ loom.net(check_host: '127.0.0.1').with_net do
102
+ has_local_net = true
103
+ end
104
+ loom.fail "should have local net" unless has_local_net
105
+ end
106
+
107
+ desc "expected check_net failures"
108
+ pattern :check_net_fail do |loom, facts|
109
+ loom.net(timeout: 2, check_host: '1.1.1.1').check_net
110
+ end
111
+ end
112
+
113
+ module Files
114
+ include Loom::Pattern
115
+
116
+ desc "Reads a file"
117
+ pattern :read do |loom, facts|
118
+ loom.files("/etc/hosts").cat
119
+ end
120
+
121
+ desc "Gsubs file text"
122
+ pattern :gsub do |loom, facts|
123
+ loom.files("/tmp/garbage").write <<EOS
124
+ This is a bunch of junk
125
+ 192.123.456.0\t\thostname.xyz
126
+ EOS
127
+
128
+ loom.files("/tmp/garbage")
129
+ .cat
130
+ .gsub(pattern: /[\d]{3}/, replace: "xxx")
131
+ .append("this is something new")
132
+ .cat
133
+ end
134
+
135
+ desc "Chowns a file"
136
+ pattern :chown do |loom, facts|
137
+ loom.files("/tmp/chown.me")
138
+ .touch
139
+ .append("this file will be owned by root")
140
+
141
+ loom.sudo do
142
+ loom.files("/tmp/chown.me").chown user: :root
143
+ loom.x :ls, "-lZ", "/tmp/chown.me"
144
+
145
+ loom.files("/tmp/chown.me").chown user: :root, group: :root
146
+ end
147
+
148
+ loom.sudo { loom.exec :rm, "/tmp/chown.me" }
149
+ end
150
+ end
151
+
152
+ module Shell
153
+ include Loom::Pattern
154
+
155
+ desc "Executes some commands in a subshell"
156
+ pattern :subshell do |loom, facts|
157
+ loom << :"(echo $$; echo $BASHPID; whoami)"
158
+ loom << :"(sudo -i -u root whoami)"
159
+
160
+ loom.local << :"(echo $$; echo $BASHPID; whoami)"
161
+ # loom.local << "(sudo -i -u root whoami)"
162
+ end
163
+
164
+ desc "Tests nested sudo scenarios"
165
+ pattern :sudo do |loom, facts|
166
+ loom.sudo user: "root" do
167
+ loom << :pwd
168
+ loom << :whoami
169
+ loom.exec :touch, "loom.file"
170
+
171
+ loom.sudo do
172
+ loom << :whoami
173
+ loom << :pwd
174
+ loom.x :touch, "root.file"
175
+
176
+ loom.user.add_system_user :postgres, uid: 999
177
+ loom.sudo user: :postgres do
178
+ loom << :whoami
179
+ loom.cd "/tmp" do
180
+ loom << :pwd
181
+ loom.x :touch, "postgres.file"
182
+ end
183
+ end
184
+ loom.user.remove :postgres
185
+
186
+ loom.x :touch, "root.file2"
187
+ end
188
+ end
189
+
190
+ loom.cd "/tmp" do
191
+ loom << :pwd
192
+ loom.sudo user: :root, cmd: :pwd do loom << :pwd end
193
+ loom << :pwd
194
+ end
195
+
196
+ end
197
+ end
198
+
199
+ module Parent
200
+ include Loom::Pattern
201
+
202
+ with_facts :outer_fact => :outer, :replaced => :original
203
+
204
+ before do
205
+ puts "Test::Parent => before"
206
+ end
207
+
208
+ after do
209
+ puts "Test::Parent => after"
210
+ end
211
+
212
+ desc "Checks facts on a parent pattern"
213
+ pattern :check_facts do |loom, facts|
214
+ unless facts[:outer_fact] == :outer
215
+ raise "expected outer fact => #{facts[:outer_fact]}"
216
+ end
217
+ end
218
+
219
+ let(:a_let_key) { "the value" }
220
+ let(:a_fact_based_let) { |facts| facts[:outer_fact].to_s + "/let" }
221
+ let(:a_referencing_let) { a_let_key + " referenced" }
222
+
223
+ desc "Checks let defines"
224
+ pattern :check_lets do |loom, facts|
225
+ raise "bad let :a_let_key" unless a_let_key == "the value"
226
+ raise "bad let :a_fact_based_let" unless a_fact_based_let == "outer/let"
227
+
228
+ unless a_referencing_let == "the value referenced"
229
+ raise "bad let :a_referencing_let => #{a_referencing_let}"
230
+ end
231
+
232
+ puts "a_let_key: %s" % a_let_key
233
+ puts "a_fact_based_let: %s" % a_fact_based_let
234
+ end
235
+
236
+ module Child
237
+ include Loom::Pattern
238
+
239
+ with_facts :inner_fact => :inner, :replaced => :override
240
+ let(:a_let_key) { |facts| facts[:inner_fact].to_s + " overrides parent" }
241
+
242
+ before do
243
+ puts "Test::Parent::Child => before"
244
+ end
245
+
246
+ after do
247
+ puts "Test::Parent::Child => after"
248
+ end
249
+
250
+ desc "Check let overrides"
251
+ pattern :check_let_overrides do |loom, facts|
252
+ raise "bad let :a_let_key" unless a_let_key == "inner overrides parent"
253
+ raise "bad let :a_fact_based_let" unless a_fact_based_let == "outer/let"
254
+
255
+ puts "child a_let_key: %s" % a_let_key
256
+ puts "child a_fact_based_let: %s" % a_fact_based_let
257
+ end
258
+
259
+ desc "Checks inherited facts on a cihld pattern"
260
+ pattern :check_facts do |loom, facts|
261
+ unless facts[:inner_fact] == :inner
262
+ raise "expected inner fact => #{facts[:inner_fact]}"
263
+ end
264
+ unless facts[:outer_fact] == :outer
265
+ raise "expected outer fact => #{facts[:outer_fact]}"
266
+ end
267
+ unless facts[:replaced] == :override
268
+ raise "expected replaced fact => #{facts[:replaced_fact]}"
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ module User
275
+ include Loom::Pattern
276
+
277
+ desc "Adds a bunch of users and then removes them right away"
278
+ pattern :add_users do |loom, facts|
279
+ loom.sudo do
280
+ loom.user.add :nara, uid: 1001, home_dir: "/home/nara"
281
+ loom.user.add :marrian, home_dir: "/home/marrian"
282
+
283
+ loom.user.add_system_user :app, uid: 900
284
+ loom.user.add_system_user :batch
285
+
286
+ loom.user.remove :nara
287
+ loom.user.remove :marrian
288
+ loom.user.remove :app
289
+ loom.user.remove :batch
290
+ end
291
+ end
292
+
293
+ desc "Makes the postgres user a sudoer"
294
+ pattern :sudoers do |loom, facts|
295
+ loom.sudo do
296
+ loom.user.add_system_user :postgres, uid: 999
297
+ loom.user.make_sudoer :postgres
298
+ loom.user.remove :postgres
299
+ end
300
+ end
301
+ end
302
+
303
+ module Package
304
+ include Loom::Pattern
305
+
306
+ namespace :pkg
307
+
308
+ before do |loom, facts|
309
+ puts "#{self} in before"
310
+ end
311
+
312
+ after do
313
+ puts "#{self} in after"
314
+ end
315
+
316
+ desc "Updates the default package manager cache"
317
+ pattern :update_cache do |loom, facts|
318
+ loom.sudo { loom.pkg.update_cache }
319
+ end
320
+
321
+ desc "Installs Apache HTTP server"
322
+ pattern :install_httpd do |loom, facts|
323
+ loom.sudo do
324
+ loom.pkg.install 'apache2' unless loom.pkg.installed? 'apache2'
325
+ end
326
+ end
327
+
328
+ desc "Installs Facter GEM"
329
+ pattern :install_facter do |loom, facts|
330
+ loom.sudo do
331
+ loom.pkg[:gem].ensure_installed :facter
332
+ end
333
+ end
334
+ end
335
+
336
+ module ErrorHandling
337
+ include Loom::Pattern
338
+
339
+ namespace :err
340
+
341
+ desc "Handle SSH disconnection errors"
342
+ pattern :ssh_disconnect do |loom, facts|
343
+ if facts[:really_really_reboot]
344
+ loom.sudo cmd: :reboot
345
+ else
346
+ puts "to REALLY reboot set fact[:really_really_reboot] = true"
347
+ end
348
+ end
349
+ end
350
+
351
+ module VMs
352
+ include Loom::Pattern
353
+
354
+ desc "Check if some virtualbox vms exist"
355
+ pattern :vm_exists? do |loom, facts|
356
+ vm0_exists = loom.local.vbox.check_exists "vm0.local"
357
+ puts "Virtualbox VM 'vm0.local' exists: #{vm0_exists}"
358
+ end
359
+
360
+ desc "Check if some virtualbox vms exist"
361
+ pattern :list do |loom, facts|
362
+ loom.local.vbox.list
363
+ end
364
+
365
+ desc "Takes a snapshot of a VM"
366
+ pattern :snap do |loom, facts|
367
+ loom.local.vbox.snapshot "vm0.local", snapshot_name: "test:snap"
368
+ loom.local.vbox.snapshot "vm0.local", action: :delete, snapshot_name: "test:snap"
369
+ end
370
+ end