From a8da6dfe04ae08d1402aea6f92f12f92a8c32066 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Thu, 23 Nov 2023 12:27:51 +0530 Subject: [PATCH] net/network_manager: do not set "may-fail" to False for both ipv4 and ipv6 If "may-fail" is set to False in the Network Manager keyfile for both ipv4 and ipv6, it essentially means both ipv4 and ipv6 network initialization must succeed for the overall network configuration to succeed. This means, for environments where only ipv4 or ipv6 is available but not both and we need to configure both ipv4 and ipv6 options, the overall network configuration will fail. This is not what we want. When both ipv4 and ipv6 are configured, it is enough for the overall configuration to succeed if any one succeeds. Therefore, set "may-fail" to True for both ipv4 and ipv6 if and only if both ipv4 and ipv6 are configured in the Network Manager keyfile and "may-fail" is set to False for both. If both ipv4 and ipv6 are configured in the keyfile and if for any of them "may-fail" is already set to True, then do nothing. All other cases remain same as before. Please see discussions in PR #4474. Signed-off-by: Ani Sinha --- cloudinit/net/network_manager.py | 55 ++++++++++++++++++++++++++++++++ tests/unittests/test_net.py | 24 +++++++------- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py index 8374cfcc8789..3793fd11c412 100644 --- a/cloudinit/net/network_manager.py +++ b/cloudinit/net/network_manager.py @@ -71,6 +71,53 @@ def _set_default(self, section, option, value): if not self.config.has_option(section, option): self.config[section][option] = value + def _config_option_is_set(self, section, option): + """ + Checks if a config option is set. Returns True if it is, + else returns False. + """ + return self.config.has_section(section) and self.config.has_option( + section, option + ) + + def _get_config_option(self, section, option): + """ + Returns the value of a config option if its set, + else returns None. + """ + if self._config_option_is_set(section, option): + return self.config[section][option] + else: + return None + + def _change_set_config_option(self, section, option, value): + """ + Overrides the value of a config option if its already set. + Else, if the config option is not set, it does nothing. + """ + if self._config_option_is_set(section, option): + self.config[section][option] = value + + def _set_mayfail_true_if_both_false(self): + """ + If for both ipv4 and ipv6, 'may-fail' is set to be False, + set it to True for both of them. + """ + for family in ["ipv4", "ipv6"]: + if not self._config_option_is_set(family, "may-fail"): + # if either ipv4 or ipv6 sections are not set/configured, + # do not do anything. + return + if self._get_config_option(family, "may-fail") == "true": + # if for either ipv4 or ipv6, 'may-fail' is 'true', do + # not do anything. + return + + # if we landed here, it means both ipv4 and ipv6 are configured + # and both have 'may-fail' set to 'false'. So set both to 'true'. + for family in ["ipv4", "ipv6"]: + self._change_set_config_option(family, "may-fail", "true") + def _set_ip_method(self, family, subnet_type): """ Ensures there's appropriate [ipv4]/[ipv6] for given family @@ -116,6 +163,14 @@ def _set_ip_method(self, family, subnet_type): self.config[family]["method"] = method self._set_default(family, "may-fail", "false") + # we do not want to set may-fail to false for both ipv4 and ipv6 at the + # at the same time. This will make the network configuration work only + # when both ipv4 and ipv6 succeeds. This may not be what we want. + # If we have configured both ipv4 and ipv6, any one succeeding should + # be enough. Therefore, if "may-fail" is set to False for both ipv4 + # and ipv6, set them both to True. + self._set_mayfail_true_if_both_false() + def _add_numbered(self, section, key_prefix, value): """ Adds a numbered property, such as address or route, ensuring diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index 3e8f721f098b..5ad910ee9b2e 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -1425,11 +1425,11 @@ [ipv4] method=auto - may-fail=false + may-fail=true [ipv6] method=auto - may-fail=false + may-fail=true """ ), @@ -1558,12 +1558,12 @@ [ipv4] method=manual - may-fail=false + may-fail=true address1=192.168.14.2/24 [ipv6] method=manual - may-fail=false + may-fail=true address1=2001:1::1/64 """ @@ -1598,11 +1598,11 @@ [ipv6] method=auto - may-fail=false + may-fail=true [ipv4] method=auto - may-fail=false + may-fail=true """ ), @@ -2876,12 +2876,12 @@ [ipv4] method=manual - may-fail=false + may-fail=true address1=192.168.14.2/24 [ipv6] method=manual - may-fail=false + may-fail=true address1=2001:1::1/64 route1=::/0,2001:4800:78ff:1b::1 @@ -3537,7 +3537,7 @@ [ipv4] method=manual - may-fail=false + may-fail=true address1=192.168.0.2/24 gateway=192.168.0.1 route1=10.1.3.0/24,192.168.0.3 @@ -3545,7 +3545,7 @@ [ipv6] method=manual - may-fail=false + may-fail=true address1=2001:1::1/92 route1=2001:67c::/32,2001:67c:1562::1 route2=3001:67c::/32,3001:67c:15::1 @@ -3659,14 +3659,14 @@ [ipv4] method=manual - may-fail=false + may-fail=true address1=192.168.2.2/24 address2=192.168.1.2/24 gateway=192.168.1.1 [ipv6] method=manual - may-fail=false + may-fail=true address1=2001:1::bbbb/96 route1=::/0,2001:1::1