commit e4c322229612b708ab6e07baf719ca4bd2f61d91
Author: Nacho Barrientos <nacho.barrientos@cern.ch>
Date:   Fri Nov 13 13:53:19 2020 +0100

    Use concat for table conf generation
    
    This way other components of the module will be able to add extra stuff
    to the table definitions like sets.

diff --git a/files/config/puppet-inet-filter.nft b/files/config/puppet-inet-filter.nft
index 39835ec..71af3be 100644
--- a/files/config/puppet-inet-filter.nft
+++ b/files/config/puppet-inet-filter.nft
@@ -1,4 +1,3 @@
-table inet filter {
   include "/etc/nftables/puppet/inet-filter-chain-*.nft"
 
   # something we want for all
@@ -11,4 +10,3 @@ table inet filter {
     ip protocol icmp icmp type echo-request limit rate 4/second accept
     ip6 nexthdr ipv6-icmp icmpv6 type echo-request limit rate 4/second accept
   }
-}
diff --git a/files/config/puppet-ip-nat.nft b/files/config/puppet-ip-nat.nft
index 4caee69..a08867e 100644
--- a/files/config/puppet-ip-nat.nft
+++ b/files/config/puppet-ip-nat.nft
@@ -1,3 +1 @@
-table ip nat {
   include "/etc/nftables/puppet/ip-nat-chain-*.nft"
-}
diff --git a/files/config/puppet-ip6-nat.nft b/files/config/puppet-ip6-nat.nft
index 83a0255..2202b46 100644
--- a/files/config/puppet-ip6-nat.nft
+++ b/files/config/puppet-ip6-nat.nft
@@ -1,3 +1 @@
-table ip6 nat {
   include "/etc/nftables/puppet/ip6-nat-chain-*.nft"
-}
diff --git a/manifests/config.pp b/manifests/config.pp
index 475978e..036aa45 100644
--- a/manifests/config.pp
+++ b/manifests/config.pp
@@ -5,21 +5,46 @@ define nftables::config(
   Optional[Variant[String,Array[String,1]]]
     $source = undef,
 ){
-  Package['nftables'] -> file{
-    "/etc/nftables/puppet/${name}.nft":
-      ensure => file,
-      owner  => root,
-      group  => root,
-      mode   => '0640',
+  $concat_name = "nftables-${name}"
+
+  Package['nftables'] -> concat{
+    $concat_name:
+      path           => "/etc/nftables/puppet/${name}.nft",
+      ensure_newline => true,
+      owner          => root,
+      group          => root,
+      mode           => '0640',
   } ~> Service['nftables']
 
+  $data = split($name, '-')
+
+  concat::fragment {
+    "${concat_name}-header":
+      target  => $concat_name,
+      order   => '00',
+      content => "table ${data[0]} ${data[1]} {",
+  }
+
   if $source {
-    File["/etc/nftables/puppet/${name}.nft"]{
-      source => $source,
+    concat::fragment {
+      "${concat_name}-body":
+        target => $concat_name,
+        order  => 98,
+        source => $source,
     }
   } else {
-    File["/etc/nftables/puppet/${name}.nft"]{
-      content => $content,
+    concat::fragment {
+      "${concat_name}-body":
+        target  => $concat_name,
+        order   => '98',
+        content => $content,
     }
   }
+
+  concat::fragment {
+    "${concat_name}-footer":
+      target  => $concat_name,
+      order   => '99',
+      content => '}',
+  }
 }
diff --git a/spec/classes/inet_filter_spec.rb b/spec/classes/inet_filter_spec.rb
index f7d1e8d..43ba59b 100644
--- a/spec/classes/inet_filter_spec.rb
+++ b/spec/classes/inet_filter_spec.rb
@@ -10,14 +10,38 @@ describe 'nftables' do
       it { is_expected.to compile }
 
       it {
-        is_expected.to contain_file('/etc/nftables/puppet/inet-filter.nft').with(
-          ensure: 'file',
+        is_expected.to contain_concat('nftables-inet-filter').with(
+          path:   '/etc/nftables/puppet/inet-filter.nft',
+          ensure: 'present',
           owner:  'root',
           group:  'root',
           mode:   '0640',
         )
       }
 
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-header').with(
+          target:  'nftables-inet-filter',
+          content: %r{^table inet filter \{$},
+          order:   '00',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-body').with(
+          target:  'nftables-inet-filter',
+          order:   '98',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-inet-filter-footer').with(
+          target:  'nftables-inet-filter',
+          content: %r{^\}$},
+          order:   '99',
+        )
+      }
+
       context 'chain input' do
         it {
           is_expected.to contain_concat('nftables-inet-filter-chain-INPUT').with(
diff --git a/spec/classes/ip_nat_spec.rb b/spec/classes/ip_nat_spec.rb
index b9e5481..23e9eed 100644
--- a/spec/classes/ip_nat_spec.rb
+++ b/spec/classes/ip_nat_spec.rb
@@ -10,8 +10,9 @@ describe 'nftables' do
       it { is_expected.to compile }
 
       it {
-        is_expected.to contain_file('/etc/nftables/puppet/ip-nat.nft').with(
-          ensure: 'file',
+        is_expected.to contain_concat('nftables-ip-nat').with(
+          path:   '/etc/nftables/puppet/ip-nat.nft',
+          ensure: 'present',
           owner:  'root',
           group:  'root',
           mode:   '0640',
@@ -19,14 +20,61 @@ describe 'nftables' do
       }
 
       it {
-        is_expected.to contain_file('/etc/nftables/puppet/ip6-nat.nft').with(
-          ensure: 'file',
+        is_expected.to contain_concat__fragment('nftables-ip-nat-header').with(
+          target:  'nftables-ip-nat',
+          content: %r{^table ip nat \{$},
+          order:   '00',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-ip-nat-body').with(
+          target:  'nftables-ip-nat',
+          order:   '98',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-ip-nat-footer').with(
+          target:  'nftables-ip-nat',
+          content: %r{^\}$},
+          order:   '99',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat('nftables-ip6-nat').with(
+          path:   '/etc/nftables/puppet/ip6-nat.nft',
+          ensure: 'present',
           owner:  'root',
           group:  'root',
           mode:   '0640',
         )
       }
 
+      it {
+        is_expected.to contain_concat__fragment('nftables-ip6-nat-header').with(
+          target:  'nftables-ip6-nat',
+          content: %r{^table ip6 nat \{$},
+          order:   '00',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-ip6-nat-body').with(
+          target:  'nftables-ip6-nat',
+          order:   '98',
+        )
+      }
+
+      it {
+        is_expected.to contain_concat__fragment('nftables-ip6-nat-footer').with(
+          target:  'nftables-ip6-nat',
+          content: %r{^\}$},
+          order:   '99',
+        )
+      }
+
       context 'table ip nat chain prerouting' do
         it {
           is_expected.to contain_concat('nftables-ip-nat-chain-PREROUTING').with(
