commit 0c9bc3084e3f6ee8dbbd9e2c8d3564fb150ee61d
Author: hashworks <mail@hashworks.net>
Date:   Sat Feb 26 16:48:35 2022 +0100

    Add support for Arch Linux
    
    Arch Linux stores the configuration in a different path and does not
    provide firewalld without explicit installation.
    
    This basically the same as #66 – I've reused their code since it hasn't
    been merged in a while.

diff --git a/data/common.yaml b/data/common.yaml
index 2fbf0ff..1e1f06a 100644
--- a/data/common.yaml
+++ b/data/common.yaml
@@ -1 +1,3 @@
---- {}
+---
+
+nftables::configuration_path: '/etc/sysconfig/nftables.conf'
diff --git a/data/os/Archlinux.yaml b/data/os/Archlinux.yaml
new file mode 100644
index 0000000..cde7617
--- /dev/null
+++ b/data/os/Archlinux.yaml
@@ -0,0 +1,6 @@
+---
+
+# firewalld is not installed by default in Arch Linux
+nftables::firewalld_enable: false
+
+nftables::configuration_path: /etc/nftables.conf
diff --git a/files/systemd/puppet_nft.conf b/files/systemd/puppet_nft.conf
deleted file mode 100644
index 6595c49..0000000
--- a/files/systemd/puppet_nft.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-# Puppet Deployed
-[Service]
-RemainAfterExit=yes
-ExecStart=
-ExecStart=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf
-ExecReload=
-ExecReload=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf
-
diff --git a/manifests/init.pp b/manifests/init.pp
index 76e51b1..fd79eaf 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -86,6 +86,10 @@
 # @param rules
 #   Specify hashes of `nftables::rule`s via hiera
 #
+# @param configuration_path
+#   The absolute path to the principal nftables configuration file. The default
+#   varies depending on the system, and is set in the module's data.
+#
 class nftables (
   Boolean $in_ssh = true,
   Boolean $in_icmp = true,
@@ -107,19 +111,23 @@ class nftables (
   Variant[Boolean[false], Pattern[/icmp(v6|x)? type .+|tcp reset/]] $reject_with = 'icmpx type port-unreachable',
   Variant[Boolean[false], Enum['mask']] $firewalld_enable = 'mask',
   Optional[Array[Pattern[/^(ip|ip6|inet)-[-a-zA-Z0-9_]+$/],1]] $noflush_tables = undef,
+  Stdlib::Unixpath $configuration_path,
 ) {
   package { 'nftables':
     ensure => installed,
   } -> file_line {
     'enable_nftables':
       line   => 'include "/etc/nftables/puppet.nft"',
-      path   => '/etc/sysconfig/nftables.conf',
+      path   => $configuration_path,
       notify => Service['nftables'],
   } -> file {
     default:
       owner => 'root',
       group => 'root',
       mode  => '0640';
+    '/etc/nftables':
+      ensure => directory,
+      mode   => '0750';
     '/etc/nftables/puppet-preflight':
       ensure  => directory,
       mode    => '0750',
@@ -167,7 +175,9 @@ class nftables (
   systemd::dropin_file { 'puppet_nft.conf':
     ensure  => present,
     unit    => 'nftables.service',
-    content => file('nftables/systemd/puppet_nft.conf'),
+    content => epp('nftables/systemd/puppet_nft.conf.epp', {
+        'configuration_path' => $configuration_path,
+    }),
     notify  => Service['nftables'],
   }
 
diff --git a/metadata.json b/metadata.json
index 334eec9..660b79d 100644
--- a/metadata.json
+++ b/metadata.json
@@ -48,6 +48,9 @@
         "8",
         "9"
       ]
+    },
+    {
+      "operatingsystem": "Archlinux"
     }
   ],
   "requirements": [
diff --git a/spec/acceptance/all_rules_spec.rb b/spec/acceptance/all_rules_spec.rb
index 614a151..91eba9e 100644
--- a/spec/acceptance/all_rules_spec.rb
+++ b/spec/acceptance/all_rules_spec.rb
@@ -78,6 +78,14 @@ describe 'nftables class' do
         elements   => ['192.168.0.1', '10.0.0.2'],
         table      => ['inet-filter', 'ip-nat'],
       }
+      $config_path = case $facts['os']['family'] {
+        'Archlinux': {
+          '/etc/nftables.conf'
+        }
+        default: {
+          '/etc/sysconfig/nftables.conf'
+        }
+      }
       # nftables cannot be started in docker so replace service with a validation only.
       systemd::dropin_file{"zzz_docker_nft.conf":
         ensure  => present,
@@ -85,9 +93,9 @@ describe 'nftables class' do
         content => [
           "[Service]",
           "ExecStart=",
-          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "ExecReload=",
-          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "",
           ].join("\n"),
         notify  => Service["nftables"],
diff --git a/spec/acceptance/default_spec.rb b/spec/acceptance/default_spec.rb
index d0f4fe4..fac6da7 100644
--- a/spec/acceptance/default_spec.rb
+++ b/spec/acceptance/default_spec.rb
@@ -11,6 +11,14 @@ describe 'nftables class' do
       class { 'nftables':
         firewalld_enable => false,
       }
+      $config_path = case $facts['os']['family'] {
+        'Archlinux': {
+          '/etc/nftables.conf'
+        }
+        default: {
+          '/etc/sysconfig/nftables.conf'
+        }
+      }
       # nftables cannot be started in docker so replace service with a validation only.
       systemd::dropin_file{"zzz_docker_nft.conf":
         ensure  => present,
@@ -18,9 +26,9 @@ describe 'nftables class' do
         content => [
           "[Service]",
           "ExecStart=",
-          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "ExecReload=",
-          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "",
           ].join("\n"),
         notify  => Service["nftables"],
@@ -58,6 +66,14 @@ describe 'nftables class' do
       nftables::rule{'default_out-junk':
         content => 'A load of junk',
       }
+      $config_path = case $facts['os']['family'] {
+        'Archlinux': {
+          '/etc/nftables.conf'
+        }
+        default: {
+          '/etc/sysconfig/nftables.conf'
+        }
+      }
       # nftables cannot be started in docker so replace service with a validation only.
       systemd::dropin_file{"zzz_docker_nft.conf":
         ensure  => present,
@@ -65,9 +81,9 @@ describe 'nftables class' do
         content => [
           "[Service]",
           "ExecStart=",
-          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "ExecReload=",
-          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "",
           ].join("\n"),
         notify  => Service["nftables"],
@@ -90,6 +106,14 @@ describe 'nftables class' do
         inet_filter => false,
         nat => false,
       }
+      $config_path = case $facts['os']['family'] {
+        'Archlinux': {
+          '/etc/nftables.conf'
+        }
+        default: {
+          '/etc/sysconfig/nftables.conf'
+        }
+      }
       # nftables cannot be started in docker so replace service with a validation only.
       systemd::dropin_file{"zzz_docker_nft.conf":
         ensure  => present,
@@ -97,9 +121,9 @@ describe 'nftables class' do
         content => [
           "[Service]",
           "ExecStart=",
-          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "ExecReload=",
-          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "",
           ].join("\n"),
         notify  => Service["nftables"],
@@ -122,6 +146,14 @@ describe 'nftables class' do
         nat => true,
         nat_table_name => 'mycustomtablename',
       }
+      $config_path = case $facts['os']['family'] {
+        'Archlinux': {
+          '/etc/nftables.conf'
+        }
+        default: {
+          '/etc/sysconfig/nftables.conf'
+        }
+      }
       # nftables cannot be started in docker so replace service with a validation only.
       systemd::dropin_file{"zzz_docker_nft.conf":
         ensure  => present,
@@ -129,9 +161,9 @@ describe 'nftables class' do
         content => [
           "[Service]",
           "ExecStart=",
-          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecStart=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "ExecReload=",
-          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf",
+          "ExecReload=/sbin/nft -c -I /etc/nftables/puppet -f $config_path",
           "",
           ].join("\n"),
         notify  => Service["nftables"],
diff --git a/spec/classes/nftables_spec.rb b/spec/classes/nftables_spec.rb
index 4b1edd0..52141e0 100644
--- a/spec/classes/nftables_spec.rb
+++ b/spec/classes/nftables_spec.rb
@@ -14,6 +14,15 @@ describe 'nftables' do
       it { is_expected.to contain_package('nftables') }
 
       it {
+        is_expected.to contain_file('/etc/nftables').with(
+          ensure: 'directory',
+          owner: 'root',
+          group: 'root',
+          mode: '0750'
+        )
+      }
+
+      it {
         expect(subject).to contain_file('/etc/nftables/puppet.nft').with(
           ensure: 'file',
           owner: 'root',
@@ -73,18 +82,33 @@ describe 'nftables' do
         )
       }
 
-      it {
-        expect(subject).to contain_systemd__dropin_file('puppet_nft.conf').with(
-          content: %r{^ExecReload=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf$}
-        )
-      }
+      if os_facts[:os]['family'] == 'Archlinux'
+        it {
+          expect(subject).to contain_systemd__dropin_file('puppet_nft.conf').with(
+            content: %r{^ExecReload=/sbin/nft -I /etc/nftables/puppet -f /etc/nftables.conf$}
+          )
+        }
 
-      it {
-        expect(subject).to contain_service('firewalld').with(
-          ensure: 'stopped',
-          enable: 'mask'
-        )
-      }
+        it {
+          expect(subject).to contain_service('firewalld').with(
+            ensure: 'stopped',
+            enable: false
+          )
+        }
+      else
+        it {
+          expect(subject).to contain_systemd__dropin_file('puppet_nft.conf').with(
+            content: %r{^ExecReload=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf$}
+          )
+        }
+
+        it {
+          expect(subject).to contain_service('firewalld').with(
+            ensure: 'stopped',
+            enable: 'mask'
+          )
+        }
+      end
 
       it { is_expected.to contain_class('nftables::inet_filter') }
       it { is_expected.to contain_class('nftables::ip_nat') }
diff --git a/templates/systemd/puppet_nft.conf.epp b/templates/systemd/puppet_nft.conf.epp
new file mode 100644
index 0000000..b975ab9
--- /dev/null
+++ b/templates/systemd/puppet_nft.conf.epp
@@ -0,0 +1,7 @@
+# Puppet Deployed
+[Service]
+RemainAfterExit=yes
+ExecStart=
+ExecStart=/sbin/nft -I /etc/nftables/puppet -f <%= $configuration_path %>
+ExecReload=
+ExecReload=/sbin/nft -I /etc/nftables/puppet -f <%= $configuration_path %>
