|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require 'puppet_x' |
| 4 | +require 'spec_helper' |
| 5 | +require 'puppet/resource_api' |
| 6 | +require 'puppet_x/puppetlabs/firewall/utility' |
| 7 | + |
| 8 | +RSpec.describe PuppetX::Firewall::Utility do # rubocop:disable RSpec/FilePath |
| 9 | + let(:utility) { described_class } |
| 10 | + |
| 11 | + describe '#persist_iptables' do |
| 12 | + before(:each) { Facter.clear } |
| 13 | + |
| 14 | + let(:context) { Puppet::ResourceApi::PuppetContext.new(Puppet::Type.type('firewall').type_definition.definition) } |
| 15 | + |
| 16 | + context 'when proto is IPv4' do |
| 17 | + let(:proto) { 'IPv4' } |
| 18 | + |
| 19 | + it 'and OS family is RedHat' do |
| 20 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'RedHat' }) |
| 21 | + expect(Puppet::Provider).to receive(:execute).with(['/usr/libexec/iptables/iptables.init', 'save']) |
| 22 | + |
| 23 | + utility.persist_iptables(context, 'test', proto) |
| 24 | + end |
| 25 | + |
| 26 | + it 'and OS family is Debian' do |
| 27 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'Debian' }) |
| 28 | + allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.4') |
| 29 | + expect(Puppet::Provider).to receive(:execute).with(['/usr/sbin/service', 'iptables-persistent', 'save']) |
| 30 | + |
| 31 | + utility.persist_iptables(context, 'test', proto) |
| 32 | + end |
| 33 | + |
| 34 | + it 'and OS family is Archlinux' do |
| 35 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'Archlinux' }) |
| 36 | + expect(Puppet::Provider).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules']) |
| 37 | + |
| 38 | + utility.persist_iptables(context, 'test', proto) |
| 39 | + end |
| 40 | + |
| 41 | + it 'and OS family is Suse' do |
| 42 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'Suse' }) |
| 43 | + expect(Puppet::Provider).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/sysconfig/iptables']) |
| 44 | + |
| 45 | + utility.persist_iptables(context, 'test', proto) |
| 46 | + end |
| 47 | + end |
| 48 | + |
| 49 | + context 'when proto is IPv6' do |
| 50 | + let(:proto) { 'IPv6' } |
| 51 | + |
| 52 | + it 'and OS family is RedHat' do |
| 53 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'RedHat' }) |
| 54 | + expect(Puppet::Provider).to receive(:execute).with(['/usr/libexec/iptables/ip6tables.init', 'save']) |
| 55 | + |
| 56 | + utility.persist_iptables(context, 'test', proto) |
| 57 | + end |
| 58 | + |
| 59 | + it 'and OS family is Debian' do |
| 60 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'Debian' }) |
| 61 | + allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('1.2') |
| 62 | + expect(Puppet::Provider).to receive(:execute).with(['/usr/sbin/service', 'netfilter-persistent', 'save']) |
| 63 | + |
| 64 | + utility.persist_iptables(context, 'test', proto) |
| 65 | + end |
| 66 | + |
| 67 | + it 'and OS family is Archlinux' do |
| 68 | + allow(Facter.fact('os')).to receive(:value).and_return({ 'family' => 'Archlinux' }) |
| 69 | + expect(Puppet::Provider).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/ip6tables-save > /etc/iptables/ip6tables.rules']) |
| 70 | + |
| 71 | + utility.persist_iptables(context, 'test', proto) |
| 72 | + end |
| 73 | + end |
| 74 | + end |
| 75 | + |
| 76 | + describe '#create_absent' do |
| 77 | + it { |
| 78 | + expect(utility.create_absent(:name, { chain: 'INPUT', table: 'filter', protocol: 'IPv4' })).to eql({ chain: 'INPUT', table: 'filter', protocol: 'IPv4', ensure: 'absent' }) |
| 79 | + } |
| 80 | + |
| 81 | + it { expect(utility.create_absent(:name, 'test')).to eql({ name: 'test', ensure: 'absent' }) } |
| 82 | + end |
| 83 | + |
| 84 | + describe '#host_to_ip' do |
| 85 | + it { |
| 86 | + allow(Resolv).to receive(:each_address).at_least(:once).with('puppetlabs.com').and_yield('96.126.112.51').and_yield('2001:DB8:4650::13:8A') |
| 87 | + expect(utility.host_to_ip('puppetlabs.com', 'IPv4')).to eql '96.126.112.51/32' |
| 88 | + expect(utility.host_to_ip('puppetlabs.com', 'IPv6')).to eql '2001:db8:4650::13:8a/128' |
| 89 | + } |
| 90 | + |
| 91 | + it { expect(utility.host_to_ip('96.126.112.51')).to eql '96.126.112.51/32' } |
| 92 | + it { expect(utility.host_to_ip('96.126.112.51/32')).to eql '96.126.112.51/32' } |
| 93 | + it { expect(utility.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334')).to eql '2001:db8:85a3::8a2e:370:7334/128' } |
| 94 | + it { expect(utility.host_to_ip('2001:db8:1234::/48')).to eql '2001:db8:1234::/48' } |
| 95 | + it { expect(utility.host_to_ip('0.0.0.0/0')).to be_nil } |
| 96 | + it { expect(utility.host_to_ip('::/0')).to be_nil } |
| 97 | + end |
| 98 | + |
| 99 | + describe '#host_to_mask' do |
| 100 | + it { |
| 101 | + allow(Resolv).to receive(:each_address).at_least(:once).with('puppetlabs.com').and_yield('96.126.112.51').and_yield('2001:DB8:4650::13:8A') |
| 102 | + expect(utility.host_to_mask('puppetlabs.com', 'IPv4')).to eql '96.126.112.51/32' |
| 103 | + expect(utility.host_to_mask('! puppetlabs.com', 'IPv6')).to eql '! 2001:db8:4650::13:8a/128' |
| 104 | + } |
| 105 | + |
| 106 | + it { expect(utility.host_to_mask('96.126.112.51', 'IPv4')).to eql '96.126.112.51/32' } |
| 107 | + it { expect(utility.host_to_mask('!96.126.112.51', 'IPv4')).to eql '! 96.126.112.51/32' } |
| 108 | + it { expect(utility.host_to_mask('96.126.112.51/32', 'IPv4')).to eql '96.126.112.51/32' } |
| 109 | + it { expect(utility.host_to_mask('! 96.126.112.51/32', 'IPv4')).to eql '! 96.126.112.51/32' } |
| 110 | + it { expect(utility.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334', 'IPv6')).to eql '2001:db8:85a3::8a2e:370:7334/128' } |
| 111 | + it { expect(utility.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334', 'IPv6')).to eql '! 2001:db8:85a3::8a2e:370:7334/128' } |
| 112 | + it { expect(utility.host_to_mask('2001:db8:1234::/48', 'IPv6')).to eql '2001:db8:1234::/48' } |
| 113 | + it { expect(utility.host_to_mask('! 2001:db8:1234::/48', 'IPv6')).to eql '! 2001:db8:1234::/48' } |
| 114 | + it { expect(utility.host_to_mask('0.0.0.0/0', 'IPv4')).to be_nil } |
| 115 | + it { expect(utility.host_to_mask('!0.0.0.0/0', 'IPv4')).to be_nil } |
| 116 | + it { expect(utility.host_to_mask('::/0', 'IPv6')).to be_nil } |
| 117 | + it { expect(utility.host_to_mask('! ::/0', 'IPv6')).to be_nil } |
| 118 | + end |
| 119 | + |
| 120 | + describe '#icmp_name_to_number' do |
| 121 | + context 'with proto unsupported' do |
| 122 | + ['inet5', 'inet8', 'foo'].each do |proto| |
| 123 | + it "rejects invalid proto #{proto}" do |
| 124 | + expect { utility.icmp_name_to_number('echo-reply', proto) } |
| 125 | + .to raise_error(ArgumentError, "unsupported protocol family '#{proto}'") |
| 126 | + end |
| 127 | + end |
| 128 | + end |
| 129 | + |
| 130 | + context 'with proto IPv4' do |
| 131 | + let(:proto) { 'IPv4' } |
| 132 | + |
| 133 | + it { expect(utility.icmp_name_to_number('echo-reply', proto)).to eql '0' } |
| 134 | + it { expect(utility.icmp_name_to_number('destination-unreachable', proto)).to eql '3' } |
| 135 | + it { expect(utility.icmp_name_to_number('source-quench', proto)).to eql '4' } |
| 136 | + it { expect(utility.icmp_name_to_number('redirect', proto)).to eql '6' } |
| 137 | + it { expect(utility.icmp_name_to_number('echo-request', proto)).to eql '8' } |
| 138 | + it { expect(utility.icmp_name_to_number('router-advertisement', proto)).to eql '9' } |
| 139 | + it { expect(utility.icmp_name_to_number('router-solicitation', proto)).to eql '10' } |
| 140 | + it { expect(utility.icmp_name_to_number('time-exceeded', proto)).to eql '11' } |
| 141 | + it { expect(utility.icmp_name_to_number('parameter-problem', proto)).to eql '12' } |
| 142 | + it { expect(utility.icmp_name_to_number('timestamp-request', proto)).to eql '13' } |
| 143 | + it { expect(utility.icmp_name_to_number('timestamp-reply', proto)).to eql '14' } |
| 144 | + it { expect(utility.icmp_name_to_number('address-mask-request', proto)).to eql '17' } |
| 145 | + it { expect(utility.icmp_name_to_number('address-mask-reply', proto)).to eql '18' } |
| 146 | + end |
| 147 | + |
| 148 | + context 'with proto IPv6' do |
| 149 | + let(:proto) { 'IPv6' } |
| 150 | + |
| 151 | + it { expect(utility.icmp_name_to_number('destination-unreachable', proto)).to eql '1' } |
| 152 | + it { expect(utility.icmp_name_to_number('time-exceeded', proto)).to eql '3' } |
| 153 | + it { expect(utility.icmp_name_to_number('parameter-problem', proto)).to eql '4' } |
| 154 | + it { expect(utility.icmp_name_to_number('echo-request', proto)).to eql '128' } |
| 155 | + it { expect(utility.icmp_name_to_number('echo-reply', proto)).to eql '129' } |
| 156 | + it { expect(utility.icmp_name_to_number('router-solicitation', proto)).to eql '133' } |
| 157 | + it { expect(utility.icmp_name_to_number('router-advertisement', proto)).to eql '134' } |
| 158 | + it { expect(utility.icmp_name_to_number('neighbour-solicitation', proto)).to eql '135' } |
| 159 | + it { expect(utility.icmp_name_to_number('neighbour-advertisement', proto)).to eql '136' } |
| 160 | + it { expect(utility.icmp_name_to_number('redirect', proto)).to eql '137' } |
| 161 | + end |
| 162 | + end |
| 163 | + |
| 164 | + describe '#log_level_name_to_number' do |
| 165 | + it { expect(utility.log_level_name_to_number('2')).to eql '2' } |
| 166 | + it { expect(utility.log_level_name_to_number('4')).to eql '4' } |
| 167 | + it { expect(utility.log_level_name_to_number('panic')).to eql '0' } |
| 168 | + it { expect(utility.log_level_name_to_number('alert')).to eql '1' } |
| 169 | + it { expect(utility.log_level_name_to_number('crit')).to eql '2' } |
| 170 | + it { expect(utility.log_level_name_to_number('err')).to eql '3' } |
| 171 | + it { expect(utility.log_level_name_to_number('warn')).to eql '4' } |
| 172 | + it { expect(utility.log_level_name_to_number('not')).to eql '5' } |
| 173 | + it { expect(utility.log_level_name_to_number('info')).to eql '6' } |
| 174 | + it { expect(utility.log_level_name_to_number('debug')).to eql '7' } |
| 175 | + it { expect(utility.log_level_name_to_number('fail')).to be_nil } |
| 176 | + end |
| 177 | + |
| 178 | + describe '#to_hex32' do |
| 179 | + it { expect(utility.to_hex32('0')).to eql '0x0' } |
| 180 | + it { expect(utility.to_hex32('0x32')).to eql '0x32' } |
| 181 | + it { expect(utility.to_hex32('42')).to eql '0x2a' } |
| 182 | + it { expect(utility.to_hex32('4294967295')).to eql '0xffffffff' } |
| 183 | + it { expect(utility.to_hex32('4294967296')).to be_nil } |
| 184 | + it { expect(utility.to_hex32('-1')).to be_nil } |
| 185 | + it { expect(utility.to_hex32('bananas')).to be_nil } |
| 186 | + end |
| 187 | + |
| 188 | + describe '#mark_mask_to_hex' do |
| 189 | + it { expect(utility.mark_mask_to_hex('0')).to eql '0x0/0xffffffff' } |
| 190 | + it { expect(utility.mark_mask_to_hex('0x32/0')).to eql '0x32/0x0' } |
| 191 | + it { expect(utility.mark_mask_to_hex('42')).to eql '0x2a/0xffffffff' } |
| 192 | + it { expect(utility.mark_mask_to_hex('4294967295/42')).to eql '0xffffffff/0x2a' } |
| 193 | + end |
| 194 | + |
| 195 | + describe '#mark_to_hex' do |
| 196 | + it { expect(utility.mark_to_hex('0')).to eql '0x0' } |
| 197 | + it { expect(utility.mark_to_hex('! 0x32')).to eql '! 0x32' } |
| 198 | + it { expect(utility.mark_to_hex('42')).to eql '0x2a' } |
| 199 | + it { expect(utility.mark_to_hex('! 4294967295')).to eql '! 0xffffffff' } |
| 200 | + end |
| 201 | + |
| 202 | + describe '#proto_number_to_name' do |
| 203 | + it { expect(utility.proto_number_to_name('1')).to eql 'icmp' } |
| 204 | + it { expect(utility.proto_number_to_name('2')).to eql 'igmp' } |
| 205 | + it { expect(utility.proto_number_to_name('4')).to eql 'ipencap' } |
| 206 | + it { expect(utility.proto_number_to_name('6')).to eql 'tcp' } |
| 207 | + it { expect(utility.proto_number_to_name('7')).to eql 'cbt' } |
| 208 | + it { expect(utility.proto_number_to_name('17')).to eql 'udp' } |
| 209 | + it { expect(utility.proto_number_to_name('47')).to eql 'gre' } |
| 210 | + it { expect(utility.proto_number_to_name('50')).to eql 'esp' } |
| 211 | + it { expect(utility.proto_number_to_name('51')).to eql 'ah' } |
| 212 | + it { expect(utility.proto_number_to_name('89')).to eql 'ospf' } |
| 213 | + it { expect(utility.proto_number_to_name('103')).to eql 'pim' } |
| 214 | + it { expect(utility.proto_number_to_name('112')).to eql 'vrrp' } |
| 215 | + it { expect(utility.proto_number_to_name('132')).to eql 'sctp' } |
| 216 | + |
| 217 | + it 'rejects invalid number 619' do |
| 218 | + expect { utility.proto_number_to_name('619') }.to raise_error(ArgumentError, 'Unsupported proto number: 619') |
| 219 | + end |
| 220 | + end |
| 221 | + |
| 222 | + describe '#dscp_number_to_class' do |
| 223 | + it { expect(utility.dscp_number_to_class('0x0a')).to eql 'af11' } |
| 224 | + it { expect(utility.dscp_number_to_class('0x0c')).to eql 'af12' } |
| 225 | + it { expect(utility.dscp_number_to_class('0x0e')).to eql 'af13' } |
| 226 | + it { expect(utility.dscp_number_to_class('0x12')).to eql 'af21' } |
| 227 | + it { expect(utility.dscp_number_to_class('0x14')).to eql 'af22' } |
| 228 | + it { expect(utility.dscp_number_to_class('0x16')).to eql 'af23' } |
| 229 | + it { expect(utility.dscp_number_to_class('0x1a')).to eql 'af31' } |
| 230 | + it { expect(utility.dscp_number_to_class('0x1c')).to eql 'af32' } |
| 231 | + it { expect(utility.dscp_number_to_class('0x1e')).to eql 'af33' } |
| 232 | + it { expect(utility.dscp_number_to_class('0x22')).to eql 'af41' } |
| 233 | + it { expect(utility.dscp_number_to_class('0x24')).to eql 'af42' } |
| 234 | + it { expect(utility.dscp_number_to_class('0x26')).to eql 'af43' } |
| 235 | + it { expect(utility.dscp_number_to_class('0x08')).to eql 'cs1' } |
| 236 | + it { expect(utility.dscp_number_to_class('0x10')).to eql 'cs2' } |
| 237 | + it { expect(utility.dscp_number_to_class('0x18')).to eql 'cs3' } |
| 238 | + it { expect(utility.dscp_number_to_class('0x20')).to eql 'cs4' } |
| 239 | + it { expect(utility.dscp_number_to_class('0x28')).to eql 'cs5' } |
| 240 | + it { expect(utility.dscp_number_to_class('0x30')).to eql 'cs6' } |
| 241 | + it { expect(utility.dscp_number_to_class('0x38')).to eql 'cs7' } |
| 242 | + it { expect(utility.dscp_number_to_class('0x2e')).to eql 'ef' } |
| 243 | + it { expect(utility.dscp_number_to_class('0x66')).to be_nil } |
| 244 | + end |
| 245 | +end |
0 commit comments