!4 package upgrade

From: @kymayl
Reviewed-by: @crrs666
Signed-off-by: @crrs666
This commit is contained in:
openeuler-ci-bot 2021-07-08 05:25:49 +00:00 committed by Gitee
commit f3cdd4990e
17 changed files with 1604 additions and 77 deletions

View File

@ -0,0 +1,166 @@
From 80c97b27707b036f0a54988ade4bda3ccb342b34 Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
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 <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
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 <ffmancera@riseup.net>
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 <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
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

View File

@ -0,0 +1,29 @@
From b26ab850172a41557cad42cc011bd00d7c108c88 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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

View File

@ -0,0 +1,223 @@
From ccdcd8f86544a6364109a0c0142d05a5afacf64e Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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

View File

@ -0,0 +1,137 @@
From 95d77329b30c9a9a435a881941e27f9a1bed074e Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
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 <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
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 <ffmancera@riseup.net>
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=<enum NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED of type NM.ActiveConnectionStateReason> <enum NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED of type NM.DeviceStateReason>
```
Integration test added
Ref: https://bugzilla.redhat.com/1947287
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
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

View File

@ -0,0 +1,163 @@
From 72edab395316ba1ae69ea4d788b0572c935759ac Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
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 <ffmancera@riseup.net>
Signed-off-by: Gris Ge <fge@redhat.com>
---
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

View File

@ -0,0 +1,222 @@
From 48c7645ce8849ac31298e6c2b1d5661d0f581279 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
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

View File

@ -0,0 +1,86 @@
From af8199135907d300014b5052571ca3e445455af7 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
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

View File

@ -0,0 +1,74 @@
From e503eb8241dda600ef16741c29cab83443ae0528 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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 <fge@redhat.com>
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 <fge@redhat.com>
---
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

View File

@ -0,0 +1,35 @@
From b1e94d1aa04f51b2d15711c8e7ab37198b173065 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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

View File

@ -0,0 +1,32 @@
From 355bc8f052e35084405343a0b94ccf06007c31f3 Mon Sep 17 00:00:00 2001
From: Gris Ge <fge@redhat.com>
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 <fge@redhat.com>
---
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

View File

@ -1,50 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=yD6X
-----END PGP PUBLIC KEY BLOCK-----

Binary file not shown.

View File

@ -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-----

BIN
nmstate-1.0.2.tar.gz Normal file

Binary file not shown.

16
nmstate-1.0.2.tar.gz.asc Normal file
View File

@ -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-----

379
nmstate.gpg Normal file
View File

@ -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-----
xsFNBF6haTkBEAC7CAiPirCR/zQSYKNozitSZMrXQk1BLeG0LuWgLdOeT7R0WU7m
063HA8geCOTqAPn7jV+EWHvww7881IhX2g/CIKd/j+pEqDL6G/Mp5+AEj78FpHBJ
RMPyl3I8gK183JJe/F5BhSowoO4Joll09McQ+3DL0pA7YabXYIRPGhbBNZfmK41f
psNsEarcjJtJVsT+S7gh98EX9/F2fL71LKCpacPXdaJjYd1eVVXISe43w0z99CuD
VHo9nfUDmq2NZvPKjZSJBLmrpzNoHVCC9Dq163ehZqTyiL9pCsnnbwN2SqWZTWJK
ZVVjt6To4vHRoKPhwvAt3Q5PxIw0FnsSbpVvMa4yljQGVQLpEwOrK3rWrQxn8ERv
KfN3iyeOlMXqncSH52Y0M1PcyHsdxejmUZzdHrzyfNWPxfzTbJw3w9RFKXmb8alS
aFQLLrXIYF6gdwuG/Pry071jCpR0SxcStOq1DuAAJTYqYammO/hBzhsxEdgFuPQG
GVMTQRRMJocUMFwmHOeoG5KWh7HyANZ3udD+7RQ2DSqUKYoIo+Fe6MxWsrhsAUE+
xifXOElEwDIByQmz+4XkiZFrrHMOoPPlmWALT6CltEQbMo6445CeStZ+CiH1n48o
bTMVMkP9h9l20BGVFtsCL+tv1ZvsD5XPOsV0rYiiWUeh+8KyVTTx6kpmDQARAQAB
zTFGZXJuYW5kbyBGZXJuYW5kZXogTWFuY2VyYSA8ZmZtYW5jZXJhQHJpc2V1cC5u
ZXQ+wsGUBBMBCAA+FiEEfUQ+BAINyWGvqJXerIciWuEsPqMFAl6haTkCGwMFCQHh
M4AFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQrIciWuEsPqO/GQ/9GlCzor44
RXKEFJnBy30faExWHpqfYbC8e9QVmIJ9EdJALjEFTc/Ca9Wyz9d4248TvLjs3hi9
OrQkbv7FAseFSDfRLLmvIL0p+wyMFVwUFFYqHOxqaNgpHs/DcwULqojRNqKdqAr3
0RgYVGUGPrKu3zalR70TVM+LkY4pnKqt2w5lZYg2T+f+bGQt7xnZHmIHmtp8McM4
um/wuEaRyCrgzbeUlYiBBmdPgSKiCfCfmiwaA7JYGPHbbTx1P66ZmrD1Oh73VAus
hoP9q4cr8u5+fS+P45h86G7ufz3GOPJDGB8bEs9GJEe2YqTtBilT7pVNn/zZTzg3
/XgXRbSWLnlmgCsu6HiYdGt2WyzyzNNWrRLIKlUinDvtSRDgRAJsRdyCdwz0HFWg
MYD6mtyDOw0FOfCJOFsDYosBEbk2ugedO0CkHh/egrpCnzwYPTKzqLw9eoiFeHsc
g9AtGLRDa9MZz7wfe3h+rknUZ8cOyidERH3pkgxa6WSqOvotIAc9WTzVTH8/ZHou
JissnKCe9DSv61iTq5GGRL04Haj2pxgRkadkeFRf7RHLHFGY80Z0RTU5IcDderAc
eDwFn2nge03/q13O8gMT8Zp3UgxhOxzPgkz/T02tLJW3oo3oFhLG6wyd+H501S33
RbfvmKI+xYBWp51iFh04sBoh9PfZVO3rV13OwU0EXqFpOQEQAJ++bjajjD5BPz9Y
LyB5JzfnnuL6B82sRyiDHTyhMuCnxDoP4nyMvwtexjR5r+p3QfWAnhMcBNcdmwR1
E7eNtp4+FR6SeuNLCODbGq1z5n/WW85HkgewH87jp63r9YytEZUfkxhR3Bab+FnQ
1rBgxwvVZNV1wgRbW59HLQeoks/bEf/K3kUuy8OlMiaSAxQqedyK595A/SJJS+Fq
84Xd+RV584DMH1Yg/NmawFJqqTk/ub0ALDpwBwBAjyXlbr1eiNLgFB4nI5htwN4G
iY6jsej4Y0G8IJCjlZlfBLo1hVi/7FXfRpmT6DHbAdQcCHCJzzwMtCKKZtnuD8Fw
qNPA3gRpL9ce5S6Ni/ZmLXiIx5Mz4+OYyOSYGlr275gK0M7ft2X+vW//9QKnFQM5
fB9aZpX8+x2lR0Nrs8xFbsipLPRYw0e5VnqgaPIZAX0/CYfVz3Y0f87Y0nbsQkNk
eJxxTWKnhVbBgB5E9eBtD2BmkFNMZB7E8ekWm8aSZfhct9Sl3vaQgLinA/xa2fSM
GLh/FmZ8xjmF/4KRlo5u7c6llAw2I2M/6YFoH9oitinkvvqEfibWj2yDss5RR0Xv
q00oM99fRLvX2V0tM9lJFE/n+OPwa6Csu+3VJK4p4o5voUkISpjFSWUohk6oFGIA
yop/risjmB6DqS+m4OOl1aHDSe3vABEBAAHCwXwEGAEIACYWIQR9RD4EAg3JYa+o
ld6shyJa4Sw+owUCXqFpOQIbDAUJAeEzgAAKCRCshyJa4Sw+o5DFD/9GjTsXLHM5
KwgO9/pNFq4AmRC686SjQ2dYpbnf8jBwPtY0jFLwaMcPxxxg+ZdLnFc09oDEj6FS
4y+m2DzuoYMhdixxJAqVGMBoUM8lC7ZAYk4TBe9miC0oFZmSNeaOpQ75XSNczekB
p9M/4PfSqZZkKBkDwOd+w1Qc7T7hV4tAmss+uPxxFGFsjCgXiTMt2e6C+5hd3tMt
lTbHfLoqyrojr667Hi1E5cC9o+jUxmJ+h6Ryqv4vTx/U+u1/qePpgTblppuZ5WN/
wT0sKeYzaxFtnS/ALcKTaKq8crw58J77+0TjK07EN8LoG8WymRq4lr1rPHDu72Pw
p5WoCTOXSLqQpLuocRvkJM6QtAdu9nEiQVo0yNX0X3Eq5imy6tZV8ktAu/dw4+i+
TVugheQ6nEyH7PjTVUcVhElWShC7c2kitFU5OvExgX0Z/HzpwAg0LNnHwVF0veAE
t7Xy/ID7LNpgiWMErHa7W+ioGEt8cP4ttRnFBVp72SyauxJr/0oJ4/GcWhmAcy7J
j7VCX1To4XwVxQ4Xzi9nXC/G4/WB5hNGHUSqMBBHdFYi1nZSYaiPcuxS945v7Lg/
hPw+0jMyoWIfs6leT8QnnEfg4nW+OAs/FV9dSZg3bvHr4/LF/EMt1hT0YeZuM3Vc
qvuXBO8wSn2p2qJiu3fconD4UQ/pBfQwDQ==
=seEJ
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -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<mayilin@kylinos.cn> - 1.0.2-11
- Package upgrade
* Fri Jul 2 2021 kymayl<mayilin@kylinos.cn> - 0.2.7-1
- Package init with version 0.2.7-1