Skip to content

Commit 0805b45

Browse files
committed
Add a socket_service definition
For systemd socket activated services it's needed to have both the .socket and .service unit defintions in place when starting the service. Prior to 97dd16f the systemctl daemon-reload took care of it, but now this must be done explicitly. This new defined type makes it easy and reduces the burden on modules that define the unit/service pair.
1 parent 81f3eb5 commit 0805b45

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed

manifests/socket_service.pp

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# @summary Create a systemd socket activated service
2+
# @api public
3+
#
4+
# Systemd socket activated services have their own dependencies. This is a
5+
# convenience wrapper around systemd::unit_file.
6+
#
7+
# @param name [Pattern['^[^/]+$']]
8+
# The target unit file to create
9+
# @param socket_content
10+
# The content for the socket unit file. Required if ensure isn't absent.
11+
# @param service_content
12+
# The content for the service unit file. Required if ensure isn't absent.
13+
# @param enable
14+
# Whether to enable or disable the service. By default this is derived from
15+
# $ensure but can be overridden for advanced use cases where the service is
16+
# running during a migration but shouldn't be enabled on boot.
17+
define systemd::socket_service (
18+
Enum['running', 'stopped', 'present', 'absent'] $ensure = 'running',
19+
Optional[String[1]] $socket_content = undef,
20+
Optional[String[1]] $service_content = undef,
21+
Optional[Boolean] $enable = undef,
22+
) {
23+
assert_type(Pattern['^[^/]+$'], $name)
24+
25+
if $ensure != 'absent' {
26+
assert_type(NotUndef, $socket_content)
27+
assert_type(NotUndef, $service_content)
28+
}
29+
30+
$active = $ensure ? {
31+
'running' => true,
32+
'stopped' => false,
33+
'absent' => false,
34+
default => undef,
35+
}
36+
$real_enable = pick($enable, $active)
37+
38+
$unit_file_ensure = bool2str($ensure == 'absent', 'absent', 'present')
39+
40+
systemd::unit_file { "${name}.socket":
41+
ensure => $unit_file_ensure,
42+
content => $socket_content,
43+
active => $active,
44+
enable => $real_enable,
45+
}
46+
47+
systemd::unit_file { "${name}.service":
48+
ensure => $unit_file_ensure,
49+
content => $service_content,
50+
active => $active,
51+
enable => $real_enable,
52+
}
53+
54+
if $active or $real_enable {
55+
# Systemd needs both .socket and .service to be loaded when starting the
56+
# service. The unit_file takes care of matching, this ensures the
57+
# non-matching order.
58+
File["/etc/systemd/system/${name}.socket"] -> Service["${name}.service"]
59+
File["/etc/systemd/system/${name}.service"] -> Service["${name}.socket"]
60+
}
61+
}

spec/defines/socket_service_spec.rb

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
require 'spec_helper'
2+
3+
describe 'systemd::socket_service' do
4+
let(:title) { 'myservice' }
5+
6+
on_supported_os.each do |os, facts|
7+
context "on #{os}" do
8+
context 'ensure => running' do
9+
let(:params) do
10+
{
11+
ensure: 'running',
12+
socket_content: "[Socket]\nListenStream=/run/myservice.socket\n",
13+
service_content: "[Service]\nType=notify\n",
14+
}
15+
end
16+
17+
it { is_expected.to compile.with_all_deps }
18+
it 'sets up the socket unit file' do
19+
is_expected.to contain_file('/etc/systemd/system/myservice.socket')
20+
.with_ensure('file')
21+
.with_content(%r{\[Socket\]})
22+
.that_comes_before(['Service[myservice.socket]', 'Service[myservice.service]'])
23+
end
24+
it 'sets up the socket service' do
25+
is_expected.to contain_service('myservice.socket')
26+
.with_ensure(true)
27+
.with_enable(true)
28+
end
29+
it 'sets up the service unit file' do
30+
is_expected.to contain_file('/etc/systemd/system/myservice.service')
31+
.with_ensure('file')
32+
.with_content(%r{\[Service\]})
33+
.that_comes_before('Service[myservice.service]')
34+
end
35+
it 'sets up the service service' do
36+
is_expected.to contain_service('myservice.service')
37+
.with_ensure(true)
38+
.with_enable(true)
39+
end
40+
41+
context 'enable => false' do
42+
let(:params) { super().merge(enable: false) }
43+
44+
it { is_expected.to compile.with_all_deps }
45+
it 'sets up the socket service' do
46+
is_expected.to contain_service('myservice.socket')
47+
.with_ensure(true)
48+
.with_enable(false)
49+
end
50+
it 'sets up the service service' do
51+
is_expected.to contain_service('myservice.service')
52+
.with_ensure(true)
53+
.with_enable(false)
54+
end
55+
end
56+
end
57+
58+
context 'ensure => stopped' do
59+
let(:params) do
60+
{
61+
ensure: 'stopped',
62+
socket_content: "[Socket]\nListenStream=/run/myservice.socket\n",
63+
service_content: "[Service]\nType=notify\n",
64+
}
65+
end
66+
67+
it { is_expected.to compile.with_all_deps }
68+
it 'sets up the socket unit file' do
69+
is_expected.to contain_file('/etc/systemd/system/myservice.socket')
70+
.with_ensure('file')
71+
.with_content(%r{\[Socket\]})
72+
.that_comes_before(['Service[myservice.socket]', 'Service[myservice.service]'])
73+
end
74+
it 'sets up the socket service' do
75+
is_expected.to contain_service('myservice.socket')
76+
.with_ensure(false)
77+
.with_enable(false)
78+
end
79+
it 'sets up the service unit file' do
80+
is_expected.to contain_file('/etc/systemd/system/myservice.service')
81+
.with_ensure('file')
82+
.with_content(%r{\[Service\]})
83+
.that_comes_before('Service[myservice.service]')
84+
end
85+
it 'sets up the service service' do
86+
is_expected.to contain_service('myservice.service')
87+
.with_ensure(false)
88+
.with_enable(false)
89+
end
90+
91+
context 'enable => true' do
92+
let(:params) { super().merge(enable: true) }
93+
94+
it { is_expected.to compile.with_all_deps }
95+
it 'sets up the socket service' do
96+
is_expected.to contain_service('myservice.socket')
97+
.with_ensure(false)
98+
.with_enable(true)
99+
end
100+
it 'sets up the service service' do
101+
is_expected.to contain_service('myservice.service')
102+
.with_ensure(false)
103+
.with_enable(true)
104+
end
105+
end
106+
end
107+
108+
context 'ensure => present' do
109+
let(:params) do
110+
{
111+
ensure: 'present',
112+
socket_content: "[Socket]\nListenStream=/run/myservice.socket\n",
113+
service_content: "[Service]\nType=notify\n",
114+
}
115+
end
116+
117+
it { is_expected.to compile.with_all_deps }
118+
it 'sets up the socket unit file' do
119+
is_expected.to contain_file('/etc/systemd/system/myservice.socket')
120+
.with_ensure('file')
121+
.with_content(%r{\[Socket\]})
122+
end
123+
it "doesn't set up the socket service" do
124+
is_expected.not_to contain_service('myservice.socket')
125+
end
126+
it 'sets up the service unit file' do
127+
is_expected.to contain_file('/etc/systemd/system/myservice.service')
128+
.with_ensure('file')
129+
.with_content(%r{\[Service\]})
130+
end
131+
it "doesn't set up the service service" do
132+
is_expected.not_to contain_service('myservice.service')
133+
end
134+
135+
context 'enable => true' do
136+
let(:params) { super().merge(enable: true) }
137+
138+
it { is_expected.to compile.with_all_deps }
139+
it 'sets up the socket service' do
140+
is_expected.to contain_service('myservice.socket')
141+
.without_ensure
142+
.with_enable(true)
143+
end
144+
it 'sets up the service service' do
145+
is_expected.to contain_service('myservice.service')
146+
.without_ensure
147+
.with_enable(true)
148+
end
149+
end
150+
end
151+
152+
context 'ensure => absent' do
153+
let(:params) do
154+
{
155+
ensure: 'absent',
156+
}
157+
end
158+
159+
it { is_expected.to compile.with_all_deps }
160+
it 'sets up the socket unit file' do
161+
is_expected.to contain_file('/etc/systemd/system/myservice.socket')
162+
.with_ensure('absent')
163+
.without_content
164+
.that_requires('Service[myservice.socket]')
165+
end
166+
it 'sets up the socket service' do
167+
is_expected.to contain_service('myservice.socket')
168+
.with_ensure(false)
169+
.with_enable(false)
170+
end
171+
it 'sets up the service unit file' do
172+
is_expected.to contain_file('/etc/systemd/system/myservice.service')
173+
.with_ensure('absent')
174+
.without_content
175+
.that_requires('Service[myservice.service]')
176+
end
177+
it 'sets up the service service' do
178+
is_expected.to contain_service('myservice.service')
179+
.with_ensure(false)
180+
.with_enable(false)
181+
end
182+
end
183+
end
184+
end
185+
end

0 commit comments

Comments
 (0)