appforce-spawn 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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