TT#47255 Add comprehensive test of network config for /etc/network/interfaces

Since we manage this as a template, the configuration is getting more and more
complex and it's important to have comprehensive tests that help us to detect
problems when we add options and change templates.

Change-Id: Ieff8449f3d6d1cd74a9b44d49e1642a1bf02efc2
changes/70/24770/6
Manuel Montecelo 8 years ago
parent 43ac83d1d6
commit f6596cc9cf

@ -0,0 +1,37 @@
# directory name where ngcpcfg is managed through git
[ -n "${NGCPCTL_BASE:-}" ] || NGCPCTL_BASE="$(pwd)/"
[ -n "${NGCPCTL_MAIN:-}" ] || NGCPCTL_MAIN="${NGCPCTL_BASE}/fixtures/repos/"
[ -n "${NGCPCTL_CONFIG:-}" ] || NGCPCTL_CONFIG="${NGCPCTL_MAIN}/config.yml"
[ -n "${HOST_CONFIG:-}" ] || HOST_CONFIG="${NGCPCTL_MAIN}/config.$(hostname).yml"
[ -n "${LOCAL_CONFIG:-}" ] || LOCAL_CONFIG="${NGCPCTL_MAIN}/config.local.yml"
[ -n "${CONSTANTS_CONFIG:-}" ] || CONSTANTS_CONFIG="${NGCPCTL_MAIN}/constants.yml"
[ -n "${NETWORK_CONFIG:-}" ] || NETWORK_CONFIG="${NGCPCTL_MAIN}/network_network_interfaces.yml"
[ -n "${RTP_INTERFACES_CONFIG:-}" ] || RTP_INTERFACES_CONFIG="/etc/ngcp-rtpengine-daemon/interfaces.yml"
[ -n "${EXTRA_CONFIG_DIR:-}" ] || EXTRA_CONFIG_DIR="${NGCPCTL_MAIN}/config.d/"
# configuration dirs that should be managed
[ -n "${CONFIG_POOL:-}" ] || CONFIG_POOL='/etc /var'
# location of templates
[ -n "${TEMPLATE_POOL_BASE:-}" ] || TEMPLATE_POOL_BASE="${NGCPCTL_MAIN}/templates"
# location of service definitions
[ -n "${SERVICES_POOL_BASE:-}" ] || SERVICES_POOL_BASE="${NGCPCTL_MAIN}/templates"
# Backward compatibility config for upgrade mr3.4*->mr3.5*
# it can be removed when the next LTS is released:
[ -n "${TEMPLATE_POOL:-}" ] || TEMPLATE_POOL="${TEMPLATE_POOL_BASE}/etc"
[ -n "${SERVICES_POOL:-}" ] || SERVICES_POOL="${SERVICES_POOL_BASE}/etc"
# timestamp format for console output
[ -n "${TIME_FORMAT:-}" ] || TIME_FORMAT="+%F %T"
# Run-time state directory
[ -n "${RUN_DIR:-}" ] || RUN_DIR='/var/run'
# directory holding files for internal state of ngcpcfg
[ -n "${STATE_FILES_DIR:-}" ] || STATE_FILES_DIR='/var/lib/ngcpcfg/state/'
# validate configs using kwalify schema
[ -n "${VALIDATE_SCHEMA:-}" ] || VALIDATE_SCHEMA="false"
## END OF FILE #################################################################

@ -0,0 +1,74 @@
# File autogenerated by ngcpcfg
# eth11 ----------------------
auto eth11
iface eth11 inet manual
pre-up ethtool -K eth11 sg off
# --------------------------------------------
# eth22 ----------------------
auto eth22
iface eth22 inet manual
pre-up ethtool -K eth22 sg off
# --------------------------------------------
# bond0 ----------------------
auto bond0
iface bond0 inet static
address 10.10.10.2
netmask 255.0.0.0
gateway 10.10.10.254
bond-slaves eth11 eth22
bond-mode active-backup
bond-miimon 100
# --------------------------------------------
# lo ----------------------
auto lo
iface lo inet loopback
iface lo inet6 loopback
# --------------------------------------------
# eth46 ----------------------
auto eth46
iface eth46 inet static
address 127.11.22.33
netmask 255.0.0.0
gateway 127.11.22.254
hwaddress c0:ff:ee:15:90:0d
dns-nameservers 127.0.0.1 1.1.1.1
iface eth46 inet6 static
address 2001:aaaa:1111:bbbb:2222:cccc:3333:dddd
netmask 64
gateway 2001:aaaa:1111:bbbb:2222:cccc:3333:0001
hwaddress c0:ff:ee:15:90:0d
dns-nameservers ::1 2606:4700:4700::1111
# --------------------------------------------
# vlan1111 ----------------------
auto vlan1111
iface vlan1111 inet static
address 10.11.11.11
netmask 255.0.0.0
gateway 10.11.11.254
vlan-raw-device bond0
# --------------------------------------------
# vlan2222 ----------------------
auto vlan2222
iface vlan2222 inet static
address 10.22.22.22
netmask 255.0.0.0
gateway 10.22.22.254
vlan-raw-device bond0
# --------------------------------------------
# vlan3333 ----------------------
auto vlan3333
iface vlan3333 inet static
address 10.33.33.33
netmask 255.0.0.0
gateway 10.33.33.254
vlan-raw-device bond0
# --------------------------------------------

@ -0,0 +1,83 @@
---
hosts:
self:
bond0:
bond_miimon: '100'
bond_mode: active-backup
bond_slaves: eth11 eth22
gateway: 10.10.10.254
ip: 10.10.10.2
netmask: 255.0.0.0
dbnode: '1'
eth11:
dhcp: yes
hwaddr: 11:11:11:11:11:11
mtu: '1111'
eth22:
dhcp: yes
hwaddr: 22:22:22:22:22:22
mtu: '2222'
eth46:
dns_nameservers:
- 127.0.0.1
- 1.1.1.1
- ::1
- 2606:4700:4700::1111
gateway: 127.11.22.254
hwaddr: c0:ff:ee:15:90:0d
ip: 127.11.22.33
netmask: 255.0.0.0
v6gateway: 2001:aaaa:1111:bbbb:2222:cccc:3333:0001
v6ip: 2001:aaaa:1111:bbbb:2222:cccc:3333:dddd
v6netmask: '64'
interfaces:
- lo
- eth46
- bond0
- eth11
- eth22
- vlan1111
- vlan2222
- vlan3333
lo:
ip: 127.0.0.1
netmask: 255.255.255.0
type:
- sip_int
- ha_int
- web_ext
- sip_ext
- rtp_ext
- ssh_ext
- mon_ext
role:
- proxy
- lb
- mgmt
vlan1111:
gateway: 10.11.11.254
ip: 10.11.11.11
netmask: 255.0.0.0
type:
- ha_int
- ssh_ext
- stor_int
vlan_raw_device: bond0
vlan2222:
gateway: 10.22.22.254
ip: 10.22.22.22
netmask: 255.0.0.0
type:
- mon_ext
- ssh_ext
vlan_raw_device: bond0
vlan3333:
gateway: 10.33.33.254
ip: 10.33.33.33
netmask: 255.0.0.0
type:
- web_ext
- web_int
vlan_raw_device: bond0
status: online
swraiddevices: []

@ -0,0 +1,322 @@
# File autogenerated by ngcpcfg
[%
hostname = ngcp.get_hostname();
# in SPCE there's no proper hostname, but "self", default to it
UNLESS hosts.${hostname};
hostname = 'self';
END;
MACRO print_start_interface BLOCK;
"# ${interface} ----------------------\n";
"auto ${interface}\n";
END;
MACRO print_end_interface BLOCK;
"# --------------------------------------------\n\n";
END;
MACRO print_bond_fields BLOCK;
IF iface.bond_slaves;
bslaves = iface.bond_slaves.join(" ").trim();
" bond-slaves ${bslaves}\n";
END;
IF iface.bond_mode;
" bond-mode ${iface.bond_mode}\n";
END;
IF iface.bond_miimon;
" bond-miimon ${iface.bond_miimon}\n";
END;
IF iface.bond_primary;
" bond-primary ${iface.bond_primary}\n";
END;
IF iface.bond_updelay;
" bond-updelay ${iface.bond_updelay}\n";
END;
IF iface.bond_downdelay;
" bond-downdelay ${iface.bond_downdelay}\n";
END;
IF iface.bond_xmit_hash_policy;
" bond-xmit-hash-policy ${iface.bond_xmit_hash_policy}\n";
END;
END;
MACRO print_hwaddress BLOCK;
IF iface.hwaddr;
" hwaddress ${iface.hwaddr}\n";
END;
END;
MACRO print_mtu BLOCK;
IF iface.mtu;
IF (iface.ip or iface.v6ip or iface.dhcp == 'yes' or iface.v6dhcp == 'yes');
" mtu ${iface.mtu}\n";
ELSE;
" pre-up ip link set dev ${iface.name} mtu ${iface.mtu}\n";
END;
END;
END;
MACRO print_hardware_options BLOCK;
print_hwaddress;
print_mtu;
END;
MACRO print_address_v4 BLOCK;
IF iface.ip;
" address ${iface.ip}\n";
END;
END;
MACRO print_address_v6 BLOCK;
IF iface.v6ip;
" address ${iface.v6ip}\n";
END;
END;
MACRO print_netmask_v4 BLOCK;
IF iface.netmask;
" netmask ${iface.netmask}\n";
END;
END;
MACRO print_netmask_v6 BLOCK;
IF iface.v6netmask;
" netmask ${iface.v6netmask}\n";
END;
END;
MACRO print_gateway_v4 BLOCK;
gateway = iface.gateway.trim();
IF gateway;
" gateway ${gateway}\n";
END;
END;
MACRO print_gateway_v6 BLOCK;
gateway = iface.v6gateway.trim();
IF gateway;
" gateway ${gateway}\n";
END;
END;
MACRO print_dns_nameservers_v4 BLOCK;
nservers = iface.dns_nameservers.grep('\.').join(" ").trim();
IF nservers;
" dns-nameservers ${nservers}\n";
END;
END;
MACRO print_dns_nameservers_v6 BLOCK;
nservers = iface.dns_nameservers.grep(':').join(" ").trim();
IF nservers;
" dns-nameservers ${nservers}\n";
END;
END;
MACRO print_vlan_raw_device BLOCK;
IF iface.vlan_raw_device;
devs = iface.vlan_raw_device.join(" ").trim();
" vlan-raw-device ${devs}\n";
END;
END;
MACRO print_pre_up_v4 BLOCK;
IF iface.pre_up;
FOREACH rule IN iface.pre_up;
" pre-up ${rule}\n";
END;
END;
END;
MACRO print_pre_up_v6 BLOCK;
IF iface.v6pre_up;
FOREACH rule IN iface.v6pre_up;
" pre-up ${rule}\n";
END;
END;
END;
MACRO print_post_up_v4 BLOCK;
IF iface.post_up;
FOREACH rule IN iface.post_up;
" post-up ${rule}\n";
END;
END;
END;
MACRO print_post_up_v6 BLOCK;
IF iface.v6post_up;
FOREACH rule IN iface.v6post_up;
" post-up ${rule}\n";
END;
END;
END;
MACRO print_pre_down_v4 BLOCK;
IF iface.pre_down;
FOREACH rule IN iface.pre_down;
" pre-down ${rule}\n";
END;
END;
END;
MACRO print_pre_down_v6 BLOCK;
IF iface.v6pre_down;
FOREACH rule IN iface.v6pre_down;
" pre-down ${rule}\n";
END;
END;
END;
MACRO print_post_down_v4 BLOCK;
IF iface.post_down;
FOREACH rule IN iface.post_down;
" post-down ${rule}\n";
END;
END;
END;
MACRO print_post_down_v6 BLOCK;
IF iface.v6post_down;
FOREACH rule IN iface.v6post_down;
" post-down ${rule}\n";
END;
END;
END;
MACRO print_up_down_v4 BLOCK;
print_pre_up_v4;
print_post_up_v4;
print_pre_down_v4;
print_post_down_v4;
END;
MACRO print_up_down_v6 BLOCK;
print_pre_up_v6;
print_post_up_v6;
print_pre_down_v6;
print_post_down_v6;
END;
MACRO print_interface BLOCK;
iface = hosts.${hostname}.${interface};
print_start_interface(interface=interface);
IF interface == 'lo';
"iface ${interface} inet loopback\n";
"iface ${interface} inet6 loopback\n";
ELSE;
# ipv4
IF iface.manual == 'yes';
"iface ${interface} inet manual\n";
print_hardware_options(iface=iface);
print_up_down_v4(iface=iface);
ELSIF iface.dhcp == 'yes';
"iface ${interface} inet dhcp\n";
ELSIF iface.ip;
"iface ${interface} inet static\n";
print_address_v4(iface=iface);
print_netmask_v4(iface=iface);
print_gateway_v4(iface=iface);
ELSE;
ipv4=no;
END;
# ipv4-related fields
IF iface.ip or iface.dhcp == 'yes';
# common, they can be attached to any protocol of the interface
print_hardware_options(iface=iface);
print_bond_fields(iface=iface);
print_vlan_raw_device(iface=iface);
print_dns_nameservers_v4(iface=iface);
print_up_down_v4(iface=iface);
END;
# ipv6
IF iface.v6manual == 'yes';
"iface ${interface} inet6 manual\n";
print_hardware_options(iface=iface);
print_up_down_v6(iface=iface);
ELSIF iface.v6dhcp == 'yes';
"iface ${interface} inet6 dhcp\n";
ELSIF iface.v6ip;
"iface ${interface} inet6 static\n";
print_address_v6(iface=iface);
print_netmask_v6(iface=iface);
print_gateway_v6(iface=iface);
ELSE;
ipv6=no;
END;
# ipv6-related fields
IF iface.v6ip or iface.v6dhcp == 'yes';
# common, they can be attached to any protocol of the interface
print_hardware_options(iface=iface);
print_bond_fields(iface=iface);
print_vlan_raw_device(iface=iface);
print_dns_nameservers_v6(iface=iface);
print_up_down_v6(iface=iface);
END;
# disable "Duplicate Address Detection", it creates problems with HA resource transfer
IF iface.shared_v6ip;
" dad-attempts 0\n";
" pre-up echo 0 > /proc/sys/net/ipv6/conf/${interface}/accept_dad\n";
END;
IF ipv4 == 'no' and ipv6 == 'no';
"# ERROR, neither IPv4 nor IPv6 present in network configuration\n";
END;
END;
print_end_interface();
END;
all_interfaces = hosts.${hostname}.interfaces;
# print bond* interfaces in the beginning, needs to happen before vlan* start to
# use them, otherwise "ifup -a" does not work
FOREACH interface IN all_interfaces;
# "# debug: host ${hostname}: processing interface ${interface}\n";
iface = hosts.${hostname}.${interface};
IF iface.bond_slaves;
interfaces_in_bond = iface.bond_slaves.split(" ");
FOREACH phys_interface IN interfaces_in_bond;
print_start_interface(interface=phys_interface);
"iface ${phys_interface} inet manual\n";
" pre-up ethtool -K ${phys_interface} sg off\n";
print_hardware_options(iface=iface);
print_up_down_v4(iface=iface);
print_end_interface();
# remove now to not process again, but lists do not allow to remove
# elements straight away
all_interfaces = all_interfaces.join(" ").remove("${phys_interface}").split(" +");
END;
print_interface(interface=interface);
END;
END;
# print non-bond* and non-tun* interfaces
FOREACH interface IN all_interfaces;
# "# debug: host ${hostname}: processing interface ${interface}\n";
iface = hosts.${hostname}.${interface};
UNLESS iface.bond_slaves or interface.match('^tun[0-9]+$');
print_interface(interface=interface);
END;
END;
-%]

@ -0,0 +1,48 @@
#!/usr/bin/env py.test-3
import filecmp
import os
import pytest
import re
import tempfile
import sys
@pytest.mark.tt_47255
def test_network_interfaces(ngcpcfgcli, tmpdir):
tmpdir = tempfile.mkdtemp(prefix='ngcp-', suffix='-pytest-output')
out = ngcpcfgcli("build", "--ignore-branch-check",
"/etc/network/interfaces",
env={
'NGCP_BASE_TT2': os.getcwd(),
'NGCP_SOCKETFILE': '/tmp/ngcpcfg.socket',
'OUTPUT_DIRECTORY': tmpdir,
'NGCPCFG': 'fixtures/ngcpcfg_network_interfaces.cfg',
})
# debug, only printed in logs in case of error
print("stdout:")
print(out.stdout.replace("\\n", "\n"))
print("stderr:")
print(out.stderr.replace("\\n", "\n"))
regex1 = re.compile(r"Generating .*/etc/network/interfaces: OK")
assert re.search(regex1, out.stdout)
regex2 = re.compile(r"Error")
assert not re.search(regex2, out.stdout)
assert not re.search(regex2, out.stderr)
output_file = os.path.join(tmpdir, "etc/network/interfaces")
test_file = "fixtures/output/network_interfaces"
assert os.path.exists(output_file)
assert os.path.exists(test_file)
# debug
if not filecmp.cmp(output_file, test_file):
print("output_file:")
print(open(output_file).read())
print("test_file:")
print(open(test_file).read())
assert filecmp.cmp(output_file, test_file)
Loading…
Cancel
Save