Skip to content

Commit bda346c

Browse files
(FACT-2872_2) Reimplement linux networking resolver
1 parent e09fd27 commit bda346c

15 files changed

+596
-270
lines changed

acceptance/tests/facts/networking_facts.rb

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,96 @@
11
test_name 'C59029: networking facts should be fully populated' do
22
tag 'risk:high'
33

4-
#
5-
# This test is intended to ensure that networking facts resolves
6-
# as expected across supported platforms.
7-
#
4+
#
5+
# This test is intended to ensure that networking facts resolve
6+
# as expected across supported platforms.
7+
#
88

99
@ip_regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
1010
@netmask_regex = /^(((128|192|224|240|248|252|254)\.0\.0\.0)|(255\.(0|128|192|224|240|248|252|254)\.0\.0)|(255\.255\.(0|128|192|224|240|248|252|254)\.0)|(255\.255\.255\.(0|128|192|224|240|248|252|254)))$/
1111

1212
expected_networking = {
13-
"networking.dhcp" => agent['platform'] =~ /fedora-32|el-8-aarch64/ ? '' : @ip_regex, # https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/426
14-
"networking.ip" => @ip_regex,
15-
"networking.ip6" => /[a-f0-9]+:+/,
16-
"networking.mac" => /[a-f0-9]{2}:/,
17-
"networking.mtu" => /\d+/,
18-
"networking.netmask" => @netmask_regex,
19-
"networking.netmask6" => /[a-f0-9]+:/,
20-
"networking.network" => @ip_regex,
21-
"networking.network6" => /([a-f0-9]+)?:([a-f0-9]+)?/
13+
%w[networking dhcp] => agent['platform'] =~ /fedora-32|el-8-aarch64/ ? '' : @ip_regex, # https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/426
14+
%w[networking ip] => @ip_regex,
15+
%w[networking ip6] => /[a-f0-9]+:+/,
16+
%w[networking mac] => /[a-f0-9]{2}:/,
17+
%w[networking mtu] => /\d+/,
18+
%w[networking netmask] => @netmask_regex,
19+
%w[networking netmask6] => /[a-f0-9]+:/,
20+
%w[networking network] => @ip_regex,
21+
%w[networking network6] => /([a-f0-9]+)?:([a-f0-9]+)?/,
22+
%w[networking scope6] => /link|host|site|global|compat/
2223
}
2324

2425
agents.each do |agent|
2526
primary_interface = fact_on(agent, 'networking.primary')
2627
refute_empty(primary_interface)
2728

2829
expected_bindings = {
29-
"networking.interfaces.#{primary_interface}.bindings.0.address" => @ip_regex,
30-
"networking.interfaces.#{primary_interface}.bindings.0.netmask" => @netmask_regex,
31-
"networking.interfaces.#{primary_interface}.bindings.0.network" => @ip_regex,
32-
"networking.interfaces.#{primary_interface}.bindings6.0.address" => /[a-f0-9:]+/,
33-
"networking.interfaces.#{primary_interface}.bindings6.0.netmask" => /[a-f0-9:]+/,
34-
"networking.interfaces.#{primary_interface}.bindings6.0.network" => /[a-f0-9:]+/
30+
['networking', 'interfaces', primary_interface, 'bindings', 0, 'address'] => @ip_regex,
31+
['networking', 'interfaces', primary_interface, 'bindings', 0, 'netmask'] => @netmask_regex,
32+
['networking', 'interfaces', primary_interface, 'bindings', 0, 'network'] => @ip_regex,
33+
['networking', 'interfaces', primary_interface, 'bindings6', 0, 'address'] => /[a-f0-9:]+/,
34+
['networking', 'interfaces', primary_interface, 'bindings6', 0, 'netmask'] => /[a-f0-9:]+/,
35+
['networking', 'interfaces', primary_interface, 'bindings6', 0, 'network'] => /[a-f0-9:]+/,
36+
['networking', 'interfaces', primary_interface, 'bindings6', 0, 'scope6'] => /link|host|site|global|compat/
3537
}
3638

3739
if agent['platform'] =~ /eos|solaris|aix|cisco/
3840
#remove the invalid networking facts on eccentric platforms
39-
expected_networking.delete("networking.ip6")
40-
expected_networking.delete("networking.netmask6")
41-
expected_networking.delete("networking.network6")
41+
expected_networking.delete(%w[networking ip6])
42+
expected_networking.delete(%w[networking netmask6])
43+
expected_networking.delete(%w[networking network6])
44+
expected_networking.delete(%w[networking scope6])
4245

4346
#remove invalid bindings for the primary networking interface eccentric platforms
44-
expected_bindings.delete("networking.interfaces.#{primary_interface}.bindings6.0.address")
45-
expected_bindings.delete("networking.interfaces.#{primary_interface}.bindings6.0.netmask")
46-
expected_bindings.delete("networking.interfaces.#{primary_interface}.bindings6.0.network")
47+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings6', 0, 'address'])
48+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings6', 0, 'netmask'])
49+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings6', 0, 'network'])
50+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings6', 0, 'scope6'])
4751
end
4852

4953
if agent['platform'] =~ /aix|sparc|cisco|huawei|sles|s390x/
5054
# some of our testing platforms do not use DHCP
51-
expected_networking.delete("networking.dhcp")
55+
expected_networking.delete(%w[networking dhcp])
5256
end
5357

5458
if agent['platform'] =~ /cisco/
5559
# Cisco main interface does not define netmask or network
56-
expected_networking.delete("networking.network")
57-
expected_networking.delete("networking.netmask")
60+
expected_networking.delete(%w[networking network])
61+
expected_networking.delete(%w[networking netmask])
5862

5963
#remove invalid bindings for Cisco's primary networking interface
60-
expected_bindings.delete("networking.interfaces.#{primary_interface}.bindings.0.netmask")
61-
expected_bindings.delete("networking.interfaces.#{primary_interface}.bindings.0.network")
64+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings', 0, 'netmask'])
65+
expected_bindings.delete(['networking', 'interfaces', primary_interface, 'bindings', 0, 'network'])
6266
end
6367

68+
networking_facts = JSON.parse(on(agent, facter('networking --json')).stdout)
69+
6470
step "Ensure the Networking fact resolves with reasonable values for at least one interface" do
65-
expected_networking.each do |fact, value|
66-
assert_match(value, fact_on(agent, fact).to_s)
71+
expected_networking.each do |fact_tokens, regex|
72+
assert_match(regex, networking_facts.dig(*fact_tokens).to_s)
6773
end
6874
end
6975

7076
step "Ensure bindings for the primary networking interface are present" do
71-
expected_bindings.each do |fact, value|
72-
assert_match(value, fact_on(agent, fact).to_s)
77+
expected_bindings.each do |fact_tokens, regex|
78+
assert_match(regex, networking_facts.dig(*fact_tokens).to_s)
7379
end
7480
end
7581
end
7682

7783
# Verify that IP Address v6 and network v6 is retrieved correctly and does not contain the interface identifier
7884
agents.each do |agent|
7985
if agent['platform'] =~ /windows/
80-
step("verify that ipaddress6 is retrieved correctly") do
81-
on(agent, facter("ipaddress6")) do |facter_result|
86+
step "verify that ipaddress6 is retrieved correctly" do
87+
on(agent, facter('ipaddress6')) do |facter_result|
8288
assert_match(/^[a-fA-F0-9:]+$/, facter_result.stdout.chomp)
8389
end
8490
end
8591

86-
step("verify that network6 is retrieved correctly") do
87-
on(agent, facter("network6")) do |facter_result|
92+
step "verify that network6 is retrieved correctly" do
93+
on(agent, facter('network6')) do |facter_result|
8894
assert_match(/([a-fA-F0-9:]+)?:([a-fA-F0-9:]+)?$/, facter_result.stdout.chomp)
8995
end
9096
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
test_name 'networking facts with secondary ip' do
2+
tag 'risk:high'
3+
4+
confine :except, :platform => 'windows'
5+
confine :except, :platform => 'aix'
6+
confine :except, :platform => 'osx'
7+
confine :except, :platform => 'solaris'
8+
#
9+
# This test is intended to ensure that networking facts resolve secondary ips
10+
# as expected across supported platforms.
11+
#
12+
13+
@ip_regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
14+
@netmask_regex = /^(((128|192|224|240|248|252|254)\.0\.0\.0)|(255\.(0|128|192|224|240|248|252|254)\.0\.0)|(255\.255\.(0|128|192|224|240|248|252|254)\.0)|(255\.255\.255\.(0|128|192|224|240|248|252|254)))$/
15+
16+
def expected_interfaces(interface, count)
17+
expected_interfaces = {}
18+
(1..count).each do |index|
19+
expected_interfaces.merge!(expected_bindings(ip_name(interface, index), 1))
20+
expected_interfaces.merge!(
21+
{
22+
['networking', 'interfaces', "#{ip_name(interface, index)}", 'ip'] => @ip_regex,
23+
['networking', 'interfaces', "#{ip_name(interface, index)}", 'netmask'] => @netmask_regex,
24+
['networking', 'interfaces', "#{ip_name(interface, index)}", 'network'] => @ip_regex
25+
}
26+
)
27+
end
28+
expected_interfaces
29+
end
30+
31+
def expected_bindings(interface, count)
32+
expected_bindings = {}
33+
(1..count).each do |index|
34+
expected_bindings.merge!(
35+
{
36+
['networking', 'interfaces', "#{interface}", 'bindings', index - 1, 'address'] => @ip_regex,
37+
['networking', 'interfaces', "#{interface}", 'bindings', index - 1, 'netmask'] => @netmask_regex,
38+
['networking', 'interfaces', "#{interface}", 'bindings', index - 1, 'network'] => @ip_regex
39+
}
40+
)
41+
end
42+
expected_bindings
43+
end
44+
45+
def ip_name(interface, index)
46+
"#{interface}:#{index}"
47+
end
48+
49+
agents.each do |agent|
50+
interface = fact_on(agent, 'networking.primary')
51+
52+
step "Add secondary ip without labels" do
53+
on(agent, "ip addr add 11.0.0.0/24 dev #{interface}")
54+
end
55+
56+
step "Add two secondary ips with label" do
57+
on(agent, "ip addr add 11.0.0.1/24 dev #{interface} label #{ip_name(interface, 1)}")
58+
on(agent, "ip addr add 11.0.0.2/24 dev #{interface} label #{ip_name(interface, 2)}")
59+
end
60+
61+
networking_facts = JSON.parse(on(agent, facter('networking --json')).stdout)
62+
63+
step "Check secondary interfaces are found" do
64+
expected_interfaces(interface, 2).each do |fact_tokens, regex|
65+
assert_match(regex, networking_facts.dig(*fact_tokens).to_s)
66+
end
67+
end
68+
69+
step "Check secondary interfaces are inside the bindings of the primary interface" do
70+
expected_bindings(interface, 4).each do |fact_tokens, regex|
71+
assert_match(regex, networking_facts.dig(*fact_tokens).to_s)
72+
end
73+
end
74+
75+
teardown do
76+
on(agent, "ip addr del 11.0.0.0/24 dev #{interface}")
77+
# On Ubuntu 16, deleting the first secondary ip, deletes all of them.
78+
# Next commands may fail, because the ips they attempt to delete, no longer exist.
79+
on(agent, "ip addr del 11.0.0.1/24 dev #{interface}", :acceptable_exit_codes => [0, 2])
80+
on(agent, "ip addr del 11.0.0.2/24 dev #{interface}", :acceptable_exit_codes => [0, 2])
81+
end
82+
end
83+
end
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
test_name 'networking facts with vlans' do
2+
tag 'risk:high'
3+
4+
confine :except, :platform => 'windows'
5+
confine :except, :platform => 'aix'
6+
confine :except, :platform => 'osx'
7+
confine :except, :platform => 'solaris'
8+
confine :except, :platform => 'amazon' # unable to create VLANs on Amazon 6
9+
10+
#
11+
# This test is intended to ensure that networking facts resolve vlans
12+
# as expected across supported platforms.
13+
#
14+
15+
@ip_regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
16+
@netmask_regex = /^(((128|192|224|240|248|252|254)\.0\.0\.0)|(255\.(0|128|192|224|240|248|252|254)\.0\.0)|(255\.255\.(0|128|192|224|240|248|252|254)\.0)|(255\.255\.255\.(0|128|192|224|240|248|252|254)))$/
17+
18+
def vlan(interface, index)
19+
"#{interface}.#{index}"
20+
end
21+
22+
def expected_bindings(interface, count)
23+
expected_bindings = {}
24+
(1..count).each do |index|
25+
expected_bindings.merge!(
26+
{
27+
['networking', 'interfaces', vlan(interface, index).to_s, 'bindings', 0, 'address'] => @ip_regex,
28+
['networking', 'interfaces', vlan(interface, index).to_s, 'bindings', 0, 'netmask'] => @netmask_regex,
29+
['networking', 'interfaces', vlan(interface, index).to_s, 'bindings', 0, 'network'] => @ip_regex,
30+
%W[networking interfaces #{vlan(interface, index)} ip] => @ip_regex,
31+
%W[networking interfaces #{vlan(interface, index)} mac] => /[a-f0-9]{2}:/,
32+
%W[networking interfaces #{vlan(interface, index)} mtu] => /\d+/,
33+
%W[networking interfaces #{vlan(interface, index)} netmask] => @netmask_regex,
34+
%W[networking interfaces #{vlan(interface, index)} network] => @ip_regex
35+
}
36+
)
37+
end
38+
expected_bindings
39+
end
40+
41+
agents.each do |agent|
42+
operating_system = fact_on(agent, 'operatingsystem')
43+
release = fact_on(agent, 'operatingsystemrelease')
44+
45+
if operating_system == 'Amazon' && release == '2017.03'
46+
skip_test 'Not able to create VLANs on Amazon 6'
47+
end
48+
49+
interface = fact_on(agent, 'networking.primary')
50+
51+
step "Add two vlans" do
52+
on(agent, "ip link add link #{interface} name #{vlan(interface, 1)} type vlan id 1")
53+
on(agent, "ip addr add 11.0.0.1/24 dev #{vlan(interface, 1)}")
54+
on(agent, "ip link add link #{interface} name #{vlan(interface, 2)} type vlan id 2")
55+
on(agent, "ip addr add 11.0.0.2/24 dev #{vlan(interface, 2)}")
56+
end
57+
58+
step "Check vlans are found" do
59+
networking_facts = JSON.parse(on(agent, facter('networking --json')).stdout)
60+
61+
expected_bindings(interface, 2).each do |fact_tokens, regex|
62+
assert_match(regex, networking_facts.dig(*fact_tokens).to_s)
63+
end
64+
end
65+
66+
teardown do
67+
on(agent, "ip link delete #{vlan(interface, 1)}")
68+
on(agent, "ip link delete #{vlan(interface, 2)}")
69+
end
70+
end
71+
end

0 commit comments

Comments
 (0)