diff --git a/REFERENCE.md b/REFERENCE.md
index c6f9b3f2e..448c3d828 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -82,6 +82,7 @@ environment.
* [`glob`](#glob): Uses same patterns as Dir#glob.
* [`grep`](#grep): This function searches through an array and returns any elements that match
the provided regular expression.
+* [`has_interface_with`](#has_interface_with): DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
* [`has_interface_with`](#has_interface_with): Returns boolean based on kind and value.
* [`has_ip_address`](#has_ip_address): Returns true if the client has the requested IP address on some interface.
* [`has_ip_network`](#has_ip_network): Returns true if the client has an IP address within the requested network.
@@ -179,6 +180,7 @@ the provided regular expression.
* [`stdlib::ensure`](#stdlib--ensure): function to cast ensure parameter to resource specific value
* [`stdlib::extname`](#stdlib--extname): Returns the Extension (the Portion of Filename in Path starting from the
last Period).
+* [`stdlib::has_interface_with`](#stdlib--has_interface_with): Returns boolean based on network interfaces present and their attribute values.
* [`stdlib::ip_in_range`](#stdlib--ip_in_range): Returns true if the ipaddress is within the given CIDRs
* [`stdlib::sha256`](#stdlib--sha256): Run a SHA256 calculation against a given value.
* [`stdlib::start_with`](#stdlib--start_with): Returns true if str starts with one of the prefixes given. Each of the prefixes should be a String.
@@ -2584,6 +2586,24 @@ Returns: `Any` array of elements that match the provided regular expression.
grep(['aaa','bbb','ccc','aaaddd'], 'aaa') # Returns ['aaa','aaaddd']
```
+### `has_interface_with`
+
+Type: Ruby 4.x API
+
+DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
+
+#### `has_interface_with(Any *$args)`
+
+The has_interface_with function.
+
+Returns: `Any`
+
+##### `*args`
+
+Data type: `Any`
+
+
+
### `has_interface_with`
Type: Ruby 3.x API
@@ -4881,6 +4901,64 @@ Data type: `String`
The Filename
+### `stdlib::has_interface_with`
+
+Type: Ruby 4.x API
+
+Can be called with one, or two arguments.
+
+#### `stdlib::has_interface_with(String[1] $interface)`
+
+The stdlib::has_interface_with function.
+
+Returns: `Boolean` Returns `true` if `interface` exists and `false` otherwise
+
+##### Examples
+
+###### When called with a single argument, the presence of the interface is checked
+
+```puppet
+stdlib::has_interface_with('lo') # Returns `true`
+```
+
+##### `interface`
+
+Data type: `String[1]`
+
+The name of an interface
+
+#### `stdlib::has_interface_with(Enum['macaddress','netmask','ipaddress','network','ip','mac'] $kind, String[1] $value)`
+
+The stdlib::has_interface_with function.
+
+Returns: `Boolean` Returns `true` if any of the interfaces in the `networking` fact has a `kind` attribute with the value `value`. Otherwise returns `false`
+
+##### Examples
+
+###### Checking if an interface exists with a given mac address
+
+```puppet
+stdlib::has_interface_with('macaddress', 'x:x:x:x:x:x') # Returns `false`
+```
+
+###### Checking if an interface exists with a given IP address
+
+```puppet
+stdlib::has_interface_with('ipaddress', '127.0.0.1') # Returns `true`
+```
+
+##### `kind`
+
+Data type: `Enum['macaddress','netmask','ipaddress','network','ip','mac']`
+
+A supported interface attribute
+
+##### `value`
+
+Data type: `String[1]`
+
+The value of the attribute
+
### `stdlib::ip_in_range`
Type: Ruby 4.x API
diff --git a/lib/puppet/functions/has_interface_with.rb b/lib/puppet/functions/has_interface_with.rb
new file mode 100644
index 000000000..d166bb42f
--- /dev/null
+++ b/lib/puppet/functions/has_interface_with.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+# @summary DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
+Puppet::Functions.create_function(:has_interface_with) do
+ dispatch :deprecation_gen do
+ repeated_param 'Any', :args
+ end
+ def deprecation_gen(*args)
+ call_function('deprecation', 'has_interface_with', 'This method is deprecated, please use stdlib::has_interface_with instead.')
+ call_function('stdlib::has_interface_with', *args)
+ end
+end
diff --git a/lib/puppet/functions/stdlib/has_interface_with.rb b/lib/puppet/functions/stdlib/has_interface_with.rb
new file mode 100644
index 000000000..3bfbc0f42
--- /dev/null
+++ b/lib/puppet/functions/stdlib/has_interface_with.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+# @summary Returns boolean based on network interfaces present and their attribute values.
+#
+# Can be called with one, or two arguments.
+Puppet::Functions.create_function(:'stdlib::has_interface_with') do
+ # @param interface
+ # The name of an interface
+ # @return [Boolean] Returns `true` if `interface` exists and `false` otherwise
+ # @example When called with a single argument, the presence of the interface is checked
+ # stdlib::has_interface_with('lo') # Returns `true`
+ dispatch :has_interface do
+ param 'String[1]', :interface
+ return_type 'Boolean'
+ end
+
+ # @param kind
+ # A supported interface attribute
+ # @param value
+ # The value of the attribute
+ # @return [Boolean] Returns `true` if any of the interfaces in the `networking` fact has a `kind` attribute with the value `value`. Otherwise returns `false`
+ # @example Checking if an interface exists with a given mac address
+ # stdlib::has_interface_with('macaddress', 'x:x:x:x:x:x') # Returns `false`
+ # @example Checking if an interface exists with a given IP address
+ # stdlib::has_interface_with('ipaddress', '127.0.0.1') # Returns `true`
+ dispatch :has_interface_with do
+ param "Enum['macaddress','netmask','ipaddress','network','ip','mac']", :kind
+ param 'String[1]', :value
+ return_type 'Boolean'
+ end
+
+ def has_interface(interface) # rubocop:disable Naming/PredicateName
+ interfaces.key? interface
+ end
+
+ def has_interface_with(kind, value) # rubocop:disable Naming/PredicateName
+ # For compatibility with older version of function that used the legacy facts, alias `ip` with `ipaddress` and `mac` with `macaddress`
+ kind = 'ip' if kind == 'ipaddress'
+ kind = 'mac' if kind == 'macaddress'
+
+ interfaces.any? { |_interface, params| params[kind] == value }
+ end
+
+ def interfaces
+ closure_scope['facts']['networking']['interfaces']
+ end
+end
diff --git a/spec/functions/has_interface_with_spec.rb b/spec/functions/has_interface_with_spec.rb
index d55f58ead..45d4d9680 100644
--- a/spec/functions/has_interface_with_spec.rb
+++ b/spec/functions/has_interface_with_spec.rb
@@ -4,13 +4,49 @@
describe 'has_interface_with' do
it { is_expected.not_to eq(nil) }
- it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
- it { is_expected.to run.with_params('one', 'two', 'three').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
+ it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{expects between 1 and 2 arguments, got none}) }
+ it { is_expected.to run.with_params('one', 'two', 'three').and_raise_error(ArgumentError, %r{expects between 1 and 2 arguments, got 3}) }
# We need to mock out the Facts so we can specify how we expect this function
# to behave on different platforms.
context 'when on Mac OS X Systems' do
- let(:facts) { { interfaces: 'lo0,gif0,stf0,en1,p2p0,fw0,en0,vmnet1,vmnet8,utun0' } }
+ let(:facts) do
+ {
+ 'networking' => {
+ 'interfaces' => {
+ 'lo0' => {
+ 'bindings' => [
+ {
+ 'address' => '127.0.0.1',
+ 'netmask' => '255.0.0.0',
+ 'network' => '127.0.0.0'
+ },
+ ],
+ "bindings6": [
+ {
+ 'address' => '::1',
+ 'netmask' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'network' => '::1'
+ },
+ {
+ 'address' => 'fe80::1',
+ 'netmask' => 'ffff:ffff:ffff:ffff::',
+ 'network' => 'fe80::'
+ },
+ ],
+ 'ip' => '127.0.0.1',
+ 'ip6' => '::1',
+ 'mtu' => 16_384,
+ 'netmask' => '255.0.0.0',
+ 'netmask6' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'network' => '127.0.0.0',
+ 'network6' => '::1',
+ 'scope6' => 'host'
+ },
+ }
+ }
+ }
+ end
it { is_expected.to run.with_params('lo0').and_return(true) }
it { is_expected.to run.with_params('lo').and_return(false) }
@@ -19,23 +55,93 @@
context 'when on Linux Systems' do
let(:facts) do
{
- interfaces: 'eth0,lo',
- ipaddress: '10.0.0.1',
- ipaddress_lo: '127.0.0.1',
- ipaddress_eth0: '10.0.0.1',
- muppet: 'kermit',
- muppet_lo: 'mspiggy',
- muppet_eth0: 'kermit',
+ 'networking' => {
+ 'interfaces' => {
+ 'eth0' => {
+ 'bindings' => [
+ {
+ 'address' => '10.0.2.15',
+ 'netmask' => '255.255.255.0',
+ 'network' => '10.0.2.0'
+ },
+ ],
+ 'bindings6' => [
+ {
+ 'address' => 'fe80::5054:ff:fe8a:fee6',
+ 'netmask' => 'ffff:ffff:ffff:ffff::',
+ 'network' => 'fe80::'
+ },
+ ],
+ 'dhcp' => '10.0.2.2',
+ 'ip' => '10.0.2.15',
+ 'ip6' => 'fe80::5054:ff:fe8a:fee6',
+ 'mac' => '52:54:00:8a:fe:e6',
+ 'mtu' => 1500,
+ 'netmask' => '255.255.255.0',
+ 'netmask6' => 'ffff:ffff:ffff:ffff::',
+ 'network' => '10.0.2.0',
+ 'network6' => 'fe80::'
+ },
+ 'eth1' => {
+ 'bindings' => [
+ {
+ 'address' => '10.0.0.2',
+ 'netmask' => '255.255.255.0',
+ 'network' => '10.0.0.0'
+ },
+ ],
+ 'bindings6' => [
+ {
+ 'address' => 'fe80::a00:27ff:fed1:d28c',
+ 'netmask' => 'ffff:ffff:ffff:ffff::',
+ 'network' => 'fe80::'
+ },
+ ],
+ 'ip' => '10.0.0.2',
+ 'ip6' => 'fe80::a00:27ff:fed1:d28c',
+ 'mac' => '08:00:27:d1:d2:8c',
+ 'mtu' => 1500,
+ 'netmask' => '255.255.255.0',
+ 'netmask6' => 'ffff:ffff:ffff:ffff::',
+ 'network' => '10.0.0.0',
+ 'network6' => 'fe80::'
+ },
+ 'lo' => {
+ 'bindings' => [
+ {
+ 'address' => '127.0.0.1',
+ 'netmask' => '255.0.0.0',
+ 'network' => '127.0.0.0'
+ },
+ ],
+ 'bindings6' => [
+ {
+ 'address' => '::1',
+ 'netmask' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'network' => '::1'
+ },
+ ],
+ 'ip' => '127.0.0.1',
+ 'ip6' => '::1',
+ 'mtu' => 65_536,
+ 'netmask' => '255.0.0.0',
+ 'netmask6' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ 'network' => '127.0.0.0',
+ 'network6' => '::1'
+ }
+ },
+ },
}
end
it { is_expected.to run.with_params('lo').and_return(true) }
it { is_expected.to run.with_params('lo0').and_return(false) }
it { is_expected.to run.with_params('ipaddress', '127.0.0.1').and_return(true) }
- it { is_expected.to run.with_params('ipaddress', '10.0.0.1').and_return(true) }
+ it { is_expected.to run.with_params('ipaddress', '10.0.0.2').and_return(true) }
it { is_expected.to run.with_params('ipaddress', '8.8.8.8').and_return(false) }
- it { is_expected.to run.with_params('muppet', 'kermit').and_return(true) }
- it { is_expected.to run.with_params('muppet', 'mspiggy').and_return(true) }
- it { is_expected.to run.with_params('muppet', 'bigbird').and_return(false) }
+ it { is_expected.to run.with_params('netmask', '255.255.255.0').and_return(true) }
+ it { is_expected.to run.with_params('macaddress', '52:54:00:8a:fe:e6').and_return(true) }
+ it { is_expected.to run.with_params('network', '42.0.0.0').and_return(false) }
+ it { is_expected.to run.with_params('network', '10.0.0.0').and_return(true) }
end
end