appforce-spawn 0.5.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.
- checksums.yaml +7 -0
- data/.appforce.example +4 -0
- data/.gitignore +8 -0
- data/Gemfile +17 -0
- data/History +85 -0
- data/README.md +144 -0
- data/ansible/README.md +31 -0
- data/ansible/common.yml +6 -0
- data/ansible/roles/common/tasks/.keep +0 -0
- data/ansible/roles/common/tasks/active_users.yml +23 -0
- data/ansible/roles/common/tasks/groups.yml +28 -0
- data/ansible/roles/common/tasks/inactive_users.yml +26 -0
- data/ansible/roles/common/tasks/main.yml +5 -0
- data/ansible/roles/common/tasks/setup.yml +6 -0
- data/ansible/roles/scout/tasks/.keep +0 -0
- data/ansible/roles/scout/tasks/install.yml +28 -0
- data/ansible/roles/scout/tasks/main.yml +2 -0
- data/ansible/roles/scout/vars/.keep +0 -0
- data/ansible/rvm.yml +13 -0
- data/ansible/scout.yml +6 -0
- data/ansible/site.yml +4 -0
- data/appforce-spawn.gemspec +24 -0
- data/bin/appforce-spawn +161 -0
- data/lib/appforce-spawn.rb +1 -0
- data/lib/appforce/config.rb +50 -0
- data/lib/appforce/logger.rb +25 -0
- data/lib/appforce/spawn.rb +312 -0
- data/lib/appforce/spawn/api.rb +4 -0
- data/lib/appforce/spawn/api/call.rb +217 -0
- data/lib/appforce/spawn/exceptions.rb +30 -0
- data/lib/appforce/spawn/runner.rb +143 -0
- data/lib/appforce/spawn/template.rb +102 -0
- data/lib/appforce/spawn/version.rb +10 -0
- data/spec/api_call_spec.rb +380 -0
- data/spec/config_spec.rb +51 -0
- data/spec/fixtures/all_host_data.json +12 -0
- data/spec/fixtures/appforce_config.yml +4 -0
- data/spec/fixtures/fake_private_key.yml +2 -0
- data/spec/fixtures/host_scout_vars.yml +10 -0
- data/spec/fixtures/hosts +8 -0
- data/spec/fixtures/inactive_users.yml +3 -0
- data/spec/fixtures/malformed_appforce_config.yml +4 -0
- data/spec/fixtures/private_key_vars.yml +4 -0
- data/spec/fixtures/scout_main.yml +2 -0
- data/spec/fixtures/users.yml +6 -0
- data/spec/fixtures/vars.yml +4 -0
- data/spec/logger_spec.rb +85 -0
- data/spec/runner_spec.rb +308 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/template_spec.rb +160 -0
- data/spec/version_spec.rb +9 -0
- data/tmp/.keep +0 -0
- metadata +151 -0
data/spec/fixtures/hosts
ADDED
data/spec/logger_spec.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
RSpec.describe Appforce::Logger do
|
4
|
+
before do
|
5
|
+
logger = Logger.new('/dev/null')
|
6
|
+
Appforce::Spawn.logger = logger
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.header' do
|
10
|
+
context 'input string is under 74 chars in length' do
|
11
|
+
before do
|
12
|
+
@header = Appforce::Logger.header('This is a test header')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return a string' do
|
16
|
+
expect(@header.class).to eq String
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should be 78 characters in length' do
|
20
|
+
expect(@header.length).to eq 78
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should start with a blank space' do
|
24
|
+
expect(@header).to start_with ' == '
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should end with an equals sign' do
|
28
|
+
expect(@header).to end_with '='
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'input string is over 74 chars in length' do
|
34
|
+
before do
|
35
|
+
@header = Appforce::Logger.header('this is a really long string that is over seventy four characters long, I swear')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return a string' do
|
39
|
+
expect(@header.class).to eq String
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should be greater than 78 characters in length' do
|
43
|
+
expect(@header.length).to be > 78
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should start with a blank space' do
|
47
|
+
expect(@header).to start_with ' == '
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should end with an equals sign' do
|
51
|
+
expect(@header).to_not end_with '='
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.footer' do
|
58
|
+
before do
|
59
|
+
@footer = Appforce::Logger.footer
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should return a string' do
|
63
|
+
expect(@footer.class).to eq String
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should be 78 characters in length' do
|
67
|
+
expect(@footer.length).to eq 78
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should start with a space and an equals sign' do
|
71
|
+
expect(@footer).to start_with ' ='
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should end with an equals sign' do
|
75
|
+
expect(@footer).to end_with '='
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should contain only equals signs and a space at the front' do
|
79
|
+
expect(@footer.scan('=').count).to eq 77
|
80
|
+
expect(@footer.scan(/\s/).count).to eq 1
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
RSpec.describe Appforce::Spawn::Api::Call do
|
4
|
+
before do
|
5
|
+
logger = Logger.new('/dev/null')
|
6
|
+
Appforce::Spawn.logger = logger
|
7
|
+
Appforce::Config.load_config(file_fixture_path('appforce_config.yml'))
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.can_run?' do
|
11
|
+
context 'all files exists' do
|
12
|
+
before do
|
13
|
+
allow(File).to receive(:exist?).with('./vars.yml') { true }
|
14
|
+
allow(File).to receive(:exist?).with('./active_users.yml') { true }
|
15
|
+
allow(File).to receive(:exist?).with('./inactive_users.yml') { true }
|
16
|
+
allow(File).to receive(:exist?).with('./hosts') { true }
|
17
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
18
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
19
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return true' do
|
23
|
+
expect(Appforce::Spawn::Runner.can_run?).to be_truthy
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'vars.yml file is missing' do
|
28
|
+
before do
|
29
|
+
allow(File).to receive(:exist?).with('./vars.yml') { false }
|
30
|
+
allow(File).to receive(:exist?).with('./active_users.yml') { true }
|
31
|
+
allow(File).to receive(:exist?).with('./inactive_users.yml') { true }
|
32
|
+
allow(File).to receive(:exist?).with('./hosts') { true }
|
33
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
34
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
35
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should raise a Appforce::Spawn::MissingFile exception' do
|
39
|
+
expect { Appforce::Spawn::Runner.can_run? }.to raise_exception(Appforce::Spawn::MissingFile)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'active_users.yml file is missing' do
|
44
|
+
before do
|
45
|
+
allow(File).to receive(:exist?).with('./vars.yml') { true }
|
46
|
+
allow(File).to receive(:exist?).with('./active_users.yml') { false }
|
47
|
+
allow(File).to receive(:exist?).with('./inactive_users.yml') { true }
|
48
|
+
allow(File).to receive(:exist?).with('./hosts') { true }
|
49
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
50
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
51
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should raise a Appforce::Spawn::MissingFile exception' do
|
55
|
+
expect { Appforce::Spawn::Runner.can_run? }.to raise_exception(Appforce::Spawn::MissingFile)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'inactive_users.yml file is missing' do
|
60
|
+
before do
|
61
|
+
allow(File).to receive(:exist?).with('./vars.yml') { true }
|
62
|
+
allow(File).to receive(:exist?).with('./active_users.yml') { true }
|
63
|
+
allow(File).to receive(:exist?).with('./inactive_users.yml') { false }
|
64
|
+
allow(File).to receive(:exist?).with('./hosts') { true }
|
65
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
66
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
67
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should raise a Appforce::Spawn::MissingFile exception' do
|
71
|
+
expect { Appforce::Spawn::Runner.can_run? }.to raise_exception(Appforce::Spawn::MissingFile)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'hosts file is missing' do
|
76
|
+
before do
|
77
|
+
allow(File).to receive(:exist?).with('./vars.yml') { true }
|
78
|
+
allow(File).to receive(:exist?).with('./active_users.yml') { true }
|
79
|
+
allow(File).to receive(:exist?).with('./inactive_users.yml') { true }
|
80
|
+
allow(File).to receive(:exist?).with('./hosts') { false }
|
81
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
82
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
83
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should raise a Appforce::Spawn::MissingFile exception' do
|
87
|
+
expect { Appforce::Spawn::Runner.can_run? }.to raise_exception(Appforce::Spawn::MissingFile)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'all files are available and runner can run' do
|
93
|
+
before do
|
94
|
+
allow(Appforce::Spawn::Runner).to receive(:can_run?).and_return(true)
|
95
|
+
allow(File).to receive(:open).and_return(file_fixture('vars.yml'))
|
96
|
+
allow(Appforce::Spawn::Runner).to receive(:system).and_return(true)
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '.run_playbook' do
|
100
|
+
it 'will log out info and execute a system command' do
|
101
|
+
Appforce::Spawn::Runner.run_playbook
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '.run_dryrun' do
|
106
|
+
it 'will log out info and execute a system command' do
|
107
|
+
Appforce::Spawn::Runner.run_dryrun
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '.ansible_ping' do
|
112
|
+
it 'will log out info and execute a system command' do
|
113
|
+
Appforce::Spawn::Runner.ansible_ping
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '.display_ansible_command' do
|
118
|
+
it 'will write the ansible command to the logger' do
|
119
|
+
Appforce::Spawn::Runner.display_ansible_command
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '.display_ansible_ping_command' do
|
124
|
+
it 'will write the ansible ping command to the logger' do
|
125
|
+
Appforce::Spawn::Runner.display_ansible_ping_command
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '.check_dependencies' do
|
131
|
+
context 'ansible not installed' do
|
132
|
+
before do
|
133
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(nil)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'will raise an exception' do
|
137
|
+
expect { Appforce::Spawn::Runner.send(:check_dependencies) }.to raise_exception
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'ansible version is bad' do
|
142
|
+
before do
|
143
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
144
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(nil)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'will raise an exception' do
|
148
|
+
expect { Appforce::Spawn::Runner.send(:check_dependencies) }.to raise_exception
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'ansible galaxy role for rvm is not installed' do
|
153
|
+
before do
|
154
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
155
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
156
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(nil)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'will raise an exception' do
|
160
|
+
expect { Appforce::Spawn::Runner.send(:check_dependencies) }.to raise_exception
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'all dependacies are met' do
|
165
|
+
before do
|
166
|
+
allow(Appforce::Spawn::Runner).to receive(:ansible_installed?).and_return(true)
|
167
|
+
allow(Appforce::Spawn::Runner).to receive(:good_ansible_version?).and_return(true)
|
168
|
+
allow(Appforce::Spawn::Runner).to receive(:rvm_galaxy_installed?).and_return(true)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'will return true' do
|
172
|
+
expect(Appforce::Spawn::Runner.send(:check_dependencies)).to be_truthy
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'private methods' do
|
178
|
+
describe '.ansible_installed?' do
|
179
|
+
context 'returns the result of a match data (true)' do
|
180
|
+
before do
|
181
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('which ansible').and_return('/usr/bin/ansible')
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'return a non nil value' do
|
185
|
+
expect(Appforce::Spawn::Runner.send(:ansible_installed?)).to_not be_nil
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'returns the result of a match data (false)' do
|
190
|
+
before do
|
191
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('which ansible').and_return('')
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'it will return nil' do
|
195
|
+
expect(Appforce::Spawn::Runner.send(:ansible_installed?)).to be_nil
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '.good_ansible_version?' do
|
201
|
+
context 'version is good' do
|
202
|
+
before do
|
203
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('ansible --version').and_return("ansible 1.8.4\n configured module search path = None\n")
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'return a non nil value' do
|
207
|
+
expect(Appforce::Spawn::Runner.send(:good_ansible_version?)).to_not be_nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'version is bad' do
|
212
|
+
before do
|
213
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('ansible --version').and_return("ansible 1.8.2\n configured module search path = None\n")
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'it will return nil' do
|
217
|
+
expect(Appforce::Spawn::Runner.send(:good_ansible_version?)).to be_nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe '.rvm_galaxy_installed?' do
|
223
|
+
context 'role is installed' do
|
224
|
+
before do
|
225
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('ansible-galaxy list').and_return("- rvm_io.rvm1-ruby, v1.3.5\n")
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'return a non nil value' do
|
229
|
+
expect(Appforce::Spawn::Runner.send(:rvm_galaxy_installed?)).to_not be_nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context 'role is not installed' do
|
234
|
+
before do
|
235
|
+
allow(Appforce::Spawn::Runner).to receive(:`).with('ansible-galaxy list').and_return("")
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'it will return nil' do
|
239
|
+
expect(Appforce::Spawn::Runner.send(:rvm_galaxy_installed?)).to be_nil
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe '.ansible_command' do
|
245
|
+
context 'it fails to load the vars.yml file' do
|
246
|
+
before do
|
247
|
+
allow(File).to receive(:open).and_raise(Exception)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'it will raise an Excpetion' do
|
251
|
+
expect { Appforce::Spawn::Runner.send(:ansible_command) }.to raise_exception
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'it successfully loads vars.yml file' do
|
256
|
+
before do
|
257
|
+
allow(File).to receive(:open).and_return(file_fixture('vars.yml'))
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'will return the ansible command with vars' do
|
261
|
+
expect(Appforce::Spawn::Runner.send(:ansible_command)).to match /ansible_user=username/
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'it successfully loads vars.yml file with a private key' do
|
266
|
+
before do
|
267
|
+
allow(File).to receive(:open).and_return(file_fixture('private_key_vars.yml'))
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'will return the ansible command with vars' do
|
271
|
+
expect(Appforce::Spawn::Runner.send(:ansible_command)).to match /private-key=/
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe '.ansible_ping_command' do
|
277
|
+
context 'it fails to load the vars.yml file' do
|
278
|
+
before do
|
279
|
+
allow(File).to receive(:open).and_raise(Exception)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'it will raise an Excpetion' do
|
283
|
+
expect { Appforce::Spawn::Runner.send(:ansible_ping_command) }.to raise_exception
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
context 'it successfully loads vars.yml file' do
|
288
|
+
before do
|
289
|
+
allow(File).to receive(:open).and_return(file_fixture('vars.yml'))
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'will return the ansible command with vars' do
|
293
|
+
expect(Appforce::Spawn::Runner.send(:ansible_ping_command)).to match /username/
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
context 'it successfully loads vars.yml file with a private key' do
|
298
|
+
before do
|
299
|
+
allow(File).to receive(:open).and_return(file_fixture('private_key_vars.yml'))
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'will return the ansible command with vars' do
|
303
|
+
expect(Appforce::Spawn::Runner.send(:ansible_ping_command)).to match /private-key=/
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|