diff --git a/REFERENCE.md b/REFERENCE.md
index d38a01ba..98a7b939 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::Slice`](#Systemd--Unit--Slice): Possible keys for the [Slice] section of a unit file
* [`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
@@ -849,6 +850,18 @@ systemd::manage_dropin { 'user-aklog.conf':
}
```
+##### set memory limits on the user slices
+
+```puppet
+systemd::manage_dropin { 'userlimits.conf':
+ unit => 'user-.slice',
+ slice_entry => {
+ MemoryMax => '10G',
+ MemoryAccounting => true,
+ }
+}
+```
+
#### Parameters
The following parameters are available in the `systemd::manage_dropin` defined type:
@@ -865,6 +878,7 @@ The following parameters are available in the `systemd::manage_dropin` defined t
* [`notify_service`](#-systemd--manage_dropin--notify_service)
* [`daemon_reload`](#-systemd--manage_dropin--daemon_reload)
* [`unit_entry`](#-systemd--manage_dropin--unit_entry)
+* [`slice_entry`](#-systemd--manage_dropin--slice_entry)
* [`service_entry`](#-systemd--manage_dropin--service_entry)
* [`install_entry`](#-systemd--manage_dropin--install_entry)
* [`timer_entry`](#-systemd--manage_dropin--timer_entry)
@@ -965,6 +979,14 @@ key value pairs for [Unit] section of the unit file
Default value: `undef`
+##### `slice_entry`
+
+Data type: `Optional[Systemd::Unit::Slice]`
+
+key value pairs for [Slice] section of the unit file
+
+Default value: `undef`
+
##### `service_entry`
Data type: `Optional[Systemd::Unit::Service]`
@@ -1108,6 +1130,7 @@ The following parameters are available in the `systemd::manage_unit` defined typ
* [`service_parameters`](#-systemd--manage_unit--service_parameters)
* [`daemon_reload`](#-systemd--manage_unit--daemon_reload)
* [`unit_entry`](#-systemd--manage_unit--unit_entry)
+* [`slice_entry`](#-systemd--manage_unit--slice_entry)
* [`service_entry`](#-systemd--manage_unit--service_entry)
* [`install_entry`](#-systemd--manage_unit--install_entry)
* [`timer_entry`](#-systemd--manage_unit--timer_entry)
@@ -1224,6 +1247,14 @@ key value pairs for [Unit] section of the unit file.
Default value: `undef`
+##### `slice_entry`
+
+Data type: `Optional[Systemd::Unit::Slice]`
+
+key value pairs for [Slice] section of the unit file
+
+Default value: `undef`
+
##### `service_entry`
Data type: `Optional[Systemd::Unit::Service]`
@@ -2495,6 +2526,46 @@ Possible strings for ExecStart, ExecStartPrep, ...
Alias of `Variant[Enum[''], Pattern[/^[@\-:]*(\+|!|!!)?[@\-:]*\/.*/], Pattern[/^[@\-:]*(\+|!|!!)?[@\-:]*[^\/]*(\s.*)?$/]]`
+### `Systemd::Unit::Slice`
+
+Possible keys for the [Slice] section of a unit file
+
+* **See also**
+ * https://www.freedesktop.org/software/systemd/man/systemd.slice.html
+ * https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html
+
+Alias of
+
+```puppet
+Struct[{
+ Optional['CPUAccounting'] => Boolean,
+ Optional['CPUQuota'] => Pattern['^([1-9][0-9]*)%$'],
+ Optional['CPUShares'] => Integer[2,262144],
+ Optional['Delegate'] => Boolean,
+ Optional['DeviceAllow'] => String[1],
+ Optional['DevicePolicy'] => Enum['auto','closed','strict'],
+ Optional['IOAccounting'] => Boolean,
+ Optional['IODeviceWeight'] => Array[Hash[Stdlib::Absolutepath, Integer[1,10000], 1, 1]],
+ Optional['IOReadBandwidthMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOReadIOPSMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOWeight'] => Integer[1,10000],
+ Optional['IOWriteBandwidthMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOWriteIOPSMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['MemoryAccounting'] => Boolean,
+ Optional['MemoryHigh'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryLimit'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'], # dep'd in systemd
+ Optional['MemoryLow'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryMax'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryMin'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemorySwapMax'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['Slice'] => String[1],
+ Optional['StartupCPUShares'] => Integer[2,262144],
+ Optional['StartupIOWeight'] => Integer[1,10000],
+ Optional['TasksAccounting'] => Boolean,
+ Optional['TasksMax'] => Variant[Integer[1],Pattern['^(infinity|([1-9][0-9]?$|^100)%)$']],
+ }]
+```
+
### `Systemd::Unit::Socket`
Possible keys for the [Socket] section of a unit file
diff --git a/manifests/manage_dropin.pp b/manifests/manage_dropin.pp
index aada1e86..41761a7d 100644
--- a/manifests/manage_dropin.pp
+++ b/manifests/manage_dropin.pp
@@ -50,6 +50,15 @@
# }
# }
#
+# @example set memory limits on the user slices
+# systemd::manage_dropin { 'userlimits.conf':
+# unit => 'user-.slice',
+# slice_entry => {
+# MemoryMax => '10G',
+# MemoryAccounting => true,
+# }
+# }
+#
# @param unit The unit to create a dropfile for
# @param filename The target unit file to create. The filename of the drop in. The full path is determined using the path, unit and this filename.
# @param ensure The state of this dropin file
@@ -62,6 +71,7 @@
# @param notify_service Notify a service for the unit, if it exists
# @param daemon_reload Call systemd::daemon_reload
# @param unit_entry key value pairs for [Unit] section of the unit file
+# @param slice_entry key value pairs for [Slice] section of the unit file
# @param service_entry key value pairs for [Service] section of the unit file
# @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
@@ -82,6 +92,7 @@
Boolean $daemon_reload = true,
Optional[Systemd::Unit::Install] $install_entry = undef,
Optional[Systemd::Unit::Unit] $unit_entry = undef,
+ Optional[Systemd::Unit::Slice] $slice_entry = undef,
Optional[Systemd::Unit::Service] $service_entry = undef,
Optional[Systemd::Unit::Timer] $timer_entry = undef,
Optional[Systemd::Unit::Path] $path_entry = undef,
@@ -99,6 +110,10 @@
fail("Systemd::Manage_dropin[${name}]: for unit ${unit} socket_entry is only valid for socket units")
}
+ if $slice_entry and $unit !~ Pattern['^[^/]+\.slice'] {
+ fail("Systemd::Manage_dropin[${name}]: for unit ${unit} slice_entry is only valid for slice units")
+ }
+
systemd::dropin_file { $name:
ensure => $ensure,
filename => $filename,
@@ -113,6 +128,7 @@
daemon_reload => $daemon_reload,
content => epp('systemd/unit_file.epp', {
'unit_entry' => $unit_entry,
+ 'slice_entry' => $slice_entry,
'service_entry' => $service_entry,
'install_entry' => $install_entry,
'timer_entry' => $timer_entry,
diff --git a/manifests/manage_unit.pp b/manifests/manage_unit.pp
index 7aefe5f9..63419e82 100644
--- a/manifests/manage_unit.pp
+++ b/manifests/manage_unit.pp
@@ -88,6 +88,7 @@
# call `systemd::daemon-reload` to ensure that the modified unit file is loaded
#
# @param unit_entry key value pairs for [Unit] section of the unit file.
+# @param slice_entry key value pairs for [Slice] section of the unit file
# @param service_entry key value pairs for [Service] section of the unit file.
# @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
@@ -109,6 +110,7 @@
Boolean $daemon_reload = true,
Optional[Systemd::Unit::Install] $install_entry = undef,
Optional[Systemd::Unit::Unit] $unit_entry = undef,
+ Optional[Systemd::Unit::Slice] $slice_entry = undef,
Optional[Systemd::Unit::Service] $service_entry = undef,
Optional[Systemd::Unit::Timer] $timer_entry = undef,
Optional[Systemd::Unit::Path] $path_entry = undef,
@@ -128,6 +130,10 @@
fail("Systemd::Manage_unit[${name}]: socket_entry is only valid for socket units")
}
+ if $slice_entry and $name !~ Pattern['^[^/]+\.slice'] {
+ fail("Systemd::Manage_unit[${name}]: slice_entry is only valid for slice units")
+ }
+
if $ensure != 'absent' and $name =~ Pattern['^[^/]+\.service'] and !$service_entry {
fail("Systemd::Manage_unit[${name}]: service_entry is required for service units")
}
@@ -146,6 +152,7 @@
daemon_reload => $daemon_reload,
content => epp('systemd/unit_file.epp', {
'unit_entry' => $unit_entry,
+ 'slice_entry' => $slice_entry,
'service_entry' => $service_entry,
'install_entry' => $install_entry,
'timer_entry' => $timer_entry,
diff --git a/spec/defines/manage_dropin_spec.rb b/spec/defines/manage_dropin_spec.rb
index 4c0f6ef9..14110aba 100644
--- a/spec/defines/manage_dropin_spec.rb
+++ b/spec/defines/manage_dropin_spec.rb
@@ -37,7 +37,8 @@
is_expected.to contain_systemd__dropin_file('foobar.conf').
with_content(%r{^LimitCORE=infinity$}).
with_content(%r{^DefaultDependencies=true$}).
- with_content(%r{^SyslogIdentifier=simple$})
+ with_content(%r{^SyslogIdentifier=simple$}).
+ without_content(%r{^\[Slice\]$})
}
end
@@ -92,6 +93,18 @@
it { is_expected.to compile.and_raise_error(%r{timer_entry is only valid for timer units}) }
end
+
+ context 'with a slice entry' do
+ let(:params) do
+ super().merge(
+ slice_entry: {
+ 'MemoryMax' => '100G',
+ }
+ )
+ end
+
+ it { is_expected.to compile.and_raise_error(%r{slice_entry is only valid for slice units}) }
+ end
end
context 'on a timer' do
@@ -113,6 +126,27 @@
}
end
+ context 'on a slice' do
+ let(:params) do
+ {
+ unit: 'user-.slice',
+ slice_entry: {
+ 'MemoryMax' => '10G',
+ 'MemoryAccounting' => true,
+ }
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+
+ it {
+ is_expected.to contain_systemd__dropin_file('foobar.conf').
+ with_unit('user-.slice').
+ with_content(%r{^MemoryMax=10G$}).
+ with_content(%r{^MemoryAccounting=true$})
+ }
+ end
+
context 'on a path unit' do
let(:params) do
{
diff --git a/spec/defines/manage_unit_spec.rb b/spec/defines/manage_unit_spec.rb
index 8629a595..c72020d9 100644
--- a/spec/defines/manage_unit_spec.rb
+++ b/spec/defines/manage_unit_spec.rb
@@ -42,7 +42,8 @@
with_content(%r{^\[Install\]$}).
with_content(%r{^Description=My great service$}).
with_content(%r{^Description=has two lines of description$}).
- with_content(%r{^Type=oneshot$})
+ with_content(%r{^Type=oneshot$}).
+ without_content(%r{^\[Slice\]$})
}
context 'with no service_entry' do
@@ -71,6 +72,14 @@
it { is_expected.to compile.and_raise_error(%r{timer_entry is only valid for timer units}) }
end
+ context 'with a slice entry' do
+ let(:params) do
+ super().merge(slice_entry: { 'IOWeight' => 100 })
+ end
+
+ it { is_expected.to compile.and_raise_error(%r{slice_entry is only valid for slice units}) }
+ end
+
context 'with a path entry' do
let(:params) do
super().merge(path_entry: { 'PathExists' => '/etc/passwd' })
@@ -161,6 +170,30 @@
}
end
+ context 'on a slice unit' do
+ let(:title) { 'myslice.slice' }
+ let(:params) do
+ {
+ unit_entry: {
+ Description: 'A crazy slice',
+ },
+ slice_entry: {
+ 'MemoryMax' => '10G',
+ 'IOAccounting' => true,
+ }
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+
+ it {
+ is_expected.to contain_systemd__unit_file('myslice.slice').
+ with_content(%r{^\[Slice\]$}).
+ with_content(%r{^MemoryMax=10G$}).
+ with_content(%r{^IOAccounting=true$})
+ }
+ end
+
context 'on a path unit' do
let(:title) { 'etc-passwd.path' }
diff --git a/spec/type_aliases/systemd_unit_slice_spec.rb b/spec/type_aliases/systemd_unit_slice_spec.rb
new file mode 100644
index 00000000..9fbcdd93
--- /dev/null
+++ b/spec/type_aliases/systemd_unit_slice_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Systemd::Unit::Slice' do
+ it { is_expected.to allow_value({ 'MemoryAccounting' => true }) }
+
+ it {
+ is_expected.to allow_value(
+ {
+ 'MemoryLow' => '100',
+ 'MemoryMin' => '10%',
+ 'MemoryHigh' => '8G',
+ 'MemoryMax' => 'infinity',
+ 'MemorySwapMax' => '1T',
+ }
+ )
+ }
+
+ it { is_expected.not_to allow_value({ 'MemoryHigh' => '1P' }) }
+end
diff --git a/templates/unit_file.epp b/templates/unit_file.epp
index 565ef567..7c606a7c 100644
--- a/templates/unit_file.epp
+++ b/templates/unit_file.epp
@@ -1,5 +1,6 @@
<%- |
Optional[Hash] $unit_entry,
+ Optional[Hash] $slice_entry,
Optional[Hash] $service_entry,
Optional[Hash] $install_entry,
Optional[Hash] $timer_entry,
@@ -13,6 +14,7 @@
$_unit_sections = [
'Unit',
+ 'Slice',
'Service',
'Timer',
'Path',
diff --git a/types/unit/slice.pp b/types/unit/slice.pp
new file mode 100644
index 00000000..ed9160bd
--- /dev/null
+++ b/types/unit/slice.pp
@@ -0,0 +1,33 @@
+# @summary Possible keys for the [Slice] section of a unit file
+# @see https://www.freedesktop.org/software/systemd/man/systemd.slice.html
+# @see https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html
+#
+type Systemd::Unit::Slice = Struct[
+ {
+ Optional['CPUAccounting'] => Boolean,
+ Optional['CPUQuota'] => Pattern['^([1-9][0-9]*)%$'],
+ Optional['CPUShares'] => Integer[2,262144],
+ Optional['Delegate'] => Boolean,
+ Optional['DeviceAllow'] => String[1],
+ Optional['DevicePolicy'] => Enum['auto','closed','strict'],
+ Optional['IOAccounting'] => Boolean,
+ Optional['IODeviceWeight'] => Array[Hash[Stdlib::Absolutepath, Integer[1,10000], 1, 1]],
+ Optional['IOReadBandwidthMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOReadIOPSMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOWeight'] => Integer[1,10000],
+ Optional['IOWriteBandwidthMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['IOWriteIOPSMax'] => Array[Hash[Stdlib::Absolutepath, Pattern['^(\d+(K|M|G|T)?)$'], 1, 1]],
+ Optional['MemoryAccounting'] => Boolean,
+ Optional['MemoryHigh'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryLimit'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'], # dep'd in systemd
+ Optional['MemoryLow'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryMax'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemoryMin'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['MemorySwapMax'] => Pattern['\A(infinity|\d+(K|M|G|T|%)?(:\d+(K|M|G|T|%)?)?)\z'],
+ Optional['Slice'] => String[1],
+ Optional['StartupCPUShares'] => Integer[2,262144],
+ Optional['StartupIOWeight'] => Integer[1,10000],
+ Optional['TasksAccounting'] => Boolean,
+ Optional['TasksMax'] => Variant[Integer[1],Pattern['^(infinity|([1-9][0-9]?$|^100)%)$']],
+ }
+]