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,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