diff --git a/REFERENCE.md b/REFERENCE.md
index 4c58eccb..a2e51bb9 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -98,6 +98,8 @@ The following parameters are available in the `systemd` class:
* [`manage_resolved`](#-systemd--manage_resolved)
* [`resolved_ensure`](#-systemd--resolved_ensure)
* [`resolved_package`](#-systemd--resolved_package)
+* [`manage_nspawn`](#-systemd--manage_nspawn)
+* [`nspawn_package`](#-systemd--nspawn_package)
* [`dns`](#-systemd--dns)
* [`fallback_dns`](#-systemd--fallback_dns)
* [`domains`](#-systemd--domains)
@@ -222,6 +224,23 @@ The name of a systemd sub package needed for systemd-resolved if one needs to be
Default value: `undef`
+##### `manage_nspawn`
+
+Data type: `Boolean`
+
+Manage the systemd-nspawn@service and machinectl subsystem.
+
+Default value: `false`
+
+##### `nspawn_package`
+
+Data type: `Optional[Enum['systemd-container']]`
+
+The name of a systemd sub package needed for the nspawn tools machinectl and
+systemd-nspawn if one needs to be installed.
+
+Default value: `undef`
+
##### `dns`
Data type: `Optional[Variant[Array[String],String]]`
diff --git a/data/Debian-family.yaml b/data/Debian-family.yaml
new file mode 100644
index 00000000..5c644fa2
--- /dev/null
+++ b/data/Debian-family.yaml
@@ -0,0 +1,2 @@
+---
+systemd::nspawn_package: 'systemd-container'
diff --git a/data/Fedora.yaml b/data/Fedora.yaml
index 176f0ed1..770a5d0a 100644
--- a/data/Fedora.yaml
+++ b/data/Fedora.yaml
@@ -1,4 +1,5 @@
---
+systemd::nspawn_package: 'systemd-container'
systemd::accounting:
DefaultCPUAccounting: 'yes'
DefaultIOAccounting: 'yes'
diff --git a/data/RedHat-family-8.yaml b/data/RedHat-family-8.yaml
index c750d0ed..a60a8f54 100644
--- a/data/RedHat-family-8.yaml
+++ b/data/RedHat-family-8.yaml
@@ -1,4 +1,6 @@
---
+systemd::nspawn_package: 'systemd-container'
+
systemd::accounting:
DefaultCPUAccounting: 'yes'
DefaultBlockIOAccounting: 'yes'
diff --git a/data/RedHat-family-9.yaml b/data/RedHat-family-9.yaml
index e97f749a..9b0ac6c7 100644
--- a/data/RedHat-family-9.yaml
+++ b/data/RedHat-family-9.yaml
@@ -1,5 +1,6 @@
---
systemd::resolved_package: 'systemd-resolved'
+systemd::nspawn_package: 'systemd-container'
systemd::accounting:
DefaultCPUAccounting: 'yes'
diff --git a/manifests/init.pp b/manifests/init.pp
index 2d6de190..df9d6a66 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -31,6 +31,13 @@
# @param resolved_package
# The name of a systemd sub package needed for systemd-resolved if one needs to be installed.
#
+# @param manage_nspawn
+# Manage the systemd-nspawn@service and machinectl subsystem.
+#
+# @param nspawn_package
+# The name of a systemd sub package needed for the nspawn tools machinectl and
+# systemd-nspawn if one needs to be installed.
+#
# @param dns
# A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers.
# DNS requests are sent to one of the listed DNS servers in parallel to suitable
@@ -243,6 +250,8 @@
Stdlib::CreateResources $manage_dropins = {},
Stdlib::CreateResources $udev_rules = {},
Boolean $manage_coredump = false,
+ Boolean $manage_nspawn = false,
+ Optional[Enum['systemd-container']] $nspawn_package = undef,
Systemd::CoredumpSettings $coredump_settings = {},
Boolean $coredump_backtrace = false,
Boolean $manage_oomd = false,
diff --git a/manifests/install.pp b/manifests/install.pp
index efbd0c83..795ba4dc 100644
--- a/manifests/install.pp
+++ b/manifests/install.pp
@@ -19,4 +19,10 @@
ensure => present,
}
}
+
+ if $systemd::manage_nspawn and $systemd::nspawn_package {
+ package { $systemd::nspawn_package:
+ ensure => present,
+ }
+ }
}
diff --git a/spec/acceptance/nspwan_spec.rb b/spec/acceptance/nspwan_spec.rb
new file mode 100644
index 00000000..1442750f
--- /dev/null
+++ b/spec/acceptance/nspwan_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper_acceptance'
+
+describe 'systemd with manage_nspawn true' do
+ machinectl = (fact('os.name') == 'Debian') && %w[10 11].include?(fact('os.release.major')) ? '/bin/machinectl' : '/usr/bin/machinectl'
+
+ context 'configure nspawn' do
+ let(:manifest) do
+ <<~PUPPET
+ class { 'systemd':
+ manage_nspawn => true,
+ }
+ PUPPET
+ end
+
+ it 'works idempotently with no errors' do
+ apply_manifest(manifest, catch_failures: true)
+ apply_manifest(manifest, catch_changes: true)
+ end
+
+ describe file(machinectl) do
+ it { is_expected.to be_file }
+ end
+ end
+end
diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb
index 87edddf2..6b3ced22 100644
--- a/spec/classes/init_spec.rb
+++ b/spec/classes/init_spec.rb
@@ -20,6 +20,7 @@
it { is_expected.not_to contain_package('systemd-networkd') }
it { is_expected.not_to contain_package('systemd-timesyncd') }
it { is_expected.not_to contain_package('systemd-resolved') }
+ it { is_expected.not_to contain_package('systemd-container') }
it { is_expected.not_to contain_class('systemd::coredump') }
it { is_expected.not_to contain_class('systemd::oomd') }
it { is_expected.not_to contain_exec('systemctl set-default multi-user.target') }
@@ -279,6 +280,28 @@
}
end
+ context 'when enabling nspawn' do
+ let(:params) do
+ {
+ manage_nspawn: true,
+ }
+ end
+
+ case facts[:os]['family']
+ when 'RedHat'
+ case facts[:os]['release']['major']
+ when '7'
+ it { is_expected.not_to contain_package('systemd-container') } # rubocop:disable RSpec/RepeatedExample
+ else
+ it { is_expected.to contain_package('systemd-container').with_ensure('present') } # rubocop:disable RSpec/RepeatedExample
+ end
+ when 'Debian'
+ it { is_expected.to contain_package('systemd-container').with_ensure('present') } # rubocop:disable RSpec/RepeatedExample
+ else
+ it { is_expected.not_to contain_package('systemd-container') } # rubocop:disable RSpec/RepeatedExample
+ end
+ end
+
context 'when enabling timesyncd' do
let(:params) do
{