Skip to content

Commit 29473c6

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 40a0f77 commit 29473c6

File tree

3 files changed

+337
-0
lines changed

3 files changed

+337
-0
lines changed

REFERENCE.md

+57
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* [`systemd::modules_load`](#systemd--modules_load): Creates a modules-load.d drop file
3636
* [`systemd::network`](#systemd--network): Creates network config for systemd-networkd
3737
* [`systemd::service_limits`](#systemd--service_limits): Adds a set of custom limits to the service
38+
* [`systemd::socket_service`](#systemd--socket_service): Create a systemd socket activated service
3839
* [`systemd::timer`](#systemd--timer): Create a timer and optionally a service unit to execute with the timer unit
3940
* [`systemd::tmpfile`](#systemd--tmpfile): Creates a systemd tmpfile
4041
* [`systemd::udev::rule`](#systemd--udev--rule): Adds a custom udev rule
@@ -1333,6 +1334,62 @@ Restart the managed service after setting the limits
13331334

13341335
Default value: `true`
13351336

1337+
### <a name="systemd--socket_service"></a>`systemd::socket_service`
1338+
1339+
Systemd socket activated services have their own dependencies. This is a
1340+
convenience wrapper around systemd::unit_file.
1341+
1342+
#### Parameters
1343+
1344+
The following parameters are available in the `systemd::socket_service` defined type:
1345+
1346+
* [`name`](#-systemd--socket_service--name)
1347+
* [`ensure`](#-systemd--socket_service--ensure)
1348+
* [`socket_content`](#-systemd--socket_service--socket_content)
1349+
* [`service_content`](#-systemd--socket_service--service_content)
1350+
* [`enable`](#-systemd--socket_service--enable)
1351+
1352+
##### <a name="-systemd--socket_service--name"></a>`name`
1353+
1354+
Data type: `Pattern['^[^/]+$']`
1355+
1356+
The target unit file to create
1357+
1358+
##### <a name="-systemd--socket_service--ensure"></a>`ensure`
1359+
1360+
Data type: `Enum['running', 'stopped', 'present', 'absent']`
1361+
1362+
State of the socket service to ensure. Present means it ensures it's
1363+
present, but doesn't ensure the service state.
1364+
1365+
Default value: `'running'`
1366+
1367+
##### <a name="-systemd--socket_service--socket_content"></a>`socket_content`
1368+
1369+
Data type: `Optional[String[1]]`
1370+
1371+
The content for the socket unit file. Required if ensure isn't absent.
1372+
1373+
Default value: `undef`
1374+
1375+
##### <a name="-systemd--socket_service--service_content"></a>`service_content`
1376+
1377+
Data type: `Optional[String[1]]`
1378+
1379+
The content for the service unit file. Required if ensure isn't absent.
1380+
1381+
Default value: `undef`
1382+
1383+
##### <a name="-systemd--socket_service--enable"></a>`enable`
1384+
1385+
Data type: `Optional[Boolean]`
1386+
1387+
Whether to enable or disable the service. By default this is derived from
1388+
$ensure but can be overridden for advanced use cases where the service is
1389+
running during a migration but shouldn't be enabled on boot.
1390+
1391+
Default value: `undef`
1392+
13361393
### <a name="systemd--timer"></a>`systemd::timer`
13371394

13381395
Create a timer and optionally a service unit to execute with the timer unit

manifests/socket_service.pp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 ensure
10+
# State of the socket service to ensure. Present means it ensures it's
11+
# present, but doesn't ensure the service state.
12+
# @param socket_content
13+
# The content for the socket unit file. Required if ensure isn't absent.
14+
# @param service_content
15+
# The content for the service unit file. Required if ensure isn't absent.
16+
# @param enable
17+
# Whether to enable or disable the service. By default this is derived from
18+
# $ensure but can be overridden for advanced use cases where the service is
19+
# running during a migration but shouldn't be enabled on boot.
20+
define systemd::socket_service (
21+
Enum['running', 'stopped', 'present', 'absent'] $ensure = 'running',
22+
Optional[String[1]] $socket_content = undef,
23+
Optional[String[1]] $service_content = undef,
24+
Optional[Boolean] $enable = undef,
25+
) {
26+
assert_type(Pattern['^[^/]+$'], $name)
27+
28+
if $ensure != 'absent' {
29+
assert_type(NotUndef, $socket_content)
30+
assert_type(NotUndef, $service_content)
31+
}
32+
33+
$active = $ensure ? {
34+
'running' => true,
35+
'stopped' => false,
36+
'absent' => false,
37+
default => undef,
38+
}
39+
# https://tickets.puppetlabs.com/browse/MODULES-11018
40+
if $enable == undef and $active == undef {
41+
$real_enable = undef
42+
} else {
43+
$real_enable = pick($enable, $active)
44+
}
45+
46+
$unit_file_ensure = bool2str($ensure == 'absent', 'absent', 'present')
47+
48+
systemd::unit_file { "${name}.socket":
49+
ensure => $unit_file_ensure,
50+
content => $socket_content,
51+
active => $active,
52+
enable => $real_enable,
53+
}
54+
55+
systemd::unit_file { "${name}.service":
56+
ensure => $unit_file_ensure,
57+
content => $service_content,
58+
active => $active,
59+
enable => $real_enable,
60+
}
61+
62+
if $active != undef or $real_enable != undef {
63+
# Systemd needs both .socket and .service to be loaded when starting the
64+
# service. The unit_file takes care of matching, this ensures the
65+
# non-matching order.
66+
File["/etc/systemd/system/${name}.socket"] -> Service["${name}.service"]
67+
File["/etc/systemd/system/${name}.service"] -> Service["${name}.socket"]
68+
}
69+
}

spec/defines/socket_service_spec.rb

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

0 commit comments

Comments
 (0)