Fix ifup error message of vlan that is already configured by kickstart
The first time apply_network_config.py runs in non controllers with mgmt over VLAN, the pxeboot/mgmt interface is already configured by ifupdown. When ifup is called for the label that holds the mgmt address, the following error occurs: Error: ipv6: address already assigned. ifup: failed to bring up vlan10:1-22 This happens because since the /etc/network/interfaces.d/auto file does not exist yet, all the interfaces defined by puppet are considered "new" and are not required to be set down before ifup. This change adds logic to check if any of the newly introduced interfaces are already up, and if it is the case, adds them to the down list. Test plan [PASS] STANDARD IPv6 full install on VirtualBox (2 storages + 1 compute) Partial-Bug: 2103645 Change-Id: Id7968521606ea54085468b1e55798c75663e7561 Signed-off-by: Lucas Ratusznei Fonseca <lucas.ratuszneifonseca@windriver.com>
This commit is contained in:
parent
052751c3df
commit
36eabd877f
@ -270,8 +270,11 @@ def parse_interface_stanzas():
|
||||
|
||||
def get_current_config():
|
||||
'''Gets current network config in etc directory'''
|
||||
LOG.info(f"Parsing contents of the {ETC_DIR} directory to gather current network configuration")
|
||||
auto = parse_auto_file()
|
||||
ifaces = parse_ifcfg_files(auto)
|
||||
ifaces = parse_etc_dir()
|
||||
if len(ifaces) == 0:
|
||||
LOG.warning(f"No interface config found in {ETC_DIR}")
|
||||
return build_config(auto, ifaces, is_from_puppet=False)
|
||||
|
||||
|
||||
@ -317,31 +320,16 @@ def get_ifcfg_path(iface):
|
||||
return os.path.join(ETC_DIR, CFG_PREFIX + iface)
|
||||
|
||||
|
||||
def parse_ifcfg_files(ifaces):
|
||||
iface_configs = dict()
|
||||
for iface in ifaces:
|
||||
iface_configs[iface] = parse_ifcfg_file(iface)
|
||||
return iface_configs
|
||||
|
||||
|
||||
def parse_ifcfg_file(iface):
|
||||
path = get_ifcfg_path(iface)
|
||||
if not os.path.isfile(path):
|
||||
LOG.warning(f"Interface config file not found: '{path}'")
|
||||
return dict()
|
||||
lines = read_file_lines(path)
|
||||
_, ifaces = StanzaParser.ParseLines(lines)
|
||||
if len(ifaces) == 0:
|
||||
LOG.warning(f"No interface config found in '{path}'")
|
||||
return dict()
|
||||
if (ifconfig := ifaces.get(iface, None)) is None:
|
||||
LOG.warning(f"Config for interface '{iface}' not found in '{path}'. Instead, file has "
|
||||
f"config(s) for the following interface(s): {' '.join(sorted(ifaces.keys()))}")
|
||||
return dict()
|
||||
if len(ifaces) > 1:
|
||||
LOG.warning(f"Multiple interface configs found in '{path}': "
|
||||
f"{' '.join(sorted(ifaces.keys()))}")
|
||||
return ifconfig
|
||||
def parse_etc_dir():
|
||||
parser = StanzaParser()
|
||||
files = os.listdir(ETC_DIR)
|
||||
for file in files:
|
||||
file_path = ETC_DIR + "/" + file
|
||||
if os.path.isfile(file_path):
|
||||
LOG.info(f"Parsing file {file_path}")
|
||||
lines = read_file_lines(file_path)
|
||||
parser.parse_lines(lines)
|
||||
return parser.get_auto_and_ifaces()[1]
|
||||
|
||||
|
||||
def get_types_and_dependencies(iface_configs):
|
||||
@ -412,7 +400,10 @@ def get_modified_ifaces(new_config, current_config):
|
||||
modified = set()
|
||||
new_ifaces = new_config["ifaces"]
|
||||
current_ifaces = current_config["ifaces"]
|
||||
for iface, new_if_config in new_ifaces.items():
|
||||
for iface in new_config["auto"]:
|
||||
if iface not in current_config["auto"]:
|
||||
continue
|
||||
new_if_config = new_ifaces[iface]
|
||||
current_if_config = current_ifaces.get(iface, None)
|
||||
if not current_if_config:
|
||||
continue
|
||||
@ -468,10 +459,18 @@ def get_dependent_list(config, ifaces):
|
||||
return covered
|
||||
|
||||
|
||||
def get_down_list(current_config, comparison):
|
||||
def get_down_list(current_config, new_config, comparison):
|
||||
base_set = comparison["modified"].union(comparison["removed"])
|
||||
for iface in sorted(comparison["added"]):
|
||||
if iface not in base_set and is_iface_up(iface):
|
||||
LOG.info(f"Interface {iface} not in {ETC_DIR}/auto but currently up, "
|
||||
"adding to DOWN list")
|
||||
base_set.add(iface)
|
||||
if iface not in current_config["ifaces_types"]:
|
||||
current_config["ifaces_types"][iface] = new_config["ifaces_types"][iface]
|
||||
dependents = get_dependent_list(current_config, base_set)
|
||||
return base_set.union(dependents)
|
||||
down_list = base_set.union(dependents)
|
||||
return down_list
|
||||
|
||||
|
||||
def get_up_list(new_config, comparison):
|
||||
@ -814,10 +813,6 @@ def disable_pxeboot_interface():
|
||||
for iface in ifaces.keys():
|
||||
LOG.info(f"Turn off pxeboot install config for {iface}, will be turned on later")
|
||||
set_iface_down(iface)
|
||||
if is_label(iface):
|
||||
base_iface = get_base_iface(iface)
|
||||
LOG.info(f"Turn off pxeboot for base interface {base_iface}")
|
||||
set_iface_down(base_iface)
|
||||
|
||||
LOG.info("Remove ifcfg-pxeboot, left from kickstart install phase")
|
||||
remove_iface_config_file("pxeboot")
|
||||
@ -826,8 +821,8 @@ def disable_pxeboot_interface():
|
||||
def update_ifaces_ifupdown(new_config):
|
||||
current_config = get_current_config()
|
||||
comparison = compare_configs(new_config, current_config)
|
||||
down_list = get_down_list(current_config, comparison)
|
||||
up_list = get_up_list(new_config, comparison)
|
||||
down_list = get_down_list(current_config, new_config, comparison)
|
||||
|
||||
lock = acquire_sysinv_agent_lock() if down_list or up_list else None
|
||||
try:
|
||||
@ -852,11 +847,25 @@ def update_ifaces_online(config):
|
||||
return get_updated_ifaces(config, sorted_ifaces)
|
||||
|
||||
|
||||
def is_iface_up(iface):
|
||||
ifstate_path = IFSTATE_BASE_PATH + iface
|
||||
if os.path.isfile(ifstate_path) and read_file_text(ifstate_path).strip() == iface:
|
||||
return True
|
||||
if is_label(iface):
|
||||
return False
|
||||
operstate_path = f"{DEVLINK_BASE_PATH}{iface}/operstate"
|
||||
if os.path.isfile(operstate_path):
|
||||
state = read_file_text(operstate_path)
|
||||
if state.strip() == "up":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_iface_missing_or_down(iface):
|
||||
path = f"{DEVLINK_BASE_PATH}{iface}/operstate"
|
||||
if os.path.isfile(path):
|
||||
state = read_file_text(path)
|
||||
if state != "down":
|
||||
if state.strip() != "down":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -283,7 +283,7 @@ class FilesystemMock():
|
||||
entry[TARGET] = target_path
|
||||
self._call_listeners(entry)
|
||||
|
||||
def get_file_list(self, path):
|
||||
def listdir(self, path):
|
||||
entry = self._get_entry(path, translate_link=True)
|
||||
if entry is None:
|
||||
raise FilesystemMockError("Path does not exist")
|
||||
|
@ -21,7 +21,7 @@ class NetworkingMockError(BaseException):
|
||||
pass
|
||||
|
||||
|
||||
class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
class NetworkingMock(): # pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||
def __init__(self, fs: FilesystemMock, ifaces: list):
|
||||
self._stdout = ''
|
||||
self._history = []
|
||||
@ -32,6 +32,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
self._routes = dict()
|
||||
self._next_route_id = 0
|
||||
self._allow_multiple_default_gateways = False
|
||||
self._dhcp = dict()
|
||||
self._add_eth_ifaces(ifaces)
|
||||
self._fs.add_listener(anc.ETC_DIR, self._etc_dir_changed)
|
||||
|
||||
@ -50,13 +51,13 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
def _add_eth_iface(self, iface):
|
||||
phys_path = self._get_device_path(iface)
|
||||
self._fs.set_file_contents(phys_path + "/operstate", "down")
|
||||
self._fs.set_file_contents(phys_path + "/operstate", "down\n")
|
||||
self._fs.set_link_contents(anc.DEVLINK_BASE_PATH + iface, phys_path)
|
||||
self._links[iface] = {"adm_state": False, "virtual": False,
|
||||
"addresses": set(), "routes": set()}
|
||||
|
||||
def _parse_etc_interfaces(self):
|
||||
file_list = self._fs.get_file_list(anc.ETC_DIR)
|
||||
file_list = self._fs.listdir(anc.ETC_DIR)
|
||||
parser = anc.StanzaParser()
|
||||
for file in file_list:
|
||||
file_contents = self._fs.get_file_contents(anc.ETC_DIR + "/" + file)
|
||||
@ -149,6 +150,9 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
def get_history(self):
|
||||
return self._history
|
||||
|
||||
def enable_dhcp(self, iface_addresses):
|
||||
self._dhcp = iface_addresses
|
||||
|
||||
def _add_history(self, command, *args):
|
||||
self._history.append((command, *args))
|
||||
|
||||
@ -170,7 +174,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
return
|
||||
link["adm_state"] = state
|
||||
operstate_path = self._get_device_path(iface, link["virtual"]) + "/operstate"
|
||||
value = "up" if state else "down"
|
||||
value = "up\n" if state else "down\n"
|
||||
self._fs.set_file_contents(operstate_path, value)
|
||||
|
||||
def _create_virtual_link(self, name):
|
||||
@ -178,7 +182,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
self._print_stdout("RTNETLINK answers: File exists")
|
||||
return link, 1
|
||||
phys_path = self._get_device_path(name, True)
|
||||
self._fs.set_file_contents(phys_path + "/operstate", "down")
|
||||
self._fs.set_file_contents(phys_path + "/operstate", "down\n")
|
||||
self._fs.set_link_contents(anc.DEVLINK_BASE_PATH + name, phys_path)
|
||||
link = {"adm_state": False, "virtual": True, "addresses": set(), "routes": set()}
|
||||
self._links[name] = link
|
||||
@ -238,6 +242,12 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
link["addresses"].add(address)
|
||||
if gateway := config.get("gateway", None):
|
||||
self._add_default_gateway(iface, link, gateway)
|
||||
elif mode == "dhcp":
|
||||
if address := self._dhcp.get(iface, None):
|
||||
if address in link["addresses"]:
|
||||
raise NetworkingMockError("DHCP lease address already assigned to link "
|
||||
f"{iface}: {address}")
|
||||
link["addresses"].add(address)
|
||||
return 0
|
||||
|
||||
def _remove_routes_associated_to_address(self, link, address):
|
||||
@ -250,10 +260,14 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
self._routes.pop(route_id)
|
||||
link["routes"].remove(route_id)
|
||||
|
||||
def _remove_address(self, config, link):
|
||||
def _remove_address(self, iface, config, link):
|
||||
mode = config["mode"]
|
||||
address = None
|
||||
if mode == "static":
|
||||
address = config["address"]
|
||||
elif mode == "dhcp":
|
||||
address = self._dhcp.get(iface, None)
|
||||
if address:
|
||||
if address not in link["addresses"]:
|
||||
self._print_stdout(f"Error: ipv{address.version}: Address not found.")
|
||||
return 1
|
||||
@ -296,7 +310,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
if retcode != 0:
|
||||
return 0
|
||||
self._set_link_state(iface, link, False)
|
||||
self._remove_address(config, link)
|
||||
self._remove_address(iface, config, link)
|
||||
return 0
|
||||
|
||||
def _set_slave_up(self, iface, config): # pylint: disable=no-self-use,unused-argument
|
||||
@ -324,7 +338,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
link, retcode = self._get_link(iface)
|
||||
if retcode != 0:
|
||||
return 0
|
||||
self._remove_address(config, link)
|
||||
self._remove_address(iface, config, link)
|
||||
self._set_link_state(iface, link, False)
|
||||
for slave in config["slaves"]:
|
||||
self._unenslave_iface(slave)
|
||||
@ -359,7 +373,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
link, retcode = self._get_link(iface)
|
||||
if retcode != 0:
|
||||
return 0
|
||||
self._remove_address(config, link)
|
||||
self._remove_address(iface, config, link)
|
||||
self._set_link_state(iface, link, False)
|
||||
self._remove_virtual_link(iface)
|
||||
return 0
|
||||
@ -375,7 +389,7 @@ class NetworkingMock(): # pylint: disable=too-many-instance-attributes
|
||||
parent = config["parent"]
|
||||
link, retcode = self._get_link(parent)
|
||||
if retcode == 0:
|
||||
self._remove_address(config, link)
|
||||
self._remove_address(parent, config, link)
|
||||
return 0
|
||||
|
||||
def _set_ifstate(self, iface, state):
|
||||
@ -1038,8 +1052,10 @@ class BaseTestCase(testtools.TestCase):
|
||||
def _add_logger_mock(self):
|
||||
self._log = LoggerMock()
|
||||
|
||||
def _add_nw_mock(self, static_links):
|
||||
def _add_nw_mock(self, static_links, dhcp_config=None):
|
||||
self._nwmock = NetworkingMock(self._fs, static_links)
|
||||
if dhcp_config:
|
||||
self._nwmock.enable_dhcp(dhcp_config)
|
||||
|
||||
def _add_scmd_mock(self):
|
||||
self._scmdmock = SystemCommandMock(self._nwmock)
|
||||
@ -1048,6 +1064,7 @@ class BaseTestCase(testtools.TestCase):
|
||||
with (
|
||||
mock.patch("src.bin.apply_network_config.path_exists", self._fs.exists),
|
||||
mock.patch("os.remove", self._fs.delete),
|
||||
mock.patch("os.listdir", self._fs.listdir),
|
||||
mock.patch("builtins.open", self._fs.open),
|
||||
mock.patch.multiple("os.path",
|
||||
isfile=self._fs.isfile,
|
||||
@ -1174,70 +1191,6 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
"post-up echo # > /proc/sys/net/ipv6/conf/enp0s8/autoconf\n"
|
||||
"stx-description ifname:etc0,net:None\n")
|
||||
|
||||
def test_parse_valid_ifcfg_file(self):
|
||||
self._add_fs_mock({anc.ETC_DIR + "/ifcfg-enp0s8": self._IFACE_FILE})
|
||||
config = self._mocked_call([self._mock_fs], anc.parse_ifcfg_file, "enp0s8")
|
||||
self.assertEqual(6, len(config))
|
||||
self.assertEqual("enp0s8 inet static", config["iface"])
|
||||
self.assertEqual("12.12.1.55", config["address"])
|
||||
self.assertEqual("255.255.255.0", config["netmask"])
|
||||
self.assertEqual("9000", config["mtu"])
|
||||
self.assertEqual("echo # > /proc/sys/net/ipv6/conf/enp0s8/autoconf", config["post-up"])
|
||||
self.assertEqual("ifname:etc0,net:None", config["stx-description"])
|
||||
|
||||
def test_parse_missing_ifcfg_file(self):
|
||||
self._add_fs_mock()
|
||||
self._add_logger_mock()
|
||||
config = self._mocked_call([self._mock_fs, self._mock_logger],
|
||||
anc.parse_ifcfg_file, "enp0s8")
|
||||
self.assertEqual(0, len(config))
|
||||
self.assertEqual(LoggerMock.WARNING, self._log.get_history()[-1][0])
|
||||
self.assertEqual(f"Interface config file not found: '{anc.ETC_DIR + '/ifcfg-enp0s8'}'",
|
||||
self._log.get_history()[-1][1])
|
||||
|
||||
def test_parse_ifcfg_file_with_multiple_config(self):
|
||||
path = anc.ETC_DIR + "/ifcfg-enp0s8"
|
||||
self._add_fs_mock({path: self._IFACE_FILE +
|
||||
"iface enp0s9 inet static\n"
|
||||
"mtu 9000\n"
|
||||
"stx-description ifname:etc1,net:None\n"})
|
||||
self._add_logger_mock()
|
||||
config = self._mocked_call([self._mock_fs, self._mock_logger],
|
||||
anc.parse_ifcfg_file, "enp0s8")
|
||||
self.assertEqual(6, len(config))
|
||||
self.assertEqual(LoggerMock.WARNING, self._log.get_history()[-1][0])
|
||||
self.assertEqual(f"Multiple interface configs found in '{path}': enp0s8 enp0s9",
|
||||
self._log.get_history()[-1][1])
|
||||
|
||||
def test_parse_invalid_ifcfg_file(self):
|
||||
path = anc.ETC_DIR + "/ifcfg-enp0s8"
|
||||
self._add_fs_mock({path: "invalid content line 1\n"
|
||||
"invalid content line 2\n"
|
||||
"invalid content line 3\n"})
|
||||
self._add_logger_mock()
|
||||
config = self._mocked_call([self._mock_fs, self._mock_logger],
|
||||
anc.parse_ifcfg_file, "enp0s8")
|
||||
self.assertEqual(0, len(config))
|
||||
self.assertEqual(LoggerMock.WARNING, self._log.get_history()[-1][0])
|
||||
self.assertEqual(f"No interface config found in '{path}'", self._log.get_history()[-1][1])
|
||||
|
||||
def test_parse_ifcfg_file_with_unrelated_ifaces(self):
|
||||
path = anc.ETC_DIR + "/ifcfg-enp0s8"
|
||||
self._add_fs_mock({path: "iface enp0s9 inet static\n"
|
||||
"mtu 9000\n"
|
||||
"stx-description ifname:etc1,net:None\n"
|
||||
"iface enp0s10 inet static\n"
|
||||
"mtu 9000\n"
|
||||
"stx-description ifname:etc2,net:None\n"})
|
||||
self._add_logger_mock()
|
||||
config = self._mocked_call([self._mock_fs, self._mock_logger],
|
||||
anc.parse_ifcfg_file, "enp0s8")
|
||||
self.assertEqual(0, len(config))
|
||||
self.assertEqual(LoggerMock.WARNING, self._log.get_history()[-1][0])
|
||||
self.assertEqual(f"Config for interface 'enp0s8' not found in '{path}'. Instead, "
|
||||
f"file has config(s) for the following interface(s): enp0s10 enp0s9",
|
||||
self._log.get_history()[-1][1])
|
||||
|
||||
def test_parse_auto_file(self):
|
||||
self._add_fs_mock({anc.ETC_DIR + "/auto":
|
||||
"auto lo enp0s3\tenp0s3:1-17 enp0s8 vlan100"})
|
||||
@ -1253,6 +1206,87 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
self.assertEqual(f"Auto file not found: '{anc.ETC_DIR + '/auto'}'",
|
||||
self._log.get_history()[-1][1])
|
||||
|
||||
def test_parse_etc_dir(self):
|
||||
contents = dict()
|
||||
contents[anc.ETC_DIR + "/auto"] = (
|
||||
"auto lo enp0s3 vlan20\n")
|
||||
contents[anc.ETC_DIR + "/oam-config"] = (
|
||||
"iface enp0s3 inet manual\n"
|
||||
"iface vlan20 inet static\n"
|
||||
"address 177.122.10.34\n"
|
||||
"netmask 255.255.255.0\n"
|
||||
"gateway 177.122.10.1\n"
|
||||
"vlan-raw-device enp0s3\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-lo"] = (
|
||||
"auto lo\n"
|
||||
"iface lo inet loopback\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-enp0s8"] = (
|
||||
"auto enp0s8\n"
|
||||
"iface enp0s8 inet manual\n"
|
||||
"post-up echo 0 > /proc/sys/net/ipv6/conf/enp0s8/autoconf; "
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_ra; " # noqa: E131
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_redirects\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-pxeboot"] = (
|
||||
"auto enp0s8:2\n"
|
||||
"iface enp0s8:2 inet dhcp\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-vlan10"] = (
|
||||
"auto vlan10\n"
|
||||
"iface vlan10 inet static\n"
|
||||
"address 192.168.204.75\n"
|
||||
"netmask 255.255.255.0\n"
|
||||
"vlan-raw-device enp0s8\n")
|
||||
|
||||
self._add_fs_mock(contents)
|
||||
self._add_logger_mock()
|
||||
|
||||
iface_configs = self._mocked_call([self._mock_fs, self._mock_logger], anc.parse_etc_dir)
|
||||
|
||||
sorted_contents = [(ifname, sorted(iface_configs[ifname].items()))
|
||||
for ifname in sorted(iface_configs.keys())]
|
||||
self.assertEqual([
|
||||
('enp0s3', [('iface', 'enp0s3 inet manual')]),
|
||||
('enp0s8', [('iface', 'enp0s8 inet manual'),
|
||||
('post-up', 'echo 0 > /proc/sys/net/ipv6/conf/enp0s8/autoconf; echo 0 > '
|
||||
'/proc/sys/net/ipv6/conf/enp0s8/accept_ra; echo 0 > '
|
||||
'/proc/sys/net/ipv6/conf/enp0s8/accept_redirects')]),
|
||||
('enp0s8:2', [('iface', 'enp0s8:2 inet dhcp')]),
|
||||
('lo', [('iface', 'lo inet loopback')]),
|
||||
('vlan10', [('address', '192.168.204.75'),
|
||||
('iface', 'vlan10 inet static'),
|
||||
('netmask', '255.255.255.0'),
|
||||
('vlan-raw-device', 'enp0s8')]),
|
||||
('vlan20', [('address', '177.122.10.34'),
|
||||
('gateway', '177.122.10.1'),
|
||||
('iface', 'vlan20 inet static'),
|
||||
('netmask', '255.255.255.0'),
|
||||
('vlan-raw-device', 'enp0s3')])],
|
||||
sorted_contents)
|
||||
|
||||
self.assertEqual([
|
||||
('info', 'Parsing file /etc/network/interfaces.d/auto'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-enp0s8'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-lo'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-pxeboot'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-vlan10'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/oam-config')],
|
||||
self._log.get_history())
|
||||
|
||||
def test_get_current_config_empty(self):
|
||||
self._add_fs_mock({anc.ETC_DIR: None})
|
||||
self._add_logger_mock()
|
||||
|
||||
config = self._mocked_call([self._mock_fs, self._mock_logger], anc.get_current_config)
|
||||
|
||||
self.assertEqual({"auto": set(), "dependencies": {}, "ifaces": {}, "ifaces_types": {}},
|
||||
config)
|
||||
|
||||
self.assertEqual([
|
||||
('info', 'Parsing contents of the /etc/network/interfaces.d directory to gather '
|
||||
'current network configuration'),
|
||||
('info', "Auto file not found: '/etc/network/interfaces.d/auto'"),
|
||||
('warning', 'No interface config found in /etc/network/interfaces.d')],
|
||||
self._log.get_history())
|
||||
|
||||
def test_get_vlan_attributes_vlanNNN(self):
|
||||
dev, vlan_id = anc.get_vlan_attributes("vlan123", {"vlan-raw-device": "enp0s8"})
|
||||
self.assertEqual("enp0s8", dev)
|
||||
@ -1407,7 +1441,7 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
|
||||
def test_is_iface_missing_or_down(self):
|
||||
dev_path = "/sys/devices/pci0000:00/net/enp0s8"
|
||||
self._add_fs_mock({dev_path + "/operstate": "up",
|
||||
self._add_fs_mock({dev_path + "/operstate": "up\n",
|
||||
anc.DEVLINK_BASE_PATH + "enp0s8": (dev_path, )})
|
||||
|
||||
def check_result(value):
|
||||
@ -1416,7 +1450,7 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
|
||||
check_result(False)
|
||||
|
||||
self._fs.set_file_contents(anc.DEVLINK_BASE_PATH + "enp0s8/operstate", "down")
|
||||
self._fs.set_file_contents(anc.DEVLINK_BASE_PATH + "enp0s8/operstate", "down\n")
|
||||
check_result(True)
|
||||
|
||||
self._fs.delete(anc.DEVLINK_BASE_PATH + "enp0s8")
|
||||
@ -1523,7 +1557,7 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
raise Exception(f"Unexpected system command: '{cmd}'")
|
||||
|
||||
dev_path = "/sys/devices/pci0000:00/net/enp0s8"
|
||||
self._add_fs_mock({dev_path + "/operstate": "up",
|
||||
self._add_fs_mock({dev_path + "/operstate": "up\n",
|
||||
anc.DEVLINK_BASE_PATH + "enp0s8": (dev_path, ),
|
||||
anc.IFSTATE_BASE_PATH + "enp0s8": "enp0s8"})
|
||||
self._add_logger_mock()
|
||||
@ -2155,32 +2189,45 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
self._log.get_history())
|
||||
|
||||
def test_disable_kickstart_pxeboot(self):
|
||||
etc_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo", "enp0s8"],
|
||||
"lo": {},
|
||||
"enp0s8": {}, },
|
||||
}
|
||||
|
||||
puppet_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo", "enp0s8", "enp0s8:2-3", "enp0s8:2-4"],
|
||||
"auto": ["lo", "enp0s8", "vlan10", "vlan10:1-5"],
|
||||
"lo": {},
|
||||
"enp0s8": {"address": "169.254.202.2/24"},
|
||||
"enp0s8:2-3": {"address": "192.168.204.2/24"},
|
||||
"enp0s8:2-4": {"address": "fd01::2/64"}},
|
||||
"enp0s8": {"mode": "dhcp"},
|
||||
"vlan10": {"raw_dev": "enp0s8"},
|
||||
"vlan10:1-5": {"raw_dev": "enp0s8", "address": "192.168.204.75/24",
|
||||
"gateway": "192.168.204.2"}},
|
||||
}
|
||||
|
||||
contents = FILE_GEN.generate_file_tree(puppet_files=puppet_cfg, etc_files=etc_cfg)
|
||||
contents = FILE_GEN.generate_file_tree(puppet_files=puppet_cfg)
|
||||
contents[anc.ETC_DIR + "/ifcfg-lo"] = (
|
||||
"auto lo\n"
|
||||
"iface lo inet loopback\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-enp0s8"] = (
|
||||
"auto enp0s8\n"
|
||||
"iface enp0s8 inet manual\n"
|
||||
"post-up echo 0 > /proc/sys/net/ipv6/conf/enp0s8/autoconf; "
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_ra; " # noqa: E131
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_redirects\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-pxeboot"] = (
|
||||
"auto enp0s8:2\n"
|
||||
"iface enp0s8:2 inet dhcp\n"
|
||||
" post-up echo 0 > /proc/sys/net/ipv6/conf/enp0s8/autoconf; "
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_ra; " # noqa: E131
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_redirects\n")
|
||||
"post-up echo 0 > /proc/sys/net/ipv6/conf/enp0s8/autoconf; "
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_ra; " # noqa: E131
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/enp0s8/accept_redirects\n")
|
||||
contents[anc.ETC_DIR + "/ifcfg-vlan10"] = (
|
||||
"auto vlan10\n"
|
||||
"iface vlan10 inet static\n"
|
||||
"address 192.168.204.75\n"
|
||||
"netmask 255.255.255.0\n"
|
||||
"gateway 192.168.204.2\n"
|
||||
"vlan-raw-device enp0s8\n"
|
||||
"post-up echo 0 > /proc/sys/net/ipv6/conf/vlan10/autoconf; "
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/vlan10/accept_ra; " # noqa: E131
|
||||
"echo 0 > /proc/sys/net/ipv6/conf/vlan10/accept_redirects\n")
|
||||
|
||||
self._add_fs_mock(contents)
|
||||
self._add_nw_mock(["lo", "enp0s8"])
|
||||
self._add_nw_mock(["lo", "enp0s8"], {"enp0s8": IPNetwork("169.254.202.131/24")})
|
||||
self._add_scmd_mock()
|
||||
self._add_logger_mock()
|
||||
self._nwmock.apply_auto()
|
||||
@ -2188,14 +2235,139 @@ class GeneralTests(BaseTestCase): # pylint: disable=too-many-public-methods
|
||||
self._mocked_call([self._mock_fs, self._mock_syscmd,
|
||||
self._mock_sysinv_lock, self._mock_logger], anc.update_interfaces)
|
||||
|
||||
self.assertEqual([
|
||||
'enp0s8 UP 169.254.202.131/24',
|
||||
'lo UP',
|
||||
'vlan10 UP VLAN(enp0s8,10) 192.168.204.75/24'],
|
||||
self._nwmock.get_links_status())
|
||||
|
||||
self.assertEqual([
|
||||
('info', 'Turn off pxeboot install config for enp0s8:2, will be turned on later'),
|
||||
('info', 'Bringing enp0s8:2 down'),
|
||||
('info', 'Turn off pxeboot for base interface enp0s8'),
|
||||
('info', 'Bringing enp0s8 down'),
|
||||
('info', 'Remove ifcfg-pxeboot, left from kickstart install phase'),
|
||||
('info', 'Removing /etc/network/interfaces.d/ifcfg-pxeboot')],
|
||||
self._log.get_history()[:6])
|
||||
('info', 'Removing /etc/network/interfaces.d/ifcfg-pxeboot'),
|
||||
('info', 'Parsing contents of the /etc/network/interfaces.d directory to gather '
|
||||
'current network configuration'),
|
||||
('info', "Auto file not found: '/etc/network/interfaces.d/auto'"),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-enp0s8'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-lo'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-vlan10'),
|
||||
('info', 'Added interfaces: enp0s8 lo vlan10 vlan10:1-5'),
|
||||
('info', 'Interface enp0s8 not in /etc/network/interfaces.d/auto but currently up, '
|
||||
'adding to DOWN list'),
|
||||
('info', 'Interface lo not in /etc/network/interfaces.d/auto but currently up, '
|
||||
'adding to DOWN list'),
|
||||
('info', 'Interface vlan10 not in /etc/network/interfaces.d/auto but currently up, '
|
||||
'adding to DOWN list'),
|
||||
('info', 'Bringing vlan10 down'),
|
||||
('info', 'Bringing enp0s8 down'),
|
||||
('info', 'Bringing lo down'),
|
||||
('info', 'Bringing lo up'),
|
||||
('info', 'Bringing enp0s8 up'),
|
||||
('info', 'Bringing vlan10 up'),
|
||||
('info', 'Bringing vlan10:1-5 up')],
|
||||
self._log.get_history())
|
||||
|
||||
def test_add_interface_link_up(self):
|
||||
etc_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo"],
|
||||
"lo": {}},
|
||||
}
|
||||
|
||||
puppet_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo", "enp0s9", "enp0s9:4-17"],
|
||||
"lo": {},
|
||||
"enp0s9": {},
|
||||
"enp0s9:4-17": {"address": "188.177.12.44/24"}},
|
||||
}
|
||||
|
||||
contents = FILE_GEN.generate_file_tree(puppet_files=puppet_cfg, etc_files=etc_cfg)
|
||||
self._add_fs_mock(contents)
|
||||
self._add_nw_mock(["lo", "enp0s9"])
|
||||
self._add_scmd_mock()
|
||||
self._add_logger_mock()
|
||||
self._nwmock.apply_auto()
|
||||
self._nwmock.ip_link_set_up("enp0s9")
|
||||
self._nwmock.ip_addr_add("12.12.12.77/24", "enp0s9")
|
||||
|
||||
self.assertEqual([
|
||||
'enp0s9 UP 12.12.12.77/24',
|
||||
'lo UP'],
|
||||
self._nwmock.get_links_status())
|
||||
|
||||
self._mocked_call([self._mock_fs, self._mock_syscmd,
|
||||
self._mock_sysinv_lock, self._mock_logger], anc.update_interfaces)
|
||||
|
||||
self.assertEqual([
|
||||
'enp0s9 UP 188.177.12.44/24',
|
||||
'lo UP'],
|
||||
self._nwmock.get_links_status())
|
||||
|
||||
self.assertEqual([
|
||||
('info', 'Parsing contents of the /etc/network/interfaces.d directory to gather '
|
||||
'current network configuration'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/auto'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-lo'),
|
||||
('info', 'Added interfaces: enp0s9 enp0s9:4-17'),
|
||||
('info', 'Interface enp0s9 not in /etc/network/interfaces.d/auto but currently up, '
|
||||
'adding to DOWN list'),
|
||||
('info', 'Bringing enp0s9 down'),
|
||||
('info', 'Bringing enp0s9 up'),
|
||||
('info', 'Bringing enp0s9:4-17 up')],
|
||||
self._log.get_history())
|
||||
|
||||
def test_add_interface_currently_up(self):
|
||||
etc_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo"],
|
||||
"lo": {},
|
||||
"enp0s9": {"address": "192.168.12.45/24"}},
|
||||
}
|
||||
|
||||
puppet_cfg = {
|
||||
"interfaces": {
|
||||
"auto": ["lo", "enp0s9", "enp0s9:4-17"],
|
||||
"lo": {},
|
||||
"enp0s9": {},
|
||||
"enp0s9:4-17": {"address": "188.177.12.44/24"}},
|
||||
}
|
||||
|
||||
contents = FILE_GEN.generate_file_tree(puppet_files=puppet_cfg, etc_files=etc_cfg)
|
||||
self._add_fs_mock(contents)
|
||||
self._add_nw_mock(["lo", "enp0s9"])
|
||||
self._add_scmd_mock()
|
||||
self._add_logger_mock()
|
||||
self._nwmock.apply_auto()
|
||||
self._nwmock.ifup("enp0s9")
|
||||
|
||||
self.assertEqual([
|
||||
'enp0s9 UP 192.168.12.45/24',
|
||||
'lo UP'],
|
||||
self._nwmock.get_links_status())
|
||||
|
||||
self._mocked_call([self._mock_fs, self._mock_syscmd,
|
||||
self._mock_sysinv_lock, self._mock_logger], anc.update_interfaces)
|
||||
|
||||
self.assertEqual([
|
||||
'enp0s9 UP 188.177.12.44/24',
|
||||
'lo UP'],
|
||||
self._nwmock.get_links_status())
|
||||
|
||||
self.assertEqual([
|
||||
('info', 'Parsing contents of the /etc/network/interfaces.d directory to gather '
|
||||
'current network configuration'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/auto'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-enp0s9'),
|
||||
('info', 'Parsing file /etc/network/interfaces.d/ifcfg-lo'),
|
||||
('info', 'Added interfaces: enp0s9 enp0s9:4-17'),
|
||||
('info', 'Interface enp0s9 not in /etc/network/interfaces.d/auto but currently up, '
|
||||
'adding to DOWN list'),
|
||||
('info', 'Bringing enp0s9 down'),
|
||||
('info', 'Bringing enp0s9 up'),
|
||||
('info', 'Bringing enp0s9:4-17 up')],
|
||||
self._log.get_history())
|
||||
|
||||
def test_execute_system_cmd(self):
|
||||
retcode, stdout = anc.execute_system_cmd('echo "test_execute_system_cmd"')
|
||||
@ -2451,7 +2623,7 @@ class MigrationBaseTestCase(BaseTestCase):
|
||||
self._mock_sysinv_lock, self._mock_logger], anc.apply_config, False)
|
||||
|
||||
def _check_etc_file_list(self, to_cfg):
|
||||
files = self._fs.get_file_list(anc.ETC_DIR)
|
||||
files = self._fs.listdir(anc.ETC_DIR)
|
||||
etc_ifaces = []
|
||||
has_auto = False
|
||||
for file in files:
|
||||
|
Loading…
x
Reference in New Issue
Block a user