From a6807aedc66dbf8b0d504438dbfabd8627e3d5d5 Mon Sep 17 00:00:00 2001
From: Thomas Bellman <bellman@lysator.liu.se>
Date: Mon, 4 Oct 2021 20:44:13 +0200
Subject: [PATCH] New definition for managing systemd unit files.

This adds a new definition, systemd::unit, for managing unit files
in /etc/systemd/system.  The content of the unit file can be given
as a hash of hashes (like in the systemd::unit_options definition),
as a string, or as a path or puppet: URL to a file to copy.

Since we use the same ERB template file for formatting the hash of
hashes into an ini-style file in both systemd::unit_options and
systemd::unit, we have renamed the template file to "unitfile.erb",
to be more neutral.  The comment at the end mentioning from where
the file is managed, now takes the Puppet definition as a parameter,
set by the definition.
---
 manifests/unit.pp                             | 123 ++++++++++++++++++
 manifests/unit_options.pp                     |   3 +-
 .../{unit_options.conf.erb => unitfile.erb}   |   2 +-
 3 files changed, 126 insertions(+), 2 deletions(-)
 create mode 100644 manifests/unit.pp
 rename templates/{unit_options.conf.erb => unitfile.erb} (89%)

diff --git a/manifests/unit.pp b/manifests/unit.pp
new file mode 100644
index 0000000..a4560d4
--- /dev/null
+++ b/manifests/unit.pp
@@ -0,0 +1,123 @@
+# Copyright © 2021   Thomas Bellman, Linköping, Sweden
+# Licensed under the GNU LGPL v3+; see the README file for more information.
+
+
+/*
+ * Manage systemd units.
+ *
+ * This actually manages a config file in /etc/systemd/system/<service>.
+ * The name parameter must be on the format
+ *
+ *     UNITNAME "." TYPE
+ *
+ * where
+ *
+ *  - UNITNAME is the name of the service, e.g. "sshd" or "getty@".
+ *  - TYPE is the unit type, e.g. "service", "socket", et.c; see
+ *    systemd.unit(5).
+ *
+ * The content of the unit file can be specified in one of three ways
+ *  - the 'options' parameter, specifying the content as a hash of hashes,
+ *  - the 'content' parameter, specifying the content as a string,
+ *  - the 'source' parameter, specifying a file or Puppet URL to copy.
+ */
+define systemd::unit(
+	# Hash of hash of options to put in the unit file.  The keys in the
+	# top level hash are the sections in the config file, e.g. "Unit",
+	# "Service", "Socket".  The inner hashes are mappings from option
+	# names to values.
+	#
+	# This parameter is mutually exclusive with the 'source' and
+	# 'content' parameters.
+	#
+	# If the value of an option is a (possibly nested) list, one option
+	# line will be generated for each element in the list.  This is to
+	# support multi-value options, e.g. "ExecStart" in a service config,
+	# or "ListenStream" in a socket config.
+	#
+	# If the option name starts with a minus sign ("-"), an extra line
+	# setting that option to the empty string is prepended, in order to
+	# reset that option to the empty list, as systemd would otherwise
+	# just append the new value(s) to the existing list.
+	#
+	$options=undef,
+
+	# String to put in the unit file.  This is equivalent to the
+	# 'content' parameter on the 'file' resource type.
+	#
+	# This parameter is mutally exclusive with the 'source' and
+	# 'options' parameters.
+	#
+	$content=undef,
+
+	# Path or puppet: URL to a file to copy into the unit file.  This is
+	# equivalent to the 'source' parameter on the 'file' resource type.
+	#
+	# This parameter is mutally exclusive with the 'options' and
+	# 'content' parameters.
+	#
+	$source=undef,
+
+	# List of comment lines to add to the start of the parameter file.
+	# The list may be nested, and individual "lines" are allowed to
+	# contain newlines, turning them into multiple comment lines.
+	# This is only used if the 'options' parameter is used to specify
+	# the content of the unit file.
+	#
+	$comment=[],
+
+	# One of 'present' of 'absent'.
+	#
+	$ensure='present',
+)
+{
+    include systemd::vars
+    include systemd::daemon_reload
+
+    if ($name !~ /^([^\/.]+)\.([^\/.]+)$/)
+    {
+	fail("Systemd::Unit[${title}]:",
+	     " Name not on format <service>.<type>, ``${name}''")
+    }
+    if (($source != undef and $content == undef and $options == undef) or
+	($source == undef and $content != undef and $options == undef) or
+	($source == undef and $content == undef and $options != undef) or
+	($ensure == 'absent'))
+    {
+	# OK
+    } else {
+	fail("Systemd::Unit[${title}]:",
+	     "Exactly one of 'source', 'content' and 'options' must be used")
+    }
+
+    $systemd_resource_type = 'Unit'
+    $filepath = "${systemd::vars::etcdir}/${name}"
+
+    case $ensure
+    {
+	'present': {
+	    $xcontent = $options ? {
+		undef   => $content,
+		default => template('systemd/unitfile.erb'),
+	    }
+	    file {
+		$filepath:
+		    ensure => file,
+		    content => $xcontent, source => $source,
+		    owner => 'root', group => 'root', mode => '0444',
+		    notify => Class['systemd::daemon_reload'];
+	    }
+	}
+	'absent': {
+	    file {
+		$filepath:
+		    ensure => absent,
+		    notify => Class['systemd::daemon_reload'];
+	    }
+	}
+	default: {
+	    fail("Systemd::Unit[${title}]:",
+		 " Bad parameter ensure, ``${ensure}''")
+	}
+    }
+}
diff --git a/manifests/unit_options.pp b/manifests/unit_options.pp
index 6989b48..1fb646b 100644
--- a/manifests/unit_options.pp
+++ b/manifests/unit_options.pp
@@ -70,6 +70,7 @@ define systemd::unit_options(
 	     " ``${name}''")
     }
 
+    $systemd_resource_type = 'Unit_options'
     $unitdir = "${systemd::vars::etcdir}/${unitname}.${unittype}.d"
     $filepath = "${unitdir}/${filename}.conf"
 
@@ -84,7 +85,7 @@ define systemd::unit_options(
 	    file {
 		$filepath:
 		    ensure => file,
-		    content => template('systemd/unit_options.conf.erb'),
+		    content => template('systemd/unitfile.erb'),
 		    owner => 'root', group => 'root', mode => '0444',
 		    notify => Class['systemd::daemon_reload'];
 	    }
diff --git a/templates/unit_options.conf.erb b/templates/unitfile.erb
similarity index 89%
rename from templates/unit_options.conf.erb
rename to templates/unitfile.erb
index 8cdf01b..c3b3221 100644
--- a/templates/unit_options.conf.erb
+++ b/templates/unitfile.erb
@@ -22,4 +22,4 @@
 <%       end -%>
 <%    end %>
 <% end -%>
-# Managed by Puppet:  Systemd::Unit_options[<%= @title %>]
+# Managed by Puppet:  Systemd::<%= @systemd_resource_type %>[<%= @title %>]
-- 
GitLab