From 5371ac0db74711898c2e2369045c93ddb05fdc42 Mon Sep 17 00:00:00 2001 From: Steve Traylen Date: Thu, 15 Jun 2023 00:16:35 +0200 Subject: [PATCH] Socket support for manage unit and dropin A socket file can now be created: ```puppet systemd::manage_unit{'arc.socket': ensure => present, unit_entry => { 'Description' => 'My great socket', }, socket_entry => { 'Type' => 'simple', 'ExecStart' => '/usr/sbin/arcd /usr/libexec/arcd/arcd.pl', 'StandardInput => 'socket', } ``` All socket directives from 253. * https://www.freedesktop.org/software/systemd/man/systemd.socket.html --- REFERENCE.md | 128 +++++++++++++++++- manifests/manage_dropin.pp | 3 + manifests/manage_unit.pp | 37 ++++- spec/defines/manage_dropin_spec.rb | 20 +++ spec/defines/manage_unit_spec.rb | 26 ++++ spec/type_aliases/systemd_unit_socket_spec.rb | 20 +++ templates/unit_file.epp | 2 + types/unit/socket.pp | 65 +++++++++ 8 files changed, 297 insertions(+), 4 deletions(-) create mode 100644 spec/type_aliases/systemd_unit_socket_spec.rb create mode 100644 types/unit/socket.pp diff --git a/REFERENCE.md b/REFERENCE.md index a8a5e781..56ef372c 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -65,6 +65,7 @@ * [`Systemd::Unit::Path`](#Systemd--Unit--Path): Possible keys for the [Path] section of a unit file * [`Systemd::Unit::Service`](#Systemd--Unit--Service): Possible keys for the [Service] section of a unit file * [`Systemd::Unit::Service::Exec`](#Systemd--Unit--Service--Exec): Possible strings for ExecStart, ExecStartPrep, ... +* [`Systemd::Unit::Socket`](#Systemd--Unit--Socket): Possible keys for the [Socket] section of a unit file * [`Systemd::Unit::Timer`](#Systemd--Unit--Timer): Possible keys for the [Timer] section of a unit file * [`Systemd::Unit::Unit`](#Systemd--Unit--Unit): Possible keys for the [Unit] section of a unit file @@ -826,6 +827,7 @@ The following parameters are available in the `systemd::manage_dropin` defined t * [`install_entry`](#-systemd--manage_dropin--install_entry) * [`timer_entry`](#-systemd--manage_dropin--timer_entry) * [`path_entry`](#-systemd--manage_dropin--path_entry) +* [`socket_entry`](#-systemd--manage_dropin--socket_entry) ##### `unit` @@ -953,6 +955,14 @@ key value pairs for [Path] section of the unit file Default value: `undef` +##### `socket_entry` + +Data type: `Optional[Systemd::Unit::Socket]` + +key value pairs for the [Socket] section of the unit file + +Default value: `undef` + ### `systemd::manage_unit` Generate unit file from template @@ -984,7 +994,7 @@ systemd::manage_unit { 'myrunner.service': ```puppet systemd::manage_unit { 'passwd-mon.path': ensure => present, - unit_entry => { + unit_entry => { 'Description' => 'Monitor the passwd file', }, path_entry => { @@ -992,8 +1002,41 @@ systemd::manage_unit { 'passwd-mon.path': 'Unit' => 'passwd-mon.service', }, install_entry => { - 'WantedBy' => 'multi-user.target', + 'WantedBy' => 'multi-user.target', + }, +} +``` + +##### Generate a socket and service (xinetd style) + +```puppet +systemd::manage_unit {'arcd.socket': + ensure => 'present', + unit_entry => { + 'Description' => 'arcd.service', + } + socket_entry => { + 'ListenStream' => 4241, + 'Accept' => true, + 'BindIPv6Only' => 'both', + install_entry => { + 'WantedBy' => 'sockets.target', + } +} + +systemd::manage_unit{'arcd@.service': + ensure => 'present', + enable => true, + active => true, + unit_entry => { + 'Description' => 'arc sever for %i', }, + + service_entry => { + 'Type' => 'simple', + 'ExecStart' => /usr/sbin/arcd /usr/libexec/arcd/arcd.pl, + 'StandardInput' => 'socket', + } } ``` @@ -1019,6 +1062,7 @@ The following parameters are available in the `systemd::manage_unit` defined typ * [`install_entry`](#-systemd--manage_unit--install_entry) * [`timer_entry`](#-systemd--manage_unit--timer_entry) * [`path_entry`](#-systemd--manage_unit--path_entry) +* [`socket_entry`](#-systemd--manage_unit--socket_entry) ##### `name` @@ -1160,6 +1204,14 @@ key value pairs for [Path] section of the unit file. Default value: `undef` +##### `socket_entry` + +Data type: `Optional[Systemd::Unit::Socket]` + +kev value paors for [Socket] section of the unit file. + +Default value: `undef` + ### `systemd::modules_load` Creates a modules-load.d drop file @@ -2310,6 +2362,78 @@ Possible strings for ExecStart, ExecStartPrep, ... Alias of `Variant[Enum[''], Pattern[/^[@\-:]*(\+|!|!!)?[@\-:]*\/.*/], Pattern[/^[@\-:]*(\+|!|!!)?[@\-:]*[^\/]*(\s.*)?$/]]` +### `Systemd::Unit::Socket` + +Possible keys for the [Socket] section of a unit file + +* **See also** + * https://www.freedesktop.org/software/systemd/man/systemd.socket.html + +Alias of + +```puppet +Struct[{ + Optional['ListenStream'] => Variant[Stdlib::Port,String[1]], + Optional['ListenDatagram'] => Variant[Stdlib::Port,String[1]], + Optional['ListenSequentialPacket'] => Variant[Stdlib::Port,String[1]], + Optional['ListenFIFO'] => Stdlib::Unixpath, + Optional['ListenSpecial'] => Stdlib::Unixpath, + Optional['ListenNetlink'] => String[1], + Optional['ListenMessageQueue'] => Pattern[/\A\/.*\z/], + Optional['ListenUSBFunction'] => Stdlib::Unixpath, + Optional['SocketProtocol'] => Enum['udplite', 'sctp'], + Optional['BindIPv6Only'] => Enum['default', 'both', 'ipv6-only'], + Optional['Backlog'] => Integer[0], + Optional['BindToDevice'] => String[1], + Optional['SocketUser'] => String[1], + Optional['SocketGroup'] => String[1], + Optional['SocketMode'] => Stdlib::Filemode, + Optional['DirectoryMode'] => Stdlib::Filemode, + Optional['Accept'] => Boolean, + Optional['Writable'] => Boolean, + Optional['FlushPending'] => Boolean, + Optional['MaxConnections'] => Integer[0], + Optional['MaxConnectionsPerSource'] => Integer[0], + Optional['KeepAlive'] => Boolean, + Optional['KeepAliveTimeSec'] => Integer[0], + Optional['KeepAliveIntervalSec'] => Integer[0], + Optional['KeepAliveProbes'] => Integer[0], + Optional['NoDelay'] => Boolean, + Optional['Priority'] => Integer, + Optional['DeferAcceptSec'] => Integer[0], + Optional['ReceiveBuffer'] => Variant[Integer[0],String[1]], + Optional['SendBuffer'] => Variant[Integer[0],String[1]], + Optional['IPTOS'] => Variant[Integer,Enum['low-delay', 'throughput', 'reliability', 'low-cost']], + Optional['IPTTL'] => Integer[0], + Optional['Mark'] => String[1], + Optional['ReusePort'] => Boolean, + Optional['SmackLabel'] => String[1], + Optional['SmackLabelIPIn'] => String[1], + Optional['SmackLabelIPOut'] => String[1], + Optional['SELinuxContextFromNet'] => Boolean, + Optional['PipeSize'] => Variant[Integer[0],String[1]], + Optional['FreeBind'] => Boolean, + Optional['Transparent'] => Boolean, + Optional['Broadcast'] => Boolean, + Optional['PassCredentials'] => Boolean, + Optional['PassSecurity'] => Boolean, + Optional['PassPacketInfo'] => Boolean, + Optional['Timestamping'] => Enum['off', 'us', 'usec', 'ns'], + Optional['TCPCongestion'] => Enum['westwood', 'veno', 'cubic', 'lp'], + Optional['ExecStartPre'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStartPost'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStopPre'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStopPost'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['TimeoutSec'] => String[1], + Optional['Service'] => Systemd::Unit, + Optional['RemoveOnStop'] => Boolean, + Optional['Symlinks'] => Variant[Stdlib::Unixpath,Array[Stdlib::Unixpath,1]], + Optional['FileDescriptorName'] => String[1,255], + Optional['TriggerLimitIntervalSec'] => String[1], + Optional['TriggerLimitBurst'] => Integer[0], + }] +``` + ### `Systemd::Unit::Timer` Possible keys for the [Timer] section of a unit file diff --git a/manifests/manage_dropin.pp b/manifests/manage_dropin.pp index 334a9680..75399e1e 100644 --- a/manifests/manage_dropin.pp +++ b/manifests/manage_dropin.pp @@ -48,6 +48,7 @@ # @param install_entry key value pairs for [Install] section of the unit file # @param timer_entry key value pairs for [Timer] section of the unit file # @param path_entry key value pairs for [Path] section of the unit file +# @param socket_entry key value pairs for the [Socket] section of the unit file # define systemd::manage_dropin ( Systemd::Unit $unit, @@ -66,6 +67,7 @@ Optional[Systemd::Unit::Service] $service_entry = undef, Optional[Systemd::Unit::Timer] $timer_entry = undef, Optional[Systemd::Unit::Path] $path_entry = undef, + Optional[Systemd::Unit::Socket] $socket_entry = undef, ) { if $timer_entry and $unit !~ Pattern['^[^/]+\.timer'] { fail("Systemd::Manage_dropin[${name}]: for unit ${unit} timer_entry is only valid for timer units") @@ -93,6 +95,7 @@ 'install_entry' => $install_entry, 'timer_entry' => $timer_entry, 'path_entry' => $path_entry, + 'socket_entry' => $socket_entry, }), } } diff --git a/manifests/manage_unit.pp b/manifests/manage_unit.pp index 0e026225..7e73213c 100644 --- a/manifests/manage_unit.pp +++ b/manifests/manage_unit.pp @@ -21,7 +21,7 @@ # @example Genenerate a path unit # systemd::manage_unit { 'passwd-mon.path': # ensure => present, -# unit_entry => { +# unit_entry => { # 'Description' => 'Monitor the passwd file', # }, # path_entry => { @@ -29,10 +29,40 @@ # 'Unit' => 'passwd-mon.service', # }, # install_entry => { -# 'WantedBy' => 'multi-user.target', +# 'WantedBy' => 'multi-user.target', # }, # } # +# @example Generate a socket and service (xinetd style) +# systemd::manage_unit {'arcd.socket': +# ensure => 'present', +# unit_entry => { +# 'Description' => 'arcd.service', +# } +# socket_entry => { +# 'ListenStream' => 4241, +# 'Accept' => true, +# 'BindIPv6Only' => 'both', +# install_entry => { +# 'WantedBy' => 'sockets.target', +# } +# } +# +# systemd::manage_unit{'arcd@.service': +# ensure => 'present', +# enable => true, +# active => true, +# unit_entry => { +# 'Description' => 'arc sever for %i', +# }, +# +# service_entry => { +# 'Type' => 'simple', +# 'ExecStart' => /usr/sbin/arcd /usr/libexec/arcd/arcd.pl, +# 'StandardInput' => 'socket', +# } +# } +# # @param name [Pattern['^[^/]+\.(service|socket|device|mount|automount|swap|target|path|timer|slice|scope)$']] # The target unit file to create # @@ -57,6 +87,7 @@ # @param install_entry key value pairs for [Install] section of the unit file. # @param timer_entry key value pairs for [Timer] section of the unit file # @param path_entry key value pairs for [Path] section of the unit file. +# @param socket_entry kev value paors for [Socket] section of the unit file. # define systemd::manage_unit ( Enum['present', 'absent'] $ensure = 'present', @@ -76,6 +107,7 @@ Optional[Systemd::Unit::Service] $service_entry = undef, Optional[Systemd::Unit::Timer] $timer_entry = undef, Optional[Systemd::Unit::Path] $path_entry = undef, + Optional[Systemd::Unit::Socket] $socket_entry = undef, ) { assert_type(Systemd::Unit, $name) @@ -109,6 +141,7 @@ 'install_entry' => $install_entry, 'timer_entry' => $timer_entry, 'path_entry' => $path_entry, + 'socket_entry' => $socket_entry, }), } } diff --git a/spec/defines/manage_dropin_spec.rb b/spec/defines/manage_dropin_spec.rb index e5007f51..a5a9ed25 100644 --- a/spec/defines/manage_dropin_spec.rb +++ b/spec/defines/manage_dropin_spec.rb @@ -112,6 +112,26 @@ with_content(%r{^PathExists=/etc/hosts$}) } end + + context 'on a socket unit' do + let(:params) do + { + unit: 'special.socket', + socket_entry: { + 'ListenMessageQueue' => '/panic', + } + } + end + + it { is_expected.to compile.with_all_deps } + + it { + is_expected.to contain_systemd__dropin_file('foobar.conf'). + with_unit('special.socket'). + with_content(%r{^\[Socket\]$}). + with_content(%r{^ListenMessageQueue=/panic$}) + } + end end end end diff --git a/spec/defines/manage_unit_spec.rb b/spec/defines/manage_unit_spec.rb index 5795f745..ecce9b11 100644 --- a/spec/defines/manage_unit_spec.rb +++ b/spec/defines/manage_unit_spec.rb @@ -106,6 +106,32 @@ } end + context 'on a socket unit' do + let(:title) { 'arcd.socket' } + let(:params) do + { + unit_entry: { + Description: 'A crazy socket', + }, + socket_entry: { + 'ListenStream' => 4241, + 'Accept' => true, + 'BindIPv6Only' => 'both' + } + } + end + + it { is_expected.to compile.with_all_deps } + + it { + is_expected.to contain_systemd__unit_file('arcd.socket'). + with_content(%r{^\[Socket\]$}). + with_content(%r{^ListenStream=4241$}). + with_content(%r{^Accept=true$}). + with_content(%r{^BindIPv6Only=both$}) + } + end + context 'on a path unit' do let(:title) { 'etc-passwd.path' } diff --git a/spec/type_aliases/systemd_unit_socket_spec.rb b/spec/type_aliases/systemd_unit_socket_spec.rb new file mode 100644 index 00000000..bd007961 --- /dev/null +++ b/spec/type_aliases/systemd_unit_socket_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Systemd::Unit::Socket' do + %w[ListenStream ListenDatagram ListenSequentialPacket].each do |assert| + context "with a key of #{assert} can have values of a path" do + it { is_expected.to allow_value({ assert => 200 }) } + it { is_expected.to allow_value({ assert => '/etc/passwd' }) } + it { is_expected.to allow_value({ assert => '@/tmp/socket' }) } + end + end + + %w[ListenMessageQueue].each do |assert| + context "with a key of #{assert} can have values of a queue" do + it { is_expected.to allow_value({ assert => '/mything' }) } + it { is_expected.not_to allow_value({ assert => 'mything' }) } + end + end +end diff --git a/templates/unit_file.epp b/templates/unit_file.epp index 05067e0f..1a979041 100644 --- a/templates/unit_file.epp +++ b/templates/unit_file.epp @@ -4,6 +4,7 @@ Optional[Hash] $install_entry, Optional[Hash] $timer_entry, Optional[Hash] $path_entry, + Optional[Hash] $socket_entry, | -%> <%- @@ -15,6 +16,7 @@ 'Service', 'Timer', 'Path', + 'Socket', 'Install', ] diff --git a/types/unit/socket.pp b/types/unit/socket.pp new file mode 100644 index 00000000..6acab1c8 --- /dev/null +++ b/types/unit/socket.pp @@ -0,0 +1,65 @@ +# @summary Possible keys for the [Socket] section of a unit file +# @see https://www.freedesktop.org/software/systemd/man/systemd.socket.html +# +type Systemd::Unit::Socket = Struct[ + { + Optional['ListenStream'] => Variant[Stdlib::Port,String[1]], + Optional['ListenDatagram'] => Variant[Stdlib::Port,String[1]], + Optional['ListenSequentialPacket'] => Variant[Stdlib::Port,String[1]], + Optional['ListenFIFO'] => Stdlib::Unixpath, + Optional['ListenSpecial'] => Stdlib::Unixpath, + Optional['ListenNetlink'] => String[1], + Optional['ListenMessageQueue'] => Pattern[/\A\/.*\z/], + Optional['ListenUSBFunction'] => Stdlib::Unixpath, + Optional['SocketProtocol'] => Enum['udplite', 'sctp'], + Optional['BindIPv6Only'] => Enum['default', 'both', 'ipv6-only'], + Optional['Backlog'] => Integer[0], + Optional['BindToDevice'] => String[1], + Optional['SocketUser'] => String[1], + Optional['SocketGroup'] => String[1], + Optional['SocketMode'] => Stdlib::Filemode, + Optional['DirectoryMode'] => Stdlib::Filemode, + Optional['Accept'] => Boolean, + Optional['Writable'] => Boolean, + Optional['FlushPending'] => Boolean, + Optional['MaxConnections'] => Integer[0], + Optional['MaxConnectionsPerSource'] => Integer[0], + Optional['KeepAlive'] => Boolean, + Optional['KeepAliveTimeSec'] => Integer[0], + Optional['KeepAliveIntervalSec'] => Integer[0], + Optional['KeepAliveProbes'] => Integer[0], + Optional['NoDelay'] => Boolean, + Optional['Priority'] => Integer, + Optional['DeferAcceptSec'] => Integer[0], + Optional['ReceiveBuffer'] => Variant[Integer[0],String[1]], + Optional['SendBuffer'] => Variant[Integer[0],String[1]], + Optional['IPTOS'] => Variant[Integer,Enum['low-delay', 'throughput', 'reliability', 'low-cost']], + Optional['IPTTL'] => Integer[0], + Optional['Mark'] => String[1], + Optional['ReusePort'] => Boolean, + Optional['SmackLabel'] => String[1], + Optional['SmackLabelIPIn'] => String[1], + Optional['SmackLabelIPOut'] => String[1], + Optional['SELinuxContextFromNet'] => Boolean, + Optional['PipeSize'] => Variant[Integer[0],String[1]], + Optional['FreeBind'] => Boolean, + Optional['Transparent'] => Boolean, + Optional['Broadcast'] => Boolean, + Optional['PassCredentials'] => Boolean, + Optional['PassSecurity'] => Boolean, + Optional['PassPacketInfo'] => Boolean, + Optional['Timestamping'] => Enum['off', 'us', 'usec', 'ns'], + Optional['TCPCongestion'] => Enum['westwood', 'veno', 'cubic', 'lp'], + Optional['ExecStartPre'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStartPost'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStopPre'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['ExecStopPost'] => Variant[Systemd::Unit::Service::Exec,Array[Systemd::Unit::Service::Exec,1]], + Optional['TimeoutSec'] => String[1], + Optional['Service'] => Systemd::Unit, + Optional['RemoveOnStop'] => Boolean, + Optional['Symlinks'] => Variant[Stdlib::Unixpath,Array[Stdlib::Unixpath,1]], + Optional['FileDescriptorName'] => String[1,255], + Optional['TriggerLimitIntervalSec'] => String[1], + Optional['TriggerLimitBurst'] => Integer[0], + } +]