loom-core 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/bin/loom +5 -1
  4. data/lib/loom/config.rb +10 -3
  5. data/lib/loom/facts/fact_set.rb +7 -1
  6. data/lib/loom/mods/module.rb +3 -4
  7. data/lib/loom/pattern/definition_context.rb +1 -1
  8. data/lib/loom/pattern/dsl.rb +113 -32
  9. data/lib/loom/pattern/reference_set.rb +7 -7
  10. data/lib/loom/runner.rb +8 -0
  11. data/lib/loom/shell/api.rb +2 -0
  12. data/lib/loom/version.rb +1 -1
  13. data/lib/loomext/corefacts/system_info_provider.rb +2 -1
  14. data/lib/loomext/coremods/all.rb +2 -1
  15. data/lib/loomext/coremods/exec.rb +10 -0
  16. data/lib/loomext/coremods/git.rb +19 -0
  17. data/lib/loomext/coremods/package/adapter.rb +1 -1
  18. data/lib/loomext/coremods/systemd.rb +1 -0
  19. data/lib/loomext/coremods/systemd/all.rb +2 -0
  20. data/lib/loomext/coremods/{system.rb → systemd/systemd.rb} +19 -5
  21. data/lib/loomext/coremods/systemd/systemd_units.rb +69 -0
  22. data/scripts/harness.sh +1 -0
  23. data/spec/.loom/error_handling.loom +15 -0
  24. data/spec/.loom/fail.loom +20 -0
  25. data/spec/.loom/files.loom +39 -0
  26. data/spec/.loom/net.loom +21 -0
  27. data/spec/.loom/pattern_context.loom +78 -0
  28. data/spec/.loom/pkg.loom +33 -0
  29. data/spec/.loom/shell.loom +46 -0
  30. data/spec/.loom/test.loom +73 -0
  31. data/spec/.loom/user.loom +29 -0
  32. data/spec/.loom/vms.loom +22 -0
  33. data/spec/loom/facts/fact_set_spec.rb +57 -0
  34. data/spec/loom/pattern/dsl_spec.rb +58 -9
  35. data/spec/loom/shell/harness_blob_spec.rb +1 -1
  36. data/spec/loom/shell/harness_command_builder_spec.rb +1 -1
  37. data/spec/loomext/coremods/systemd_spec.rb +31 -0
  38. data/spec/runloom.sh +12 -19
  39. data/spec/scripts/harness_spec.rb +1 -1
  40. data/spec/shared/loom_internals_helper.rb +41 -0
  41. data/spec/spec_helper.rb +5 -1
  42. data/spec/systemd.loom +22 -0
  43. data/spec/test_loom_spec.rb +95 -17
  44. data/test +2 -0
  45. metadata +26 -5
  46. data/spec/test.loom +0 -370
@@ -0,0 +1,29 @@
1
+ # Tests for LoomExt::CoreMods::User
2
+ module User
3
+ include Loom::Pattern
4
+
5
+ desc "Adds a bunch of users and then removes them right away"
6
+ pattern :add_users do |loom, facts|
7
+ loom.sudo do
8
+ loom.user.add :nara, uid: 1001, home_dir: "/home/nara"
9
+ loom.user.add :marrian, home_dir: "/home/marrian"
10
+
11
+ loom.user.add_system_user :app, uid: 900
12
+ loom.user.add_system_user :batch
13
+
14
+ loom.user.remove :nara
15
+ loom.user.remove :marrian
16
+ loom.user.remove :app
17
+ loom.user.remove :batch
18
+ end
19
+ end
20
+
21
+ desc "Makes the postgres user a sudoer"
22
+ pattern :sudoers do |loom, facts|
23
+ loom.sudo do
24
+ loom.user.add_system_user :postgres, uid: 999
25
+ loom.user.make_sudoer :postgres
26
+ loom.user.remove :postgres
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # Tests for LoomExt::CoreMods::Vbox.
2
+ # Currently disabled
3
+ module VMs
4
+ include Loom::Pattern
5
+
6
+ desc "Check if some virtualbox vms exist"
7
+ pattern :vm_exists? do |loom, facts|
8
+ vm0_exists = loom.local.vbox.check_exists "vm0.local"
9
+ puts "Virtualbox VM 'vm0.local' exists: #{vm0_exists}"
10
+ end
11
+
12
+ desc "Check if some virtualbox vms exist"
13
+ pattern :list do |loom, facts|
14
+ loom.local.vbox.list
15
+ end
16
+
17
+ desc "Takes a snapshot of a VM"
18
+ pattern :snap do |loom, facts|
19
+ loom.local.vbox.snapshot "vm0.local", snapshot_name: "test:snap"
20
+ loom.local.vbox.snapshot "vm0.local", action: :delete, snapshot_name: "test:snap"
21
+ end
22
+ end
@@ -0,0 +1,57 @@
1
+ require 'loom/facts'
2
+
3
+ describe Loom::Facts::FactSet do
4
+
5
+ let(:fact_set) { Loom::Facts::FactSet.new hostspec, facts }
6
+ let(:hostspec) { Loom::HostSpec.new "dummy.host" }
7
+ let(:facts) {{
8
+ :fact_a => :a,
9
+ :fact_b => [:other, :facts]
10
+ }}
11
+
12
+ subject { fact_set }
13
+
14
+ let(:other_fact_set) { Loom::Facts::FactSet.new hostspec, other_facts }
15
+ let(:other_facts) {{
16
+ :fact_y => :y,
17
+ :fact_z => :z,
18
+ }}
19
+
20
+ context Loom::Facts::EMPTY do
21
+
22
+ subject { Loom::Facts::EMPTY }
23
+
24
+ it "should equal Facts.is_empty?" do
25
+ expect(Loom::Facts.is_empty? subject).to be true
26
+
27
+ # sanity
28
+ expect(Loom::Facts.is_empty?({})).to be false
29
+ expect(Loom::Facts.is_empty?(fact_set)).to be false
30
+ end
31
+ end
32
+
33
+ context :merge do
34
+ it "merges with other fact sets" do
35
+ new_facts = subject.merge other_fact_set
36
+ expect(new_facts[:fact_a]).to be :a
37
+ expect(new_facts[:fact_y]).to be :y
38
+ end
39
+
40
+ it "merges with other hashes" do
41
+ new_facts = subject.merge :other_stuff => :in_a_hash
42
+ expect(new_facts[:fact_a]).to be :a
43
+ expect(new_facts[:other_stuff]).to be :in_a_hash
44
+ end
45
+ end
46
+
47
+ context :[] do
48
+
49
+ it "returns EMPTY for no result" do
50
+ expect(fact_set[:invalid_key]).to be Loom::Facts::EMPTY
51
+ end
52
+
53
+ it "gets facts by name" do
54
+ expect(fact_set[:fact_a]).to be :a
55
+ end
56
+ end
57
+ end
@@ -12,7 +12,7 @@ describe Loom::Pattern::DSL do
12
12
  end
13
13
 
14
14
  before do
15
- # bit buckets the logs
15
+ # intercept logs
16
16
  @logger_io = StringIO.new
17
17
  Loom.configure do |config|
18
18
  config.log_device = @logger_io
@@ -28,7 +28,7 @@ describe Loom::Pattern::DSL do
28
28
  context "pattern basics" do
29
29
 
30
30
  let(:loom_file) do
31
- <<EOS
31
+ <<RB_LOOM
32
32
  desc "a description of pattern_under_test"
33
33
  pattern :pattern_under_test do |loom, facts|
34
34
  loom.do_outer_thing
@@ -42,7 +42,7 @@ describe Loom::Pattern::DSL do
42
42
  loom.do_inner_thing
43
43
  end
44
44
  end
45
- EOS
45
+ RB_LOOM
46
46
  end
47
47
 
48
48
  it "defines a Pattern::Reference" do
@@ -67,7 +67,7 @@ EOS
67
67
  context "#let" do
68
68
 
69
69
  let(:loom_file) do
70
- <<EOS
70
+ <<RB_LOOM
71
71
  let(:let_var_1) { "let var 1"}
72
72
  let(:let_var_2) { "let var 2"}
73
73
 
@@ -92,7 +92,7 @@ EOS
92
92
  loom.do_inner_thing(let_var_1, let_var_2, let_var_3)
93
93
  end
94
94
  end
95
- EOS
95
+ RB_LOOM
96
96
  end
97
97
 
98
98
  it "defines :let declartions at the top level" do
@@ -117,7 +117,7 @@ EOS
117
117
  context "#with_facts" do
118
118
 
119
119
  let(:loom_file) do
120
- <<EOS
120
+ <<RB_LOOM
121
121
  with_facts :outer_fact => :outer
122
122
 
123
123
  desc "a description of pattern_under_test"
@@ -135,7 +135,7 @@ EOS
135
135
  loom.do_inner_thing(facts[:outer_fact], facts[:inner_fact])
136
136
  end
137
137
  end
138
- EOS
138
+ RB_LOOM
139
139
  end
140
140
 
141
141
  it "defines fact sets at the top level" do
@@ -151,10 +151,59 @@ EOS
151
151
  end
152
152
  end
153
153
 
154
+ context "#report" do
155
+
156
+ let(:report_fact_set) { a_fact_set.merge :the_report_facts => [1,2,3] }
157
+ let(:loom_file) do
158
+ <<RB_LOOM
159
+ let(:the_let_facts) { [:a, :b] }
160
+
161
+ report :the_report_facts
162
+ report :the_let_facts
163
+
164
+ report :the_other_facts do
165
+ { :some => :other, :stuff => :ok }
166
+ end
167
+
168
+ report :by_another_form, format: :json do
169
+ { :other => :data }
170
+ end
171
+ RB_LOOM
172
+ end
173
+
174
+ let(:new_stdio) { StringIO.new }
175
+ before { $stdout = new_stdio }
176
+ after { $stdout = STDOUT }
177
+
178
+ it 'prints the called report by fact value' do
179
+ @reference_set['the_report_facts'].call fake_shell, report_fact_set
180
+ report_output = new_stdio.string
181
+ expect(report_output).to eql [1,2,3].to_yaml
182
+ end
183
+
184
+ it 'prints the called report by let value' do
185
+ @reference_set['the_let_facts'].call fake_shell, report_fact_set
186
+ report_output = new_stdio.string
187
+ expect(report_output).to eql [:a, :b].to_yaml
188
+ end
189
+
190
+ it 'prints the given report block' do
191
+ @reference_set['the_other_facts'].call fake_shell, report_fact_set
192
+ report_output = new_stdio.string
193
+ expect(report_output).to eql({:some => :other, :stuff => :ok}.to_yaml)
194
+ end
195
+
196
+ it 'prints data in different formats' do
197
+ @reference_set['by_another_form'].call fake_shell, report_fact_set
198
+ report_output = new_stdio.string
199
+ expect(report_output.strip).to eql('{"other":"data"}')
200
+ end
201
+ end
202
+
154
203
  context "hooks" do
155
204
 
156
205
  let(:loom_file) do
157
- <<EOS
206
+ <<RB_LOOM
158
207
 
159
208
  let(:hook_order) { [] }
160
209
 
@@ -179,7 +228,7 @@ EOS
179
228
  loom.do_inner_thing(hook_order)
180
229
  end
181
230
  end
182
- EOS
231
+ RB_LOOM
183
232
  end
184
233
 
185
234
  it "executes outer before hooks first and after hooks last" do
@@ -1,4 +1,4 @@
1
- describe Loom::Shell::HarnessBlob do
1
+ xdescribe Loom::Shell::HarnessBlob do
2
2
 
3
3
  HARNESS = "./scripts/harness.sh"
4
4
 
@@ -1,4 +1,4 @@
1
- describe Loom::Shell::HarnessCommandBuilder do
1
+ xdescribe Loom::Shell::HarnessCommandBuilder do
2
2
 
3
3
  let(:cmd) do
4
4
  <<CMD
@@ -0,0 +1,31 @@
1
+ describe LoomExt::CoreMods::Systemd do
2
+ include LoomSpec::LoomInternalsHelper
3
+
4
+ let(:fake_loom) { create_fake_shell_api }
5
+ let(:a_fact_set) { create_fact_set }
6
+ let(:pattern_list_units) { @reference_set['list_units'] }
7
+
8
+ before do
9
+ # intercept logs
10
+ @logger_io = capture_logs_to_io
11
+ @reference_set = create_reference_set loom_file
12
+ end
13
+
14
+ context "actions" do
15
+
16
+ let(:loom_file) do
17
+ <<RB
18
+ require "loomext/all"
19
+ desc "lists systemd-units"
20
+ pattern :list_units do |l,_|
21
+ l.systemd.is_loaded?(:my_service)
22
+ end
23
+ RB
24
+ end
25
+
26
+ it "should execute this" do
27
+ pattern_list_units.call fake_loom, a_fact_set
28
+ expect(fake_loom.cmd_execution_args.join(' '.strip)).to eql 'my_service'
29
+ end
30
+ end
31
+ end
@@ -1,35 +1,28 @@
1
1
  #!/bin/sh
2
+ pattern_file="${1}"
3
+ if [ "${pattern_file}" = "" ]; then
4
+ echo "Usage: $0 <spec/path/to/.loom/file>"
5
+ exit 1
6
+ fi
2
7
 
3
- spec_file="spec/test.loom"
8
+ spec_file="spec/${pattern_file}"
4
9
  all_patterns=$(bin/loom patterns --print \
5
10
  -t \
6
11
  -l ${spec_file})
7
12
 
13
+ shift
8
14
  addl_args="${@}"
9
15
 
16
+ # TODO: Fix this to bring up a local container via
17
+ # systemd-nspawn. Either an alpine host, or something else really
18
+ # cheap and fast. NO DOCKER. Will rkt ever be a reasonable option?
10
19
  bin/loom weave ${all_patterns} \
11
20
  -t \
12
21
  -l ${spec_file} \
13
22
  -X log_level=info \
14
- -H vm0.local \
23
+ -H rp0 \
24
+ -V \
15
25
  -X sshkit_log_level=warn \
16
26
  -X log_device=stderr \
17
27
  -X run_failure_strategy=cowboy \
18
28
  ${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
@@ -1,7 +1,7 @@
1
1
  require 'base64'
2
2
  require 'tmpdir'
3
3
 
4
- describe 'loom harness script' do
4
+ xdescribe 'loom harness script' do
5
5
 
6
6
  HARNESS = "./scripts/harness.sh"
7
7
 
@@ -0,0 +1,41 @@
1
+ require './lib/loom'
2
+ require './lib/loomext/all'
3
+
4
+ module LoomSpec
5
+ module LoomInternalsHelper
6
+ FAKE_FACTS = { :fact_one => 1, :fact_two => :two }
7
+
8
+ def create_fact_set(fake_host: 'fake.host', fake_facts: FAKE_FACTS)
9
+ Loom::Facts::FactSet.new fake_host, fake_facts
10
+ end
11
+
12
+ def create_fake_shell_api
13
+ Loom::Shell::FakeApi.new
14
+ end
15
+
16
+ def create_reference_set(loom_file_src=nil, path: 'loom/file/path')
17
+ loom_file_src ||= File.read(path)
18
+ Loom::Pattern::ReferenceSet::Builder.create(loom_file_src, path)
19
+ end
20
+
21
+ def capture_logs_to_io
22
+ logger_io = StringIO.new
23
+ Loom.configure do |config|
24
+ config.log_device = logger_io
25
+ end
26
+ logger_io
27
+ end
28
+
29
+ def create_dry_run_shell
30
+ end
31
+
32
+ def create_config(**config_map)
33
+ Loom::Config.new config_map
34
+ end
35
+
36
+ def create_mod_loader(config: nil)
37
+ config ||= create_config
38
+ Loom::Mod::ModLoader.new config
39
+ end
40
+ end
41
+ end
@@ -1,6 +1,10 @@
1
- Dir.glob('./spec/shared/**/*.rb').each { |f| require f }
2
1
  require './lib/loom'
3
2
 
3
+ Dir.glob('./spec/shared/**/*.rb').each do |f|
4
+ $stderr.puts "requiring spec helper: #{f}"
5
+ require f
6
+ end
7
+
4
8
  # This file was generated by the `rspec --init` command. Conventionally, all
5
9
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
10
  # The generated `.rspec` file contains `--require spec_helper` which will cause
@@ -0,0 +1,22 @@
1
+ module Systemd
2
+ include Loom::Pattern
3
+
4
+ report :sshd_status, format: :json do |l, _|
5
+ l.systemd_units("sshd.service").status
6
+ end
7
+
8
+ report :units, format: :raw do |l, _|
9
+ l.systemd_units.list
10
+ end
11
+
12
+ report :sockets, format: :raw do |l, _|
13
+ l.systemd_sockets.list
14
+ end
15
+
16
+ report :timers, format: :raw do |l, _|
17
+ l.systemd_timers.list
18
+ end
19
+ end
20
+
21
+
22
+
@@ -1,5 +1,85 @@
1
1
  require 'open3'
2
2
 
3
+ describe "spec .loom files" do
4
+ include LoomSpec::LoomInternalsHelper
5
+
6
+ LOOM_FILES = Dir.glob "spec/.loom/**/*.loom"
7
+
8
+ # Tests disabled until this runs on an overlayfs container
9
+ XFILE_SET = {
10
+ "error_handling.loom" => true,
11
+ "files.loom" => true,
12
+ "pkg.loom" => true,
13
+ "user.loom" => true,
14
+ "vms.loom" => true,
15
+ }
16
+
17
+ EXPECTED_EXIT_CODE = {
18
+ "fail.loom" => 103
19
+ }
20
+
21
+ SPEC_TAGS = {
22
+ :integration => true,
23
+ :long => true
24
+ }
25
+
26
+ let(:host) { "rp0" }
27
+ let(:patterns) { ref_set.slugs }
28
+ let(:command) {[
29
+ "bin/loom weave #{patterns.join " "}",
30
+ "-t",
31
+ "-l #{loom_file}",
32
+ "-X log_level=info",
33
+ "-H #{host}",
34
+ "-V",
35
+ "-X sshkit_log_level=warn",
36
+ "-X log_device=stderr",
37
+ "-X run_failure_strategy=cowboy",
38
+ ]}
39
+
40
+ # bundle exec rspec --tag smoke
41
+ context "test.loom" do
42
+ let(:loom_file) { LOOM_FILES.select { |p| p.match?(/test.loom/) }.first }
43
+ let(:ref_set) { create_reference_set(path: loom_file) }
44
+ let(:patterns) { ref_set.slugs.select { |s| s.match?(/^smoke:/) } }
45
+ let(:host) { "localhost" }
46
+
47
+ it "should pass a few tests quickly", :smoke => true do
48
+ exec = command.join(' ')
49
+ output = `#{exec}`
50
+ expect($?.exitstatus).to eq 0
51
+ end
52
+ end
53
+
54
+ # bundle exec rspec --tag integration
55
+ LOOM_FILES.each do |loom_file|
56
+ context File.basename loom_file do
57
+ let(:loom_file) { loom_file }
58
+ let(:ref_set) { create_reference_set(path: loom_file) }
59
+
60
+ if XFILE_SET[File.basename(loom_file)]
61
+ xit "should pass all the tests",
62
+ SPEC_TAGS.merge(:file => File.basename(loom_file)) {}
63
+ else
64
+ it "should pass all tests",
65
+ SPEC_TAGS.merge(:file => File.basename(loom_file)) do
66
+ exec = command.join(' ')
67
+ puts exec
68
+ # TODO pattern match the commands on STDOUT (see comment in
69
+ # .loom/test.loom)
70
+ output = `#{exec}`
71
+
72
+ basename = File.basename(loom_file)
73
+ expected_exit_code = EXPECTED_EXIT_CODE[basename] || 0
74
+ expect($?.exitstatus).to eq expected_exit_code
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ # Archived 10/26/2018
82
+
3
83
  # TODO: fix this test to run the runloom.sh script. Currently running
4
84
  # the loom script in a child process from ruby runs without a
5
85
  # TTY. This causes the sshkit/net:ssh connection to connect abnormally
@@ -33,25 +113,23 @@ require 'open3'
33
113
  # /home/erick/.gem/ruby/gems/sshkit-1.11.3/lib/sshkit/backends/abstract.rb:141:in `tap'
34
114
  # /home/erick/.gem/ruby/gems/sshkit-1.11.3/lib/sshkit/backends/abstract.rb:141:in `create_command_and_execute'
35
115
  # /home/erick/workspace/src/loom/lib/loom/shell.rb:91:in `execute'
116
+ # xit "executes successfully" do
36
117
 
37
- describe "spec/test.loom file" do
118
+ # exit_status = nil
38
119
 
39
- let(:runloom) { File.join File.dirname(__FILE__), 'runloom.sh' }
120
+ # # https://stackoverflow.com/questions/6338908/ruby-difference-between-exec-system-and-x-or-backticks
121
+ # output = `#{runloom} -F fact_1=1,fact_2=2,fact_3=3`
40
122
 
41
- it "executes successfully" do
42
- exit_status = nil
43
- `#{runloom}`
44
- # Open3.popen3(runloom) do |stdin,stdout,stderr,wait_thred|
45
- # puts "running #{runloom}"
46
- # while line=stderr.gets do
47
- # puts line
48
- # end
49
- #
50
- # exit_status = wait_thred.value
51
- # end
123
+ # # Open3.popen3(runloom) do |stdin,stdout,stderr,wait_thred|
124
+ # # puts "running #{runloom}"
125
+ # # while line=stderr.gets do
126
+ # # puts line
127
+ # # end
128
+ # #
129
+ # # exit_status = wait_thred.value
130
+ # # end
52
131
 
53
- puts "exit status: #{$?.exitstatus}"
132
+ # puts "exit status: #{$?.exitstatus}"
54
133
 
55
- expect($?.exitstatus).to eq 0
56
- end
57
- end
134
+ # expect($?.exitstatus).to eq 0
135
+ # end