poise-service 1.0.0

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/.gitignore +10 -0
  3. data/.kitchen.travis.yml +4 -0
  4. data/.kitchen.yml +9 -0
  5. data/.travis.yml +23 -0
  6. data/.yardopts +6 -0
  7. data/Berksfile +27 -0
  8. data/Gemfile +33 -0
  9. data/LICENSE +201 -0
  10. data/README.md +381 -0
  11. data/Rakefile +17 -0
  12. data/chef/attributes/default.rb +19 -0
  13. data/chef/templates/systemd.service.erb +13 -0
  14. data/chef/templates/sysvinit.sh.erb +177 -0
  15. data/chef/templates/upstart.conf.erb +37 -0
  16. data/lib/poise_service.rb +25 -0
  17. data/lib/poise_service/cheftie.rb +18 -0
  18. data/lib/poise_service/error.rb +20 -0
  19. data/lib/poise_service/resources.rb +28 -0
  20. data/lib/poise_service/resources/poise_service.rb +161 -0
  21. data/lib/poise_service/resources/poise_service_test.rb +200 -0
  22. data/lib/poise_service/resources/poise_service_user.rb +136 -0
  23. data/lib/poise_service/service_mixin.rb +192 -0
  24. data/lib/poise_service/service_providers.rb +37 -0
  25. data/lib/poise_service/service_providers/base.rb +193 -0
  26. data/lib/poise_service/service_providers/dummy.rb +100 -0
  27. data/lib/poise_service/service_providers/systemd.rb +63 -0
  28. data/lib/poise_service/service_providers/sysvinit.rb +86 -0
  29. data/lib/poise_service/service_providers/upstart.rb +117 -0
  30. data/lib/poise_service/utils.rb +45 -0
  31. data/lib/poise_service/version.rb +19 -0
  32. data/poise-service.gemspec +41 -0
  33. data/test/cookbooks/poise-service_test/metadata.rb +18 -0
  34. data/test/cookbooks/poise-service_test/providers/mixin.rb +43 -0
  35. data/test/cookbooks/poise-service_test/recipes/default.rb +47 -0
  36. data/test/cookbooks/poise-service_test/recipes/mixin.rb +34 -0
  37. data/test/cookbooks/poise-service_test/resources/mixin.rb +26 -0
  38. data/test/gemfiles/chef-12.gemfile +19 -0
  39. data/test/gemfiles/master.gemfile +22 -0
  40. data/test/integration/default/serverspec/Gemfile +19 -0
  41. data/test/integration/default/serverspec/default_spec.rb +45 -0
  42. data/test/integration/default/serverspec/mixin_spec.rb +37 -0
  43. data/test/spec/resources/poise_service_spec.rb +235 -0
  44. data/test/spec/resources/poise_service_user_spec.rb +119 -0
  45. data/test/spec/service_mixin_spec.rb +164 -0
  46. data/test/spec/service_providers/base_spec.rb +231 -0
  47. data/test/spec/service_providers/dummy_spec.rb +91 -0
  48. data/test/spec/service_providers/systemd_spec.rb +98 -0
  49. data/test/spec/service_providers/sysvinit_spec.rb +96 -0
  50. data/test/spec/service_providers/upstart_spec.rb +300 -0
  51. data/test/spec/spec_helper.rb +50 -0
  52. data/test/spec/utils_spec.rb +44 -0
  53. metadata +172 -0
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ source 'https://rubygems.org/'
18
+
19
+ gem 'poise-service-spechelper'
@@ -0,0 +1,45 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'poise_service/spec_helper'
18
+
19
+ # CentOS 6 doesn't show upstart services in chkconfig, which is how specinfra
20
+ # checkes what is enabled.
21
+ old_upstart = os[:family] == 'redhat' && os[:release].start_with?('6')
22
+
23
+ describe 'default provider' do
24
+ it_should_behave_like 'a poise_service_test', 'default', 5000, !old_upstart
25
+
26
+ describe process('ruby /usr/bin/poise_test') do
27
+ it { is_expected.to be_running }
28
+ end
29
+ end
30
+
31
+ describe 'sysvinit provider', unless: File.exists?('/no_sysvinit') do
32
+ it_should_behave_like 'a poise_service_test', 'sysvinit', 6000
33
+ end
34
+
35
+ describe 'upstart provider', unless: File.exists?('/no_upstart') do
36
+ it_should_behave_like 'a poise_service_test', 'upstart', 7000, !old_upstart
37
+ end
38
+
39
+ describe 'systemd provider', unless: File.exists?('/no_systemd') do
40
+ it_should_behave_like 'a poise_service_test', 'systemd', 8000
41
+ end
42
+
43
+ describe 'dummy provider' do
44
+ it_should_behave_like 'a poise_service_test', 'dummy', 9000, false
45
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'net/http'
18
+ require 'uri'
19
+
20
+ require 'serverspec'
21
+ set :backend, :exec
22
+
23
+ describe 'poise_service_test_mixin' do
24
+ let(:port) { }
25
+ let(:url) { "http://localhost:#{port}/" }
26
+ subject { Net::HTTP.get(URI(url)) }
27
+
28
+ describe 'default' do
29
+ let(:port) { 4000 }
30
+ it { is_expected.to eq 'Hello world!'}
31
+ end
32
+
33
+ describe 'update' do
34
+ let(:port) { 4001 }
35
+ it { is_expected.to eq 'second' }
36
+ end
37
+ end
@@ -0,0 +1,235 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'spec_helper'
18
+
19
+ describe PoiseService::Resources::PoiseService::Resource do
20
+ service_provider('auto')
21
+ service_resource_hints(%i{debian redhat upstart systemd})
22
+
23
+ describe 'provider lookup' do
24
+ recipe(subject: false) do
25
+ poise_service 'test'
26
+ end
27
+ subject do
28
+ chef_run.find_resource(:poise_service, 'test').provider_for_action(:enable).class.provides
29
+ end
30
+
31
+ context 'auto on debian' do
32
+ service_resource_hints(:debian)
33
+ it { is_expected.to eq :sysvinit }
34
+ end # /context auto on debian
35
+
36
+ context 'auto on redhat' do
37
+ service_resource_hints(:redhat)
38
+ it { is_expected.to eq :sysvinit }
39
+ end # /context auto on redhat
40
+
41
+ context 'auto on upstart' do
42
+ service_resource_hints(:upstart)
43
+ it { is_expected.to eq :upstart }
44
+ end # /context auto on upstart
45
+
46
+ context 'auto on systemd' do
47
+ service_resource_hints(:systemd)
48
+ it { is_expected.to eq :systemd }
49
+ end # /context auto on systemd
50
+
51
+ context 'auto on multiple systems' do
52
+ service_resource_hints(%i{debian invokerd upstart})
53
+ it { is_expected.to eq :upstart }
54
+ end # /context auto on multiple systems
55
+
56
+ context 'global override' do
57
+ service_provider('sysvinit')
58
+ it { is_expected.to eq :sysvinit }
59
+ end # /context global override
60
+
61
+ context 'per-service override' do
62
+ service_provider('test', 'sysvinit')
63
+ it { is_expected.to eq :sysvinit }
64
+ end # /context global override
65
+
66
+ context 'per-service override for a different service' do
67
+ service_provider('other', 'sysvinit')
68
+ it { is_expected.to eq :systemd }
69
+ end # /context global override for a different service
70
+
71
+ context 'recipe DSL override' do
72
+ recipe(subject: false) do
73
+ poise_service 'test' do
74
+ provider :sysvinit
75
+ end
76
+ end
77
+ it { is_expected.to eq :sysvinit }
78
+ end # /context recipe DSL override
79
+ end # /describe provider lookup
80
+
81
+ describe '#clean_signal' do
82
+ let(:signal) { }
83
+ subject do
84
+ described_class.new(nil, nil).send(:clean_signal, signal)
85
+ end
86
+
87
+ context 'with a short string' do
88
+ let(:signal) { 'term' }
89
+ it { is_expected.to eq 'TERM' }
90
+ end # /context with a short string
91
+
92
+ context 'with a long string' do
93
+ let(:signal) { 'sigterm' }
94
+ it { is_expected.to eq 'TERM' }
95
+ end # /context with a long string
96
+
97
+ context 'with a short string in caps' do
98
+ let(:signal) { 'TERM' }
99
+ it { is_expected.to eq 'TERM' }
100
+ end # /context with a short string in caps
101
+
102
+ context 'with a long string in caps' do
103
+ let(:signal) { 'SIGTERM' }
104
+ it { is_expected.to eq 'TERM' }
105
+ end # /context with a long string in caps
106
+
107
+ context 'with a number' do
108
+ let(:signal) { 15 }
109
+ it { is_expected.to eq 'TERM' }
110
+ end # /context with a number
111
+
112
+ context 'with a symbol' do
113
+ let(:signal) { :term }
114
+ it { is_expected.to eq 'TERM' }
115
+ end # /context with a symbol
116
+
117
+ context 'with an invalid string' do
118
+ let(:signal) { 'nope' }
119
+ it { expect { subject }.to raise_error PoiseService::Error }
120
+ end # /context with an invalid string
121
+
122
+ context 'with an invalid number' do
123
+ let(:signal) { 100 }
124
+ it { expect { subject }.to raise_error PoiseService::Error }
125
+ end # /context with an invalid number
126
+ end # /describe #clean_stop_signal
127
+
128
+ describe '#options' do
129
+ subject { chef_run.find_resource('poise_service', 'test') }
130
+ recipe(subject: false) do
131
+ poise_service 'test' do
132
+ options template: 'source.erb'
133
+ options :sysvinit, template: 'override.erb'
134
+ end
135
+ end
136
+
137
+ its(:options) { are_expected.to eq({'template' => 'source.erb'}) }
138
+ it { expect(subject.options(:sysvinit)).to eq({'template' => 'override.erb'}) }
139
+ end # /describe #options
140
+
141
+ describe '#default_directory' do
142
+ let(:user) { 'root' }
143
+ subject do
144
+ described_class.new('test', chef_run.run_context).tap {|r| r.user(user) }.send(:default_directory)
145
+ end
146
+
147
+ context 'with root' do
148
+ context 'on Linux' do
149
+ let(:chefspec_options) { {platform: 'ubuntu', version: '14.04'} }
150
+ it { is_expected.to eq '/' }
151
+ end # /context 'on Linux
152
+
153
+ context 'on Windows' do
154
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
155
+ it { is_expected.to eq 'C:\\' }
156
+ end # /context on Windows
157
+ end # /context with root
158
+
159
+ context 'with a normal user' do
160
+ let(:user) { 'poise' }
161
+ before do
162
+ expect(Dir).to receive(:home).with('poise').and_return('/home/poise')
163
+ end
164
+
165
+ it { is_expected.to eq '/home/poise' }
166
+ end # /context with a normal user
167
+
168
+ context 'with an invalid user' do
169
+ let(:user) { 'poise' }
170
+ before do
171
+ expect(Dir).to receive(:home).with('poise').and_raise(ArgumentError)
172
+ end
173
+
174
+ it { is_expected.to eq '/' }
175
+ end # /context with an invalid user
176
+ end # /describe #default_directory
177
+
178
+ describe '#restart_on_update' do
179
+ service_provider('sysvinit')
180
+ step_into(:poise_service)
181
+ before do
182
+ allow(File).to receive(:exists?).and_call_original
183
+ allow(File).to receive(:exists?).with('/etc/init.d/test').and_return(true)
184
+ end
185
+ subject { chef_run.template('/etc/init.d/test') }
186
+
187
+ context 'with true' do
188
+ recipe(subject: false) do
189
+ poise_service 'test' do
190
+ command 'myapp --serve'
191
+ end
192
+ end
193
+ it { is_expected.to notify('poise_service[test]').to(:restart) }
194
+ end # /context with true
195
+
196
+ context 'with false' do
197
+ recipe(subject: false) do
198
+ poise_service 'test' do
199
+ command 'myapp --serve'
200
+ restart_on_update false
201
+ end
202
+ end
203
+ it { is_expected.to_not notify('poise_service[test]').to(:restart) }
204
+ end # /context with false
205
+
206
+ context 'with immediately' do
207
+ recipe(subject: false) do
208
+ poise_service 'test' do
209
+ command 'myapp --serve'
210
+ restart_on_update 'immediately'
211
+ end
212
+ end
213
+ it { is_expected.to notify('poise_service[test]').to(:restart).immediately }
214
+ end # /context with immediately
215
+
216
+ context 'with :immediately' do
217
+ recipe(subject: false) do
218
+ poise_service 'test' do
219
+ command 'myapp --serve'
220
+ restart_on_update :immediately
221
+ end
222
+ end
223
+ it { is_expected.to notify('poise_service[test]').to(:restart).immediately }
224
+ end # /context with :immediately
225
+ end # /describe #restart_on_update
226
+
227
+ describe '#pid' do
228
+ subject { described_class.new(nil, nil) }
229
+ it do
230
+ fake_pid = double('pid')
231
+ expect(subject).to receive(:provider_for_action).with(:pid).and_return(double(pid: fake_pid))
232
+ expect(subject.pid).to eq fake_pid
233
+ end
234
+ end # /describe #pid
235
+ end
@@ -0,0 +1,119 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'spec_helper'
18
+
19
+ describe PoiseService::Resources::PoiseServiceUser do
20
+ step_into(:poise_service_user)
21
+ recipe do
22
+ poise_service_user 'poise'
23
+ end
24
+
25
+ it { is_expected.to create_group('poise').with(gid: nil, system: true) }
26
+ it { is_expected.to create_user('poise').with(gid: 'poise', home: nil, system: true, uid: nil) }
27
+
28
+ context 'with an explicit user and group name' do
29
+ recipe do
30
+ poise_service_user 'poise' do
31
+ user 'poise_user'
32
+ group 'poise_group'
33
+ end
34
+ end
35
+
36
+ it { is_expected.to create_group('poise_group').with(gid: nil, system: true) }
37
+ it { is_expected.to create_user('poise_user').with(gid: 'poise_group', home: nil, system: true, uid: nil) }
38
+ end # /context with an explicit user and group name
39
+
40
+ context 'with no group' do
41
+ recipe do
42
+ poise_service_user 'poise' do
43
+ group false
44
+ end
45
+ end
46
+
47
+ it { is_expected.to_not create_group('poise') }
48
+ it { is_expected.to create_user('poise').with(gid: nil, home: nil, system: true, uid: nil) }
49
+ end # /context with no group
50
+
51
+ context 'with explicit uid' do
52
+ recipe do
53
+ poise_service_user 'poise' do
54
+ uid 100
55
+ end
56
+ end
57
+
58
+ it { is_expected.to create_group('poise').with(gid: nil, system: true) }
59
+ it { is_expected.to create_user('poise').with(gid: 'poise', home: nil, system: true, uid: 100) }
60
+ end # /context with explicit uid
61
+
62
+ context 'with explicit gid' do
63
+ recipe do
64
+ poise_service_user 'poise' do
65
+ gid 100
66
+ end
67
+ end
68
+
69
+ it { is_expected.to create_group('poise').with(gid: 100, system: true) }
70
+ it { is_expected.to create_user('poise').with(gid: 'poise', home: nil, system: true, uid: nil) }
71
+ end # /context with explicit gid
72
+
73
+ context 'with home directory' do
74
+ recipe do
75
+ poise_service_user 'poise' do
76
+ home '/home/poise'
77
+ end
78
+ end
79
+
80
+ it { is_expected.to create_group('poise').with(gid: nil, system: true) }
81
+ it { is_expected.to create_user('poise').with(gid: 'poise', home: '/home/poise', system: true, uid: nil) }
82
+ end # /context with home directory
83
+
84
+ context 'with action :remove' do
85
+ recipe do
86
+ poise_service_user 'poise' do
87
+ action :remove
88
+ end
89
+ end
90
+
91
+ it { is_expected.to remove_group('poise') }
92
+ it { is_expected.to remove_user('poise') }
93
+
94
+ context 'with an explicit user and group name' do
95
+ recipe do
96
+ poise_service_user 'poise' do
97
+ action :remove
98
+ user 'poise_user'
99
+ group 'poise_group'
100
+ end
101
+ end
102
+
103
+ it { is_expected.to remove_group('poise_group') }
104
+ it { is_expected.to remove_user('poise_user') }
105
+ end # /context with an explicit user and group name
106
+
107
+ context 'with no group' do
108
+ recipe do
109
+ poise_service_user 'poise' do
110
+ action :remove
111
+ group false
112
+ end
113
+ end
114
+
115
+ it { is_expected.to_not remove_group('poise') }
116
+ it { is_expected.to remove_user('poise') }
117
+ end # /context with no group
118
+ end # context with action :remove
119
+ end