Skip to content

Commit 1dd922d

Browse files
committed
Modernise has_interface_with function
Convert the function to the modern function API as a namespaced function and use the `networking` fact instead of legacy facts. A non-namespaced shim is also created (but marked deprecated), to preserve compatibility.
1 parent 39f1e80 commit 1dd922d

File tree

4 files changed

+258
-14
lines changed

4 files changed

+258
-14
lines changed

REFERENCE.md

+78
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ environment.
8282
* [`glob`](#glob): Uses same patterns as Dir#glob.
8383
* [`grep`](#grep): This function searches through an array and returns any elements that match
8484
the provided regular expression.
85+
* [`has_interface_with`](#has_interface_with): DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
8586
* [`has_interface_with`](#has_interface_with): Returns boolean based on kind and value.
8687
* [`has_ip_address`](#has_ip_address): Returns true if the client has the requested IP address on some interface.
8788
* [`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.
179180
* [`stdlib::ensure`](#stdlib--ensure): function to cast ensure parameter to resource specific value
180181
* [`stdlib::extname`](#stdlib--extname): Returns the Extension (the Portion of Filename in Path starting from the
181182
last Period).
183+
* [`stdlib::has_interface_with`](#stdlib--has_interface_with): Returns boolean based on network interfaces present and their attribute values.
182184
* [`stdlib::ip_in_range`](#stdlib--ip_in_range): Returns true if the ipaddress is within the given CIDRs
183185
* [`stdlib::sha256`](#stdlib--sha256): Run a SHA256 calculation against a given value.
184186
* [`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.
25842586
grep(['aaa','bbb','ccc','aaaddd'], 'aaa') # Returns ['aaa','aaaddd']
25852587
```
25862588

2589+
### <a name="has_interface_with"></a>`has_interface_with`
2590+
2591+
Type: Ruby 4.x API
2592+
2593+
DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
2594+
2595+
#### `has_interface_with(Any *$args)`
2596+
2597+
The has_interface_with function.
2598+
2599+
Returns: `Any`
2600+
2601+
##### `*args`
2602+
2603+
Data type: `Any`
2604+
2605+
2606+
25872607
### <a name="has_interface_with"></a>`has_interface_with`
25882608

25892609
Type: Ruby 3.x API
@@ -4881,6 +4901,64 @@ Data type: `String`
48814901

48824902
The Filename
48834903

4904+
### <a name="stdlib--has_interface_with"></a>`stdlib::has_interface_with`
4905+
4906+
Type: Ruby 4.x API
4907+
4908+
Can be called with one, or two arguments.
4909+
4910+
#### `stdlib::has_interface_with(String[1] $interface)`
4911+
4912+
The stdlib::has_interface_with function.
4913+
4914+
Returns: `Boolean` Returns `true` if `interface` exists and `false` otherwise
4915+
4916+
##### Examples
4917+
4918+
###### When called with a single argument, the presence of the interface is checked
4919+
4920+
```puppet
4921+
stdlib::has_interface_with('lo') # Returns `true`
4922+
```
4923+
4924+
##### `interface`
4925+
4926+
Data type: `String[1]`
4927+
4928+
The name of an interface
4929+
4930+
#### `stdlib::has_interface_with(Enum['macaddress','netmask','ipaddress','network','ip','mac'] $kind, String[1] $value)`
4931+
4932+
The stdlib::has_interface_with function.
4933+
4934+
Returns: `Boolean` Returns `true` if any of the interfaces in the `networking` fact has a `kind` attribute with the value `value`. Otherwise returns `false`
4935+
4936+
##### Examples
4937+
4938+
###### Checking if an interface exists with a given mac address
4939+
4940+
```puppet
4941+
stdlib::has_interface_with('macaddress', 'x:x:x:x:x:x') # Returns `false`
4942+
```
4943+
4944+
###### Checking if an interface exists with a given IP address
4945+
4946+
```puppet
4947+
stdlib::has_interface_with('ipaddress', '127.0.0.1') # Returns `true`
4948+
```
4949+
4950+
##### `kind`
4951+
4952+
Data type: `Enum['macaddress','netmask','ipaddress','network','ip','mac']`
4953+
4954+
A supported interface attribute
4955+
4956+
##### `value`
4957+
4958+
Data type: `String[1]`
4959+
4960+
The value of the attribute
4961+
48844962
### <a name="stdlib--ip_in_range"></a>`stdlib::ip_in_range`
48854963

48864964
Type: Ruby 4.x API
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
# @summary DEPRECATED. Use the namespaced function [`stdlib::has_interface_with`](#stdlibhas_interface_with) instead.
4+
Puppet::Functions.create_function(:has_interface_with) do
5+
dispatch :deprecation_gen do
6+
repeated_param 'Any', :args
7+
end
8+
def deprecation_gen(*args)
9+
call_function('deprecation', 'has_interface_with', 'This method is deprecated, please use stdlib::has_interface_with instead.')
10+
call_function('stdlib::has_interface_with', *args)
11+
end
12+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# frozen_string_literal: true
2+
3+
# @summary Returns boolean based on network interfaces present and their attribute values.
4+
#
5+
# Can be called with one, or two arguments.
6+
Puppet::Functions.create_function(:'stdlib::has_interface_with') do
7+
# @param interface
8+
# The name of an interface
9+
# @return [Boolean] Returns `true` if `interface` exists and `false` otherwise
10+
# @example When called with a single argument, the presence of the interface is checked
11+
# stdlib::has_interface_with('lo') # Returns `true`
12+
dispatch :has_interface do
13+
param 'String[1]', :interface
14+
return_type 'Boolean'
15+
end
16+
17+
# @param kind
18+
# A supported interface attribute
19+
# @param value
20+
# The value of the attribute
21+
# @return [Boolean] Returns `true` if any of the interfaces in the `networking` fact has a `kind` attribute with the value `value`. Otherwise returns `false`
22+
# @example Checking if an interface exists with a given mac address
23+
# stdlib::has_interface_with('macaddress', 'x:x:x:x:x:x') # Returns `false`
24+
# @example Checking if an interface exists with a given IP address
25+
# stdlib::has_interface_with('ipaddress', '127.0.0.1') # Returns `true`
26+
dispatch :has_interface_with do
27+
param "Enum['macaddress','netmask','ipaddress','network','ip','mac']", :kind
28+
param 'String[1]', :value
29+
return_type 'Boolean'
30+
end
31+
32+
def has_interface(interface) # rubocop:disable Naming/PredicateName
33+
interfaces.key? interface
34+
end
35+
36+
def has_interface_with(kind, value) # rubocop:disable Naming/PredicateName
37+
# For compatibility with older version of function that used the legacy facts, alias `ip` with `ipaddress` and `mac` with `macaddress`
38+
kind = 'ip' if kind == 'ipaddress'
39+
kind = 'mac' if kind == 'macaddress'
40+
41+
interface = interfaces.find { |_interface, params| params[kind] == value }
42+
!interface.nil?
43+
end
44+
45+
def interfaces
46+
closure_scope['facts']['networking']['interfaces']
47+
end
48+
end

spec/functions/has_interface_with_spec.rb

+120-14
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,49 @@
44

55
describe 'has_interface_with' do
66
it { is_expected.not_to eq(nil) }
7-
it { is_expected.to run.with_params.and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
8-
it { is_expected.to run.with_params('one', 'two', 'three').and_raise_error(Puppet::ParseError, %r{wrong number of arguments}i) }
7+
it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{expects between 1 and 2 arguments, got none}) }
8+
it { is_expected.to run.with_params('one', 'two', 'three').and_raise_error(ArgumentError, %r{expects between 1 and 2 arguments, got 3}) }
99

1010
# We need to mock out the Facts so we can specify how we expect this function
1111
# to behave on different platforms.
1212
context 'when on Mac OS X Systems' do
13-
let(:facts) { { interfaces: 'lo0,gif0,stf0,en1,p2p0,fw0,en0,vmnet1,vmnet8,utun0' } }
13+
let(:facts) do
14+
{
15+
'networking' => {
16+
'interfaces' => {
17+
'lo0' => {
18+
'bindings' => [
19+
{
20+
'address' => '127.0.0.1',
21+
'netmask' => '255.0.0.0',
22+
'network' => '127.0.0.0'
23+
},
24+
],
25+
"bindings6": [
26+
{
27+
'address' => '::1',
28+
'netmask' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
29+
'network' => '::1'
30+
},
31+
{
32+
'address' => 'fe80::1',
33+
'netmask' => 'ffff:ffff:ffff:ffff::',
34+
'network' => 'fe80::'
35+
},
36+
],
37+
'ip' => '127.0.0.1',
38+
'ip6' => '::1',
39+
'mtu' => 16_384,
40+
'netmask' => '255.0.0.0',
41+
'netmask6' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
42+
'network' => '127.0.0.0',
43+
'network6' => '::1',
44+
'scope6' => 'host'
45+
},
46+
}
47+
}
48+
}
49+
end
1450

1551
it { is_expected.to run.with_params('lo0').and_return(true) }
1652
it { is_expected.to run.with_params('lo').and_return(false) }
@@ -19,23 +55,93 @@
1955
context 'when on Linux Systems' do
2056
let(:facts) do
2157
{
22-
interfaces: 'eth0,lo',
23-
ipaddress: '10.0.0.1',
24-
ipaddress_lo: '127.0.0.1',
25-
ipaddress_eth0: '10.0.0.1',
26-
muppet: 'kermit',
27-
muppet_lo: 'mspiggy',
28-
muppet_eth0: 'kermit',
58+
'networking' => {
59+
'interfaces' => {
60+
'eth0' => {
61+
'bindings' => [
62+
{
63+
'address' => '10.0.2.15',
64+
'netmask' => '255.255.255.0',
65+
'network' => '10.0.2.0'
66+
},
67+
],
68+
'bindings6' => [
69+
{
70+
'address' => 'fe80::5054:ff:fe8a:fee6',
71+
'netmask' => 'ffff:ffff:ffff:ffff::',
72+
'network' => 'fe80::'
73+
},
74+
],
75+
'dhcp' => '10.0.2.2',
76+
'ip' => '10.0.2.15',
77+
'ip6' => 'fe80::5054:ff:fe8a:fee6',
78+
'mac' => '52:54:00:8a:fe:e6',
79+
'mtu' => 1500,
80+
'netmask' => '255.255.255.0',
81+
'netmask6' => 'ffff:ffff:ffff:ffff::',
82+
'network' => '10.0.2.0',
83+
'network6' => 'fe80::'
84+
},
85+
'eth1' => {
86+
'bindings' => [
87+
{
88+
'address' => '10.0.0.2',
89+
'netmask' => '255.255.255.0',
90+
'network' => '10.0.0.0'
91+
},
92+
],
93+
'bindings6' => [
94+
{
95+
'address' => 'fe80::a00:27ff:fed1:d28c',
96+
'netmask' => 'ffff:ffff:ffff:ffff::',
97+
'network' => 'fe80::'
98+
},
99+
],
100+
'ip' => '10.0.0.2',
101+
'ip6' => 'fe80::a00:27ff:fed1:d28c',
102+
'mac' => '08:00:27:d1:d2:8c',
103+
'mtu' => 1500,
104+
'netmask' => '255.255.255.0',
105+
'netmask6' => 'ffff:ffff:ffff:ffff::',
106+
'network' => '10.0.0.0',
107+
'network6' => 'fe80::'
108+
},
109+
'lo' => {
110+
'bindings' => [
111+
{
112+
'address' => '127.0.0.1',
113+
'netmask' => '255.0.0.0',
114+
'network' => '127.0.0.0'
115+
},
116+
],
117+
'bindings6' => [
118+
{
119+
'address' => '::1',
120+
'netmask' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
121+
'network' => '::1'
122+
},
123+
],
124+
'ip' => '127.0.0.1',
125+
'ip6' => '::1',
126+
'mtu' => 65_536,
127+
'netmask' => '255.0.0.0',
128+
'netmask6' => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
129+
'network' => '127.0.0.0',
130+
'network6' => '::1'
131+
}
132+
},
133+
},
29134
}
30135
end
31136

32137
it { is_expected.to run.with_params('lo').and_return(true) }
33138
it { is_expected.to run.with_params('lo0').and_return(false) }
34139
it { is_expected.to run.with_params('ipaddress', '127.0.0.1').and_return(true) }
35-
it { is_expected.to run.with_params('ipaddress', '10.0.0.1').and_return(true) }
140+
it { is_expected.to run.with_params('ipaddress', '10.0.0.2').and_return(true) }
36141
it { is_expected.to run.with_params('ipaddress', '8.8.8.8').and_return(false) }
37-
it { is_expected.to run.with_params('muppet', 'kermit').and_return(true) }
38-
it { is_expected.to run.with_params('muppet', 'mspiggy').and_return(true) }
39-
it { is_expected.to run.with_params('muppet', 'bigbird').and_return(false) }
142+
it { is_expected.to run.with_params('netmask', '255.255.255.0').and_return(true) }
143+
it { is_expected.to run.with_params('macaddress', '52:54:00:8a:fe:e6').and_return(true) }
144+
it { is_expected.to run.with_params('network', '42.0.0.0').and_return(false) }
145+
it { is_expected.to run.with_params('network', '10.0.0.0').and_return(true) }
40146
end
41147
end

0 commit comments

Comments
 (0)