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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.appforce.example +4 -0
  3. data/.gitignore +8 -0
  4. data/Gemfile +17 -0
  5. data/History +85 -0
  6. data/README.md +144 -0
  7. data/ansible/README.md +31 -0
  8. data/ansible/common.yml +6 -0
  9. data/ansible/roles/common/tasks/.keep +0 -0
  10. data/ansible/roles/common/tasks/active_users.yml +23 -0
  11. data/ansible/roles/common/tasks/groups.yml +28 -0
  12. data/ansible/roles/common/tasks/inactive_users.yml +26 -0
  13. data/ansible/roles/common/tasks/main.yml +5 -0
  14. data/ansible/roles/common/tasks/setup.yml +6 -0
  15. data/ansible/roles/scout/tasks/.keep +0 -0
  16. data/ansible/roles/scout/tasks/install.yml +28 -0
  17. data/ansible/roles/scout/tasks/main.yml +2 -0
  18. data/ansible/roles/scout/vars/.keep +0 -0
  19. data/ansible/rvm.yml +13 -0
  20. data/ansible/scout.yml +6 -0
  21. data/ansible/site.yml +4 -0
  22. data/appforce-spawn.gemspec +24 -0
  23. data/bin/appforce-spawn +161 -0
  24. data/lib/appforce-spawn.rb +1 -0
  25. data/lib/appforce/config.rb +50 -0
  26. data/lib/appforce/logger.rb +25 -0
  27. data/lib/appforce/spawn.rb +312 -0
  28. data/lib/appforce/spawn/api.rb +4 -0
  29. data/lib/appforce/spawn/api/call.rb +217 -0
  30. data/lib/appforce/spawn/exceptions.rb +30 -0
  31. data/lib/appforce/spawn/runner.rb +143 -0
  32. data/lib/appforce/spawn/template.rb +102 -0
  33. data/lib/appforce/spawn/version.rb +10 -0
  34. data/spec/api_call_spec.rb +380 -0
  35. data/spec/config_spec.rb +51 -0
  36. data/spec/fixtures/all_host_data.json +12 -0
  37. data/spec/fixtures/appforce_config.yml +4 -0
  38. data/spec/fixtures/fake_private_key.yml +2 -0
  39. data/spec/fixtures/host_scout_vars.yml +10 -0
  40. data/spec/fixtures/hosts +8 -0
  41. data/spec/fixtures/inactive_users.yml +3 -0
  42. data/spec/fixtures/malformed_appforce_config.yml +4 -0
  43. data/spec/fixtures/private_key_vars.yml +4 -0
  44. data/spec/fixtures/scout_main.yml +2 -0
  45. data/spec/fixtures/users.yml +6 -0
  46. data/spec/fixtures/vars.yml +4 -0
  47. data/spec/logger_spec.rb +85 -0
  48. data/spec/runner_spec.rb +308 -0
  49. data/spec/spec_helper.rb +53 -0
  50. data/spec/template_spec.rb +160 -0
  51. data/spec/version_spec.rb +9 -0
  52. data/tmp/.keep +0 -0
  53. metadata +151 -0
@@ -0,0 +1,4 @@
1
+ ---
2
+ api_host: http://afuka.synctree.com
3
+ api_version: VERSION_STRING
4
+ api_token: INVALID_TOKEN
@@ -0,0 +1,2 @@
1
+ ---
2
+ fake: key
@@ -0,0 +1,10 @@
1
+ ---
2
+ scout_config:
3
+ - name: 'account_key:'
4
+ value: 11n1r1asdnc9ndfn1dfnpkc
5
+ - name: 'ruby_path:'
6
+ value: "/home/synctree/.rvm/rubies/ruby-2.2.0/bin/ruby"
7
+ - name: 'display_name:'
8
+ value: ubuntu-test01
9
+ - name: 'environment:'
10
+ value: staging
@@ -0,0 +1,8 @@
1
+ [cluster]
2
+ super-cool.compute.amazonaws.com
3
+
4
+ [rvm]
5
+ super-cool.compute.amazonaws.com
6
+
7
+ [scout]
8
+ super-cool.compute.amazonaws.com
@@ -0,0 +1,3 @@
1
+ ---
2
+ users:
3
+ - dead.user
@@ -0,0 +1,4 @@
1
+ ---
2
+ api_host: http://afuka.synctree.com
3
+ api_version: VERSION_STRING
4
+ THIS IS MALFORMED api_token: INVALID_TOKEN
@@ -0,0 +1,4 @@
1
+ ---
2
+ ansible_user: username
3
+ ansible_password: false
4
+ ansible_private_key: true
@@ -0,0 +1,2 @@
1
+ ---
2
+ account_key: TOKEN
@@ -0,0 +1,6 @@
1
+ ---
2
+ users:
3
+ - name: john.doe
4
+ authorized:
5
+ - ssh-rsa superpublickey
6
+ groups: uber,user
@@ -0,0 +1,4 @@
1
+ ---
2
+ ansible_user: username
3
+ ansible_password: false
4
+ ansible_private_key: false
@@ -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
@@ -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