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,101 @@
1
+ require 'loom/host_spec'
2
+
3
+ describe Loom::HostSpec do
4
+
5
+ subject { Loom::HostSpec.new host_string }
6
+
7
+ context "local strings" do
8
+
9
+ context "with no user/nor port" do
10
+ let(:host_string) { "localhost" }
11
+
12
+ it "parses localhost configurations" do
13
+ expect(subject.is_localhost?).to be true
14
+ expect(subject.is_remote?).to be false
15
+ end
16
+
17
+ it "has been parsed" do
18
+ expect(subject.hostname).to eq "localhost"
19
+ expect(subject.user).to be nil
20
+ expect(subject.port).to be nil
21
+ end
22
+ end
23
+
24
+ context "with a user" do
25
+ let(:host_string) { "ej@localhost" }
26
+
27
+ it "parses configurations as remote" do
28
+ expect(subject.is_localhost?).to be false
29
+ expect(subject.is_remote?).to be true
30
+ end
31
+
32
+ it "has been parsed" do
33
+ expect(subject.hostname).to eq "localhost"
34
+ expect(subject.user).to eq "ej"
35
+ expect(subject.port).to be nil
36
+ end
37
+ end
38
+
39
+ context "with a port" do
40
+ let(:host_string) { "localhost:22" }
41
+
42
+ it "parses configurations as remote" do
43
+ expect(subject.is_localhost?).to be false
44
+ expect(subject.is_remote?).to be true
45
+ end
46
+
47
+ it "has been parsed" do
48
+ expect(subject.hostname).to eq "localhost"
49
+ expect(subject.user).to be nil
50
+ expect(subject.port).to eq 22
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ context "remote strings" do
57
+
58
+ let(:host_string) { "erick@remote.machine:27" }
59
+
60
+ it "parses user@localhost configurations as remote" do
61
+ expect(subject.is_localhost?).to be false
62
+ expect(subject.is_remote?).to be true
63
+ end
64
+
65
+ it "has been parsed" do
66
+ expect(subject.user).to eq "erick"
67
+ expect(subject.hostname).to eq "remote.machine"
68
+ expect(subject.port).to eq 27
69
+ end
70
+ end
71
+
72
+ context "ipv4 addresses" do
73
+ let(:host_string) { "erick@192.168.1.100:27" }
74
+
75
+ it "parses user@localhost configurations as remote" do
76
+ expect(subject.is_localhost?).to be false
77
+ expect(subject.is_remote?).to be true
78
+ end
79
+
80
+ it "has been parsed" do
81
+ expect(subject.user).to eq "erick"
82
+ expect(subject.hostname).to eq "192.168.1.100"
83
+ expect(subject.port).to eq 27
84
+ end
85
+ end
86
+
87
+ context "ipv6 addresses" do
88
+ let(:host_string) { "[2a02:120b:2c28:5920:6257:18ff:febf:13c8:22]" }
89
+
90
+ it "parses user@localhost configurations as remote" do
91
+ expect(subject.is_localhost?).to be false
92
+ expect(subject.is_remote?).to be true
93
+ end
94
+
95
+ it "has been parsed" do
96
+ expect(subject.hostname).to eq "2a02:120b:2c28:5920:6257:18ff:febf:13c8"
97
+ expect(subject.user).to be nil
98
+ expect(subject.port).to eq 22
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,154 @@
1
+ require "loom/config"
2
+ require "loom/inventory"
3
+ require "tmpdir"
4
+ require "yaml"
5
+
6
+ describe Loom::Inventory do
7
+
8
+ HOSTLIST = %w[host1 host2 host3]
9
+ HOSTGROUPS = {
10
+ :group1 => %w[g1host g2host],
11
+ :duplicate_group => %w[host1]
12
+ }
13
+
14
+ INVENTORY_HOSTLIST = [
15
+ 'inv.host1',
16
+ 'inv.host2',
17
+ :inventory_group => ['inv.group.host'],
18
+ 'string_group' => ['string.group.host']
19
+ ]
20
+
21
+ class TmpInventoryFile
22
+ def self.transaction(search_paths_list, &block)
23
+ Dir.mktmpdir do |dir|
24
+ search_paths_list << dir
25
+
26
+ File.open File.join(dir, "inventory.yml"), "w" do
27
+ |f| f << INVENTORY_HOSTLIST.to_yaml
28
+ end
29
+ yield
30
+ end
31
+ end
32
+ end
33
+
34
+ CONFIG_DEFAULTS = {
35
+ :loom_search_paths => []
36
+ }
37
+
38
+ let(:config_map) { {} }
39
+ let(:config) do
40
+ Loom::Config.configure do |c|
41
+ CONFIG_DEFAULTS.merge(config_map).each { |k,v| c[k] = v }
42
+ end
43
+ end
44
+
45
+ context "methods" do
46
+
47
+ subject { Loom::Inventory::InventoryList.new hostlist, hostgroups }
48
+ let(:hostlist) { HOSTLIST }
49
+ let(:hostgroups) { {} }
50
+
51
+ it "#hosts should parse hostnames" do
52
+ expect(subject.hosts.first).to be_a Loom::HostSpec
53
+ expect(subject.hosts.size).to be 3
54
+ end
55
+
56
+ it "#disable marks hosts #disabled?" do
57
+ expect(subject.disabled? "host1").to be false
58
+ subject.disable "host1"
59
+ expect(subject.disabled? "host1").to be true
60
+ expect(subject.disabled? "host2").to be false
61
+ end
62
+
63
+ it "lists #hostnames" do
64
+ expect(subject.hostnames).to eql %w[host1 host2 host3]
65
+ end
66
+
67
+ context "with groups" do
68
+
69
+ let(:hostgroups) { HOSTGROUPS }
70
+
71
+ context "#hostnames" do
72
+ it "#hostnames includes hostnames from the group" do
73
+ expect(subject.hostnames).to include("g1host")
74
+ end
75
+
76
+ it "only lists unique hosts" do
77
+ expect(subject.hostnames.size).to be 5
78
+ end
79
+ end
80
+
81
+ it "lists #group_names" do
82
+ expect(subject.group_names).to eq [:group1, :duplicate_group]
83
+ end
84
+ end
85
+ end
86
+
87
+ context "#total_inventory" do
88
+
89
+ subject { Loom::Inventory::InventoryList.total_inventory config }
90
+
91
+ context "with explicit hosts configured" do
92
+
93
+ let(:config_map) { {:inventory_hosts => %w[confighost1 confighost2]} }
94
+
95
+ it "gets hosts from config" do
96
+ expect(subject.hostnames).to eq %w[confighost1 confighost2]
97
+ end
98
+ end
99
+
100
+ context "with inventory files" do
101
+
102
+ # To be passed into the TmpInventoryFile.transaction by :around
103
+ let(:config_map) { {:loom_search_paths => []} }
104
+
105
+ around(:example) do |example|
106
+ TmpInventoryFile.transaction config_map[:loom_search_paths], &example
107
+ end
108
+
109
+ it "finds hosts in the tmp config" do
110
+ expected = %w[inv.host1 inv.host2 inv.group.host string.group.host]
111
+ expect(subject.hostnames).to match_array expected
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ context "#active_inventory" do
118
+
119
+ subject { Loom::Inventory::InventoryList.active_inventory config }
120
+
121
+ context "with inventory file" do
122
+
123
+ around(:example) do |example|
124
+ TmpInventoryFile.transaction config_map[:loom_search_paths], &example
125
+ end
126
+
127
+ context "with explicit hosts" do
128
+
129
+ # To be passed into the TmpInventoryFile.transaction by :around
130
+ let(:config_map) do
131
+ {:inventory_hosts => HOSTLIST, :loom_search_paths => []}
132
+ end
133
+
134
+ it "gets only explicit hosts from config" do
135
+ expect(subject.hostnames).to eq HOSTLIST
136
+ end
137
+ end
138
+
139
+ context "with explicit groups" do
140
+
141
+ # To be passed into the TmpInventoryFile.transaction by :around
142
+ let(:config_map) do
143
+ {:inventory_groups => [:inventory_group, :string_group],
144
+ :loom_search_paths => []}
145
+ end
146
+
147
+ it "gets only explicit hosts from config" do
148
+ expect(subject.hostnames).to match_array %w[inv.group.host string.group.host]
149
+ end
150
+
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,275 @@
1
+ require "loom/method_signature"
2
+
3
+ describe Loom::MethodSignature do
4
+
5
+ module MethodModule
6
+ def one_req_arg(req); end
7
+ def two_req_args(req1, req2); end
8
+
9
+ def opt_arg(opt=nil); end
10
+ def two_opt_args(opt1=1, opt2=nil); end
11
+
12
+ def rest_args(*rest); end
13
+ def req_and_rest_args(req, *rest); end
14
+ def req_and_opt_and_rest_args(req, opt=nil, *rest); end
15
+
16
+ def one_keyreq_arg(keyreq:); end
17
+ def two_keyreq_args(keyreq1:, keyreq2:); end
18
+
19
+ def one_key_arg(key: 1); end
20
+ def two_key_args(key1: 1, key2: nil); end
21
+
22
+ def keyrest_arg(**keyrest); end
23
+ def key_and_keyrest_arg(keyreq:, key: 2, **keyrest); end
24
+
25
+ def block_arg(&block); end
26
+
27
+ def all_args(req, opt=1, *rest, keyreq:, key: 2, **keyrest, &block); end
28
+ def no_args; end
29
+
30
+ class << self
31
+ def [](method_name)
32
+ MethodModule.instance_method method_name
33
+ end
34
+ end
35
+ end
36
+
37
+ context Loom::MethodSignature do
38
+
39
+ context "#one_req_arg" do
40
+ subject { Loom::MethodSignature.new MethodModule[:one_req_arg] }
41
+
42
+ it "has the right signature" do
43
+ expect(subject.req_args.size).to be 1
44
+ end
45
+
46
+ it "implements has_xyz_args?" do
47
+ expect(subject.has_req_args?).to be true
48
+ expect(subject.has_opt_args?).to be false
49
+ expect(subject.has_rest_args?).to be false
50
+ end
51
+ end
52
+
53
+ context "#one_req_arg" do
54
+ subject { Loom::MethodSignature.new MethodModule[:one_keyreq_arg] }
55
+
56
+ it "has the right signature" do
57
+ expect(subject.keyreq_args.size).to be 1
58
+ end
59
+
60
+ it "implements has_xyz_args?" do
61
+ expect(subject.has_keyreq_args?).to be true
62
+ expect(subject.has_key_args?).to be false
63
+ expect(subject.has_keyrest_args?).to be false
64
+ end
65
+ end
66
+
67
+ context "#keyrest_arg" do
68
+ subject { Loom::MethodSignature.new MethodModule[:keyrest_arg] }
69
+
70
+ it "has the right signature" do
71
+ expect(subject.keyrest_args.size).to be 1
72
+ end
73
+
74
+ it "implements has_xyz_args?" do
75
+ expect(subject.has_keyreq_args?).to be false
76
+ expect(subject.has_key_args?).to be false
77
+ expect(subject.has_keyrest_args?).to be true
78
+ end
79
+ end
80
+
81
+ context "#two_key_args" do
82
+ subject { Loom::MethodSignature.new MethodModule[:two_key_args] }
83
+
84
+ it "has the right signature" do
85
+ expect(subject.req_args.size).to be 0
86
+ expect(subject.opt_args.size).to be 0
87
+ expect(subject.rest_args.size).to be 0
88
+
89
+ expect(subject.keyreq_args.size).to be 0
90
+ expect(subject.key_args.size).to be 2
91
+ expect(subject.keyrest_args.size).to be 0
92
+
93
+ expect(subject.block_args.size).to be 0
94
+ end
95
+ end
96
+
97
+ context "#all_args" do
98
+ subject { Loom::MethodSignature.new MethodModule[:all_args] }
99
+
100
+ it "has the right signature" do
101
+ expect(subject.req_args.size).to be 1
102
+ expect(subject.opt_args.size).to be 1
103
+ expect(subject.rest_args.size).to be 1
104
+
105
+ expect(subject.keyreq_args.size).to be 1
106
+ expect(subject.key_args.size).to be 1
107
+ expect(subject.keyrest_args.size).to be 1
108
+
109
+ expect(subject.block_args.size).to be 1
110
+ end
111
+
112
+ it "implements has_xyz_args?" do
113
+ expect(subject.has_req_args?).to be true
114
+ expect(subject.has_opt_args?).to be true
115
+ expect(subject.has_rest_args?).to be true
116
+
117
+ expect(subject.has_keyreq_args?).to be true
118
+ expect(subject.has_key_args?).to be true
119
+ expect(subject.has_keyrest_args?).to be true
120
+
121
+ expect(subject.has_block_args?).to be true
122
+ end
123
+ end
124
+
125
+ context "#no_args" do
126
+ subject { Loom::MethodSignature.new MethodModule[:no_args] }
127
+
128
+ it "has the right signature" do
129
+ expect(subject.req_args.size).to be 0
130
+ expect(subject.opt_args.size).to be 0
131
+ expect(subject.rest_args.size).to be 0
132
+
133
+ expect(subject.keyreq_args.size).to be 0
134
+ expect(subject.key_args.size).to be 0
135
+ expect(subject.keyrest_args.size).to be 0
136
+ expect(subject.block_args.size).to be 0
137
+ end
138
+
139
+ it "implements has_xyz_args?" do
140
+ expect(subject.has_req_args?).to be false
141
+ expect(subject.has_opt_args?).to be false
142
+ expect(subject.has_rest_args?).to be false
143
+
144
+ expect(subject.has_keyreq_args?).to be false
145
+ expect(subject.has_key_args?).to be false
146
+ expect(subject.has_keyrest_args?).to be false
147
+
148
+ expect(subject.has_block_args?).to be false
149
+ end
150
+ end
151
+ end
152
+
153
+ context Loom::MethodSignature::MatchSpec do
154
+
155
+ context 'with required argument matching' do
156
+
157
+ subject { Loom::MethodSignature::MatchSpec.builder.req_args(1).build }
158
+ let(:passing_methods) { [:one_req_arg, :rest] }
159
+
160
+ MethodModule.instance_methods.each do |m|
161
+ it "checks ##{m} for matches" do
162
+ v = passing_methods.include? m
163
+ expect(subject.match?(MethodModule[m])).to be v
164
+ end
165
+ end
166
+ end
167
+
168
+ context 'with optional argument matching' do
169
+
170
+ subject { Loom::MethodSignature::MatchSpec.builder.opt_args(1).build }
171
+ let(:passing_methods) { [:opt_arg, :rest] }
172
+
173
+ MethodModule.instance_methods.each do |m|
174
+ it "checks ##{m} for matches" do
175
+ v = passing_methods.include? m
176
+ expect(subject.match?(MethodModule[m])).to be v
177
+ end
178
+ end
179
+ end
180
+
181
+ context 'with required keyword argument matching' do
182
+
183
+ subject { Loom::MethodSignature::MatchSpec.builder.keyreq_args(1).build }
184
+ let(:passing_methods) { [:one_keyreq_arg] }
185
+
186
+ MethodModule.instance_methods.each do |m|
187
+ it "checks ##{m} for matches" do
188
+ v = passing_methods.include? m
189
+ expect(subject.match?(MethodModule[m])).to be v
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'with optional keyword argument matching' do
195
+
196
+ subject { Loom::MethodSignature::MatchSpec.builder.key_args(1).build }
197
+ let(:passing_methods) { [:one_key_arg] }
198
+
199
+ MethodModule.instance_methods.each do |m|
200
+ it "checks ##{m} for matches" do
201
+ v = passing_methods.include? m
202
+ expect(subject.match?(MethodModule[m])).to be v
203
+ end
204
+ end
205
+ end
206
+
207
+ context 'with a pattern signature' do
208
+
209
+ subject do
210
+ Loom::MethodSignature::MatchSpec.builder
211
+ .req_args(2)
212
+ .has_rest_args(nil)
213
+ .has_keyrest_args(nil)
214
+ .has_block(nil)
215
+ .build
216
+ end
217
+
218
+ let(:valid) { lambda do |loom, config| end }
219
+ let(:valid2) { lambda do |loom, config, *args| end }
220
+ let(:valid3) { lambda do |*args| end }
221
+ let(:invalid) { lambda do |loom, config, other| end }
222
+
223
+ it "checks :valid passes for well formatted pattern" do
224
+ expect(subject.match?(valid)).to be true
225
+ end
226
+
227
+ it "checks :valid2 passes for well formatted pattern" do
228
+ expect(subject.match?(valid2)).to be true
229
+ end
230
+
231
+ it "checks :valid2 passes for well formatted pattern" do
232
+ expect(subject.match?(valid3)).to be true
233
+ end
234
+
235
+ it "checks :invalid fails for badly formatted pattern" do
236
+ expect(subject.match?(invalid)).to be false
237
+ end
238
+
239
+ end
240
+
241
+ context 'with a mod signature' do
242
+
243
+ subject do
244
+ Loom::MethodSignature::MatchSpec.builder
245
+ .req_args(2)
246
+ .has_rest_args(nil)
247
+ .has_keyrest_args(true)
248
+ .has_block(nil)
249
+ .build
250
+ end
251
+
252
+ let(:valid) { lambda do |loom, config, *args, **rest| end }
253
+ let(:valid2) { lambda do |loom, config, **rest| end }
254
+ let(:valid3) { lambda do |loom, config, foo:, bar: nil| end }
255
+ let(:invalid) { lambda do |loom, config, foo, bar| end }
256
+
257
+ it "checks :valid passes for well formatted pattern" do
258
+ expect(subject.match?(valid)).to be true
259
+ end
260
+
261
+ it "checks :valid2 passes for well formatted pattern" do
262
+ expect(subject.match?(valid2)).to be true
263
+ end
264
+
265
+ it "checks :valid3 passes for well formatted pattern" do
266
+ expect(subject.match?(valid3)).to be true
267
+ end
268
+
269
+ it "checks :invalid fails for badly formatted pattern" do
270
+ expect(subject.match?(invalid)).to be false
271
+ end
272
+
273
+ end
274
+ end
275
+ end