From ff24e916798fa2f264480c9dd57d5b1e70c183d5 Mon Sep 17 00:00:00 2001 From: Benedikt Trefzer Date: Wed, 10 Dec 2025 16:27:15 +0100 Subject: [PATCH] refactor the libvirt_generate_mac_addresses function Include the 'source' key if available generate unique mac adresses for interface configs which are not including network name and portgroup by using the whole interface configuration (without the filter setting). Attention: these changes have the potetial to change your mac adresses upon upgrade ! --- REFERENCE.md | 12 ++++- .../libvirt_generate_mac_addresses.rb | 11 ++++- .../libvirt_generate_mac_addresses_spec.rb | 44 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/REFERENCE.md b/REFERENCE.md index 8d72878..c0436cd 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -2046,13 +2046,21 @@ Type: Ruby 3.x API Generates MAC addresses for all interfaces in the array which do not yet have an address specified. The MAC addresses are based on the domain name, network and -portgroup. The function libvirt_generate_mac is used to generate a single mac address. +portgroup or the whole interface configuration (excluding the 'filter' key, to avoid +mac changes when the firewall rules change).#{' '} +The function libvirt_generate_mac is used to generate a single mac address. +Additional remark: If the same network config is attached to a node twice +the resulting mac address is the same ! #### `libvirt_generate_mac_addresses(Any $hash)` Generates MAC addresses for all interfaces in the array which do not yet have an address specified. The MAC addresses are based on the domain name, network and -portgroup. The function libvirt_generate_mac is used to generate a single mac address. +portgroup or the whole interface configuration (excluding the 'filter' key, to avoid +mac changes when the firewall rules change).#{' '} +The function libvirt_generate_mac is used to generate a single mac address. +Additional remark: If the same network config is attached to a node twice +the resulting mac address is the same ! Returns: `Any` the interfacess with mac address diff --git a/lib/puppet/parser/functions/libvirt_generate_mac_addresses.rb b/lib/puppet/parser/functions/libvirt_generate_mac_addresses.rb index a8660ff..3769ae7 100644 --- a/lib/puppet/parser/functions/libvirt_generate_mac_addresses.rb +++ b/lib/puppet/parser/functions/libvirt_generate_mac_addresses.rb @@ -4,7 +4,11 @@ module Puppet::Parser::Functions newfunction(:libvirt_generate_mac_addresses, type: :rvalue, doc: <<-ENDHEREDOC) do |args| Generates MAC addresses for all interfaces in the array which do not yet have an address specified. The MAC addresses are based on the domain name, network and - portgroup. The function libvirt_generate_mac is used to generate a single mac address. + portgroup or the whole interface configuration (excluding the 'filter' key, to avoid + mac changes when the firewall rules change).#{' '} + The function libvirt_generate_mac is used to generate a single mac address. + Additional remark: If the same network config is attached to a node twice + the resulting mac address is the same ! @param hash of interfaces @return the interfacess with mac address @@ -21,8 +25,11 @@ module Puppet::Parser::Functions iface['mac'] = if iface['network'] function_libvirt_generate_mac([domain_name, iface['network'], iface['portgroup']]) + elsif iface['source'] && iface['source']['network'] + function_libvirt_generate_mac([domain_name, iface['source']['network'], iface['source']['portgroup']]) else - function_libvirt_generate_mac(['blah']) + function_libvirt_generate_mac([domain_name, iface.reject { |k, _v| k == 'filter' }.to_s]) + # iface.reject{|k, v| k == 'filter'} end end end diff --git a/spec/functions/libvirt_generate_mac_addresses_spec.rb b/spec/functions/libvirt_generate_mac_addresses_spec.rb index e1045b8..5cc9edc 100644 --- a/spec/functions/libvirt_generate_mac_addresses_spec.rb +++ b/spec/functions/libvirt_generate_mac_addresses_spec.rb @@ -37,10 +37,54 @@ { 'network' => 'test', 'portgroup' => 'he' }, { 'network' => 'test', 'portgroup' => 'll', 'mac' => '42:42:42:42:42:42' }, { 'network' => 'prod', 'portgroup' => 'oo' }, + { 'network' => 'nopo' }, ]).and_return([ { 'network' => 'test', 'portgroup' => 'he', 'mac' => '52:54:00:d8:54:bc' }, { 'network' => 'test', 'portgroup' => 'll', 'mac' => '42:42:42:42:42:42' }, { 'network' => 'prod', 'portgroup' => 'oo', 'mac' => '52:54:00:b8:cf:03' }, + { 'network' => 'nopo', 'mac' => '52:54:00:14:ec:f8' }, + ]) + } + end + + context 'with interface source and predefined mac' do + it { + is_expected.to run.with_params([ + { 'source' => { 'network' => 'test' }, 'mac' => '42:42::42:42:42:42' }, + ]).and_return([ + { 'source' => { 'network' => 'test' }, 'mac' => '42:42::42:42:42:42' }, + ]) + } + end + + context 'with multiple mixed source interfaces' do + it { + is_expected.to run.with_params([ + { 'source' => { 'network' => 'test', 'portgroup' => 'he' } }, + { 'source' => { 'network' => 'test', 'portgroup' => 'll' }, 'mac' => '42:42:42:42:42:42' }, + { 'source' => { 'network' => 'prod', 'portgroup' => 'oo' } }, + { 'source' => { 'network' => 'nopo' } }, + ]).and_return([ + { 'source' => { 'network' => 'test', 'portgroup' => 'he' }, 'mac' => '52:54:00:d8:54:bc' }, + { 'source' => { 'network' => 'test', 'portgroup' => 'll' }, 'mac' => '42:42:42:42:42:42' }, + { 'source' => { 'network' => 'prod', 'portgroup' => 'oo' }, 'mac' => '52:54:00:b8:cf:03' }, + { 'source' => { 'network' => 'nopo' }, 'mac' => '52:54:00:14:ec:f8' }, + ]) + } + end + + context 'with ignoring filter rules' do + it { + is_expected.to run.with_params([ + { 'interface_type' => 'bridge', 'source' => { 'bridge' => 'virbr0' } }, + { 'interface_type' => 'bridge', 'source' => { 'bridge' => 'virbr0' }, 'filter' => 'clean-traffic' }, + { 'interface_type' => 'user' }, + { 'interface_type' => 'user', 'filter' => 'clean-traffic' }, + ]).and_return([ + { 'interface_type' => 'bridge', 'source' => { 'bridge' => 'virbr0' }, 'mac' => '52:54:00:79:e5:40' }, + { 'interface_type' => 'bridge', 'source' => { 'bridge' => 'virbr0' }, 'filter' => 'clean-traffic', 'mac' => '52:54:00:79:e5:40' }, + { 'interface_type' => 'user', 'mac' => '52:54:00:12:36:36' }, + { 'interface_type' => 'user', 'filter' => 'clean-traffic', 'mac' => '52:54:00:12:36:36' }, ]) } end