summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-06-23 17:33:17 +0200
committerHugo Hörnquist <hugo@lysator.liu.se>2023-06-23 17:33:17 +0200
commitaede37be1b70ed4e53081682a6ec4814c348cb49 (patch)
tree3d29d58540a0ec9a71a3894a90268d3be6088a77
parentRemove everything. (diff)
downloadnspawn-aede37be1b70ed4e53081682a6ec4814c348cb49.tar.gz
nspawn-aede37be1b70ed4e53081682a6ec4814c348cb49.tar.xz
Add new modules content.
This module is designed differently. It makes no attempt to manage templates. It still attempts to manage machines, but this should probably move to Puppet tasks or similar, with the static configuration mostly doing cleanup.
-rw-r--r--facts.d/btrfs.py6
-rw-r--r--manifests/init.pp45
-rw-r--r--manifests/machine.pp89
-rw-r--r--metadata.json29
-rw-r--r--pdk.yaml2
-rw-r--r--templates/systemd/nspawn.epp313
-rw-r--r--types/systemd/bind.pp12
-rw-r--r--types/systemd/nspawn.pp115
-rw-r--r--types/systemd/resourcelimit7
9 files changed, 618 insertions, 0 deletions
diff --git a/facts.d/btrfs.py b/facts.d/btrfs.py
new file mode 100644
index 0000000..dcb6001
--- /dev/null
+++ b/facts.d/btrfs.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+import btrfs
+
+with btrfs.FileSystem('/var/lib/machines') as fs:
+ for subvolume in fs.subvolumes():
diff --git a/manifests/init.pp b/manifests/init.pp
new file mode 100644
index 0000000..3eedbae
--- /dev/null
+++ b/manifests/init.pp
@@ -0,0 +1,45 @@
+# @summary Configures systemd nspawn containers
+# @param config
+# Shared configuration for all machines, as per systemd.nspawn(5).
+#
+# See nspawn::machine's documentation for how it's merged.
+#
+# @param machines
+# Set of machines to be configured. Creates `nspawn::machine` resources.
+# See that resource type for acceptable options.
+#
+# @param template_dir
+# Location of template subvolumes.
+#
+# @param purge
+# Should old .nspawn files be purged.
+class nspawn (
+ Nspawn::Systemdconfig $config,
+ Stdlib::Abspath $template_dir = '/var/lib/templates',
+ Hash[String, Hash[String, Any]] $machines = {},
+ Boolean $purge = true,
+) {
+ # These aren't parameters since they aren't configurable.
+ # However, move them to the parameters if it turns out that
+ # different distributions place these files in different places.
+ # Location of nspawn files.
+ $nspawn_dir = '/etc/systemd/nspawn'
+ # Location of machine subvolumes.
+ $machine_dir = '/var/lib/machines'
+
+ file { $nspawn_dir:
+ ensure => directory,
+ purge => $purge,
+ recurse => true,
+ }
+
+ file { $template_dir:
+ ensure => directory,
+ }
+
+ file { $machine_dir:
+ ensure => directory,
+ }
+
+ create::resources('nspawn::machine', $machines)
+}
diff --git a/manifests/machine.pp b/manifests/machine.pp
new file mode 100644
index 0000000..8b09715
--- /dev/null
+++ b/manifests/machine.pp
@@ -0,0 +1,89 @@
+# @summary Configuration and provisioning for a single container.
+# @param name
+# Will be used for both the directory name, and the hostname in the container.
+# @param template
+# Which template this machine should be configured from.
+#
+# Templates needs to be manually configured behorehand.
+#
+# The value 'none' is special, since it allows the machine to be
+# managed without a template. The template parameter is however
+# required, since a machine without a template needs to be manually
+# configured through some other mean.
+#
+# @param domain
+# Domain part of FQDN of container.
+#
+# @param config
+# Configuration for the machine, as per systemd.nspawn(5).
+# Will be merged with `nspawn::config` per the `$merge` variable.
+#
+# @param merge
+# How this nodes configuration should be merged with the defalut hash.
+#
+# - deep
+# Stdlib's `deep_merge` will be used, with us on the right.
+# - shallow
+# `$nspawn::config + $config`
+# - replace
+# The upstream will be ignored.
+#
+# @param ensure
+define nspawn::machine (
+ Variant[String, Enum['none']] $template,
+ String $domain = $trusted['domain'],
+ Nspawn::Systemdconfig $config,
+ Enum['deep', 'shallow', 'override'] $merge = 'deep',
+ Enum['present', 'absent'] $ensure = 'present',
+) {
+ $root = "${nspawn::machine_dir}/${name}"
+
+ $final_config = $merge ? {
+ 'deep' => deep_merge($nspawn::config, $config),
+ 'shallow' => $nspawn::config + $config,
+ 'override' => $config,
+ }
+
+ file { "${nspawn::nspawn_dir}/${name}.nspawn":
+ ensure => $ensure,
+ content => epp("${module_name}/systemd/nspawn.epp", {
+ 'data' => $final_config
+ }),
+ }
+
+ if $ensure == 'present' {
+ # if $machine_dir has a quota set, then this inherits it
+ unless $template == 'none' {
+ exec { "Initialize ${name} from template":
+ cmd => [
+ 'btrfs', 'snapshot',
+ "${nspawn::template_dir}/${template}",
+ $root,
+ ],
+ creates => $root,
+ path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
+ }
+ }
+
+ file { "${root}/etc/passwd":
+ content => "${name}\n",
+ }
+
+ file_line { "${root}/etc/hosts ::1":
+ line => "::1\t${name}.${domain}\t${name}",
+ match => "${name}.${domain}",
+ path => "${root}/etc/hosts",
+ }
+ } else {
+ service { "systemd-nspawn@${name}":
+ ensure => stopped,
+ enable => false,
+ }
+
+ exec { "Remove btrfs subvolume ${root}":
+ cmd => ['btrfs', 'subvolume', 'delete', $root],
+ onlyif => [['test', '-d', $root]],
+ path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
+ }
+ }
+}
diff --git a/metadata.json b/metadata.json
new file mode 100644
index 0000000..4201259
--- /dev/null
+++ b/metadata.json
@@ -0,0 +1,29 @@
+{
+ "name": "HugoNikanor-nspawn",
+ "version": "0.1.0",
+ "author": "Hugo Hörnquist",
+ "license": "Apache-2.0",
+ "summary": "Manages Systemd-Nspawn containers",
+ "source": "https://git.hornquist.se/puppet/nspawn",
+ "dependencies": [
+ {
+ "name": "puppetlabs/stdlib",
+ "version_requirement": ">= 6.0.0 < 9.0.0"
+ }
+ ],
+ "requirements": [
+ {
+ "name": "puppet",
+ "version_requirement": ">= 5.5.10 < 8.0.0"
+ }
+ ],
+ "operatingsystem_support": [
+ {
+ "operatingsystem": "Archlinux"
+ }
+ ],
+ "pdk-version": "2.5.0",
+ "template-url": "pdk-default#2.5.0",
+ "template-ref": "tags/2.5.0-0-g369d483"
+}
+
diff --git a/pdk.yaml b/pdk.yaml
new file mode 100644
index 0000000..4bef4bd
--- /dev/null
+++ b/pdk.yaml
@@ -0,0 +1,2 @@
+---
+ignore: []
diff --git a/templates/systemd/nspawn.epp b/templates/systemd/nspawn.epp
new file mode 100644
index 0000000..ee79ba0
--- /dev/null
+++ b/templates/systemd/nspawn.epp
@@ -0,0 +1,313 @@
+<%- | Nspawn::Systemd::Nspawn $data | -%>
+
+[Exec]
+<%- $exec = $data['Exec'] -%>
+<%- if $exec['Boot'] == false { -%>
+Boot=no
+<%- } elsif $exec['Boot'] == true { -%>
+Boot=yes
+<%- } -%>
+<%- if $exec['Ephemeral'] == false { -%>
+Ephemeral=no
+<%- } elsif $exec['Ephemeral'] == true { -%>
+Ephemeral=yes
+<%- } -%>
+<%- if $exec['ProcessTwo'] == false { -%>
+ProcessTwo=no
+<%- } elsif $exec['ProcessTwo'] == true { -%>
+ProcessTwo=yes
+<%- } -%>
+<%- unless $exec['Parameters'] =~ Undef { -%>
+<%- if $exec['Parameters'] =~ String { -%>
+Parameters=<%= $exec['Parameters'] %>
+<%- } else { -%>
+Parameters=<%= $exec['Parameters'].map |$param| {
+ if ' ' in $param {
+ if '"' in $param {
+ "'${param}'"
+ } else {
+ "\"${param}\""
+ }
+ } else {
+ $param
+ }
+}.join(' ') %>
+<%- } } -%>
+<%- unless $exec['Environment'] =~ Undef { -%>
+<%- $exec['Environment'].each |$key, $value| { -%>
+Environment=<%= $key %>=<%= $value %>
+<%- } } -%>
+<%- unless $exec['User'] =~ Undef { -%>
+User=<%= $exec['User'] %>
+<%- } -%>
+<%- unless $exec['WorkingDirectory'] =~ Undef { -%>
+WorkingDirectory=<%= $exec['WorkingDirectory'] %>
+<%- } -%>
+<%- unless $exec['PivotRoot'] =~ Undef { -%>
+PivotRoot=<%= $exec['PivotRoot'] %>
+<%- } -%>
+<%- unless $exec['Capability'] =~ Undef { -%>
+Capability=<% if $exec['Capability'] == 'all' {%>all<%} else { %><%= $exec['Capability'].join(' ') -%>
+<%- } } -%>
+<%- unless $exec['DropCapability'] =~ Undef { -%>
+DropCapability=<% if $exec['DropCapability'] == 'all' {%>all<%} else { %><%= $exec['DropCapability'].join(' ') -%>
+<%- } } -%>
+<%- unless $exec['AmbientCapability'] =~ Undef { -%>
+AmbientCapability=<%= $exec['AmbientCapability'].join(' ') -%>
+<%- } -%>
+<%- unless $exec['NoNewPrivileges'] =~ Undef { -%>
+NoNewPrivileges=<%= if $exec['NoNewPrivileges'] { 'yes' } else { 'no' }%>
+<%- } -%>
+<%- unless $exec['KillSignal'] =~ Undef { -%>
+KillSignal=<%= $exec['KillSignal'] %>
+<%- } -%>
+<%- unless $exec['Personality'] =~ Undef { -%>
+Personality=<%= $exec['Personality'] %>
+<%- } -%>
+<%- unless $exec['MachineID'] =~ Undef { -%>
+MachineID=<%= $exec['MachineID'] %>
+<%- } -%>
+<%- unless $exec['PrivateUsers'] =~ Undef { -%>
+PrivateUsers=<%=
+if $exec['PrivateUsers'] =~ Boolean {
+ if $exec['PrivateUsers'] { 'yes' } else { 'no' }
+} elsif $exec['PrivateUsers'] =~ Tuple {
+ "<%= $exec['PrivateUsers'].join(':') %>"
+} else {
+ $exec['PrivateUsers']
+} %><%- } -%>
+<%- unless $exec['NotifyReady'] =~ Undef { -%>
+NotifyReady=<%= if $exec['NotifyReady'] { 'yes' } else { 'no' }%>
+<%- } -%>
+<%- unless $exec['SystemCallFilter'] =~ Undef { -%>
+SystemCallFilter=<%= $exec['SystemCallFilter'].join(' ') %>
+<%- } -%>
+<%- unless $exec['LimitCPU'] =~ Undef { -%>
+<%- if $exec['LimitCPU'] =~ Tuple { -%>
+LimitCPU=<%= $exec['LimitCPU'].join(':') %>
+<%- } else { -%>
+LimitCPU=<%= $exec['LimitCPU'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitFSIZE'] =~ Undef { -%>
+<%- if $exec['LimitFSIZE'] =~ Tuple { -%>
+LimitFSIZE=<%= $exec['LimitFSIZE'].join(':') %>
+<%- } else { -%>
+LimitFSIZE=<%= $exec['LimitFSIZE'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitDATA'] =~ Undef { -%>
+<%- if $exec['LimitDATA'] =~ Tuple { -%>
+LimitDATA=<%= $exec['LimitDATA'].join(':') %>
+<%- } else { -%>
+LimitDATA=<%= $exec['LimitDATA'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitSTACK'] =~ Undef { -%>
+<%- if $exec['LimitSTACK'] =~ Tuple { -%>
+LimitSTACK=<%= $exec['LimitSTACK'].join(':') %>
+<%- } else { -%>
+LimitSTACK=<%= $exec['LimitSTACK'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['limitSTACK'] =~ Undef { -%>
+<%- if $exec['limitSTACK'] =~ Tuple { -%>
+limitSTACK=<%= $exec['limitSTACK'].join(':') %>
+<%- } else { -%>
+limitSTACK=<%= $exec['limitSTACK'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitCORE'] =~ Undef { -%>
+<%- if $exec['LimitCORE'] =~ Tuple { -%>
+LimitCORE=<%= $exec['LimitCORE'].join(':')%>
+<%- } else { -%>
+LimitCORE=<%= $exec['LimitCORE'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LIMITRSS'] =~ Undef { -%>
+<%- if $exec['LIMITRSS'] =~ Tuple { -%>
+LIMITRSS=<%= $exec['LIMITRSS'].join(':') %>
+<%- } else { -%>
+LIMITRSS=<%= $exec['LIMITRSS'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitNOFILE'] =~ Undef { -%>
+<%- if $exec['LimitNOFILE'] =~ Tuple { -%>
+LimitNOFILE=<%= $exec['LimitNOFILE'].join(':') %>
+<%- } else { -%>
+LimitNOFILE=<%= $exec['LimitNOFILE'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitAS'] =~ Undef { -%>
+<%- if $exec['LimitAS'] =~ Tuple { -%>
+LimitAS=<%= $exec['LimitAS'].join(':') %>
+<%- } else { -%>
+LimitAS=<%= $exec['LimitAS'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitNPROC'] =~ Undef { -%>
+<%- if $exec['LimitNPROC'] =~ Tuple { -%>
+LimitNPROC=<%= $exec['LimitNPROC'].join(':') %>
+<%- } else { -%>
+LimitNPROC=<%= $exec['LimitNPROC'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitLOCKS'] =~ Undef { -%>
+<%- if $exec['LimitLOCKS'] =~ Tuple { -%>
+LimitLOCKS=<%= $exec['LimitLOCKS'].join(':') %>
+<%- } else { -%>
+LimitLOCKS=<%= $exec['LimitLOCKS'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitSIGPENDING'] =~ Undef { -%>
+<%- if $exec['LimitSIGPENDING'] =~ Tuple { -%>
+LimitSIGPENDING=<%= $exec['LimitSIGPENDING'].join(':') %>
+<%- } else { -%>
+LimitSIGPENDING=<%= $exec['LimitSIGPENDING'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitMSGQUEUE'] =~ Undef { -%>
+<%- if $exec['LimitMSGQUEUE'] =~ Tuple { -%>
+LimitMSGQUEUE=<%= $exec['LimitMSGQUEUE'].join(':') %>
+<%- } else { -%>
+LimitMSGQUEUE=<%= $exec['LimitMSGQUEUE'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitNICE'] =~ Undef { -%>
+<%- if $exec['LimitNICE'] =~ Tuple { -%>
+LimitNICE=<%= $exec['LimitNICE'].join(':') %>
+<%- } else { -%>
+LimitNICE=<%= $exec['LimitNICE'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitRTPRIO'] =~ Undef { -%>
+<%- if $exec['LimitRTPRIO'] =~ Tuple { -%>
+LimitRTPRIO=<%= $exec['LimitRTPRIO'].join(':') %>
+<%- } else { -%>
+LimitRTPRIO=<%= $exec['LimitRTPRIO'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['LimitRTTIME'] =~ Undef { -%>
+<%- if $exec['LimitRTTIME'] =~ Tuple { -%>
+LimitRTTIME=<%= $exec['LimitRTTIME'].join(':') %>
+<%- } else { -%>
+LimitRTTIME=<%= $exec['LimitRTTIME'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['OOMScoreAdjust'] =~ Undef { -%>
+OOMScoreAdjust=<%= $exec['OOMScoreAdjust'] %>
+<%- } -%>
+<%- unless $exec['CPUAffinity'] =~ Undef { -%>
+CPUAffinity=<%= $exec['CPUAffinity'].map |$aff| {
+ if $aff =~ Tuple {
+ "${aff[0]}-${aff[1]}"
+ } else {
+ "${aff}"
+ }.join(',')
+} %>
+<%- } -%>
+<%- unless $exec['Hostname'] =~ Undef { -%>
+Hostname=<%= $exec['Hostname'] %>
+<%- } -%>
+<%- unless $exec['ResolvConf'] =~ Undef { -%>
+ResolvConf=<%= $exec['ResolvConf'] %>
+<%- } -%>
+<%- unless $exec['Timezone'] =~ Undef { -%>
+Timezone=<%= $exec['Timezone'] %>
+<%- } -%>
+<%- unless $exec['LinkJournal'] =~ Undef { -%>
+LinkJournal=<%= $exec['LinkJournal'] %>
+<%- } -%>
+
+[Files]
+<%- unless $exec['ReadOnly'] =~ Undef { -%>
+ReadOnly=<%= if $exec['ReadOnly'] { 'yes' } else { 'no' } %>
+<%- } -%>
+<%- unless $exec['Volatile'] =~ Undef { -%>
+<%- if $exec['Volatile'] =~ Boolean { -%>
+Volatile=<%= if $exec['Volatile'] { 'yes' } else { 'no' } %>
+<%- } else { -%>
+Volatile=<%= $exec['Volatile'] %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['Bind'] =~ Undef { $exec['Bind'].each |$bind| { -%>
+<%- if $bind =~ Tuple[String, String] { -%>
+Bind=<%= $bind[0] %>:<%= $bind[1] %>
+<%- } elsif $bind =~ Tuple[String, String, Array[String]] { -%>
+Bind=<%= $bind[0] %>:<%= $bind[1] %>:<%= $bind[2].join(':') %>
+<%- } elsif $bind =~ Struct { -%>
+Bind=<%= $bind['source'] %>:<%= $bind['dest'] %><%-
+if $bind['options'] { %>:<%= $bind['options'].join(':') %><%- } -%>
+<%- } else { -%>
+Bind=<%= $exec['Bind'] %>
+<%- } -%>
+<%- }} -%>
+<%- unless $exec['BindReadOnly'] =~ Undef { $exec['Bind'].each |$bind| { -%>
+<%- if $bind =~ Tuple[String, String] { -%>
+BindReadOnly=<%= $bind[0] %>:<%= $bind[1] %>
+<%- } elsif $bind =~ Tuple[String, String, Array[String]] { -%>
+BindReadOnly=<%= $bind[0] %>:<%= $bind[1] %>:<%= $bind[2].join(':') %>
+<%- } elsif $bind =~ Struct { -%>
+BindReadOnly=<%= $bind['source'] %>:<%= $bind['dest'] %><%-
+if $bind['options'] { %>:<%= $bind['options'].join(':') %><%- } -%>
+<%- } else { -%>
+BindReadOnly=<%= $exec['Bind'] %>
+<%- } -%>
+<%- }} -%>
+<%- unless $exec['BindUser'] =~ Undef {$exec['BindUser'].each |$user| { -%>
+BindUser=<%= $user %>
+<%- } } -%>
+<%- unless $exec['TemporaryFileSystem'] =~ Undef {$exec['TemporaryFileSystem'].each |$fs| { -%>
+TemporaryFileSystem=<%=
+if $fs =~ Tuple {
+ $fs.join(':')
+} else {
+ $fs
+}
+%>
+<%- } } -%>
+<%- unless $exec['Inaccessible'] =~ Undef {$exec['Inaccessible'].each |$path| { -%>
+Inaccessible=<%= $path %>
+<%- } } -%>
+<%- unless $exec['Overlay'] =~ Undef {$exec['Overlay'].each |$paths| { -%>
+Overlay=<%= $paths.join(':') %>
+<%- } } -%>
+<%- unless $exec['OverlayReadOnly'] =~ Undef {$exec['OverlayReadOnly'].each |$paths| { -%>
+OverlayReadOnly=<%= $paths.join(':') %>
+<%- } } -%>
+<%- unless $exec['PrivateUsersOwnership'] =~ Undef { -%>
+PrivateUsersOwnership=<%= $exec['PrivateUsersOwnership'] %>
+<%- } -%>
+
+[Network]
+<%- unless $exec['Private'] =~ Undef { -%>
+Private=<%= if $exec['Private'] { 'yes' } else { 'no' } %>
+<%- } -%>
+<%- unless $exec['VirtualEthernet'] =~ Undef { -%>
+VirtualEthernet=<%= if $exec['VirtualEthernet'] { 'yes' } else { 'no' } %>
+<%- } -%>
+<%- unless $exec['VirtualEthernetExtra'] =~ Undef {
+ $exec['VirtualEthernetExtra'].each |$interface| { -%>
+VirtualEthernetExtra=<%= if $interface =~ Tuple { $interface.join(':') } else { $interface } %>
+<%- } -%>
+<%- } -%>
+<%- unless $exec['Interface'] =~ Undef { -%>
+Interface=<%= $exec['Interface'].join(' ') %>
+<%- } -%>
+<%- unless $exec['MACVLAN'] =~ Undef { -%>
+MACVLAN=<%= $exec['MACVLAN'].join(' ') %>
+<%- } -%>
+<%- unless $exec['IPVLAN'] =~ Undef { -%>
+IPVLAN=<%= $exec['IPVLAN'].join(' ') %>
+<%- } -%>
+<%- unless $exec['Bridge'] =~ Undef { -%>
+Bridge=<%= $exec['Bridge'] %>
+<%- } -%>
+<%- unless $exec['Zone'] =~ Undef { -%>
+Zone=<%= $exec['Zone'] %>
+<%- } -%>
+<%- unless $exec['Port'] =~ Undef {
+ $exec['Port'].each |$p| { -%>
+Port=<%= $p.join(':') %>
+<%- } -%>
+<%- } -%>
diff --git a/types/systemd/bind.pp b/types/systemd/bind.pp
new file mode 100644
index 0000000..9554e9a
--- /dev/null
+++ b/types/systemd/bind.pp
@@ -0,0 +1,12 @@
+type Nspawn::Systemd::Bind = Variant[
+ String,
+ Tuple[String, String],
+ # TODO Typecheck options
+ Tuple[String, String, Array[String]],
+ Struct[{
+ 'source' => String,
+ 'dest' => String,
+ # TODO Typecheck options
+ 'options' => Optional[Array[String]],
+ }],
+]
diff --git a/types/systemd/nspawn.pp b/types/systemd/nspawn.pp
new file mode 100644
index 0000000..1b488c8
--- /dev/null
+++ b/types/systemd/nspawn.pp
@@ -0,0 +1,115 @@
+type Nspawn::Systemd::Nspawn = Struct[{
+ 'Exec' => Struct[{
+ 'Boot' => Optional[Boolean],
+ 'Ephemeral' => Optional[Boolean],
+ 'ProcessTwo' => Optional[Boolean],
+ 'Parameters' => Optional[Variant[
+ String,
+ Array[String],
+ ]],
+ 'Environment' => Optional[Hash[String, String]],
+ 'User' => Optional[String],
+ 'WorkingDirectory' => Optional[Stdlib::Unixpath],
+ 'PivotRoot' => Optional[Stdlib::Unixpath],
+ 'Capability' => Optional[Variant[Enum['all'], Array[String]]],
+ 'DropCapability' => Optional[Variant[Enum['all'], Array[String]]],
+ 'AmbientCapability' => Optional[Array[String]],
+ 'NoNewPrivileges' => Optional[Boolean],
+ # See signal(7) for valid signals
+ 'KillSignal' => Optional[String],
+ 'Personality' => Optional[Enum['x86', 'x86-64']],
+ 'MachineID' => Optional[Pattern[/\A[A-fa-f0-9]{32}\Z/]],
+ 'PrivateUsers' => Optional[Variant[
+ Integer,
+ Tuple[Integer, Integer],
+ Boolean,
+ Enum['yes', 'no', 'identity', 'pick']
+ ]],
+ 'NotifyReady' => Optional[Boolean],
+ # If first element is '~', then this is a blacklist
+ 'SystemCallFilter' => Optional[Array[String]],
+ 'LimitCPU' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitFSIZE' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitDATA' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitSTACK' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitCORE' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitRSS' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitNOFILE' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitAS' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitNPROC' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitMEMLOCK' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitLOCKS' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitSIGPENDING' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitMSGQUEUE' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitNICE' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitRTPRIO' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'LimitRTTIME' => Optional[Nspawn::Systemd::ResourceLimit],
+ 'OOMScoreAdjust' => Optional[Integer[-1000, 1000]],
+ 'CPUAffinity' => Optional[Array[Variant[Integer, Tuple[Integer, Integer]]]],
+ 'Hostname' => Optional[String],
+ 'ResolvConf' => Optional[Enum[
+ 'off',
+ 'copy-host',
+ 'copy-static',
+ 'copy-uplink',
+ 'copy-stub',
+ 'replace-host',
+ 'replace-static',
+ 'replace-uplink',
+ 'replace-stub',
+ 'bind-host',
+ 'bind-static',
+ 'bind-uplink',
+ 'bind-stub',
+ 'delete',
+ 'auto',
+ ]],
+ 'Timezone' => Optional[Enum[
+ 'off',
+ 'copy',
+ 'bind',
+ 'symlink',
+ 'delete',
+ 'auto',
+ ]],
+ 'LinkJournal' => Optional[Enum[
+ 'no',
+ 'host',
+ 'try-host',
+ 'guest',
+ 'try-guest',
+ 'auto',
+ ]],
+ }],
+ 'Files' => Struct[{
+ 'ReadOnly' => Optional[Boolean],
+ 'Volatile' => Optional[Variant[Boolean, Enum['state']]],
+ 'Bind' => Optional[Array[Nspawn::Systemd::Bind]],
+ 'BindReadOnly' => Optional[Array[Nspawn::Systemd::Bind]],
+ # TODO Can binduser appear multiple times?
+ 'BindUser' => Optional[Array[String]],
+ # TODO Can tmpfs appear multiple times?
+ # TODO options type
+ 'TemporaryFileSystem' => Optional[Array[Variant[String, Tuple[String, String]]]],
+ 'Inaccessible' => Optional[Array[Stdlib::Unixpath]],
+ 'Overlay' => Optional[Array[Array[String, 2]]],
+ 'OverlayReadOnly' => Optional[Array[Array[String, 2]]],
+ 'PrivateUsersOwnership' => Optional[Enum['off', 'chown', 'map', 'auto']],
+ }],
+ 'Network' => Struct[{
+ 'Private' => Optional[Boolean],
+ 'VirtualEthernet' => Optional[Boolean],
+ 'VirtualEthernetExtra' => Optional[Array[Variant[String, Tuple[String, String]]]],
+ 'Interface' => Optional[Array[String]],
+ 'MACVLAN' => Optional[Array[String]],
+ 'IPVLAN' => Optional[Array[String]],
+ 'Bridge' => Optional[String],
+ 'Zone' => Optional[String],
+ 'Port' => Optional[Array[Variant[
+ Tuple[Enum['tcp', 'udp'], Stdlib::Port, Stdlib::Port],
+ Tuple[Enum['tcp', 'udp'], Stdlib::Port],
+ Tuple[Stdlib::Port, Stdlib::Port],
+ Tuple[Stdlib::Port],
+ ]]],
+ }],
+}]
diff --git a/types/systemd/resourcelimit b/types/systemd/resourcelimit
new file mode 100644
index 0000000..3558fb5
--- /dev/null
+++ b/types/systemd/resourcelimit
@@ -0,0 +1,7 @@
+type Nspawn::Systemd::ResourceLimit = Variant[
+ Variant[Integer, enum['infinity']],
+ Tuple[
+ Variant[Integer, enum['infinity']],
+ Variant[Integer, enum['infinity']],
+ ]
+]