diff --git a/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch b/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch new file mode 100644 index 0000000..f215f9f --- /dev/null +++ b/BZ_1931355-SRIOV-wait-VF-mount-decrease.patch @@ -0,0 +1,166 @@ +From 80c97b27707b036f0a54988ade4bda3ccb342b34 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Mon, 22 Feb 2021 12:03:11 +0100 +Subject: [PATCH 1/2] SR-IOV: increase the verification timeout if SR-IOV is + present + +Certain drivers like i40e take a long time to modify the VFs in the +kernel. Nmstate is timing out on verification because of that. In order +to fix this, nmstate is incresing the verification time if SR-IOV is +present on the desired state. + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/ethernet.py | 6 ++++++ + libnmstate/netapplier.py | 18 +++++++++++++++++- + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py +index 292b7bc..ca8501b 100644 +--- a/libnmstate/ifaces/ethernet.py ++++ b/libnmstate/ifaces/ethernet.py +@@ -65,6 +65,12 @@ class EthernetIface(BaseIface): + def is_peer(self): + return self._is_peer + ++ @property ++ def is_sriov(self): ++ return self.raw.get(Ethernet.CONFIG_SUBTREE, {}).get( ++ Ethernet.SRIOV_SUBTREE ++ ) ++ + def create_sriov_vf_ifaces(self): + return [ + EthernetIface( +diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py +index cf208d1..3c5759b 100644 +--- a/libnmstate/netapplier.py ++++ b/libnmstate/netapplier.py +@@ -24,6 +24,7 @@ import time + + from libnmstate import validator + from libnmstate.error import NmstateVerificationError ++from libnmstate.schema import InterfaceType + + from .nmstate import create_checkpoints + from .nmstate import destroy_checkpoints +@@ -37,6 +38,7 @@ from .version import get_version + MAINLOOP_TIMEOUT = 35 + VERIFY_RETRY_INTERNAL = 1 + VERIFY_RETRY_TIMEOUT = 5 ++VERIFY_RETRY_TIMEOUT_INCREASE = 4 + + + def apply( +@@ -109,7 +111,13 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): + plugin.apply_changes(net_state, save_to_disk) + verified = False + if verify_change: +- for _ in range(VERIFY_RETRY_TIMEOUT): ++ if _net_state_contains_sriov_interface(net_state): ++ # If SR-IOV is present, the verification timeout is being increased ++ # to avoid timeouts due to slow drivers like i40e. ++ verify_retry = VERIFY_RETRY_TIMEOUT * VERIFY_RETRY_TIMEOUT_INCREASE ++ else: ++ verify_retry = VERIFY_RETRY_TIMEOUT ++ for _ in range(verify_retry): + try: + _verify_change(plugins, net_state) + verified = True +@@ -120,6 +128,14 @@ def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): + _verify_change(plugins, net_state) + + ++def _net_state_contains_sriov_interface(net_state): ++ for iface in net_state.ifaces.all_kernel_ifaces.values(): ++ if iface.type == InterfaceType.ETHERNET and iface.is_sriov: ++ return True ++ ++ return False ++ ++ + def _verify_change(plugins, net_state): + current_state = show_with_plugins(plugins) + net_state.verify(current_state) +-- +2.27.0 + + +From 439fe3a51a82060c5b62974c6c9fbdf403c4196b Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Mon, 22 Feb 2021 13:33:06 +0100 +Subject: [PATCH 2/2] SR-IOV: fail on verification if `total_vfs` does not + match vfs len + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/ethernet.py | 11 +++++++++++ + libnmstate/ifaces/ifaces.py | 14 ++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py +index ca8501b..55772ce 100644 +--- a/libnmstate/ifaces/ethernet.py ++++ b/libnmstate/ifaces/ethernet.py +@@ -61,6 +61,14 @@ class EthernetIface(BaseIface): + .get(Ethernet.SRIOV.TOTAL_VFS, 0) + ) + ++ @property ++ def sriov_vfs(self): ++ return ( ++ self.raw.get(Ethernet.CONFIG_SUBTREE, {}) ++ .get(Ethernet.SRIOV_SUBTREE, {}) ++ .get(Ethernet.SRIOV.VFS_SUBTREE, []) ++ ) ++ + @property + def is_peer(self): + return self._is_peer +@@ -108,6 +116,9 @@ class EthernetIface(BaseIface): + for i in range(self.sriov_total_vfs, old_sriov_total_vfs) + ] + ++ def check_total_vfs_matches_vf_list(self, total_vfs): ++ return total_vfs == len(self.sriov_vfs) ++ + + def _capitalize_sriov_vf_mac(state): + vfs = ( +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index 44c9e61..6c94a98 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -238,6 +238,8 @@ class Ifaces: + if new_iface.name not in self._kernel_ifaces: + new_iface.mark_as_desired() + new_ifaces.append(new_iface) ++ else: ++ self._kernel_ifaces[new_iface.name].mark_as_desired() + for new_iface in new_ifaces: + self._kernel_ifaces[new_iface.name] = new_iface + +@@ -656,6 +658,18 @@ class Ifaces: + cur_iface.state_for_verify(), + ) + ) ++ elif ( ++ iface.type == InterfaceType.ETHERNET and iface.is_sriov ++ ): ++ if not cur_iface.check_total_vfs_matches_vf_list( ++ iface.sriov_total_vfs ++ ): ++ raise NmstateVerificationError( ++ "The NIC exceeded the waiting time for " ++ "verification and it is failing because " ++ "the `total_vfs` does not match the VF " ++ "list length." ++ ) + + def gen_dns_metadata(self, dns_state, route_state): + iface_metadata = dns_state.gen_metadata(self, route_state) +-- +2.27.0 + diff --git a/BZ_1931751-nmstate-fix-return-code.patch b/BZ_1931751-nmstate-fix-return-code.patch new file mode 100644 index 0000000..78b6774 --- /dev/null +++ b/BZ_1931751-nmstate-fix-return-code.patch @@ -0,0 +1,29 @@ +From b26ab850172a41557cad42cc011bd00d7c108c88 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 23 Feb 2021 13:52:19 +0800 +Subject: [PATCH] nmstatectl: Fix return code of set command + +The deprecated command `set` should still return the error like +old behaviour. + +Signed-off-by: Gris Ge +--- + nmstatectl/nmstatectl.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nmstatectl/nmstatectl.py b/nmstatectl/nmstatectl.py +index df59942..c94d603 100644 +--- a/nmstatectl/nmstatectl.py ++++ b/nmstatectl/nmstatectl.py +@@ -323,7 +323,7 @@ def show(args): + + def set(args): + warnings.warn("Using 'set' is deprecated, use 'apply' instead.") +- apply(args) ++ return apply(args) + + + def apply(args): +-- +2.27.0 + diff --git a/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch b/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch new file mode 100644 index 0000000..ea46af7 --- /dev/null +++ b/BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch @@ -0,0 +1,223 @@ +From ccdcd8f86544a6364109a0c0142d05a5afacf64e Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 2 Mar 2021 15:31:20 +0800 +Subject: [PATCH] nm: Don't touch unmanaged interface unless desired + +We should ignore NetworkManager unmanaged interface when applying and +verifying unless certain interface listed in desired state explicitly. + +Introduced new plugin interface +`NmstatePlugin.get_ignored_kernel_interface_names()` where plugin may +include a list of interface names which should be ignored during +verification stage. + +Integration test case added to simulate CNV usage on partial editing +a linux bridge holding NM unmanaged interface. + +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/base_iface.py | 3 ++ + libnmstate/ifaces/ifaces.py | 26 ++++++++-------- + libnmstate/netapplier.py | 6 ++++ + libnmstate/nispor/plugin.py | 6 +++- + libnmstate/nm/plugin.py | 25 ++++++++++++++++ + libnmstate/plugin.py | 7 +++++ + tests/integration/linux_bridge_test.py | 8 +---- + tests/integration/nm/linux_bridge_test.py | 36 ++++++++++++++++++++++- + 8 files changed, 95 insertions(+), 22 deletions(-) + +diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py +index 227c1d20..e3f2a1ca 100644 +--- a/libnmstate/ifaces/base_iface.py ++++ b/libnmstate/ifaces/base_iface.py +@@ -322,6 +322,9 @@ class BaseIface: + def mark_as_up(self): + self.raw[Interface.STATE] = InterfaceState.UP + ++ def mark_as_ignored(self): ++ self.raw[Interface.STATE] = InterfaceState.IGNORE ++ + @property + def is_controller(self): + return False +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index 6c94a986..efa24aa3 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -95,7 +95,6 @@ class Ifaces: + self._kernel_ifaces = {} + self._user_space_ifaces = _UserSpaceIfaces() + self._cur_user_space_ifaces = _UserSpaceIfaces() +- self._ignored_ifaces = set() + if cur_iface_infos: + for iface_info in cur_iface_infos: + cur_iface = _to_specific_iface_obj(iface_info, save_to_disk) +@@ -143,10 +142,6 @@ class Ifaces: + ): + # Ignore interface with unknown type + continue +- if iface.is_ignore: +- self._ignored_ifaces.add( +- (iface.name, iface.type, iface.is_user_space_only) +- ) + if cur_iface: + iface.merge(cur_iface) + iface.mark_as_desired() +@@ -169,6 +164,10 @@ class Ifaces: + + self._pre_edit_validation_and_cleanup() + ++ @property ++ def _ignored_ifaces(self): ++ return [iface for iface in self.all_ifaces() if iface.is_ignore] ++ + def _apply_copy_mac_from(self): + for iface in self.all_kernel_ifaces.values(): + if iface.type not in ( +@@ -284,7 +283,7 @@ class Ifaces: + if not defiend in desire state + """ + for iface in self.all_ifaces(): +- if iface.is_up and iface.is_controller: ++ if iface.is_desired and iface.is_up and iface.is_controller: + for port_name in iface.port: + port_iface = self._kernel_ifaces[port_name] + if not port_iface.is_desired and not port_iface.is_up: +@@ -550,13 +549,14 @@ class Ifaces: + return None + + def _remove_iface(self, iface_name, iface_type): +- cur_iface = self._cur_kernel_ifaces.get(iface_name, iface_type) ++ cur_iface = self._user_space_ifaces.get(iface_name, iface_type) + if cur_iface: + self._user_space_ifaces.remove(cur_iface) + else: + cur_iface = self._kernel_ifaces.get(iface_name) + if ( +- iface_type ++ cur_iface ++ and iface_type + and iface_type != InterfaceType.UNKNOWN + and iface_type == cur_iface.type + ): +@@ -813,14 +813,14 @@ class Ifaces: + port_controller_map[port_name] = iface.name + + def _remove_ignore_interfaces(self, ignored_ifaces): +- for iface_name, iface_type, _ in ignored_ifaces: +- self._remove_iface(iface_name, iface_type) ++ for iface in ignored_ifaces: ++ self._remove_iface(iface.name, iface.type) + + # Only kernel interface can be used as port + ignored_kernel_iface_names = set( +- iface_name +- for iface_name, _, is_user_space_only in ignored_ifaces +- if not is_user_space_only ++ iface.name ++ for iface in ignored_ifaces ++ if not iface.is_user_space_only + ) + + # Remove ignored port +diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py +index 3c5759b4..a020f003 100644 +--- a/libnmstate/netapplier.py ++++ b/libnmstate/netapplier.py +@@ -107,8 +107,14 @@ def rollback(*, checkpoint=None): + + + def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): ++ for plugin in plugins: ++ for iface_name in plugin.get_ignored_kernel_interface_names(): ++ iface = net_state.ifaces.all_kernel_ifaces.get(iface_name) ++ if iface and not iface.is_desired: ++ iface.mark_as_ignored() + for plugin in plugins: + plugin.apply_changes(net_state, save_to_disk) ++ + verified = False + if verify_change: + if _net_state_contains_sriov_interface(net_state): +diff --git a/libnmstate/nispor/plugin.py b/libnmstate/nispor/plugin.py +index dc0ea760..19b21d56 100644 +--- a/libnmstate/nispor/plugin.py ++++ b/libnmstate/nispor/plugin.py +@@ -159,7 +159,11 @@ class NisporPlugin(NmstatePlugin): + np_state = NisporNetState.retrieve() + logging.debug(f"Nispor: current network state {np_state}") + for iface in net_state.ifaces.all_ifaces(): +- if iface.is_desired: ++ if iface.is_ignore: ++ logging.debug( ++ f"Nispor: Interface {iface.name} {iface.type} ignored" ++ ) ++ elif iface.is_desired: + logging.debug( + f"Nispor: desired network state {iface.to_dict()}" + ) +diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py +index 302b4cca..335d93c7 100644 +--- a/libnmstate/nm/plugin.py ++++ b/libnmstate/nm/plugin.py +@@ -36,6 +36,7 @@ from .checkpoint import get_checkpoints + from .common import NM + from .context import NmContext + from .device import get_device_common_info ++from .device import get_iface_type + from .device import list_devices + from .dns import get_running as get_dns_running + from .dns import get_running_config as get_dns_running_config +@@ -268,6 +269,21 @@ class NetworkManagerPlugin(NmstatePlugin): + ) + return NmProfiles(None).generate_config_strings(net_state) + ++ def get_ignored_kernel_interface_names(self): ++ """ ++ Return a list of unmanged kernel interface names. ++ """ ++ ignored_ifaces = set() ++ for nm_dev in list_devices(self.client): ++ if ( ++ nm_dev ++ and nm_dev.get_iface() ++ and not nm_dev.get_managed() ++ and _is_kernel_iface(nm_dev) ++ ): ++ ignored_ifaces.add(nm_dev.get_iface()) ++ return list(ignored_ifaces) ++ + + def _remove_ovs_bridge_unsupported_entries(iface_info): + """ +@@ -283,3 +299,12 @@ def _remove_ovs_bridge_unsupported_entries(iface_info): + + def _nm_utils_decode_version(): + return f"{NM.MAJOR_VERSION}.{NM.MINOR_VERSION}.{NM.MICRO_VERSION}" ++ ++ ++def _is_kernel_iface(nm_dev): ++ iface_type = get_iface_type(nm_dev) ++ return iface_type != InterfaceType.UNKNOWN and iface_type not in ( ++ InterfaceType.OVS_BRIDGE, ++ InterfaceType.OVS_INTERFACE, ++ InterfaceType.OVS_PORT, ++ ) +diff --git a/libnmstate/plugin.py b/libnmstate/plugin.py +index ef3874ff..e1d9ad58 100644 +--- a/libnmstate/plugin.py ++++ b/libnmstate/plugin.py +@@ -128,3 +128,10 @@ class NmstatePlugin(metaclass=ABCMeta): + persistently. + """ + return [] ++ ++ def get_ignored_kernel_interface_names(self): ++ """ ++ Return a list of kernel interface names which should be ignored ++ during verification stage. ++ """ ++ return [] +-- +2.29.2 + diff --git a/BZ_1961912-fix-ovs-interface-activation.patch b/BZ_1961912-fix-ovs-interface-activation.patch new file mode 100644 index 0000000..81109e5 --- /dev/null +++ b/BZ_1961912-fix-ovs-interface-activation.patch @@ -0,0 +1,137 @@ +From 95d77329b30c9a9a435a881941e27f9a1bed074e Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Wed, 5 May 2021 10:14:40 +0200 +Subject: [PATCH 1/2] nm.profile: do not activate new interfaces twice + +The current code is always adding the action MODIFIED if the interface +is marked as up on the desired state. When a new interface is being +added, Nmstate is adding two actions MODIFIED and NEW_*, that is +incorrect. + +This patch is improving the performance when creating new interfaces. + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/nm/profile.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py +index b4814d9..e117dfe 100644 +--- a/libnmstate/nm/profile.py ++++ b/libnmstate/nm/profile.py +@@ -164,7 +164,6 @@ class NmProfile: + if self._iface.is_virtual and self._nm_dev: + self._add_action(NmProfile.ACTION_DELETE_DEVICE) + elif self._iface.is_up and not self._needs_veth_activation(): +- self._add_action(NmProfile.ACTION_MODIFIED) + if not self._nm_dev: + if self._iface.type == InterfaceType.OVS_PORT: + self._add_action(NmProfile.ACTION_NEW_OVS_PORT) +@@ -176,6 +175,8 @@ class NmProfile: + self._add_action(NmProfile.ACTION_NEW_VXLAN) + else: + self._add_action(NmProfile.ACTION_NEW_IFACES) ++ else: ++ self._add_action(NmProfile.ACTION_MODIFIED) + + elif self._iface.is_down: + if self._nm_ac: +-- +2.31.1 + + +From 9ea925a9a978671881e428abf82aac39c01376e8 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Wed, 5 May 2021 10:52:32 +0200 +Subject: [PATCH 2/2] nm.profile: activate modified ovs-port first + +When removing an ovs-br with an ovs-iface attached and creating a new +ovs-br with the ovs-iface attached in the same transaction the order of +the activations is important. + +The ovs-port must be activated before the ovs-iface. If not, NM will +throw a dependency error. This error is correct because the ovs-iface +depends on the ovs-port, so it must be updated first. + +This fixes: + +``` +Traceback (most recent call last): + File "/usr/lib/python3.6/site-packages/libnmstate/nm/checkpoint.py", line 93, in _refresh_checkpoint_timeout + self._dbuspath, self._timeout, cancellable, cb, cb_data +TypeError: Argument 1 does not allow None as a value +^CTraceback (most recent call last): + File "/usr/lib/python3.6/site-packages/libnmstate/nmstate.py", line 53, in plugin_context + yield plugins + File "/usr/lib/python3.6/site-packages/libnmstate/netapplier.py", line 78, in apply + _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk) + File "/usr/lib/python3.6/site-packages/libnmstate/netapplier.py", line 116, in _apply_ifaces_state + plugin.apply_changes(net_state, save_to_disk) + File "/usr/lib/python3.6/site-packages/libnmstate/nm/plugin.py", line 204, in apply_changes + NmProfiles(self.context).apply_config(net_state, save_to_disk) + File "/usr/lib/python3.6/site-packages/libnmstate/nm/profiles.py", line 89, in apply_config + self._ctx.wait_all_finish() + File "/usr/lib/python3.6/site-packages/libnmstate/nm/context.py", line 213, in wait_all_finish + raise tmp_error +libnmstate.error.NmstateLibnmError: Activate profile uuid:3a359cd0-d68a-4c7a-ae50-f97b47390142 iface:net type: ovs-interface failed: reason= +``` + +Integration test added + +Ref: https://bugzilla.redhat.com/1947287 + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/nm/profile.py | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py +index e117dfe..b655885 100644 +--- a/libnmstate/nm/profile.py ++++ b/libnmstate/nm/profile.py +@@ -69,6 +69,8 @@ class NmProfile: + ACTION_OTHER_MASTER = "other_master" + ACTION_DELETE_PROFILE = "delete_profile" + ACTION_TOP_MASTER = "top_master" ++ ACTION_MODIFIED_OVS_PORT = "modified_ovs_port" ++ ACTION_MODIFIED_OVS_IFACE = "modified_ovs_iface" + + # This is order on group for activation/deactivation + ACTIONS = ( +@@ -81,6 +83,8 @@ class NmProfile: + ACTION_NEW_OVS_IFACE, + ACTION_NEW_VETH, + ACTION_NEW_VETH_PEER, ++ ACTION_MODIFIED_OVS_PORT, ++ ACTION_MODIFIED_OVS_IFACE, + ACTION_MODIFIED, + ACTION_NEW_VLAN, + ACTION_NEW_VXLAN, +@@ -176,7 +180,12 @@ class NmProfile: + else: + self._add_action(NmProfile.ACTION_NEW_IFACES) + else: +- self._add_action(NmProfile.ACTION_MODIFIED) ++ if self._iface.type == InterfaceType.OVS_PORT: ++ self._add_action(NmProfile.ACTION_MODIFIED_OVS_PORT) ++ if self._iface.type == InterfaceType.OVS_INTERFACE: ++ self._add_action(NmProfile.ACTION_MODIFIED_OVS_IFACE) ++ else: ++ self._add_action(NmProfile.ACTION_MODIFIED) + + elif self._iface.is_down: + if self._nm_ac: +@@ -420,6 +429,8 @@ class NmProfile: + def do_action(self, action): + if action in ( + NmProfile.ACTION_MODIFIED, ++ NmProfile.ACTION_MODIFIED_OVS_PORT, ++ NmProfile.ACTION_MODIFIED_OVS_IFACE, + NmProfile.ACTION_ACTIVATE_FIRST, + NmProfile.ACTION_TOP_MASTER, + NmProfile.ACTION_NEW_IFACES, +-- +2.31.1 + diff --git a/BZ_1961914-do-not-use-unmanaged-interface-for-dns.patch b/BZ_1961914-do-not-use-unmanaged-interface-for-dns.patch new file mode 100644 index 0000000..c6b7af3 --- /dev/null +++ b/BZ_1961914-do-not-use-unmanaged-interface-for-dns.patch @@ -0,0 +1,163 @@ +From 72edab395316ba1ae69ea4d788b0572c935759ac Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Tue, 27 Apr 2021 10:19:02 +0200 +Subject: [PATCH] net_state: mark ifaces as ignored earlier + +Nmstate is not touching unmanaged interfaces if they are not being +included in the desired state. If an unmanaged interface has a default +gateway configured and we try to add a dns server, Nmstate will pick the +unmanaged interface because at that point it is not marked as ignored. + +As the interface is being marked as ignored later, the changes are not +being applied and is failing on verification. In order to avoid this, +the unmanaged interfaces should be marked as ignored earlier so they are +not considered for DNS/Routes changes. + +Ref: https://bugzilla.redhat.com/1944582 + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/dns.py | 11 +++++++++-- + libnmstate/net_state.py | 13 +++++++++++-- + libnmstate/netapplier.py | 19 +++++++++++++------ + 3 files changed, 33 insertions(+), 10 deletions(-) + +diff --git a/libnmstate/dns.py b/libnmstate/dns.py +index 1fb2cc8..d44a869 100644 +--- a/libnmstate/dns.py ++++ b/libnmstate/dns.py +@@ -133,7 +133,7 @@ class DnsState: + Return tuple: (ipv4_iface, ipv6_iface) + """ + ipv4_iface, ipv6_iface = self._find_ifaces_with_static_gateways( +- route_state ++ ifaces, route_state + ) + if not (ipv4_iface and ipv6_iface): + ( +@@ -147,7 +147,7 @@ class DnsState: + + return ipv4_iface, ipv6_iface + +- def _find_ifaces_with_static_gateways(self, route_state): ++ def _find_ifaces_with_static_gateways(self, ifaces, route_state): + """ + Return tuple of interfaces with IPv4 and IPv6 static gateways. + """ +@@ -158,6 +158,11 @@ class DnsState: + if ipv4_iface and ipv6_iface: + return (ipv4_iface, ipv6_iface) + if route.is_gateway: ++ # Only interfaces not ignored can be considered as valid ++ # static gateway for nameservers. ++ iface = ifaces.all_kernel_ifaces.get(iface_name) ++ if iface and iface.is_ignore: ++ continue + if route.is_ipv6: + ipv6_iface = iface_name + else: +@@ -168,6 +173,8 @@ class DnsState: + ipv4_iface = None + ipv6_iface = None + for iface in ifaces.all_kernel_ifaces.values(): ++ if iface.is_ignore: ++ continue + if ipv4_iface and ipv6_iface: + return (ipv4_iface, ipv6_iface) + for family in (Interface.IPV4, Interface.IPV6): +diff --git a/libnmstate/net_state.py b/libnmstate/net_state.py +index 5dc7b43..713b7dc 100644 +--- a/libnmstate/net_state.py ++++ b/libnmstate/net_state.py +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2020 Red Hat, Inc. ++# Copyright (c) 2020-2021 Red Hat, Inc. + # + # This file is part of nmstate + # +@@ -26,8 +26,8 @@ from libnmstate.schema import Interface + from libnmstate.schema import Route + from libnmstate.schema import RouteRule + +-from .ifaces import Ifaces + from .dns import DnsState ++from .ifaces import Ifaces + from .route import RouteState + from .route_rule import RouteRuleState + from .state import state_match +@@ -37,6 +37,7 @@ class NetState: + def __init__( + self, + desire_state, ++ ignored_ifnames=[], + current_state=None, + save_to_disk=True, + gen_conf_mode=False, +@@ -49,6 +50,8 @@ class NetState: + save_to_disk, + gen_conf_mode, + ) ++ if not gen_conf_mode: ++ self._mark_ignored_kernel_ifaces(ignored_ifnames) + self._route = RouteState( + self._ifaces, + desire_state.get(Route.KEY), +@@ -70,6 +73,12 @@ class NetState: + self._ifaces.gen_route_metadata(self._route) + self._ifaces.gen_route_rule_metadata(self._route_rule, self._route) + ++ def _mark_ignored_kernel_ifaces(self, ignored_ifnames): ++ for iface_name in ignored_ifnames: ++ iface = self._ifaces.all_kernel_ifaces.get(iface_name) ++ if iface and not iface.is_desired: ++ iface.mark_as_ignored() ++ + def verify(self, current_state): + self._ifaces.verify(current_state.get(Interface.KEY)) + self._dns.verify(current_state.get(DNS.KEY)) +diff --git a/libnmstate/netapplier.py b/libnmstate/netapplier.py +index a020f00..202494d 100644 +--- a/libnmstate/netapplier.py ++++ b/libnmstate/netapplier.py +@@ -73,7 +73,10 @@ def apply( + validator.validate_capabilities( + desired_state, plugins_capabilities(plugins) + ) +- net_state = NetState(desired_state, current_state, save_to_disk) ++ ignored_ifnames = _get_ignored_interface_names(plugins) ++ net_state = NetState( ++ desired_state, ignored_ifnames, current_state, save_to_disk ++ ) + checkpoints = create_checkpoints(plugins, rollback_timeout) + _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk) + if commit: +@@ -107,11 +110,6 @@ def rollback(*, checkpoint=None): + + + def _apply_ifaces_state(plugins, net_state, verify_change, save_to_disk): +- for plugin in plugins: +- for iface_name in plugin.get_ignored_kernel_interface_names(): +- iface = net_state.ifaces.all_kernel_ifaces.get(iface_name) +- if iface and not iface.is_desired: +- iface.mark_as_ignored() + for plugin in plugins: + plugin.apply_changes(net_state, save_to_disk) + +@@ -145,3 +143,12 @@ def _net_state_contains_sriov_interface(net_state): + def _verify_change(plugins, net_state): + current_state = show_with_plugins(plugins) + net_state.verify(current_state) ++ ++ ++def _get_ignored_interface_names(plugins): ++ ifaces = set() ++ for plugin in plugins: ++ for iface_name in plugin.get_ignored_kernel_interface_names(): ++ ifaces.add(iface_name) ++ ++ return ifaces +-- +2.31.1 + diff --git a/BZ_1964439-ovs-Fix-is_ovs_running-in-container-environment.patch b/BZ_1964439-ovs-Fix-is_ovs_running-in-container-environment.patch new file mode 100644 index 0000000..5856e10 --- /dev/null +++ b/BZ_1964439-ovs-Fix-is_ovs_running-in-container-environment.patch @@ -0,0 +1,222 @@ +From 48c7645ce8849ac31298e6c2b1d5661d0f581279 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Mon, 17 May 2021 16:09:52 +0800 +Subject: [PATCH 1/2] ovs: Fix `is_ovs_running()` in container environment. + +In k8s container environment, the OVS database socket +/var/run/openvswitch/db.sock is mounted from host, so NM can managed it +without the ovs daemon running in container. + +To support that, this patch removed the top level checking on +`is_ovs_running()` and trust plugin raise the proper error on failure. + +Patched the NM plugin to check the error +`NM.DeviceStateReason.OVSDB_FAILED` on activation failure, raise +`NmstateDependencyError` if OVS DB failed to connected. + +NM will not raise any error when creating OVS internal interface with +OVSDB mounted to /dev/null, NM will keep showing the OVS interface as +ACTIVATING, changed the fallback checker to give only 30 seconds for OVS +interface to exit `NM.DeviceState.PREPARE`, if not treat it as OVS +daemon malfunctioning. + +Updated integration test case to mask(mount /dev/null) the OVS DB socket +file for simulating the stopped OVS daemon. + +Signed-off-by: Gris Ge +Signed-off-by: Fernando Fernandez Mancera +--- + libnmstate/ifaces/ovs.py | 15 ---------- + libnmstate/nm/active_connection.py | 47 ++++++++++++++++++++++++++---- + libnmstate/nm/plugin.py | 3 +- + libnmstate/validator.py | 16 +++------- + tests/integration/ovs_test.py | 41 +++++++++++--------------- + 5 files changed, 64 insertions(+), 58 deletions(-) + +diff --git a/libnmstate/ifaces/ovs.py b/libnmstate/ifaces/ovs.py +index 24d4aba..28892ad 100644 +--- a/libnmstate/ifaces/ovs.py ++++ b/libnmstate/ifaces/ovs.py +@@ -19,7 +19,6 @@ + + from copy import deepcopy + from operator import itemgetter +-import subprocess + import warnings + + from libnmstate.error import NmstateValueError +@@ -252,20 +251,6 @@ class OvsInternalIface(BaseIface): + self._info.pop(Interface.MAC, None) + + +-def is_ovs_running(): +- try: +- subprocess.run( +- ("systemctl", "status", "openvswitch"), +- stdout=subprocess.DEVNULL, +- stderr=subprocess.DEVNULL, +- check=True, +- timeout=SYSTEMCTL_TIMEOUT_SECONDS, +- ) +- return True +- except Exception: +- return False +- +- + def is_ovs_lag_port(port_state): + return port_state.get(OVSBridge.Port.LINK_AGGREGATION_SUBTREE) is not None + +diff --git a/libnmstate/nm/active_connection.py b/libnmstate/nm/active_connection.py +index ddf93a7..150256f 100644 +--- a/libnmstate/nm/active_connection.py ++++ b/libnmstate/nm/active_connection.py +@@ -20,6 +20,7 @@ + import logging + + from libnmstate.error import NmstateLibnmError ++from libnmstate.error import NmstateDependencyError + from libnmstate.error import NmstateInternalError + + from .common import GLib +@@ -33,6 +34,7 @@ from .ipv6 import is_dynamic as is_ipv6_dynamic + + NM_AC_STATE_CHANGED_SIGNAL = "state-changed" + FALLBACK_CHECKER_INTERNAL = 15 ++MAX_OVS_IFACE_PREPARE_TIME = FALLBACK_CHECKER_INTERNAL * 2 + GIO_ERROR_DOMAIN = "g-io-error-quark" + + +@@ -92,6 +94,7 @@ class ProfileActivation: + self._dev_handlers = set() + self._action = None + self._fallback_checker = None ++ self._fallback_checker_counter = 0 + + def run(self): + specific_object = None +@@ -336,19 +339,53 @@ class ProfileActivation: + self._activation_clean_up() + self._ctx.finish_async(self._action) + elif not is_activating(self._nm_ac, self._nm_dev): +- reason = f"{self._nm_ac.get_state_reason()}" ++ nm_ac_reason = f"{self._nm_ac.get_state_reason()}" ++ nm_dev_reason = None + if self._nm_dev: +- reason += f" {self._nm_dev.get_state_reason()}" ++ nm_dev_reason = self._nm_dev.get_state_reason() ++ ++ if nm_dev_reason == NM.DeviceStateReason.OVSDB_FAILED: ++ error = NmstateDependencyError( ++ f"{self._action} failed: failed to communicating with " ++ f"Open vSwitch database, {nm_dev_reason}" ++ ) ++ else: ++ reason = nm_ac_reason + ( ++ str(nm_dev_reason) if nm_dev_reason else "" ++ ) ++ error = NmstateLibnmError( ++ f"{self._action} failed: reason={reason}" ++ ) + self._activation_clean_up() +- self._ctx.fail( +- NmstateLibnmError(f"{self._action} failed: reason={reason}") +- ) ++ self._ctx.fail(error) + + def _fallback_checker_callback(self, _user_data): ++ self._fallback_checker_counter += 1 + nm_dev = get_nm_dev(self._ctx, self._iface_name, self._iface_type) + if nm_dev: + self._nm_dev = nm_dev + self._activation_progress_check() ++ # When OVSDB connection is invalid(such as been mounted as ++ # /dev/null), NM will hang on the activation of ovs internal ++ # interface with state ACITVATING with reason UNKNOWN forever with ++ # no state change signal. The fallback check only found it ++ # as activating which lead us hang till killed by idle timeout. ++ # To prevent that, when we found OVS interface interface in ++ # `NM.DeviceState.PREPARE` on in second call of fallbacker, ++ # we fail the action as NmstateDependencyError. ++ if ( ++ self._fallback_checker_counter ++ >= MAX_OVS_IFACE_PREPARE_TIME / FALLBACK_CHECKER_INTERNAL ++ and nm_dev.get_device_type() == NM.DeviceType.OVS_INTERFACE ++ and nm_dev.get_state() == NM.DeviceState.PREPARE ++ ): ++ self._ctx.fail( ++ NmstateDependencyError( ++ f"{self._action} failed: timeout on creating OVS " ++ "interface, please check Open vSwitch daemon" ++ ) ++ ) ++ + return GLib.SOURCE_CONTINUE + + +diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py +index 335d93c..da933b3 100644 +--- a/libnmstate/nm/plugin.py ++++ b/libnmstate/nm/plugin.py +@@ -23,7 +23,6 @@ from operator import itemgetter + from libnmstate.error import NmstateDependencyError + from libnmstate.error import NmstateNotSupportedError + from libnmstate.error import NmstateValueError +-from libnmstate.ifaces.ovs import is_ovs_running + from libnmstate.schema import DNS + from libnmstate.schema import Interface + from libnmstate.schema import InterfaceType +@@ -103,7 +102,7 @@ class NetworkManagerPlugin(NmstatePlugin): + @property + def capabilities(self): + capabilities = [] +- if has_ovs_capability(self.client) and is_ovs_running(): ++ if has_ovs_capability(self.client): + capabilities.append(NmstatePlugin.OVS_CAPABILITY) + if has_team_capability(self.client): + capabilities.append(NmstatePlugin.TEAM_CAPABILITY) +diff --git a/libnmstate/validator.py b/libnmstate/validator.py +index 02890b4..cd3b540 100644 +--- a/libnmstate/validator.py ++++ b/libnmstate/validator.py +@@ -22,7 +22,6 @@ import logging + + import jsonschema as js + +-from libnmstate.ifaces.ovs import is_ovs_running + from libnmstate.schema import Interface + from libnmstate.schema import InterfaceType + from libnmstate.error import NmstateDependencyError +@@ -50,7 +49,6 @@ def validate_interface_capabilities(ifaces_state, capabilities): + ifaces_types = {iface_state.get("type") for iface_state in ifaces_state} + has_ovs_capability = NmstatePlugin.OVS_CAPABILITY in capabilities + has_team_capability = NmstatePlugin.TEAM_CAPABILITY in capabilities +- ovs_is_running = is_ovs_running() + for iface_type in ifaces_types: + is_ovs_type = iface_type in ( + InterfaceType.OVS_BRIDGE, +@@ -58,18 +56,12 @@ def validate_interface_capabilities(ifaces_state, capabilities): + InterfaceType.OVS_PORT, + ) + if is_ovs_type and not has_ovs_capability: +- if not ovs_is_running: +- raise NmstateDependencyError( +- "openvswitch service is not started." +- ) +- else: +- raise NmstateDependencyError( +- "Open vSwitch NetworkManager support not installed " +- "and started" +- ) ++ raise NmstateDependencyError( ++ "Open vSwitch support not properly installed or started" ++ ) + elif iface_type == InterfaceType.TEAM and not has_team_capability: + raise NmstateDependencyError( +- "NetworkManager-team plugin not installed and started" ++ "Team support not properly installed or started" + ) + + +-- +2.31.1 + diff --git a/BZ_1964440-nm-ipv4-Deactivate-profile-when-route-removed.patch b/BZ_1964440-nm-ipv4-Deactivate-profile-when-route-removed.patch new file mode 100644 index 0000000..1ffe314 --- /dev/null +++ b/BZ_1964440-nm-ipv4-Deactivate-profile-when-route-removed.patch @@ -0,0 +1,86 @@ +From af8199135907d300014b5052571ca3e445455af7 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 25 May 2021 16:50:06 +0800 +Subject: [PATCH 2/2] nm ipv4: Deactivate profile when route removed. + +The bug https://bugzilla.redhat.com/show_bug.cgi?id=1962551 has shown +IPv4 route also share the same problem. + +Whenever we got a route removal, we deactivate that profile via +NetworkManager. + +Integration test case included. + +Signed-off-by: Gris Ge +Signed-off-by: Fernando Fernandez Mancera +--- + libnmstate/nm/profile.py | 5 +++-- + libnmstate/route.py | 19 +++++++---------- + tests/integration/route_test.py | 37 ++++++++++++++++++++++++++++++--- + 3 files changed, 45 insertions(+), 16 deletions(-) + +diff --git a/libnmstate/nm/profile.py b/libnmstate/nm/profile.py +index b655885..6b20b21 100644 +--- a/libnmstate/nm/profile.py ++++ b/libnmstate/nm/profile.py +@@ -49,7 +49,7 @@ from .translator import Api2Nm + IMPORT_NM_DEV_TIMEOUT = 5 + IMPORT_NM_DEV_RETRY_INTERNAL = 0.5 + FALLBACK_CHECKER_INTERNAL = 15 +-IPV6_ROUTE_REMOVED = "_ipv6_route_removed" ++ROUTE_REMOVED = "_route_removed" + + + class NmProfile: +@@ -193,9 +193,10 @@ class NmProfile: + elif self._iface.is_virtual and self._nm_dev: + self._add_action(NmProfile.ACTION_DELETE_DEVICE) + +- if self._iface.raw.get(IPV6_ROUTE_REMOVED): ++ if self._iface.raw.get(ROUTE_REMOVED): + # This is a workaround for NM bug: + # https://bugzilla.redhat.com/1837254 ++ # https://bugzilla.redhat.com/1962551 + self._add_action(NmProfile.ACTION_DEACTIVATE_FIRST) + + if self._iface.is_controller and self._iface.is_up: +diff --git a/libnmstate/route.py b/libnmstate/route.py +index cdea198..d373427 100644 +--- a/libnmstate/route.py ++++ b/libnmstate/route.py +@@ -36,7 +36,7 @@ from .state import StateEntry + DEFAULT_ROUTE_TABLE = 254 + + +-IPV6_ROUTE_REMOVED = "_ipv6_route_removed" ++ROUTE_REMOVED = "_route_removed" + + + class RouteEntry(StateEntry): +@@ -235,16 +235,13 @@ class RouteState: + for route in route_set: + if not rt.match(route): + new_routes.add(route) +- if route.is_ipv6: +- # The routes match and therefore it is being removed. +- # Nmstate will check if it is an IPv6 route and if so, +- # marking the interface as deactivate first. +- # +- # This is a workaround for NM bug: +- # https://bugzilla.redhat.com/1837254 +- ifaces.all_kernel_ifaces[iface_name].raw[ +- IPV6_ROUTE_REMOVED +- ] = True ++ # The routes match and therefore it is being removed. ++ # marking the interface as deactivate first. ++ # ++ # This is a workaround for NM bug: ++ # https://bugzilla.redhat.com/1837254 ++ # https://bugzilla.redhat.com/1962551 ++ ifaces.all_kernel_ifaces[iface_name].raw[ROUTE_REMOVED] = True + if new_routes != route_set: + self._routes[iface_name] = new_routes + +-- +2.31.1 + diff --git a/BZ_1966379_fix_bond_opt_tlb_dynamic_lb.patch b/BZ_1966379_fix_bond_opt_tlb_dynamic_lb.patch new file mode 100644 index 0000000..1d70d68 --- /dev/null +++ b/BZ_1966379_fix_bond_opt_tlb_dynamic_lb.patch @@ -0,0 +1,74 @@ +From e503eb8241dda600ef16741c29cab83443ae0528 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 1 Jun 2021 10:13:33 +0800 +Subject: [PATCH 1/2] nm bond: Fixing `tlb_dynamic_lb` option + +NM only takes 1 or 0 for True/False, currently only "use_carrier" +and "tlb_dynamic_lb" are boolean. + +Integration test case included. NM 1.31 is required for bug +https://bugzilla.redhat.com/show_bug.cgi?id=1959934 + +Signed-off-by: Gris Ge +--- + libnmstate/nm/bond.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libnmstate/nm/bond.py b/libnmstate/nm/bond.py +index cebac4d..067d87f 100644 +--- a/libnmstate/nm/bond.py ++++ b/libnmstate/nm/bond.py +@@ -92,7 +92,7 @@ def _nm_fix_bond_options(option_name, option_value): + option_name, option_value + ) + ) +- elif option_name == "use_carrier": ++ elif option_name in ("use_carrier", "tlb_dynamic_lb"): + option_value = 1 if option_value else 0 + + return str(option_value) +-- +2.31.1 + + +From 1d6c7715dfbcb5021016bcd7b4f1f9fa357b2f20 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 1 Jun 2021 10:41:57 +0800 +Subject: [PATCH 2/2] nm bond: Fix preserving `all_slaves_active` option + +When `all_slaves_active` was previously set via nmstate or NM, follow up +bond modification will fail with: + + NmstateNotImplementedError: Unsupported bond option: 'all_slaves_active'='0' + +This is because the option returned by `_get_bond_options_from_profiles()` is +not canonicalized. + +Expand the check to cover `1` and `0`. + +Integration test case included. + +Signed-off-by: Gris Ge +--- + libnmstate/nm/bond.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libnmstate/nm/bond.py b/libnmstate/nm/bond.py +index 067d87f..1642319 100644 +--- a/libnmstate/nm/bond.py ++++ b/libnmstate/nm/bond.py +@@ -82,9 +82,9 @@ def create_setting(iface, wired_setting, base_con_profile): + + def _nm_fix_bond_options(option_name, option_value): + if option_name == "all_slaves_active": +- if option_value == "delivered": ++ if option_value in ("delivered", "1"): + option_value = 1 +- elif option_value == "dropped": ++ elif option_value in ("dropped", "0"): + option_value = 0 + else: + raise NmstateNotImplementedError( +-- +2.31.1 + diff --git a/BZ_1966457_Fix_bond_fail_over_mac.patch b/BZ_1966457_Fix_bond_fail_over_mac.patch new file mode 100644 index 0000000..c72cc8f --- /dev/null +++ b/BZ_1966457_Fix_bond_fail_over_mac.patch @@ -0,0 +1,35 @@ +From b1e94d1aa04f51b2d15711c8e7ab37198b173065 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 1 Jun 2021 16:33:15 +0800 +Subject: [PATCH] bond: Fix bond fail_over_mac=active + +With bond interface in fail_over_mac=active and active-backup mode, +any future change via nmstate will fail as nmstate is validating +on current state instead of desire state for this bond mac restriction. + +Fixed the code to only validate bond mac restriction on desired or +changed bond interface. + +Integration test case include. + +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/bond.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libnmstate/ifaces/bond.py b/libnmstate/ifaces/bond.py +index 138386e..01859b0 100644 +--- a/libnmstate/ifaces/bond.py ++++ b/libnmstate/ifaces/bond.py +@@ -88,7 +88,7 @@ class BondIface(BaseIface): + + def pre_edit_validation_and_cleanup(self): + super().pre_edit_validation_and_cleanup() +- if self.is_up: ++ if self.is_up and (self.is_desired or self.is_changed): + self._discard_bond_option_when_mode_change() + self._validate_bond_mode() + self._fix_mac_restriced_mode() +-- +2.31.1 + diff --git a/BZ_1966457_only_validate_desired_bond.patch b/BZ_1966457_only_validate_desired_bond.patch new file mode 100644 index 0000000..fd4a581 --- /dev/null +++ b/BZ_1966457_only_validate_desired_bond.patch @@ -0,0 +1,32 @@ +From 355bc8f052e35084405343a0b94ccf06007c31f3 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 2 Jun 2021 19:53:25 +0800 +Subject: [PATCH] bond: Don't validate current bond status + +If a bond interface is only marked as changed due to other +interface(like bridge port list change), its original desire information +is fully read from current status, there is no need to validate it. + +The fix is only validate on desired bond interface. + +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/bond.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libnmstate/ifaces/bond.py b/libnmstate/ifaces/bond.py +index 01859b0..6311f5f 100644 +--- a/libnmstate/ifaces/bond.py ++++ b/libnmstate/ifaces/bond.py +@@ -88,7 +88,7 @@ class BondIface(BaseIface): + + def pre_edit_validation_and_cleanup(self): + super().pre_edit_validation_and_cleanup() +- if self.is_up and (self.is_desired or self.is_changed): ++ if self.is_up and self.is_desired: + self._discard_bond_option_when_mode_change() + self._validate_bond_mode() + self._fix_mac_restriced_mode() +-- +2.31.1 + diff --git a/gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.asc b/gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.asc deleted file mode 100644 index 5c599f3..0000000 --- a/gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.asc +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -=yD6X ------END PGP PUBLIC KEY BLOCK----- diff --git a/nmstate-0.2.7.tar.gz b/nmstate-0.2.7.tar.gz deleted file mode 100644 index 219d121..0000000 Binary files a/nmstate-0.2.7.tar.gz and /dev/null differ diff --git a/nmstate-0.2.7.tar.gz.asc b/nmstate-0.2.7.tar.gz.asc deleted file mode 100644 index d2ecc91..0000000 --- a/nmstate-0.2.7.tar.gz.asc +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.22 (GNU/Linux) - -iQIcBAABAgAGBQJeX5uWAAoJEImQFMBGPBK7oKMQAIBxLApPeRx4ueNYRhaqCBLZ -SBNfZNpxTfvVRG8fB6zKZMdgQtM4bA6Yf2F3KaZnczVbY01utbWx1tSIA/dSke3c -EFCZ/c+eE4NWDJtDGcAXuoloHLdLxpxyQYXUu0NRSD0GmMeT+oe4+Cd8DQAjqIKR -ng5R/TZ2NouwRnTEUyyLmD2tyPPOkcj2PJRyOiFf5dgdryNSbATBcutQNbbVXgVg -7Ealitp9GH+8rVhRuRFQmbbpx+zjF/keU2489IWVDU+7s5SxH9cU08tXefjS8djH -cH5KmF8CJZ429TUIkWtJbzIiqQS2IwXyOJ1KIWAfuPsfFnNIFlP4xPwSrHrp2YKG -O2RwX+///ji83hSIwC9KlWf6LXobsAa4cWXq5dIQw4Qlu7LaI+czr5xbJ6yfrdtf -YPwhWMyh3tc6IOYSXh7c9FqyalHhOwvcjnL/Gynr0qs5knFoC/buVnzgmWTqYNir -gQZaQs1nf1toc4YtsBduiwV4CmUTaS8l8pdlpZ0JLk1A9+FmXHeKgbIqqmEqcGXL -6CCqZM/dRJBLC5mDfTdZOOawkugkyVrL5g/Ygq2shgDsgeefFdP1l4o1Kh5halNj -f1fMmkUE3tMuGh0qdN79hw2R7WRgmv2rLH2PzhJbKw07k20qMEzaCay1mehS7ORy -Ccq3dYiS5o8JokEUXpqz -=p69R ------END PGP SIGNATURE----- diff --git a/nmstate-1.0.2.tar.gz b/nmstate-1.0.2.tar.gz new file mode 100644 index 0000000..60473e0 Binary files /dev/null and b/nmstate-1.0.2.tar.gz differ diff --git a/nmstate-1.0.2.tar.gz.asc b/nmstate-1.0.2.tar.gz.asc new file mode 100644 index 0000000..ef664a4 --- /dev/null +++ b/nmstate-1.0.2.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEfUQ+BAINyWGvqJXerIciWuEsPqMFAmAueEYACgkQrIciWuEs +PqPJxw//UmWdCJgoClFkEpWqWUkjMmfkGh70PoxtuOeNrAYwHv9zCHDBFjLtaDG1 +18+jakwrVIlTiFHZqfz1g3o0Te86w5rKiU2y0FBtBPZ1cdcJZk2Is5wb/JJo78n+ +9sWRfZmSN0SMiJ5HfzhTdZ2RsZYRSaDPSUxchRY03LzsBusxoK8swWu9oUHqmYKd +S3k4skP5ZQvpHtKzq9w1lfU4YAw42sRvXHW/++HqGgE0rypf+Wlcu9C+It9kVLCr +3rdp8iTGTg+LRg7LxFmEsRlmPpxhO25LaxjFvYSFnhE94xOt28KXeHBYs8hPPRwh ++z2w6zJ3hgIrLh10IPzePTWk//KNWDRaAJXQTCma1UE4jdL3+wbxb8H3vl5VCrBU +3fuj3JwfvFU1NuDf+yuJ0sCKzNXaAzpYYgfIaCaPdtBpg5jl2DTEfEF8QZKYuJDU +ueCo6reBAlwJzce433aSzBXshFbHG/RdD09duS3p84Dn6ljEN3GfJwUAC9s9TsAQ +U5+rWog6zMpVke/9yqwEf1KmqtLM3/+Ih30CHb3ZoPTf05KB14k0d1CLDdC9d9dy +gN0w8xjdTUXbUXW/XIvRVX9KWqyNI6lnZoL0MWzPwUmMxwPJkRpAVpLKpgyUrVpD +yjtLTFDZJNmfmbi2b0myFFcc2chaXmYlpLCP8vfRYJA3mCee6Xg= +=b/Mh +-----END PGP SIGNATURE----- diff --git a/nmstate.gpg b/nmstate.gpg new file mode 100644 index 0000000..1c4631f --- /dev/null +++ b/nmstate.gpg @@ -0,0 +1,379 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +qQ== +=iT4N +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=yD6X +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +jXY3xoBTq94SsA== +=Y8tq +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +qvuXBO8wSn2p2qJiu3fconD4UQ/pBfQwDQ== +=seEJ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/nmstate.spec b/nmstate.spec index 46efcbb..c276b56 100644 --- a/nmstate.spec +++ b/nmstate.spec @@ -3,14 +3,27 @@ %define libname libnmstate Name: nmstate -Version: 0.2.7 -Release: 1 +Version: 1.0.2 +Release: 11 Summary: Declarative network manager API License: LGPLv2+ URL: https://github.com/%{srcname}/%{srcname} -Source0: %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz -Source1: %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz.asc -Source2: gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.asc +#from %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz +Source0: %{srcname}-%{version}.tar.gz +#from %{url}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz.asc +Source1: %{srcname}-%{version}.tar.gz.asc +#from https://www.nmstate.io/nmstate.gpg +Source2: nmstate.gpg +Patch1: BZ_1931751-nmstate-fix-return-code.patch +Patch2: BZ_1931355-SRIOV-wait-VF-mount-decrease.patch +Patch3: BZ_1932247-nm-Don-t-touch-unmanaged-interface-unless-desired.patch +Patch4: BZ_1961914-do-not-use-unmanaged-interface-for-dns.patch +Patch5: BZ_1961912-fix-ovs-interface-activation.patch +Patch6: BZ_1964439-ovs-Fix-is_ovs_running-in-container-environment.patch +Patch7: BZ_1964440-nm-ipv4-Deactivate-profile-when-route-removed.patch +Patch8: BZ_1966379_fix_bond_opt_tlb_dynamic_lb.patch +Patch9: BZ_1966457_Fix_bond_fail_over_mac.patch +Patch10: BZ_1966457_only_validate_desired_bond.patch BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -27,7 +40,7 @@ provider support on the southbound. %package -n python3-%{libname} Summary: nmstate Python 3 API library -Requires: NetworkManager-libnm >= 1:1.22.8 +Requires: NetworkManager-libnm >= 1:1.26.0 # Use Recommends for NetworkManager because only access to NM DBus is required, # but NM could be running on a different host Recommends: NetworkManager @@ -37,15 +50,26 @@ Recommends: NetworkManager-config-server # required for OVS and team support Suggests: NetworkManager-ovs Suggests: NetworkManager-team +Requires: nispor +Requires: python3dist(varlink) +%package -n nmstate-plugin-ovsdb +Summary: nmstate plugin for OVS database manipulation +Requires: python3-%{libname} = %{?epoch:%{epoch}:}%{version}-%{release} +# The python-openvswitch rpm pacakge is not in the same repo with nmstate, +# hence state it as Recommends, no requires. +Recommends: python3dist(ovs) %description -n python3-%{libname} -This package contains the Python 3 library for Nmstate. +This package contains the Python 3 library for nmstate. + +%description -n nmstate-plugin-ovsdb +This package contains the nmstate plugin for OVS database manipulation. %prep -gpg2 --import --import-options import-export,import-minimal %{SOURCE2} > ./gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg -gpgv2 --keyring ./gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg %{SOURCE1} %{SOURCE0} -%setup -q +gpg2 --import --import-options import-export,import-minimal %{SOURCE2} > ./gpgkey-mantainers.gpg +gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0} +%autosetup -p1 %build %py3_build @@ -64,7 +88,15 @@ gpgv2 --keyring ./gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg %{SOURCE1} %license LICENSE %{python3_sitelib}/%{libname} %{python3_sitelib}/%{srcname}-*.egg-info/ +%exclude %{python3_sitelib}/%{libname}/plugins/nmstate_plugin_* +%exclude %{python3_sitelib}/%{libname}/plugins/__pycache__/nmstate_plugin_* + +%files -n nmstate-plugin-ovsdb +%{python3_sitelib}/%{libname}/plugins/nmstate_plugin_ovsdb* +%{python3_sitelib}/%{libname}/plugins/__pycache__/nmstate_plugin_ovsdb* %changelog +* Thu Jul 8 2021 kymayl - 1.0.2-11 +- Package upgrade * Fri Jul 2 2021 kymayl - 0.2.7-1 - Package init with version 0.2.7-1