From 06e91dc3188d2f829e98556da28e3fdf0a20d837 Mon Sep 17 00:00:00 2001
From: Thomas Bellman <bellman@lysator.liu.se>
Date: Sun, 5 Nov 2023 02:25:35 +0100
Subject: [PATCH] Support comments on sections and options.

In systemd::unit and systemd::unit_options, support a special syntax
in the hash of hashes for specifying comments on sections and on
individual options, where the comments get written to the systemd
unit file.

The syntax is to specify a key with a name prefixed with a hash (#)
sign.  The comment will be inserted just before the corresponding
section or option.  For example:

        options => {
            'Install' => { 'WantedBy' => 'multi-user.target' },
            'Service' => {
                'ExecStart' => '/bin/true'
                'User' => 'laureline',
                '#User' => "Don't run as Valerian",
            },
            '#Service' => [
                "This is a pretty silly service section,",
                "but we can test\nnewlines in the comment.",
            ],
        }

will generate

        [Install]
        WantedBy=multi-user.target

        # This is a pretty silly service section,
        # but we can test
        # newlines in the comment.
        [Service]
        ExecStart=/bin/true
        # Don't run as Valerian
        User=laureline

The idea is to be able to point out subtilities to readers of the
generated unit file, so someone looking at a configured system doesn't
have to go to the Puppet manifests to understand why something is done
in a specific way.

I'm not sure how useful this feature is, though.  Perhaps users will
be satisfied with having normal Puppet comments in the manifest source
code, and reading those.
---
 manifests/unit.pp         |  7 ++++++-
 manifests/unit_options.pp |  7 ++++++-
 templates/unitfile.erb    | 39 ++++++++++++++++++++++++++++-----------
 3 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/manifests/unit.pp b/manifests/unit.pp
index e1d985b..9561700 100644
--- a/manifests/unit.pp
+++ b/manifests/unit.pp
@@ -1,4 +1,4 @@
-# Copyright © 2021   Thomas Bellman, Linköping, Sweden
+# Copyright © 2021-2023   Thomas Bellman, Linköping, Sweden
 # Licensed under the GNU LGPL v3+; see the README file for more information.
 
 
@@ -35,6 +35,11 @@ define systemd::unit(
 	# support multi-value options, e.g. "ExecStart" in a service config,
 	# or "ListenStream" in a socket config.
 	#
+	# A section name (at the top level) or an option name (at the inner
+	# level) starting with a hash sign (#), e.g. "#Service" or "#User",
+	# takes a string or (nested) list of strings, which will become a
+	# comment in front of the corresponding section or option.
+	#
 	$options=undef,
 
 	# String to put in the unit file.  This is equivalent to the
diff --git a/manifests/unit_options.pp b/manifests/unit_options.pp
index badfa20..683af00 100644
--- a/manifests/unit_options.pp
+++ b/manifests/unit_options.pp
@@ -1,4 +1,4 @@
-# Copyright © 2021   Thomas Bellman, Linköping, Sweden
+# Copyright © 2021-2023   Thomas Bellman, Linköping, Sweden
 # Licensed under the GNU LGPL v3+; see the README file for more information.
 
 
@@ -44,6 +44,11 @@ define systemd::unit_options(
 	# reset that option to the empty list, as systemd would otherwise
 	# just append the new value(s) to the existing list.
 	#
+	# A section name (at the top level) or an option name (at the inner
+	# level) starting with a hash sign (#), e.g. "#Service" or "#User",
+	# takes a string or (nested) list of strings, which will become a
+	# comment in front of the corresponding section or option.
+	#
 	$options=undef,
 
 	# List of comment lines to add to the start of the parameter file.
diff --git a/templates/unitfile.erb b/templates/unitfile.erb
index 1aea7da..96cd880 100644
--- a/templates/unitfile.erb
+++ b/templates/unitfile.erb
@@ -1,19 +1,31 @@
-<%
-   # Copyright © 2021   Thomas Bellman, Linköping, Sweden
-   # Licensed under the GNU LGPL v3+; see the README file for more information.
+<%#
+  # Copyright © 2021-2023   Thomas Bellman, Linköping, Sweden
+  # Licensed under the GNU LGPL v3+; see the README file for more information.
+  #
 -%>
 <% resource_ref = "Systemd::%s[%s]" % [ @systemd_resource_type, @title, ]
-   comment_lines = [@comment].flatten.join("\n").split("\n")
-   if comment_lines.length() > 0
-      comment_lines.each do |cline|
+   unit_comments = [@comment].flatten.join("\n").split("\n")
+   unit_comments.collect! { |cline| "# " + cline }
+   unit_comments << "\n"  if unit_comments.length > 0
 -%>
-# <%= cline %>
-<%    end %>
-<% end -%>
-<% @options.sort.each do |section_name,section_options| -%>
+<%= unit_comments.join("\n") -%>
+<%#									-%>
+<%#									-%>
+<%# Loop over sections ('Unit', 'Service', et.c)			-%>
+<% @options.sort.each do |section_name, section_options|
+      next if section_name =~ /^#/
+      section_comments = (@options['#'+section_name] or []).flatten().
+	    join("\n").split("\n")
+-%>
+<%= section_comments.collect { |cline| "# " + cline + "\n" }.join("") -%>
 [<%= section_name %>]
+<%#   # Loop over options in section					-%>
 <%    section_options.sort.each do |optname,value| -%>
-<%       if optname =~ /^-(.*)/
+<%
+	 # Override instead of append to list option.
+	 # This is only valid if called from systemd::unit_options, not when
+	 # called from systemd::unit.
+         if optname =~ /^-(.*)/
             if @systemd_resource_type == 'Unit_options'
                optname = $1
 -%>
@@ -27,6 +39,11 @@
 -%>
 <%          end -%>
 <%       end -%>
+<%       next if optname =~ /^#/ -%>
+<%       opt_comments = (section_options['#'+optname] or []).flatten().
+		join("\n").split("\n")
+-%>
+<%=      opt_comments.collect { |cline| "# " + cline + "\n" }.join("") -%>
 <%       [value].flatten.each do |v| -%>
 <%= optname %>=<%= v %>
 <%       end -%>
-- 
GitLab