import nmstate-0.3.4-25.el8_3
This commit is contained in:
commit
654b4d10bc
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
SOURCES/nmstate-0.3.4.tar.gz
|
||||
SOURCES/nmstate.gpg
|
2
.nmstate.metadata
Normal file
2
.nmstate.metadata
Normal file
@ -0,0 +1,2 @@
|
||||
d732a1ccb1dfc54741a9d602179c809c3223af3a SOURCES/nmstate-0.3.4.tar.gz
|
||||
b5f872551d434e2c62b30d70471efaeede83ab44 SOURCES/nmstate.gpg
|
40
SOURCES/BZ_1858758-fix_ovs_bond.patch
Normal file
40
SOURCES/BZ_1858758-fix_ovs_bond.patch
Normal file
@ -0,0 +1,40 @@
|
||||
From 862e669fcfe02b49c0e24af210d6466197962b97 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Mon, 3 Aug 2020 11:34:44 +0800
|
||||
Subject: [PATCH] ovs: Fix bug when adding bond to existing bridge
|
||||
|
||||
When adding OVS bond/link aggregation interface to existing OVS bridge,
|
||||
nmstate will fail with error:
|
||||
|
||||
> self._ifaces[slave_name].mark_as_changed()
|
||||
E KeyError: 'bond1'
|
||||
|
||||
This is because ovs bond interface does not require a interface entry in
|
||||
desire state.
|
||||
|
||||
Fixed by check before adding dict.
|
||||
|
||||
Integration test case added.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/ifaces/ifaces.py | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
||||
index a400712..1c2ffd5 100644
|
||||
--- a/libnmstate/ifaces/ifaces.py
|
||||
+++ b/libnmstate/ifaces/ifaces.py
|
||||
@@ -217,7 +217,8 @@ class Ifaces:
|
||||
self._ifaces[iface_name].mark_as_changed()
|
||||
if cur_iface:
|
||||
for slave_name in iface.config_changed_slaves(cur_iface):
|
||||
- self._ifaces[slave_name].mark_as_changed()
|
||||
+ if slave_name in self._ifaces:
|
||||
+ self._ifaces[slave_name].mark_as_changed()
|
||||
|
||||
def _match_child_iface_state_with_parent(self):
|
||||
"""
|
||||
--
|
||||
2.28.0
|
||||
|
105
SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch
Normal file
105
SOURCES/BZ_1858762-hide_ovs_patch_port_mtu.patch
Normal file
@ -0,0 +1,105 @@
|
||||
From bc2f8445d493f8a5a4ff1ceead13d2b3ac5325cc Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Date: Sun, 26 Jul 2020 00:46:16 +0200
|
||||
Subject: [PATCH 1/2] nm.wired: do not report MTU if it is 0
|
||||
|
||||
If an interface contains an MTU with value 0, Nmstate should not report
|
||||
it because it is an special interface like OVS patch port interfaces.
|
||||
|
||||
Added a test case for this.
|
||||
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
---
|
||||
libnmstate/nm/wired.py | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libnmstate/nm/wired.py b/libnmstate/nm/wired.py
|
||||
index 27d4318..64662ac 100644
|
||||
--- a/libnmstate/nm/wired.py
|
||||
+++ b/libnmstate/nm/wired.py
|
||||
@@ -124,7 +124,9 @@ def get_info(device):
|
||||
|
||||
iface = device.get_iface()
|
||||
try:
|
||||
- info[Interface.MTU] = int(device.get_mtu())
|
||||
+ mtu = int(device.get_mtu())
|
||||
+ if mtu:
|
||||
+ info[Interface.MTU] = mtu
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
||||
|
||||
From 03aea7d7debfca0f01b60e9f406c9acdf3de3775 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Mon, 27 Jul 2020 20:51:53 +0800
|
||||
Subject: [PATCH 2/2] nm ovs: Raise NmstateNotSupportedError for
|
||||
save_to_disk=False
|
||||
|
||||
Due to limitation of NetworkManager 1.26, nmstate cannot support
|
||||
`save_to_disk=False`(ask, memory only) state for OVS interfaces.
|
||||
|
||||
Raise NmstateNotSupportedError if NetworkManager version is older than
|
||||
1.28 and has OVS interface in desire state with `save_to_disk=False`.
|
||||
|
||||
Integration test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
---
|
||||
libnmstate/nm/applier.py | 23 +++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index 4e20af5..a91cee5 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -17,9 +17,11 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
+from distutils.version import StrictVersion
|
||||
import logging
|
||||
import itertools
|
||||
|
||||
+from libnmstate.error import NmstateNotSupportedError
|
||||
from libnmstate.error import NmstateValueError
|
||||
from libnmstate.schema import Interface
|
||||
from libnmstate.schema import InterfaceState
|
||||
@@ -65,6 +67,17 @@ MASTER_IFACE_TYPES = (
|
||||
def apply_changes(context, net_state, save_to_disk):
|
||||
con_profiles = []
|
||||
|
||||
+ if (
|
||||
+ not save_to_disk
|
||||
+ and _has_ovs_interface_desired_or_changed(net_state)
|
||||
+ and StrictVersion(context.client.get_version())
|
||||
+ < StrictVersion("1.28.0")
|
||||
+ ):
|
||||
+ raise NmstateNotSupportedError(
|
||||
+ f"NetworkManager version {context.client.get_version()} does not "
|
||||
+ f"support 'save_to_disk=False' against OpenvSwitch interface"
|
||||
+ )
|
||||
+
|
||||
_preapply_dns_fix(context, net_state)
|
||||
|
||||
ifaces_desired_state = net_state.ifaces.state_to_edit
|
||||
@@ -602,3 +615,13 @@ def _preapply_dns_fix(context, net_state):
|
||||
for iface in net_state.ifaces.values():
|
||||
if iface.is_changed or iface.is_desired:
|
||||
iface.remove_dns_metadata()
|
||||
+
|
||||
+
|
||||
+def _has_ovs_interface_desired_or_changed(net_state):
|
||||
+ for iface in net_state.ifaces.values():
|
||||
+ if iface.type in (
|
||||
+ InterfaceType.OVS_BRIDGE,
|
||||
+ InterfaceType.OVS_INTERFACE,
|
||||
+ InterfaceType.OVS_PORT,
|
||||
+ ) and (iface.is_desired or iface.is_changed):
|
||||
+ return True
|
||||
--
|
||||
2.27.0
|
||||
|
59
SOURCES/BZ_1859844-fix_converting_memory_only.patch
Normal file
59
SOURCES/BZ_1859844-fix_converting_memory_only.patch
Normal file
@ -0,0 +1,59 @@
|
||||
From fc7e6b2329409b95ab1726b7b65f14c284bf67ab Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Mon, 3 Aug 2020 12:07:56 +0800
|
||||
Subject: [PATCH] nm: Fix converting memory-only profile to persistent
|
||||
|
||||
When converting memory-only profile to persistent using simple desire
|
||||
state with `state: up` only, the memory only profile will not be
|
||||
converted to persistent.
|
||||
|
||||
This is caused by `nm/applier.py` skip profile creation if desire state
|
||||
is only `state: up`.
|
||||
|
||||
The fix is checking whether current profile's persistent state is equal
|
||||
to desired.
|
||||
|
||||
Integration test case added.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 1 +
|
||||
libnmstate/nm/connection.py | 10 ++++++++++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index 4d40862..26a057f 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -125,6 +125,7 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
and cur_con_profile
|
||||
and cur_con_profile.profile
|
||||
and not net_state.ifaces[ifname].is_changed
|
||||
+ and cur_con_profile.is_memory_only != save_to_disk
|
||||
):
|
||||
# Don't create new profile if original desire does not ask
|
||||
# anything besides state:up and not been marked as changed.
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index 5804f13..1f6c734 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -162,6 +162,16 @@ class ConnectionProfile:
|
||||
assert self._con_profile is None
|
||||
self._con_profile = con_profile
|
||||
|
||||
+ @property
|
||||
+ def is_memory_only(self):
|
||||
+ if self._con_profile:
|
||||
+ profile_flags = self._con_profile.get_flags()
|
||||
+ return (
|
||||
+ NM.SettingsConnectionFlags.UNSAVED & profile_flags
|
||||
+ or NM.SettingsConnectionFlags.VOLATILE & profile_flags
|
||||
+ )
|
||||
+ return False
|
||||
+
|
||||
@property
|
||||
def devname(self):
|
||||
if self._con_profile:
|
||||
--
|
||||
2.28.0
|
||||
|
65
SOURCES/BZ_1861263-handle-external-managed-interface.patch
Normal file
65
SOURCES/BZ_1861263-handle-external-managed-interface.patch
Normal file
@ -0,0 +1,65 @@
|
||||
From ea7f304cc1ad32c3f2c25b49bf6b2663f348496a Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Tue, 28 Jul 2020 15:59:11 +0800
|
||||
Subject: [PATCH] nm: Mark external subordinate as changed
|
||||
|
||||
When user create bond with subordinate interfaces using non-NM
|
||||
tools(iproute), the NetworkManager will mark the subordinates as
|
||||
managed externally.
|
||||
|
||||
When the desire state only contains the main interface, nmstate
|
||||
noticing the slave list is unchanged, so only activate the main
|
||||
interface, then NM remove the subordinate from their main interface.
|
||||
|
||||
To workaround that, mark subordinate interfaces as changed when they are
|
||||
managed by NM as externally.
|
||||
|
||||
Integration test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index a91cee5..68d11dc 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -79,6 +79,7 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
)
|
||||
|
||||
_preapply_dns_fix(context, net_state)
|
||||
+ _mark_nm_external_subordinate_changed(context, net_state)
|
||||
|
||||
ifaces_desired_state = net_state.ifaces.state_to_edit
|
||||
ifaces_desired_state.extend(
|
||||
@@ -625,3 +626,26 @@ def _has_ovs_interface_desired_or_changed(net_state):
|
||||
InterfaceType.OVS_PORT,
|
||||
) and (iface.is_desired or iface.is_changed):
|
||||
return True
|
||||
+
|
||||
+
|
||||
+def _mark_nm_external_subordinate_changed(context, net_state):
|
||||
+ """
|
||||
+ When certain main interface contains subordinates is marked as
|
||||
+ connected(externally), it means its profile is memory only and will lost
|
||||
+ on next deactivation.
|
||||
+ For this case, we should mark the subordinate as changed.
|
||||
+ that subordinate should be marked as changed for NM to take over.
|
||||
+ """
|
||||
+ for iface in net_state.ifaces.values():
|
||||
+ if iface.type in MASTER_IFACE_TYPES:
|
||||
+ for subordinate in iface.slaves:
|
||||
+ nmdev = context.get_nm_dev(subordinate)
|
||||
+ if nmdev:
|
||||
+ nm_ac = nmdev.get_active_connection()
|
||||
+ if (
|
||||
+ nm_ac
|
||||
+ and NM.ActivationStateFlags.EXTERNAL
|
||||
+ & nm_ac.get_state_flags()
|
||||
+ ):
|
||||
+ subordinate_iface = net_state.ifaces[subordinate]
|
||||
+ subordinate_iface.mark_as_changed()
|
||||
--
|
||||
2.27.0
|
||||
|
200
SOURCES/BZ_1861668_ignore_unknown_iface.patch
Normal file
200
SOURCES/BZ_1861668_ignore_unknown_iface.patch
Normal file
@ -0,0 +1,200 @@
|
||||
From a8590744fbdd4bce9ab340ac49a7add31727b990 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Wed, 29 Jul 2020 17:51:27 +0800
|
||||
Subject: [PATCH 1/3] nm applier: Fix external managed interface been marked as
|
||||
changed
|
||||
|
||||
The net_state passing to `_mark_nm_external_subordinate_changed()`
|
||||
does not contain unknown type interface, so the
|
||||
`net_state.ifaces[subordinate]` could trigger KeyError as subordinate
|
||||
not found.
|
||||
|
||||
Changed it to use `get()` and only perform this changes to
|
||||
desired/changed interface.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index 68d11dc..d0fb5f3 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -637,7 +637,7 @@ def _mark_nm_external_subordinate_changed(context, net_state):
|
||||
that subordinate should be marked as changed for NM to take over.
|
||||
"""
|
||||
for iface in net_state.ifaces.values():
|
||||
- if iface.type in MASTER_IFACE_TYPES:
|
||||
+ if iface.is_desired or iface.is_changed and iface.is_master:
|
||||
for subordinate in iface.slaves:
|
||||
nmdev = context.get_nm_dev(subordinate)
|
||||
if nmdev:
|
||||
@@ -647,5 +647,6 @@ def _mark_nm_external_subordinate_changed(context, net_state):
|
||||
and NM.ActivationStateFlags.EXTERNAL
|
||||
& nm_ac.get_state_flags()
|
||||
):
|
||||
- subordinate_iface = net_state.ifaces[subordinate]
|
||||
- subordinate_iface.mark_as_changed()
|
||||
+ subordinate_iface = net_state.ifaces.get(subordinate)
|
||||
+ if subordinate_iface:
|
||||
+ subordinate_iface.mark_as_changed()
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From 77a05cfe726efc4a4207d57958a71e1730b6d62a Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Wed, 29 Jul 2020 18:02:52 +0800
|
||||
Subject: [PATCH 2/3] nm: Ignore externally managed interface for down/absent
|
||||
main interface
|
||||
|
||||
When main interface been marked as down or absent, its subordinate
|
||||
should be also marked as so. NetworkManager plugin should ignore
|
||||
externally managed subordinate in this case.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 26 +++++++++++---------------
|
||||
libnmstate/nm/device.py | 8 ++++++++
|
||||
2 files changed, 19 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index d0fb5f3..9cd8f9a 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -50,6 +50,7 @@ from . import vxlan
|
||||
from . import wired
|
||||
from .common import NM
|
||||
from .dns import get_dns_config_iface_names
|
||||
+from .device import is_externally_managed
|
||||
|
||||
|
||||
MAXIMUM_INTERFACE_LENGTH = 15
|
||||
@@ -265,13 +266,14 @@ def _set_ifaces_admin_state(context, ifaces_desired_state, con_profiles):
|
||||
== InterfaceState.ABSENT
|
||||
)
|
||||
for affected_nmdev in nmdevs:
|
||||
- devs_to_deactivate[
|
||||
- affected_nmdev.get_iface()
|
||||
- ] = affected_nmdev
|
||||
- if is_absent:
|
||||
- devs_to_delete_profile[
|
||||
+ if not is_externally_managed(affected_nmdev):
|
||||
+ devs_to_deactivate[
|
||||
affected_nmdev.get_iface()
|
||||
] = affected_nmdev
|
||||
+ if is_absent:
|
||||
+ devs_to_delete_profile[
|
||||
+ affected_nmdev.get_iface()
|
||||
+ ] = affected_nmdev
|
||||
if (
|
||||
is_absent
|
||||
and nmdev.is_software()
|
||||
@@ -640,13 +642,7 @@ def _mark_nm_external_subordinate_changed(context, net_state):
|
||||
if iface.is_desired or iface.is_changed and iface.is_master:
|
||||
for subordinate in iface.slaves:
|
||||
nmdev = context.get_nm_dev(subordinate)
|
||||
- if nmdev:
|
||||
- nm_ac = nmdev.get_active_connection()
|
||||
- if (
|
||||
- nm_ac
|
||||
- and NM.ActivationStateFlags.EXTERNAL
|
||||
- & nm_ac.get_state_flags()
|
||||
- ):
|
||||
- subordinate_iface = net_state.ifaces.get(subordinate)
|
||||
- if subordinate_iface:
|
||||
- subordinate_iface.mark_as_changed()
|
||||
+ if nmdev and is_externally_managed(nmdev):
|
||||
+ subordinate_iface = net_state.ifaces.get(subordinate)
|
||||
+ if subordinate_iface:
|
||||
+ subordinate_iface.mark_as_changed()
|
||||
diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py
|
||||
index 528f57d..a175b71 100644
|
||||
--- a/libnmstate/nm/device.py
|
||||
+++ b/libnmstate/nm/device.py
|
||||
@@ -23,6 +23,7 @@ from libnmstate.error import NmstateLibnmError
|
||||
|
||||
from . import active_connection as ac
|
||||
from . import connection
|
||||
+from .common import NM
|
||||
|
||||
|
||||
def activate(context, dev=None, connection_id=None):
|
||||
@@ -161,3 +162,10 @@ def get_device_common_info(dev):
|
||||
"type_name": dev.get_type_description(),
|
||||
"state": dev.get_state(),
|
||||
}
|
||||
+
|
||||
+
|
||||
+def is_externally_managed(nmdev):
|
||||
+ nm_ac = nmdev.get_active_connection()
|
||||
+ return (
|
||||
+ nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags()
|
||||
+ )
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From afb51e8421b8749962dd9ee2e31b61548de09a78 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Wed, 29 Jul 2020 18:22:32 +0800
|
||||
Subject: [PATCH 3/3] state: Remove unmanaged interface before verifying
|
||||
|
||||
Since we remove unknown type interface before sending to apply,
|
||||
we should also remove unknown type interface before verifying.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/ifaces/ifaces.py | 9 +++++----
|
||||
libnmstate/nm/device.py | 4 +---
|
||||
2 files changed, 6 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
||||
index 1ff4198..a400712 100644
|
||||
--- a/libnmstate/ifaces/ifaces.py
|
||||
+++ b/libnmstate/ifaces/ifaces.py
|
||||
@@ -286,16 +286,16 @@ class Ifaces:
|
||||
def cur_ifaces(self):
|
||||
return self._cur_ifaces
|
||||
|
||||
- def _remove_unmanaged_slaves(self):
|
||||
+ def _remove_unknown_interface_type_slaves(self):
|
||||
"""
|
||||
- When master containing unmanaged slaves, they should be removed from
|
||||
- master slave list.
|
||||
+ When master containing slaves with unknown interface type, they should
|
||||
+ be removed from master slave list before verifying.
|
||||
"""
|
||||
for iface in self._ifaces.values():
|
||||
if iface.is_up and iface.is_master and iface.slaves:
|
||||
for slave_name in iface.slaves:
|
||||
slave_iface = self._ifaces[slave_name]
|
||||
- if not slave_iface.is_up:
|
||||
+ if slave_iface.type == InterfaceType.UNKNOWN:
|
||||
iface.remove_slave(slave_name)
|
||||
|
||||
def verify(self, cur_iface_infos):
|
||||
@@ -304,6 +304,7 @@ class Ifaces:
|
||||
cur_iface_infos=cur_iface_infos,
|
||||
save_to_disk=self._save_to_disk,
|
||||
)
|
||||
+ cur_ifaces._remove_unknown_interface_type_slaves()
|
||||
for iface in self._ifaces.values():
|
||||
if iface.is_desired:
|
||||
if iface.is_virtual and iface.original_dict.get(
|
||||
diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py
|
||||
index a175b71..fdf05bc 100644
|
||||
--- a/libnmstate/nm/device.py
|
||||
+++ b/libnmstate/nm/device.py
|
||||
@@ -166,6 +166,4 @@ def get_device_common_info(dev):
|
||||
|
||||
def is_externally_managed(nmdev):
|
||||
nm_ac = nmdev.get_active_connection()
|
||||
- return (
|
||||
- nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags()
|
||||
- )
|
||||
+ return nm_ac and NM.ActivationStateFlags.EXTERNAL & nm_ac.get_state_flags()
|
||||
--
|
||||
2.28.0
|
||||
|
68
SOURCES/BZ_1862025-remove_existing_profiles.patch
Normal file
68
SOURCES/BZ_1862025-remove_existing_profiles.patch
Normal file
@ -0,0 +1,68 @@
|
||||
From 3c5337a22273717df6fb51818216816bbff77035 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Thu, 30 Jul 2020 16:54:40 +0800
|
||||
Subject: [PATCH] nm profile: Remove inactivate profile of desired interface
|
||||
|
||||
For changed/desired interface, NM should remove all its inactive
|
||||
profiles so that it could update and activate the same one.
|
||||
|
||||
Integration test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 10 +++++++++-
|
||||
libnmstate/nm/connection.py | 9 +++++++--
|
||||
2 files changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index 9cd8f9a..4d40862 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -105,6 +105,15 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
cur_con_profile = connection.ConnectionProfile(
|
||||
context, profile=con_profile
|
||||
)
|
||||
+
|
||||
+ if save_to_disk:
|
||||
+ # TODO: Need handle save_to_disk=False
|
||||
+ connection.delete_iface_profiles_except(
|
||||
+ context,
|
||||
+ ifname,
|
||||
+ cur_con_profile.profile if cur_con_profile else None,
|
||||
+ )
|
||||
+
|
||||
original_desired_iface_state = {}
|
||||
if net_state.ifaces.get(ifname):
|
||||
iface = net_state.ifaces[ifname]
|
||||
@@ -137,7 +146,6 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
con_profiles.append(new_con_profile)
|
||||
else:
|
||||
# Missing connection, attempting to create a new one.
|
||||
- connection.delete_iface_inactive_connections(context, ifname)
|
||||
new_con_profile.add(save_to_disk)
|
||||
con_profiles.append(new_con_profile)
|
||||
context.wait_all_finish()
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index 02890bc..5804f13 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -496,9 +496,14 @@ def get_device_active_connection(nm_device):
|
||||
return active_conn
|
||||
|
||||
|
||||
-def delete_iface_inactive_connections(context, ifname):
|
||||
+def delete_iface_profiles_except(context, ifname, excluded_profile):
|
||||
for con in list_connections_by_ifname(context, ifname):
|
||||
- con.delete()
|
||||
+ if (
|
||||
+ not excluded_profile
|
||||
+ or not con.profile
|
||||
+ or con.profile.get_uuid() != excluded_profile.get_uuid()
|
||||
+ ):
|
||||
+ con.delete()
|
||||
|
||||
|
||||
def list_connections_by_ifname(context, ifname):
|
||||
--
|
||||
2.28.0
|
||||
|
120
SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch
Normal file
120
SOURCES/BZ_1866269-preserve_nm_uuid_in_ovsdb.patch
Normal file
@ -0,0 +1,120 @@
|
||||
From 21e06fd5af76cc1fe65497222a04c1cffa2bc546 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Thu, 6 Aug 2020 13:07:59 +0800
|
||||
Subject: [PATCH] ovsdb: Preserve the NM external_ids
|
||||
|
||||
For newly created OVS internal interface with customer external_ids,
|
||||
the ovsdb plugin will remove the NM external_ids `NM.connection.uuid`.
|
||||
|
||||
The fix is read the current `NM.connection.uuid` before applying
|
||||
configure and merge it with original desired state.
|
||||
|
||||
Integration test cases added.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/plugins/nmstate_plugin_ovsdb.py | 69 +++++++++++++---------
|
||||
1 file changed, 40 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/plugins/nmstate_plugin_ovsdb.py b/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
index 83965e1..12ab10d 100644
|
||||
--- a/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
+++ b/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
@@ -161,7 +161,14 @@ class NmstateOvsdbPlugin(NmstatePlugin):
|
||||
return ifaces
|
||||
|
||||
def apply_changes(self, net_state, save_to_disk):
|
||||
+ # State might changed after other plugin invoked apply_changes()
|
||||
self.refresh_content()
|
||||
+ cur_iface_to_ext_ids = {}
|
||||
+ for iface_info in self.get_interfaces():
|
||||
+ cur_iface_to_ext_ids[iface_info[Interface.NAME]] = iface_info[
|
||||
+ OvsDB.OVS_DB_SUBTREE
|
||||
+ ][OvsDB.EXTERNAL_IDS]
|
||||
+
|
||||
pending_changes = []
|
||||
for iface in net_state.ifaces.values():
|
||||
if not iface.is_changed and not iface.is_desired:
|
||||
@@ -174,7 +181,34 @@ class NmstateOvsdbPlugin(NmstatePlugin):
|
||||
table_name = "Interface"
|
||||
else:
|
||||
continue
|
||||
- pending_changes.extend(_generate_db_change(table_name, iface))
|
||||
+ ids_after_nm_applied = cur_iface_to_ext_ids.get(iface.name, {})
|
||||
+ ids_before_nm_applied = (
|
||||
+ iface.to_dict()
|
||||
+ .get(OvsDB.OVS_DB_SUBTREE, {})
|
||||
+ .get(OvsDB.EXTERNAL_IDS, {})
|
||||
+ )
|
||||
+ original_desire_ids = iface.original_dict.get(
|
||||
+ OvsDB.OVS_DB_SUBTREE, {}
|
||||
+ ).get(OvsDB.EXTERNAL_IDS)
|
||||
+
|
||||
+ desire_ids = []
|
||||
+
|
||||
+ if original_desire_ids is None:
|
||||
+ desire_ids = ids_before_nm_applied
|
||||
+ else:
|
||||
+ desire_ids = original_desire_ids
|
||||
+
|
||||
+ # should include external_id created by NetworkManager.
|
||||
+ if NM_EXTERNAL_ID in ids_after_nm_applied:
|
||||
+ desire_ids[NM_EXTERNAL_ID] = ids_after_nm_applied[
|
||||
+ NM_EXTERNAL_ID
|
||||
+ ]
|
||||
+ if desire_ids != ids_after_nm_applied:
|
||||
+ pending_changes.append(
|
||||
+ _generate_db_change_external_ids(
|
||||
+ table_name, iface.name, desire_ids
|
||||
+ )
|
||||
+ )
|
||||
if pending_changes:
|
||||
if not save_to_disk:
|
||||
raise NmstateNotImplementedError(
|
||||
@@ -242,38 +276,15 @@ class NmstateOvsdbPlugin(NmstatePlugin):
|
||||
)
|
||||
|
||||
|
||||
-def _generate_db_change(table_name, iface_state):
|
||||
- return _generate_db_change_external_ids(table_name, iface_state)
|
||||
-
|
||||
-
|
||||
-def _generate_db_change_external_ids(table_name, iface_state):
|
||||
- pending_changes = []
|
||||
- desire_ids = iface_state.original_dict.get(OvsDB.OVS_DB_SUBTREE, {}).get(
|
||||
- OvsDB.EXTERNAL_IDS
|
||||
- )
|
||||
+def _generate_db_change_external_ids(table_name, iface_name, desire_ids):
|
||||
if desire_ids and not isinstance(desire_ids, dict):
|
||||
raise NmstateValueError("Invalid external_ids, should be dictionary")
|
||||
|
||||
- if desire_ids or desire_ids == {}:
|
||||
- # should include external_id required by NetworkManager.
|
||||
- merged_ids = (
|
||||
- iface_state.to_dict()
|
||||
- .get(OvsDB.OVS_DB_SUBTREE, {})
|
||||
- .get(OvsDB.EXTERNAL_IDS, {})
|
||||
- )
|
||||
- if NM_EXTERNAL_ID in merged_ids:
|
||||
- desire_ids[NM_EXTERNAL_ID] = merged_ids[NM_EXTERNAL_ID]
|
||||
-
|
||||
- # Convert all value to string
|
||||
- for key, value in desire_ids.items():
|
||||
- desire_ids[key] = str(value)
|
||||
+ # Convert all value to string
|
||||
+ for key, value in desire_ids.items():
|
||||
+ desire_ids[key] = str(value)
|
||||
|
||||
- pending_changes.append(
|
||||
- _Changes(
|
||||
- table_name, OvsDB.EXTERNAL_IDS, iface_state.name, desire_ids
|
||||
- )
|
||||
- )
|
||||
- return pending_changes
|
||||
+ return _Changes(table_name, OvsDB.EXTERNAL_IDS, iface_name, desire_ids)
|
||||
|
||||
|
||||
NMSTATE_PLUGIN = NmstateOvsdbPlugin
|
||||
--
|
||||
2.28.0
|
||||
|
44
SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch
Normal file
44
SOURCES/BZ_1869345_ovsdb_remove_all_ports.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From 913b739c8fea8e9b14d3785371c8e4f48723dbd6 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Tue, 18 Aug 2020 17:55:12 +0800
|
||||
Subject: [PATCH] ovsdb: Allowing remove all ports from OVS bridge
|
||||
|
||||
When removing all ports from OVS bridge, the OVSDB will have no
|
||||
information regarding this bridge, which cause OVSDB failed to find
|
||||
the correct row.
|
||||
|
||||
Silently ignore row not found failure and let verification stage do the
|
||||
work.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/plugins/nmstate_plugin_ovsdb.py | 8 --------
|
||||
1 file changed, 8 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/plugins/nmstate_plugin_ovsdb.py b/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
index 12ab10d..f667e8f 100644
|
||||
--- a/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
+++ b/libnmstate/plugins/nmstate_plugin_ovsdb.py
|
||||
@@ -222,19 +222,11 @@ class NmstateOvsdbPlugin(NmstatePlugin):
|
||||
def _db_write(self, changes):
|
||||
changes_index = {change.row_name: change for change in changes}
|
||||
changed_tables = set(change.table_name for change in changes)
|
||||
- updated_names = []
|
||||
for changed_table in changed_tables:
|
||||
for row in self._idl.tables[changed_table].rows.values():
|
||||
if row.name in changes_index:
|
||||
change = changes_index[row.name]
|
||||
setattr(row, change.column_name, change.column_value)
|
||||
- updated_names.append(change.row_name)
|
||||
- new_rows = set(changes_index.keys()) - set(updated_names)
|
||||
- if new_rows:
|
||||
- raise NmstatePluginError(
|
||||
- f"BUG: row {new_rows} does not exists in OVS DB "
|
||||
- "and currently we don't create new row"
|
||||
- )
|
||||
|
||||
def _start_transaction(self):
|
||||
self._transaction = Transaction(self._idl)
|
||||
--
|
||||
2.28.0
|
||||
|
111
SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch
Normal file
111
SOURCES/BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch
Normal file
@ -0,0 +1,111 @@
|
||||
From 36ee761dd0d671439323077e4f77a89071fdcd9c Mon Sep 17 00:00:00 2001
|
||||
From: Edward Haas <edwardh@redhat.com>
|
||||
Date: Wed, 7 Oct 2020 20:13:12 +0300
|
||||
Subject: [PATCH 1/2] nm, bridge, ovs: Collect only existing profiles
|
||||
|
||||
During the reporting flow, connections that are in teardown process
|
||||
no longer point to a valid profile. Avoid collecting such profiles (in
|
||||
practice, these are actually `None` objects).
|
||||
|
||||
Signed-off-by: Edward Haas <edwardh@redhat.com>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/bridge.py | 6 +++---
|
||||
libnmstate/nm/ovs.py | 4 +++-
|
||||
2 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/bridge.py b/libnmstate/nm/bridge.py
|
||||
index b885f7a..0ca6c2d 100644
|
||||
--- a/libnmstate/nm/bridge.py
|
||||
+++ b/libnmstate/nm/bridge.py
|
||||
@@ -260,9 +260,9 @@ def _get_slave_profiles_by_name(master_device):
|
||||
for dev in master_device.get_slaves():
|
||||
active_con = connection.get_device_active_connection(dev)
|
||||
if active_con:
|
||||
- slaves_profiles_by_name[
|
||||
- dev.get_iface()
|
||||
- ] = active_con.props.connection
|
||||
+ profile = active_con.props.connection
|
||||
+ if profile:
|
||||
+ slaves_profiles_by_name[dev.get_iface()] = profile
|
||||
return slaves_profiles_by_name
|
||||
|
||||
|
||||
diff --git a/libnmstate/nm/ovs.py b/libnmstate/nm/ovs.py
|
||||
index 2518773..eb373c3 100644
|
||||
--- a/libnmstate/nm/ovs.py
|
||||
+++ b/libnmstate/nm/ovs.py
|
||||
@@ -279,5 +279,7 @@ def _get_slave_profiles(master_device, devices_info):
|
||||
if active_con:
|
||||
master = active_con.props.master
|
||||
if master and (master.get_iface() == master_device.get_iface()):
|
||||
- slave_profiles.append(active_con.props.connection)
|
||||
+ profile = active_con.props.connection
|
||||
+ if profile:
|
||||
+ slave_profiles.append(profile)
|
||||
return slave_profiles
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From caf638d75e57da8770cd884782475f1c5668fd6d Mon Sep 17 00:00:00 2001
|
||||
From: Edward Haas <edwardh@redhat.com>
|
||||
Date: Wed, 7 Oct 2020 12:26:42 +0300
|
||||
Subject: [PATCH 2/2] nm, ovs: Fix report crash when OVS has dup iface names
|
||||
|
||||
In case of an existing OVS deployment which uses an identical name for
|
||||
the bridge, port and interface, libnmstate.show() exploded.
|
||||
|
||||
It is now possible to report such deployments.
|
||||
|
||||
Signed-off-by: Edward Haas <edwardh@redhat.com>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/ovs.py | 24 +++++++++++++++++++++---
|
||||
1 file changed, 21 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/ovs.py b/libnmstate/nm/ovs.py
|
||||
index eb373c3..d1f26ba 100644
|
||||
--- a/libnmstate/nm/ovs.py
|
||||
+++ b/libnmstate/nm/ovs.py
|
||||
@@ -140,7 +140,12 @@ def get_port_by_slave(nmdev):
|
||||
|
||||
|
||||
def get_ovs_info(context, bridge_device, devices_info):
|
||||
- port_profiles = _get_slave_profiles(bridge_device, devices_info)
|
||||
+ ovs_ports_info = (
|
||||
+ info
|
||||
+ for info in devices_info
|
||||
+ if is_ovs_port_type_id(info[1]["type_id"])
|
||||
+ )
|
||||
+ port_profiles = _get_slave_profiles(bridge_device, ovs_ports_info)
|
||||
ports = _get_bridge_ports_info(context, port_profiles, devices_info)
|
||||
options = _get_bridge_options(context, bridge_device)
|
||||
|
||||
@@ -203,8 +208,21 @@ def _get_bridge_port_info(context, port_profile, devices_info):
|
||||
vlan_mode = port_setting.props.vlan_mode
|
||||
|
||||
port_name = port_profile.get_interface_name()
|
||||
- port_device = context.get_nm_dev(port_name)
|
||||
- port_slave_profiles = _get_slave_profiles(port_device, devices_info)
|
||||
+ port_device = next(
|
||||
+ dev
|
||||
+ for dev, devinfo in devices_info
|
||||
+ if devinfo["name"] == port_name
|
||||
+ and is_ovs_port_type_id(devinfo["type_id"])
|
||||
+ )
|
||||
+ devices_info_excluding_bridges_and_ports = (
|
||||
+ info
|
||||
+ for info in devices_info
|
||||
+ if not is_ovs_bridge_type_id(info[1]["type_id"])
|
||||
+ and not is_ovs_port_type_id(info[1]["type_id"])
|
||||
+ )
|
||||
+ port_slave_profiles = _get_slave_profiles(
|
||||
+ port_device, devices_info_excluding_bridges_and_ports
|
||||
+ )
|
||||
port_slave_names = [c.get_interface_name() for c in port_slave_profiles]
|
||||
|
||||
if port_slave_names:
|
||||
--
|
||||
2.28.0
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 8a7f1758da4cba81d65ba4b9b06bbf4b750a6f87 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Thu, 22 Oct 2020 14:09:27 +0800
|
||||
Subject: [PATCH 1/2] nm bond: Ignore ad_actor_system=00:00:00:00:00:00
|
||||
|
||||
The ad_actor_system=00:00:00:00:00:00 is invalid in kernel as that's the
|
||||
default value of ad_actor_system.
|
||||
|
||||
NM plugin should not set that value.
|
||||
|
||||
Test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
---
|
||||
libnmstate/nm/bond.py | 9 +++++++++
|
||||
tests/integration/nm/bond_test.py | 12 ++++++++++++
|
||||
2 files changed, 21 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/nm/bond.py b/libnmstate/nm/bond.py
|
||||
index 9ea3648..d196965 100644
|
||||
--- a/libnmstate/nm/bond.py
|
||||
+++ b/libnmstate/nm/bond.py
|
||||
@@ -38,6 +38,8 @@ NM_SUPPORTED_BOND_OPTIONS = NM.SettingBond.get_valid_options(
|
||||
|
||||
SYSFS_BOND_OPTION_FOLDER_FMT = "/sys/class/net/{ifname}/bonding"
|
||||
|
||||
+BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC = "00:00:00:00:00:00"
|
||||
+
|
||||
|
||||
def create_setting(options, wired_setting):
|
||||
bond_setting = NM.SettingBond.new()
|
||||
@@ -48,6 +50,13 @@ def create_setting(options, wired_setting):
|
||||
):
|
||||
# When in MAC restricted mode, MAC address should be unset.
|
||||
wired_setting.props.cloned_mac_address = None
|
||||
+ if (
|
||||
+ option_name == "ad_actor_system"
|
||||
+ and option_value == BOND_AD_ACTOR_SYSTEM_USE_BOND_MAC
|
||||
+ ):
|
||||
+ # The all zero ad_actor_system is the kernel default value
|
||||
+ # And it is invalid to set as all zero
|
||||
+ continue
|
||||
if option_value != SYSFS_EMPTY_VALUE:
|
||||
success = bond_setting.add_option(option_name, str(option_value))
|
||||
if not success:
|
||||
--
|
||||
2.25.4
|
||||
|
@ -0,0 +1,33 @@
|
||||
From 46104725c121def5d85f492afd91e618c1c7c240 Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Date: Tue, 27 Oct 2020 12:23:18 +0100
|
||||
Subject: [PATCH 2/2] nm.ipv6: call clear_routing_rules() when creating the
|
||||
setting
|
||||
|
||||
In order to remove IPv6 routing rules Nmstate needs to call
|
||||
clear_routing_rules() on the IPv6 setting as it is done on the IPv4
|
||||
setting.
|
||||
|
||||
Added a testcase for this.
|
||||
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
---
|
||||
libnmstate/nm/ipv6.py | 1 +
|
||||
tests/integration/route_test.py | 15 +++++++++++++++
|
||||
2 files changed, 16 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/nm/ipv6.py b/libnmstate/nm/ipv6.py
|
||||
index f252578..9777c89 100644
|
||||
--- a/libnmstate/nm/ipv6.py
|
||||
+++ b/libnmstate/nm/ipv6.py
|
||||
@@ -106,6 +106,7 @@ def create_setting(config, base_con_profile):
|
||||
setting_ip.props.never_default = False
|
||||
setting_ip.props.ignore_auto_dns = False
|
||||
setting_ip.clear_routes()
|
||||
+ setting_ip.clear_routing_rules()
|
||||
setting_ip.props.gateway = None
|
||||
setting_ip.props.route_table = Route.USE_DEFAULT_ROUTE_TABLE
|
||||
setting_ip.props.route_metric = Route.USE_DEFAULT_METRIC
|
||||
--
|
||||
2.25.4
|
||||
|
103
SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch
Normal file
103
SOURCES/BZ_1901571_do_not_check_ovs_daemon_when_showing.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From 2595c75cb8488e855fc5d98bcc944c6c0ad96b54 Mon Sep 17 00:00:00 2001
|
||||
From: Quique Llorente <ellorent@redhat.com>
|
||||
Date: Tue, 24 Nov 2020 12:52:35 +0100
|
||||
Subject: [PATCH 1/2] ovs: Ignore ovs-port always
|
||||
|
||||
At containerize nmstate we cannot run "systemctl openvswitch status" so
|
||||
even with a openvswitch running at host it will appear as non running
|
||||
but the ovs information will arrive from NM dbus interface. This breaks
|
||||
nmstatectl show since ovs-port is not part of nmstate and is not
|
||||
included in the schema. This change just ignore ovs-port even if
|
||||
openvswitch appear as not running.
|
||||
|
||||
Signed-off-by: Quique Llorente <ellorent@redhat.com>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/plugin.py | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py
|
||||
index 4032359..6b6217d 100644
|
||||
--- a/libnmstate/nm/plugin.py
|
||||
+++ b/libnmstate/nm/plugin.py
|
||||
@@ -123,6 +123,8 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||||
if nm_bond.is_bond_type_id(type_id):
|
||||
bondinfo = nm_bond.get_bond_info(dev)
|
||||
iface_info.update(_ifaceinfo_bond(bondinfo))
|
||||
+ elif nm_ovs.is_ovs_port_type_id(type_id):
|
||||
+ continue
|
||||
elif NmstatePlugin.OVS_CAPABILITY in capabilities:
|
||||
if nm_ovs.is_ovs_bridge_type_id(type_id):
|
||||
iface_info["bridge"] = nm_ovs.get_ovs_info(
|
||||
@@ -133,8 +135,6 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||||
)
|
||||
elif nm_ovs.is_ovs_interface_type_id(type_id):
|
||||
iface_info.update(nm_ovs.get_interface_info(act_con))
|
||||
- elif nm_ovs.is_ovs_port_type_id(type_id):
|
||||
- continue
|
||||
|
||||
info.append(iface_info)
|
||||
|
||||
--
|
||||
2.29.2
|
||||
|
||||
|
||||
From 3202bdd08737087160ff96bcf921793ce6b8335c Mon Sep 17 00:00:00 2001
|
||||
From: Quique Llorente <ellorent@redhat.com>
|
||||
Date: Wed, 25 Nov 2020 10:28:43 +0100
|
||||
Subject: [PATCH 2/2] ovs: Ignore OVS capabilities at get interfaces
|
||||
|
||||
At containerize nmstate we cannot run "systemctl openvswitch status" so
|
||||
even with a openvswitch running at host it will appear as non running
|
||||
but the ovs information will arrive from NM dbus interface. This breaks
|
||||
nmstatectl show since ovs-port is not part of nmstate and is not
|
||||
included in the schema. This change removed the whole OVS compatibility check
|
||||
when processing the interfaces reporting.
|
||||
|
||||
Signed-off-by: Quique Llorente <ellorent@redhat.com>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/plugin.py | 18 +++++++-----------
|
||||
1 file changed, 7 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py
|
||||
index 6b6217d..06a5acd 100644
|
||||
--- a/libnmstate/nm/plugin.py
|
||||
+++ b/libnmstate/nm/plugin.py
|
||||
@@ -97,7 +97,6 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||||
|
||||
def get_interfaces(self):
|
||||
info = []
|
||||
- capabilities = self.capabilities
|
||||
|
||||
devices_info = [
|
||||
(dev, nm_device.get_device_common_info(dev))
|
||||
@@ -123,18 +122,15 @@ class NetworkManagerPlugin(NmstatePlugin):
|
||||
if nm_bond.is_bond_type_id(type_id):
|
||||
bondinfo = nm_bond.get_bond_info(dev)
|
||||
iface_info.update(_ifaceinfo_bond(bondinfo))
|
||||
+ elif nm_ovs.is_ovs_bridge_type_id(type_id):
|
||||
+ iface_info["bridge"] = nm_ovs.get_ovs_info(
|
||||
+ self.context, dev, devices_info
|
||||
+ )
|
||||
+ iface_info = _remove_ovs_bridge_unsupported_entries(iface_info)
|
||||
+ elif nm_ovs.is_ovs_interface_type_id(type_id):
|
||||
+ iface_info.update(nm_ovs.get_interface_info(act_con))
|
||||
elif nm_ovs.is_ovs_port_type_id(type_id):
|
||||
continue
|
||||
- elif NmstatePlugin.OVS_CAPABILITY in capabilities:
|
||||
- if nm_ovs.is_ovs_bridge_type_id(type_id):
|
||||
- iface_info["bridge"] = nm_ovs.get_ovs_info(
|
||||
- self.context, dev, devices_info
|
||||
- )
|
||||
- iface_info = _remove_ovs_bridge_unsupported_entries(
|
||||
- iface_info
|
||||
- )
|
||||
- elif nm_ovs.is_ovs_interface_type_id(type_id):
|
||||
- iface_info.update(nm_ovs.get_interface_info(act_con))
|
||||
|
||||
info.append(iface_info)
|
||||
|
||||
--
|
||||
2.29.2
|
||||
|
38
SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch
Normal file
38
SOURCES/BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From d7393d40aaedeea5dd8291519cddeecdfdabc849 Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Date: Mon, 7 Dec 2020 00:51:19 +0100
|
||||
Subject: [PATCH] ifaces: do not remove unmanaged orphan interfaces
|
||||
|
||||
If there are unmanaged OVS interface present in the network state, NM
|
||||
may report uncomplete information. Therefore, nmstate could consider
|
||||
them as orphan and remove it when modifying the network state.
|
||||
|
||||
In order to fix this, nmstate should not consider it orphan and remove
|
||||
it when it is not on desired state or marked as changed.
|
||||
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/ifaces/ifaces.py | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
||||
index 1c2ffd5..703e672 100644
|
||||
--- a/libnmstate/ifaces/ifaces.py
|
||||
+++ b/libnmstate/ifaces/ifaces.py
|
||||
@@ -242,8 +242,10 @@ class Ifaces:
|
||||
|
||||
def _mark_orphen_as_absent(self):
|
||||
for iface in self._ifaces.values():
|
||||
- if iface.need_parent and (
|
||||
- not iface.parent or not self._ifaces.get(iface.parent)
|
||||
+ if (
|
||||
+ iface.need_parent
|
||||
+ and (not iface.parent or not self._ifaces.get(iface.parent))
|
||||
+ and (iface.is_desired or iface.is_changed)
|
||||
):
|
||||
iface.mark_as_changed()
|
||||
iface.state = InterfaceState.ABSENT
|
||||
--
|
||||
2.18.4
|
||||
|
@ -0,0 +1,185 @@
|
||||
From 1d0656c4197f0119d156b0df7b13bffeb5c46861 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Mon, 4 Jan 2021 11:37:18 +0800
|
||||
Subject: [PATCH] sriov: Use verification retry to wait VF been created
|
||||
|
||||
When reactivating i40e interface with SR-IOV enabled, the kernel
|
||||
takes some time(1 seconds or more in my test) to get the VF interface
|
||||
ready in kernel. So at the time of libnmstate returns with success, the
|
||||
VF interface might not be ready for use yet.
|
||||
|
||||
To fix that, we include VF interfaces in desire state when PV is
|
||||
changed/desired. The verification retry will wait the VF to be ready for
|
||||
use.
|
||||
|
||||
Unit test case and integration test case included.
|
||||
|
||||
Also fixed SRIOV integration test cases which are now all passing on i40e
|
||||
NIC.
|
||||
|
||||
To test on real SRIOV NIC:
|
||||
|
||||
cd tests/integration/
|
||||
sudo env TEST_REAL_NIC=ens1f1 pytest-3 sriov_test.py -vvv
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/ifaces/ethernet.py | 28 ++++
|
||||
libnmstate/ifaces/ifaces.py | 23 +++
|
||||
libnmstate/nm/sriov.py | 2 +-
|
||||
libnmstate/nm/wired.py | 19 ++-
|
||||
tests/integration/sriov_test.py | 242 ++++++++++++++++++++++----------
|
||||
tests/lib/nm/wired_test.py | 5 +
|
||||
6 files changed, 231 insertions(+), 88 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/ifaces/ethernet.py b/libnmstate/ifaces/ethernet.py
|
||||
index b346c36..644fe6d 100644
|
||||
--- a/libnmstate/ifaces/ethernet.py
|
||||
+++ b/libnmstate/ifaces/ethernet.py
|
||||
@@ -18,6 +18,9 @@
|
||||
#
|
||||
|
||||
from libnmstate.schema import Ethernet
|
||||
+from libnmstate.schema import Interface
|
||||
+from libnmstate.schema import InterfaceType
|
||||
+from libnmstate.schema import InterfaceState
|
||||
|
||||
from .base_iface import BaseIface
|
||||
|
||||
@@ -46,6 +49,31 @@ class EthernetIface(BaseIface):
|
||||
_capitalize_sriov_vf_mac(state)
|
||||
return state
|
||||
|
||||
+ @property
|
||||
+ def sriov_total_vfs(self):
|
||||
+ return (
|
||||
+ self.raw.get(Ethernet.CONFIG_SUBTREE, {})
|
||||
+ .get(Ethernet.SRIOV_SUBTREE, {})
|
||||
+ .get(Ethernet.SRIOV.TOTAL_VFS, 0)
|
||||
+ )
|
||||
+
|
||||
+ def create_sriov_vf_ifaces(self):
|
||||
+ return [
|
||||
+ EthernetIface(
|
||||
+ {
|
||||
+ # According to manpage of systemd.net-naming-scheme(7),
|
||||
+ # SRIOV VF interface will have v{slot} in device name.
|
||||
+ # Currently, nmstate has no intention to support
|
||||
+ # user-defined udev rule on SRIOV interface naming policy.
|
||||
+ Interface.NAME: f"{self.name}v{i}",
|
||||
+ Interface.TYPE: InterfaceType.ETHERNET,
|
||||
+ # VF will be in DOWN state initialy.
|
||||
+ Interface.STATE: InterfaceState.DOWN,
|
||||
+ }
|
||||
+ )
|
||||
+ for i in range(0, self.sriov_total_vfs)
|
||||
+ ]
|
||||
+
|
||||
|
||||
def _capitalize_sriov_vf_mac(state):
|
||||
vfs = (
|
||||
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
||||
index 703e672..7723f43 100644
|
||||
--- a/libnmstate/ifaces/ifaces.py
|
||||
+++ b/libnmstate/ifaces/ifaces.py
|
||||
@@ -97,6 +97,7 @@ class Ifaces:
|
||||
self._ifaces[iface.name] = iface
|
||||
|
||||
self._create_virtual_slaves()
|
||||
+ self._create_sriov_vfs_when_changed()
|
||||
self._validate_unknown_slaves()
|
||||
self._validate_unknown_parent()
|
||||
self._gen_metadata()
|
||||
@@ -124,6 +125,28 @@ class Ifaces:
|
||||
for iface in new_ifaces:
|
||||
self._ifaces[iface.name] = iface
|
||||
|
||||
+ def _create_sriov_vfs_when_changed(self):
|
||||
+ """
|
||||
+ When plugin set the TOTAL_VFS of PF, it might take 1 seconds or
|
||||
+ more to have the VFs to be ready.
|
||||
+ Nmstate should use verification retry to make sure VFs are full ready.
|
||||
+ To do that, we include VFs into desire state.
|
||||
+ """
|
||||
+ new_ifaces = []
|
||||
+ for iface in self._ifaces.values():
|
||||
+ if (
|
||||
+ iface.is_up
|
||||
+ and (iface.is_desired or iface.is_changed)
|
||||
+ and iface.type == InterfaceType.ETHERNET
|
||||
+ and iface.sriov_total_vfs > 0
|
||||
+ ):
|
||||
+ for new_iface in iface.create_sriov_vf_ifaces():
|
||||
+ if new_iface.name not in self._ifaces:
|
||||
+ new_iface.mark_as_desired()
|
||||
+ new_ifaces.append(new_iface)
|
||||
+ for new_iface in new_ifaces:
|
||||
+ self._ifaces[new_iface.name] = new_iface
|
||||
+
|
||||
def _pre_edit_validation_and_cleanup(self):
|
||||
self._validate_over_booked_slaves()
|
||||
self._validate_vlan_mtu()
|
||||
diff --git a/libnmstate/nm/sriov.py b/libnmstate/nm/sriov.py
|
||||
index f544732..25b150c 100644
|
||||
--- a/libnmstate/nm/sriov.py
|
||||
+++ b/libnmstate/nm/sriov.py
|
||||
@@ -68,7 +68,7 @@ def create_setting(context, iface_state, base_con_profile):
|
||||
sriov_config = iface_state.get(Ethernet.CONFIG_SUBTREE, {}).get(
|
||||
Ethernet.SRIOV_SUBTREE
|
||||
)
|
||||
- if sriov_config:
|
||||
+ if sriov_config and sriov_config.get(Ethernet.SRIOV.TOTAL_VFS):
|
||||
if not _has_sriov_capability(context, ifname):
|
||||
raise NmstateNotSupportedError(
|
||||
f"Interface '{ifname}' does not support SR-IOV"
|
||||
diff --git a/libnmstate/nm/wired.py b/libnmstate/nm/wired.py
|
||||
index 64662ac..5fea2a5 100644
|
||||
--- a/libnmstate/nm/wired.py
|
||||
+++ b/libnmstate/nm/wired.py
|
||||
@@ -162,15 +162,18 @@ def _get_mac_address_from_sysfs(ifname):
|
||||
|
||||
|
||||
def _get_ethernet_info(device, iface):
|
||||
+
|
||||
ethernet = {}
|
||||
+ sriov_info = sriov.get_info(device)
|
||||
+ if sriov_info:
|
||||
+ ethernet.update(sriov_info)
|
||||
+
|
||||
try:
|
||||
speed = int(device.get_speed())
|
||||
if speed > 0:
|
||||
ethernet[Ethernet.SPEED] = speed
|
||||
- else:
|
||||
- return None
|
||||
except AttributeError:
|
||||
- return None
|
||||
+ pass
|
||||
|
||||
ethtool_results = minimal_ethtool(iface)
|
||||
auto_setting = ethtool_results[Ethernet.AUTO_NEGOTIATION]
|
||||
@@ -178,17 +181,11 @@ def _get_ethernet_info(device, iface):
|
||||
ethernet[Ethernet.AUTO_NEGOTIATION] = True
|
||||
elif auto_setting is False:
|
||||
ethernet[Ethernet.AUTO_NEGOTIATION] = False
|
||||
- else:
|
||||
- return None
|
||||
|
||||
duplex_setting = ethtool_results[Ethernet.DUPLEX]
|
||||
if duplex_setting in [Ethernet.HALF_DUPLEX, Ethernet.FULL_DUPLEX]:
|
||||
ethernet[Ethernet.DUPLEX] = duplex_setting
|
||||
- else:
|
||||
- return None
|
||||
-
|
||||
- sriov_info = sriov.get_info(device)
|
||||
- if sriov_info:
|
||||
- ethernet.update(sriov_info)
|
||||
|
||||
+ if not ethernet:
|
||||
+ return None
|
||||
return ethernet
|
||||
|
||||
|
||||
--
|
||||
2.25.4
|
||||
|
92
SOURCES/BZ_1910193-support-multiple-gateways.patch
Normal file
92
SOURCES/BZ_1910193-support-multiple-gateways.patch
Normal file
@ -0,0 +1,92 @@
|
||||
From 47bd6db50e33aaa3d3d5e3b70d5f3039122b3a5c Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Sat, 5 Sep 2020 00:36:41 +0800
|
||||
Subject: [PATCH] nm route: Add support of multiple gateways
|
||||
|
||||
Since NetworkManager 1.22.0, the `NM.SettingIPConfig.props.routes`
|
||||
support assigning multiple gateway.
|
||||
|
||||
Integration test case updated for this.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/route.py | 30 +++---------------------------
|
||||
1 file changed, 3 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/route.py b/libnmstate/nm/route.py
|
||||
index 53bcf7c..548b218 100644
|
||||
--- a/libnmstate/nm/route.py
|
||||
+++ b/libnmstate/nm/route.py
|
||||
@@ -21,7 +21,6 @@ from operator import itemgetter
|
||||
import socket
|
||||
|
||||
from libnmstate import iplib
|
||||
-from libnmstate.error import NmstateNotImplementedError
|
||||
from libnmstate.error import NmstateValueError
|
||||
from libnmstate.nm import active_connection as nm_ac
|
||||
from libnmstate.schema import Interface
|
||||
@@ -31,7 +30,6 @@ from libnmstate.schema import RouteRule
|
||||
from .common import GLib
|
||||
from .common import NM
|
||||
|
||||
-NM_ROUTE_TABLE_ATTRIBUTE = "table"
|
||||
IPV4_DEFAULT_GATEWAY_DESTINATION = "0.0.0.0/0"
|
||||
IPV6_DEFAULT_GATEWAY_DESTINATION = "::/0"
|
||||
|
||||
@@ -116,7 +114,7 @@ def get_config(acs_and_ip_profiles):
|
||||
|
||||
|
||||
def _get_per_route_table_id(nm_route, default_table_id):
|
||||
- table = nm_route.get_attribute(NM_ROUTE_TABLE_ATTRIBUTE)
|
||||
+ table = nm_route.get_attribute(NM.IP_ROUTE_ATTRIBUTE_TABLE)
|
||||
return int(table.get_uint32()) if table else default_table_id
|
||||
|
||||
|
||||
@@ -152,19 +150,7 @@ def _get_default_route_config(gateway, metric, default_table_id, iface_name):
|
||||
|
||||
def add_routes(setting_ip, routes):
|
||||
for route in routes:
|
||||
- if route[Route.DESTINATION] in (
|
||||
- IPV4_DEFAULT_GATEWAY_DESTINATION,
|
||||
- IPV6_DEFAULT_GATEWAY_DESTINATION,
|
||||
- ):
|
||||
- if setting_ip.get_gateway():
|
||||
- raise NmstateNotImplementedError(
|
||||
- "Only a single default gateway is supported due to a "
|
||||
- "limitation of NetworkManager: "
|
||||
- "https://bugzilla.redhat.com/1707396"
|
||||
- )
|
||||
- _add_route_gateway(setting_ip, route)
|
||||
- else:
|
||||
- _add_specfic_route(setting_ip, route)
|
||||
+ _add_specfic_route(setting_ip, route)
|
||||
|
||||
|
||||
def _add_specfic_route(setting_ip, route):
|
||||
@@ -181,22 +167,12 @@ def _add_specfic_route(setting_ip, route):
|
||||
)
|
||||
table_id = route.get(Route.TABLE_ID, Route.USE_DEFAULT_ROUTE_TABLE)
|
||||
ip_route.set_attribute(
|
||||
- NM_ROUTE_TABLE_ATTRIBUTE, GLib.Variant.new_uint32(table_id)
|
||||
+ NM.IP_ROUTE_ATTRIBUTE_TABLE, GLib.Variant.new_uint32(table_id)
|
||||
)
|
||||
# Duplicate route entry will be ignored by libnm.
|
||||
setting_ip.add_route(ip_route)
|
||||
|
||||
|
||||
-def _add_route_gateway(setting_ip, route):
|
||||
- setting_ip.props.gateway = route[Route.NEXT_HOP_ADDRESS]
|
||||
- setting_ip.props.route_table = route.get(
|
||||
- Route.TABLE_ID, Route.USE_DEFAULT_ROUTE_TABLE
|
||||
- )
|
||||
- setting_ip.props.route_metric = route.get(
|
||||
- Route.METRIC, Route.USE_DEFAULT_METRIC
|
||||
- )
|
||||
-
|
||||
-
|
||||
def get_static_gateway_iface(family, iface_routes):
|
||||
"""
|
||||
Return one interface with gateway for given IP family.
|
||||
--
|
||||
2.27.0
|
||||
|
419
SOURCES/BZ_1916073_better-handling-for-timeout.patch
Normal file
419
SOURCES/BZ_1916073_better-handling-for-timeout.patch
Normal file
@ -0,0 +1,419 @@
|
||||
From 803ad90f11eb57221e7805e5cba8c309bafe1de8 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Wed, 13 Jan 2021 23:51:31 +0800
|
||||
Subject: [PATCH 1/2] nm: Better handling for timeout
|
||||
|
||||
When creating 1000 VLAN along with 1000 bridge using each VLAN,
|
||||
NetworkManager might trigger two timeout:
|
||||
|
||||
* The callback raises `Gio.IOErrorEnum.TIMED_OUT` error.
|
||||
* NetworkManager never call callback, nmstate idle check trigger the
|
||||
timeout.
|
||||
|
||||
To solve above issue:
|
||||
|
||||
* Increase the nmstate idle check timeout to 5 minutes.
|
||||
|
||||
* For actions like add profile and activate profile, we add a
|
||||
fallback checker which check whether requested action is already
|
||||
finished using `GLib.timeout_source_new()`
|
||||
|
||||
* When `Gio.IOErrorEnum.TIMED_OUT` happens, ignore the failure and wait
|
||||
fallback checker.
|
||||
|
||||
* The fallback checker is only started 15 seconds after action started,
|
||||
so this does not impact small desire state.
|
||||
|
||||
Test results on RHEL 8.3 i7-8665U 2G RAM:
|
||||
|
||||
10m29.212s to create 1000 VLAN and 1000 bridge over each VLAN.
|
||||
|
||||
Changed the integration test case to test 500 VLANs + 500 bridges.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/connection.py | 67 ++++++++++++++++++++++++++++++++++++-
|
||||
libnmstate/nm/context.py | 3 +-
|
||||
2 files changed, 67 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index 1f6c734..374a379 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
-# Copyright (c) 2018-2020 Red Hat, Inc.
|
||||
+# Copyright (c) 2018-2021 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
@@ -24,11 +24,14 @@ from libnmstate.error import NmstateLibnmError
|
||||
from libnmstate.error import NmstateInternalError
|
||||
from libnmstate.error import NmstateValueError
|
||||
|
||||
+from .common import GLib
|
||||
+from .common import Gio
|
||||
from .common import NM
|
||||
from . import ipv4
|
||||
from . import ipv6
|
||||
|
||||
ACTIVATION_TIMEOUT_FOR_BRIDGE = 35 # Bridge STP requires 30 seconds.
|
||||
+FALLBACK_CHECKER_INTERNAL = 15
|
||||
|
||||
|
||||
class ConnectionProfile:
|
||||
@@ -40,6 +43,7 @@ class ConnectionProfile:
|
||||
self._nm_ac = None
|
||||
self._ac_handlers = set()
|
||||
self._dev_handlers = set()
|
||||
+ self._fallback_checker = None
|
||||
|
||||
def create(self, settings):
|
||||
self.profile = NM.SimpleConnection.new()
|
||||
@@ -102,6 +106,26 @@ class ConnectionProfile:
|
||||
self._add_connection2_callback,
|
||||
user_data,
|
||||
)
|
||||
+ self._fallback_checker = GLib.timeout_source_new(
|
||||
+ FALLBACK_CHECKER_INTERNAL * 1000
|
||||
+ )
|
||||
+ self._fallback_checker.set_callback(
|
||||
+ self._profile_add_fallback_checker_callback, action
|
||||
+ )
|
||||
+ self._fallback_checker.attach(self._ctx.context)
|
||||
+
|
||||
+ def _profile_add_fallback_checker_callback(self, action):
|
||||
+ for nm_profile in self._ctx.client.get_connections():
|
||||
+ if nm_profile.get_uuid() == self.profile.get_uuid():
|
||||
+ self._fallback_checker_cleanup()
|
||||
+ self._ctx.finish_async(action)
|
||||
+ return GLib.SOURCE_REMOVE
|
||||
+ return GLib.SOURCE_CONTINUE
|
||||
+
|
||||
+ def _fallback_checker_cleanup(self):
|
||||
+ if self._fallback_checker:
|
||||
+ self._fallback_checker.destroy()
|
||||
+ self._fallback_checker = None
|
||||
|
||||
def delete(self):
|
||||
if not self.profile:
|
||||
@@ -152,6 +176,26 @@ class ConnectionProfile:
|
||||
self._active_connection_callback,
|
||||
user_data,
|
||||
)
|
||||
+ self._fallback_checker = GLib.timeout_source_new(
|
||||
+ FALLBACK_CHECKER_INTERNAL * 1000
|
||||
+ )
|
||||
+ self._fallback_checker.set_callback(
|
||||
+ self._activation_fallback_checker_callback, action
|
||||
+ )
|
||||
+ self._fallback_checker.attach(self._ctx.context)
|
||||
+
|
||||
+ def _activation_fallback_checker_callback(self, action):
|
||||
+ if self.devname:
|
||||
+ self._nm_dev = self._ctx.get_nm_dev(self.devname)
|
||||
+ if self._nm_dev:
|
||||
+ self._activation_progress_check(action)
|
||||
+ return GLib.SOURCE_CONTINUE
|
||||
+ else:
|
||||
+ logging.warn(
|
||||
+ "Failed to get interface name from profile, "
|
||||
+ "can not perform flalback check on activation"
|
||||
+ )
|
||||
+ return GLib.SOURCE_REMOVE
|
||||
|
||||
@property
|
||||
def profile(self):
|
||||
@@ -213,6 +257,18 @@ class ConnectionProfile:
|
||||
|
||||
try:
|
||||
nm_act_con = src_object.activate_connection_finish(result)
|
||||
+ except GLib.Error as e:
|
||||
+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
|
||||
+ logging.debug(
|
||||
+ f"{action} timeout on activation, "
|
||||
+ "using fallback method to wait activation"
|
||||
+ )
|
||||
+ return
|
||||
+ else:
|
||||
+ self._ctx.fail(
|
||||
+ NmstateLibnmError(f"{action} failed: error={e}")
|
||||
+ )
|
||||
+ return
|
||||
except Exception as e:
|
||||
self._ctx.fail(NmstateLibnmError(f"{action} failed: error={e}"))
|
||||
return
|
||||
@@ -366,6 +422,7 @@ class ConnectionProfile:
|
||||
def _activation_clean_up(self):
|
||||
self._remove_ac_handlers()
|
||||
self._remove_dev_handlers()
|
||||
+ self._fallback_checker_cleanup()
|
||||
|
||||
def _is_activating(self):
|
||||
if not self._nm_ac or not self._nm_dev:
|
||||
@@ -396,6 +453,13 @@ class ConnectionProfile:
|
||||
action = user_data
|
||||
try:
|
||||
profile = src_object.add_connection2_finish(result)[0]
|
||||
+ except GLib.Error as e:
|
||||
+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
|
||||
+ logging.debug(
|
||||
+ f"{action} timeout, using fallback method to "
|
||||
+ "wait profile creation"
|
||||
+ )
|
||||
+ return
|
||||
except Exception as e:
|
||||
self._ctx.fail(
|
||||
NmstateLibnmError(f"{action} failed with error: {e}")
|
||||
@@ -410,6 +474,7 @@ class ConnectionProfile:
|
||||
)
|
||||
)
|
||||
else:
|
||||
+ self._fallback_checker_cleanup()
|
||||
self._ctx.finish_async(action)
|
||||
|
||||
def _update2_callback(self, src_object, result, user_data):
|
||||
diff --git a/libnmstate/nm/context.py b/libnmstate/nm/context.py
|
||||
index 373ffe8..bc5c41c 100644
|
||||
--- a/libnmstate/nm/context.py
|
||||
+++ b/libnmstate/nm/context.py
|
||||
@@ -31,8 +31,7 @@ from .common import Gio
|
||||
# last finish async action.
|
||||
IDLE_CHECK_INTERNAL = 5
|
||||
|
||||
-# libnm dbus connection has reply timeout 25 seconds.
|
||||
-IDLE_TIMEOUT = 25
|
||||
+IDLE_TIMEOUT = 60 * 5 # 5 minutes
|
||||
|
||||
# NetworkManage is using dbus in libnm while the dbus has limitation on
|
||||
# maximum number of pending replies per connection.(RHEL/CentOS 8 is 1024)
|
||||
--
|
||||
2.27.0
|
||||
|
||||
|
||||
From ac82d18f96aa2313583efa1477be441291e2957c Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Date: Sun, 17 Jan 2021 11:18:10 +0800
|
||||
Subject: [PATCH 2/2] nm: Use fallback checker on profile deactivation and
|
||||
delete
|
||||
|
||||
When NM is under heave loads, NM might raise timeout error when
|
||||
try to deactivate or delete a profile, to solve that this patch
|
||||
introduce the same method in 2407f98
|
||||
to have a fallback checker on whether profile is deactivated/deleted
|
||||
every 15 seconds.
|
||||
|
||||
No test case required as current `test_lot_of_vlans_with_bridges` test
|
||||
case has `state: absent` which is good enough for testing this patch.
|
||||
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/active_connection.py | 61 ++++++++++++++++++++++++------
|
||||
libnmstate/nm/connection.py | 30 +++++++++++++++
|
||||
2 files changed, 80 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/active_connection.py b/libnmstate/nm/active_connection.py
|
||||
index 062c78a..b235e8b 100644
|
||||
--- a/libnmstate/nm/active_connection.py
|
||||
+++ b/libnmstate/nm/active_connection.py
|
||||
@@ -21,12 +21,14 @@ import logging
|
||||
|
||||
from libnmstate.error import NmstateLibnmError
|
||||
|
||||
+from .common import Gio
|
||||
from .common import GLib
|
||||
from .common import GObject
|
||||
from .common import NM
|
||||
|
||||
|
||||
NM_AC_STATE_CHANGED_SIGNAL = "state-changed"
|
||||
+FALLBACK_CHECKER_INTERNAL = 15
|
||||
|
||||
|
||||
class ActivationError(Exception):
|
||||
@@ -37,6 +39,8 @@ class ActiveConnection:
|
||||
def __init__(self, context=None, nm_ac_con=None):
|
||||
self._ctx = context
|
||||
self._act_con = nm_ac_con
|
||||
+ self._signal_handler = None
|
||||
+ self._fallback_checker = None
|
||||
|
||||
nmdevs = None
|
||||
if nm_ac_con:
|
||||
@@ -75,19 +79,35 @@ class ActiveConnection:
|
||||
|
||||
action = f"Deactivate profile: {self.devname}"
|
||||
self._ctx.register_async(action)
|
||||
- handler_id = act_connection.connect(
|
||||
+ self._signal_handler = act_connection.connect(
|
||||
NM_AC_STATE_CHANGED_SIGNAL,
|
||||
self._wait_state_changed_callback,
|
||||
action,
|
||||
)
|
||||
if act_connection.props.state != NM.ActiveConnectionState.DEACTIVATING:
|
||||
- user_data = (handler_id, action)
|
||||
+ user_data = action
|
||||
self._ctx.client.deactivate_connection_async(
|
||||
act_connection,
|
||||
self._ctx.cancellable,
|
||||
self._deactivate_connection_callback,
|
||||
user_data,
|
||||
)
|
||||
+ self._fallback_checker = GLib.timeout_source_new(
|
||||
+ FALLBACK_CHECKER_INTERNAL * 1000
|
||||
+ )
|
||||
+ self._fallback_checker.set_callback(
|
||||
+ self._deactivation_fallback_checker_callback, action
|
||||
+ )
|
||||
+ self._fallback_checker.attach(self._ctx.context)
|
||||
+
|
||||
+ def _clean_up(self):
|
||||
+ if self._signal_handler:
|
||||
+ if self._act_con:
|
||||
+ self._act_con.handler_disconnect(self._signal_handler)
|
||||
+ self._signal_handler = None
|
||||
+ if self._fallback_checker:
|
||||
+ self._fallback_checker.destroy()
|
||||
+ self._fallback_checker = None
|
||||
|
||||
def _wait_state_changed_callback(self, act_con, state, reason, action):
|
||||
if self._ctx.is_cancelled():
|
||||
@@ -96,13 +116,13 @@ class ActiveConnection:
|
||||
logging.debug(
|
||||
"Connection deactivation succeeded on %s", self.devname,
|
||||
)
|
||||
+ self._clean_up()
|
||||
self._ctx.finish_async(action)
|
||||
|
||||
def _deactivate_connection_callback(self, src_object, result, user_data):
|
||||
- handler_id, action = user_data
|
||||
+ action = user_data
|
||||
if self._ctx.is_cancelled():
|
||||
- if self._act_con:
|
||||
- self._act_con.handler_disconnect(handler_id)
|
||||
+ self._clean_up()
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -116,16 +136,20 @@ class ActiveConnection:
|
||||
"Connection is not active on {}, no need to "
|
||||
"deactivate".format(self.devname)
|
||||
)
|
||||
+ elif e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
|
||||
+ logging.debug(
|
||||
+ f"{action} timeout, using fallback method to wait profile "
|
||||
+ "deactivation"
|
||||
+ )
|
||||
+ return
|
||||
else:
|
||||
- if self._act_con:
|
||||
- self._act_con.handler_disconnect(handler_id)
|
||||
+ self._clean_up()
|
||||
self._ctx.fail(
|
||||
NmstateLibnmError(f"{action} failed: error={e}")
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
- if self._act_con:
|
||||
- self._act_con.handler_disconnect(handler_id)
|
||||
+ self._clean_up()
|
||||
self._ctx.fail(
|
||||
NmstateLibnmError(
|
||||
f"BUG: Unexpected error when activating {self.devname} "
|
||||
@@ -135,8 +159,7 @@ class ActiveConnection:
|
||||
return
|
||||
|
||||
if not success:
|
||||
- if self._act_con:
|
||||
- self._act_con.handler_disconnect(handler_id)
|
||||
+ self._clean_up()
|
||||
self._ctx.fail(
|
||||
NmstateLibnmError(
|
||||
f"{action} failed: error='None returned from "
|
||||
@@ -144,6 +167,22 @@ class ActiveConnection:
|
||||
)
|
||||
)
|
||||
|
||||
+ def _deactivation_fallback_checker_callback(self, action):
|
||||
+ if self.devname:
|
||||
+ self._nmdev = self._ctx.get_nm_dev(self.devname)
|
||||
+ if self._nmdev:
|
||||
+ self._act_con = self._nmdev.get_active_connection()
|
||||
+ if (
|
||||
+ self._act_con
|
||||
+ and self._act_con.props.state
|
||||
+ != NM.ActiveConnectionState.DEACTIVATED
|
||||
+ ):
|
||||
+ return GLib.SOURCE_CONTINUE
|
||||
+
|
||||
+ self._clean_up()
|
||||
+ self._ctx.finish_async(action)
|
||||
+ return GLib.SOURCE_REMOVE
|
||||
+
|
||||
@property
|
||||
def nm_active_connection(self):
|
||||
return self._act_con
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index 374a379..af7296f 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -144,6 +144,13 @@ class ConnectionProfile:
|
||||
self._delete_connection_callback,
|
||||
user_data,
|
||||
)
|
||||
+ self._fallback_checker = GLib.timeout_source_new(
|
||||
+ FALLBACK_CHECKER_INTERNAL * 1000
|
||||
+ )
|
||||
+ self._fallback_checker.set_callback(
|
||||
+ self._delete_fallback_checker_callback, action
|
||||
+ )
|
||||
+ self._fallback_checker.attach(self._ctx.context)
|
||||
|
||||
def activate(self):
|
||||
if self.con_id:
|
||||
@@ -504,11 +511,24 @@ class ConnectionProfile:
|
||||
action = user_data
|
||||
try:
|
||||
success = src_object.delete_finish(result)
|
||||
+ except GLib.Error as e:
|
||||
+ if e.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
|
||||
+ logging.debug(
|
||||
+ f"{action} timeout, using fallback method to wait profile "
|
||||
+ "deletion"
|
||||
+ )
|
||||
+ return
|
||||
+ else:
|
||||
+ self._ctx.fail(
|
||||
+ NmstateLibnmError(f"{action} failed with error: {e}")
|
||||
+ )
|
||||
+ return
|
||||
except Exception as e:
|
||||
self._ctx.fail(NmstateLibnmError(f"{action} failed: error={e}"))
|
||||
return
|
||||
|
||||
if success:
|
||||
+ self._fallback_checker_cleanup()
|
||||
self._ctx.finish_async(action)
|
||||
else:
|
||||
self._ctx.fail(
|
||||
@@ -518,6 +538,16 @@ class ConnectionProfile:
|
||||
)
|
||||
)
|
||||
|
||||
+ def _delete_fallback_checker_callback(self, action):
|
||||
+ if self.profile:
|
||||
+ for nm_profile in self._ctx.client.get_connections():
|
||||
+ if nm_profile.get_uuid() == self.profile.get_uuid():
|
||||
+ return GLib.SOURCE_CONTINUE
|
||||
+
|
||||
+ self._fallback_checker_cleanup()
|
||||
+ self._ctx.finish_async(action)
|
||||
+ return GLib.SOURCE_REMOVE
|
||||
+
|
||||
def _reset_profile(self):
|
||||
self._con_profile = None
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
58
SOURCES/BZ_1916073_retry_on_failure_when_activate.patch
Normal file
58
SOURCES/BZ_1916073_retry_on_failure_when_activate.patch
Normal file
@ -0,0 +1,58 @@
|
||||
From 013860d2576a34a277178e6afba0935498dc4f72 Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
Date: Wed, 3 Feb 2021 11:59:05 +0100
|
||||
Subject: [PATCH] connection: retry on profile activation if libnm error
|
||||
happened
|
||||
|
||||
When activating a profile if NetworkManager fails during the activation,
|
||||
Nmstate should retry it once.
|
||||
|
||||
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
|
||||
---
|
||||
libnmstate/nm/connection.py | 19 +++++++++++++++++--
|
||||
1 file changed, 17 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index 5b9a3aee2..45cb69019 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -180,7 +180,8 @@ def activate(self):
|
||||
"BUG: Cannot activate a profile with empty profile id and "
|
||||
"empty NM.Device"
|
||||
)
|
||||
- user_data = action
|
||||
+ retry = True
|
||||
+ user_data = action, retry
|
||||
self._ctx.register_async(action)
|
||||
self._ctx.client.activate_connection_async(
|
||||
self.profile,
|
||||
@@ -267,7 +268,7 @@ def _active_connection_callback(self, src_object, result, user_data):
|
||||
if self._ctx.is_cancelled():
|
||||
self._activation_clean_up()
|
||||
return
|
||||
- action = user_data
|
||||
+ action, retry = user_data
|
||||
|
||||
try:
|
||||
nm_act_con = src_object.activate_connection_finish(result)
|
||||
@@ -279,6 +280,20 @@ def _active_connection_callback(self, src_object, result, user_data):
|
||||
)
|
||||
return
|
||||
else:
|
||||
+ if retry:
|
||||
+ retry = False
|
||||
+ user_data = action, retry
|
||||
+ specific_object = None
|
||||
+ logging.debug(f"Action {action} failed, trying again.")
|
||||
+ self._ctx.client.activate_connection_async(
|
||||
+ self.profile,
|
||||
+ self.nmdevice,
|
||||
+ specific_object,
|
||||
+ self._ctx.cancellable,
|
||||
+ self._active_connection_callback,
|
||||
+ user_data,
|
||||
+ )
|
||||
+ return
|
||||
self._ctx.fail(
|
||||
NmstateLibnmError(f"{action} failed: error={e}")
|
||||
)
|
214
SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch
Normal file
214
SOURCES/BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch
Normal file
@ -0,0 +1,214 @@
|
||||
From a85b3dddf82f9e71774229740fbae6ea843d86d6 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Mon, 18 Jan 2021 15:55:43 +0800
|
||||
Subject: [PATCH 1/2] ifaces: Don't validate undesired interface for overbook
|
||||
|
||||
There is no need to validate overbooked interface for undesired
|
||||
controller interface.
|
||||
|
||||
Unit test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/ifaces/ifaces.py | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py
|
||||
index 7723f43..ee75125 100644
|
||||
--- a/libnmstate/ifaces/ifaces.py
|
||||
+++ b/libnmstate/ifaces/ifaces.py
|
||||
@@ -437,6 +437,8 @@ class Ifaces:
|
||||
"""
|
||||
slave_master_map = {}
|
||||
for iface in self._ifaces.values():
|
||||
+ if not (iface.is_changed or iface.is_desired) or not iface.is_up:
|
||||
+ continue
|
||||
for slave_name in iface.slaves:
|
||||
cur_master = slave_master_map.get(slave_name)
|
||||
if cur_master:
|
||||
--
|
||||
2.27.0
|
||||
|
||||
|
||||
From 644d8e5f5072caaba7151e66f211eceb02ae79c3 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
Date: Thu, 21 Jan 2021 20:43:34 +0800
|
||||
Subject: [PATCH 2/2] nm vlan/vxlan: Use uuid for VLAN/VxLAN parent
|
||||
|
||||
When parent of VLAN/VxLAN is holding the same name of OVS bridge or OVS
|
||||
port, NetworkManager will fail with error failed to find interface index
|
||||
of that parent.
|
||||
|
||||
The root cause is NetworkManager try to use user space interface as
|
||||
VLAN/VxLAN parent.
|
||||
|
||||
To workaround that, use profile UUID for `NM.SettingVlan.props.parent`
|
||||
and `NM.SettingVxlan.props.parent`.
|
||||
|
||||
Integration test case included.
|
||||
|
||||
Signed-off-by: Gris Ge <fge@redhat.com>
|
||||
---
|
||||
libnmstate/nm/applier.py | 98 +++++++++++++++++++++++++++++++++++--
|
||||
libnmstate/nm/connection.py | 7 +++
|
||||
2 files changed, 100 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
|
||||
index 26a057f..8e38df5 100644
|
||||
--- a/libnmstate/nm/applier.py
|
||||
+++ b/libnmstate/nm/applier.py
|
||||
@@ -66,8 +66,6 @@ MASTER_IFACE_TYPES = (
|
||||
|
||||
|
||||
def apply_changes(context, net_state, save_to_disk):
|
||||
- con_profiles = []
|
||||
-
|
||||
if (
|
||||
not save_to_disk
|
||||
and _has_ovs_interface_desired_or_changed(net_state)
|
||||
@@ -87,6 +85,10 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
_create_proxy_ifaces_desired_state(ifaces_desired_state)
|
||||
)
|
||||
|
||||
+ # A list of tuple holding both current ConnectionProfile and new/updated
|
||||
+ # ConnectionProfile.
|
||||
+ pending_con_profiles = []
|
||||
+
|
||||
for iface_desired_state in filter(
|
||||
lambda s: s.get(Interface.STATE) != InterfaceState.ABSENT,
|
||||
ifaces_desired_state,
|
||||
@@ -131,7 +133,7 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
# anything besides state:up and not been marked as changed.
|
||||
# We don't need to do this once we support querying on-disk
|
||||
# configure
|
||||
- con_profiles.append(cur_con_profile)
|
||||
+ pending_con_profiles.append((cur_con_profile, None))
|
||||
continue
|
||||
new_con_profile = _build_connection_profile(
|
||||
context,
|
||||
@@ -143,12 +145,25 @@ def apply_changes(context, net_state, save_to_disk):
|
||||
set_conn = new_con_profile.profile.get_setting_connection()
|
||||
set_conn.props.interface_name = iface_desired_state[Interface.NAME]
|
||||
if cur_con_profile and cur_con_profile.profile:
|
||||
- cur_con_profile.update(new_con_profile, save_to_disk)
|
||||
- con_profiles.append(new_con_profile)
|
||||
+ pending_con_profiles.append((cur_con_profile, new_con_profile))
|
||||
else:
|
||||
# Missing connection, attempting to create a new one.
|
||||
+ pending_con_profiles.append((None, new_con_profile))
|
||||
+
|
||||
+ pending_con_profiles = _use_uuid_for_parent(
|
||||
+ context, pending_con_profiles, save_to_disk
|
||||
+ )
|
||||
+
|
||||
+ con_profiles = []
|
||||
+ for cur_con_profile, new_con_profile in pending_con_profiles:
|
||||
+ if cur_con_profile and new_con_profile:
|
||||
+ cur_con_profile.update(new_con_profile, save_to_disk)
|
||||
+ con_profiles.append(new_con_profile)
|
||||
+ elif cur_con_profile is None and new_con_profile:
|
||||
new_con_profile.add(save_to_disk)
|
||||
con_profiles.append(new_con_profile)
|
||||
+ elif cur_con_profile:
|
||||
+ con_profiles.append(cur_con_profile)
|
||||
context.wait_all_finish()
|
||||
|
||||
_set_ifaces_admin_state(context, ifaces_desired_state, con_profiles)
|
||||
@@ -655,3 +670,76 @@ def _mark_nm_external_subordinate_changed(context, net_state):
|
||||
subordinate_iface = net_state.ifaces.get(subordinate)
|
||||
if subordinate_iface:
|
||||
subordinate_iface.mark_as_changed()
|
||||
+
|
||||
+
|
||||
+def _use_uuid_for_parent(context, pending_con_profiles, save_to_disk):
|
||||
+ """
|
||||
+ When parent of VLAN/VxLAN is holding the same name with
|
||||
+ OVS bridge or OVS port, we should use UUID instead of interface name
|
||||
+ """
|
||||
+ new_pending_con_profiles = []
|
||||
+ kernel_iface_name_to_uuid = {}
|
||||
+ for cur_nm_profile in context.client.get_connections():
|
||||
+ connection_type = cur_nm_profile.get_connection_type()
|
||||
+ if connection_type not in (
|
||||
+ NM.SETTING_OVS_BRIDGE_SETTING_NAME,
|
||||
+ NM.SETTING_OVS_PORT_SETTING_NAME,
|
||||
+ ):
|
||||
+ kernel_iface_name_to_uuid[
|
||||
+ cur_nm_profile.get_interface_name()
|
||||
+ ] = cur_nm_profile.get_uuid()
|
||||
+ # Override existing kernel_iface_name_to_uuid with pending changes.
|
||||
+ for cur_con_profile, new_con_profile in pending_con_profiles:
|
||||
+ if new_con_profile and new_con_profile.profile:
|
||||
+ uuid = new_con_profile.profile.get_uuid()
|
||||
+ connection_type = new_con_profile.profile.get_connection_type()
|
||||
+ iface_name = new_con_profile.profile.get_interface_name()
|
||||
+ elif cur_con_profile and cur_con_profile.profile:
|
||||
+ uuid = cur_con_profile.profile.get_uuid()
|
||||
+ connection_type = cur_con_profile.profile.get_connection_type()
|
||||
+ iface_name = cur_con_profile.profile.get_interface_name()
|
||||
+ else:
|
||||
+ continue
|
||||
+
|
||||
+ if connection_type not in (
|
||||
+ NM.SETTING_OVS_BRIDGE_SETTING_NAME,
|
||||
+ NM.SETTING_OVS_PORT_SETTING_NAME,
|
||||
+ ):
|
||||
+ kernel_iface_name_to_uuid[iface_name] = uuid
|
||||
+
|
||||
+ for cur_con_profile, new_con_profile in pending_con_profiles:
|
||||
+ new_pending_con_profiles.append((cur_con_profile, new_con_profile))
|
||||
+ if not new_con_profile:
|
||||
+ continue
|
||||
+ nm_profile = new_con_profile.profile
|
||||
+ if not nm_profile:
|
||||
+ continue
|
||||
+ connection_type = nm_profile.get_connection_type()
|
||||
+ nm_setting = None
|
||||
+ if connection_type == NM.SETTING_VLAN_SETTING_NAME:
|
||||
+ nm_setting = nm_profile.get_setting_vlan()
|
||||
+ elif connection_type == NM.SETTING_VXLAN_SETTING_NAME:
|
||||
+ nm_setting = nm_profile.get_setting_vxlan()
|
||||
+ else:
|
||||
+ continue
|
||||
+ if not nm_setting:
|
||||
+ continue
|
||||
+ parent_iface_name = nm_setting.props.parent
|
||||
+ parent_uuid = kernel_iface_name_to_uuid.get(parent_iface_name)
|
||||
+ if parent_uuid:
|
||||
+ updated_con_profile = connection.ConnectionProfile(context)
|
||||
+ new_nm_settings = []
|
||||
+ for cur_nm_setting in nm_profile.get_settings():
|
||||
+ new_nm_setting = cur_nm_setting.duplicate()
|
||||
+ if new_nm_setting.get_name() in (
|
||||
+ NM.SETTING_VLAN_SETTING_NAME,
|
||||
+ NM.SETTING_VXLAN_SETTING_NAME,
|
||||
+ ):
|
||||
+ new_nm_setting.props.parent = parent_uuid
|
||||
+ new_nm_settings.append(new_nm_setting)
|
||||
+ updated_con_profile.create(new_nm_settings)
|
||||
+ new_pending_con_profiles.pop()
|
||||
+ new_pending_con_profiles.append(
|
||||
+ (cur_con_profile, updated_con_profile)
|
||||
+ )
|
||||
+ return new_pending_con_profiles
|
||||
diff --git a/libnmstate/nm/connection.py b/libnmstate/nm/connection.py
|
||||
index af7296f..5b9a3ae 100644
|
||||
--- a/libnmstate/nm/connection.py
|
||||
+++ b/libnmstate/nm/connection.py
|
||||
@@ -63,6 +63,13 @@ class ConnectionProfile:
|
||||
if self.con_id:
|
||||
self.profile = self._ctx.client.get_connection_by_id(self.con_id)
|
||||
|
||||
+ def import_by_uuid(self, uuid):
|
||||
+ for nm_profile in self._ctx.client.get_connections():
|
||||
+ if nm_profile.get_uuid() == uuid:
|
||||
+ self.profile = nm_profile
|
||||
+ return
|
||||
+ logging.debug(f"Failed to find {uuid} profile")
|
||||
+
|
||||
def update(self, con_profile, save_to_disk=True):
|
||||
flags = NM.SettingsUpdate2Flags.BLOCK_AUTOCONNECT
|
||||
if save_to_disk:
|
||||
--
|
||||
2.27.0
|
||||
|
16
SOURCES/nmstate-0.3.4.tar.gz.asc
Normal file
16
SOURCES/nmstate-0.3.4.tar.gz.asc
Normal file
@ -0,0 +1,16 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCAAdFiEEfUQ+BAINyWGvqJXerIciWuEsPqMFAl8a02UACgkQrIciWuEs
|
||||
PqMSmg//T/2C0mP+zb1pnIfcPZvc8dlNgnvtTIN8EK23b6UvxrFYKuPmqRw+Dsir
|
||||
N/9enPTUgQKAOtZs7BdtZlCmsaU2bWAF11UgRY+gcSkSVeG0j/kxHLG3sE4RbFiD
|
||||
QPKJrqRE6m+ybTOiJ0oVXkR7f2i/AVmZE3+eZHn1TzHQoKZA8MJyExYWmk7wMkfG
|
||||
KzE7jvZQ1M4Q6aZKxo4wjAkhAhFLio9HhWnl8z1bLpWWFVHqqMJ04QniDsepczCm
|
||||
ISr6grG2TW6bS93lRCdDkS4yGCAYrwZ/5eyN5eOTd/et7FqG/ExFHdVaaro5I1W5
|
||||
cbOYyZ1cI/avA9vCWCkC7DUJOh3i5BzzhHaxS65qqpM7fiLIrHZhaLQaLByMO48d
|
||||
zo1wDEwIyNvuP4bIVwRycuDhtcLnPs5QwVbfW4HKkn4ULO+inr3lJk8V3ZZ3Ghmz
|
||||
qKCrpteJTK/yJl9N2MrXxPvYYe388m4A6GGSVml4mYCd2ZMBrQ8k8fSPdlodmzVJ
|
||||
J5gpeJRqm9sdrbv7tmuDfNOjAu0o9MP0/OSA0Lb5ho3pyylGnhsZ7Zkwbn2U/1b2
|
||||
zgPmVWJqRhjq01VgderCOerxow7OvetNicrNg/9e7+eFAHV7VUowdKf3vCyk0+nl
|
||||
WGeZLxi21w2Q2RH1ThPo6uMxL3pIp7dsbVrqM7oLpUoZzGtFnq8=
|
||||
=4Hsb
|
||||
-----END PGP SIGNATURE-----
|
326
SPECS/nmstate.spec
Normal file
326
SPECS/nmstate.spec
Normal file
@ -0,0 +1,326 @@
|
||||
%?python_enable_dependency_generator
|
||||
%define srcname nmstate
|
||||
%define libname libnmstate
|
||||
|
||||
Name: nmstate
|
||||
Version: 0.3.4
|
||||
Release: 25%{?dist}
|
||||
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: https://www.nmstate.io/nmstate.gpg
|
||||
Patch1: BZ_1858762-hide_ovs_patch_port_mtu.patch
|
||||
Patch2: BZ_1861263-handle-external-managed-interface.patch
|
||||
Patch3: BZ_1861668_ignore_unknown_iface.patch
|
||||
Patch4: BZ_1862025-remove_existing_profiles.patch
|
||||
Patch5: BZ_1858758-fix_ovs_bond.patch
|
||||
Patch6: BZ_1859844-fix_converting_memory_only.patch
|
||||
Patch7: BZ_1866269-preserve_nm_uuid_in_ovsdb.patch
|
||||
Patch8: BZ_1869345_ovsdb_remove_all_ports.patch
|
||||
Patch9: BZ_1887349-Allow-duplicate-iface-name-in-ovs.patch
|
||||
Patch10: BZ_1890497-nm-bond-Ignore-ad_actor_system-00-00-00-00-00-00.patch
|
||||
Patch11: BZ_1890497-nm.ipv6-call-clear_routing_rules-when-creating-the-s.patch
|
||||
Patch12: BZ_1901571_do_not_check_ovs_daemon_when_showing.patch
|
||||
Patch13: BZ_1904889-do-not-remove-unmanaged-ovs-bridge.patch
|
||||
Patch14: BZ_1910193-support-multiple-gateways.patch
|
||||
Patch15: BZ_1908724-sriov-use-verification-retry-to-wait-VF-been-created.patch
|
||||
Patch16: BZ_1916073_better-handling-for-timeout.patch
|
||||
Patch17: BZ_1918712_use_uuid_for_vlan_vxlan_parent.patch
|
||||
Patch18: BZ_1916073_retry_on_failure_when_activate.patch
|
||||
BuildArch: noarch
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-setuptools
|
||||
BuildRequires: gnupg2
|
||||
Requires: python3-setuptools
|
||||
Requires: python3-%{libname} = %{?epoch:%{epoch}:}%{version}-%{release}
|
||||
|
||||
%description
|
||||
Nmstate is a library with an accompanying command line tool that manages host
|
||||
networking settings in a declarative manner and aimed to satisfy enterprise
|
||||
needs to manage host networking through a northbound declarative API and multi
|
||||
provider support on the southbound.
|
||||
|
||||
|
||||
%package -n python3-%{libname}
|
||||
Summary: nmstate Python 3 API library
|
||||
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
|
||||
# Avoid automatically generated profiles
|
||||
Recommends: NetworkManager-config-server
|
||||
# Use Suggests for NetworkManager-ovs and NetworkManager-team since it is only
|
||||
# required for OVS and team support
|
||||
Suggests: NetworkManager-ovs
|
||||
Suggests: NetworkManager-team
|
||||
|
||||
%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.
|
||||
|
||||
%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-mantainers.gpg
|
||||
gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0}
|
||||
%autosetup -p1
|
||||
|
||||
%build
|
||||
%py3_build
|
||||
|
||||
%install
|
||||
%py3_install
|
||||
|
||||
%files
|
||||
%doc README.md
|
||||
%doc examples/
|
||||
%{_mandir}/man8/nmstatectl.8*
|
||||
%{python3_sitelib}/nmstatectl
|
||||
%{_bindir}/nmstatectl
|
||||
|
||||
%files -n python3-%{libname}
|
||||
%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
|
||||
* Fri Feb 05 2021 Gris Ge <fge@redhat.com> - 0.3.4-25
|
||||
- Remove patch for fixing the autoconnect on existing profile. RHBZ#1918712
|
||||
|
||||
* Thu Feb 04 2021 Gris Ge <fge@redhat.com> - 0.3.4-24
|
||||
- New patch fixing activation failure with 1000 interfaces. RHBZ#1916073
|
||||
|
||||
* Wed Feb 03 2021 Gris Ge <fge@redhat.com> - 0.3.4-23
|
||||
- Enforcing autoconnect on existing profile. RHBZ#1918712
|
||||
|
||||
* Fri Jan 22 2021 Gris Ge <fge@redhat.com> - 0.3.4-22
|
||||
- Fix creating VLAN/VxLAN over interface also used for OVS. RHBZ#1918712
|
||||
|
||||
* Sun Jan 17 2021 Gris Ge <fge@redhat.com> - 0.3.4-21
|
||||
- Additional patch for profile deactivation and deletion. RHBZ#1916073
|
||||
|
||||
* Thu Jan 14 2021 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.4-20
|
||||
- Better handling for timeout on activation. RHBZ#1916073
|
||||
|
||||
* Mon Jan 04 2021 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.4-19
|
||||
- Use verification retry to wait SR-IOV VF been created. RHBZ#1908724
|
||||
|
||||
* Wed Dec 23 2020 Gris Ge <fge@redhat.com> - 0.3.4-18
|
||||
- Support multiple gateways. RHBZ#1910193
|
||||
|
||||
* Mon Dec 07 2020 Gris Ge <fge@redhat.com> - 0.3.4-17
|
||||
- Rebuild to retrigger the CI gating. RHBZ#1904889
|
||||
|
||||
* Mon Dec 07 2020 Gris Ge <fge@redhat.com> - 0.3.4-16
|
||||
- Don't remove unmanaged OVS interface. RHBZ#1904889
|
||||
|
||||
* Thu Nov 26 2020 Gris Ge <fge@redhat.com> - 0.3.4-15
|
||||
- Fix `libnmstate.show()` in container with OVS bridge. RHBZ#1901571
|
||||
|
||||
* Wed Nov 04 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.4-14
|
||||
- Ignore bond zero ad_actor_system. RHBZ#1890497
|
||||
- Fix clear IPv6 routing rules.
|
||||
|
||||
* Wed Oct 14 2020 Gris Ge <fge@redhat.com> - 0.3.4-13
|
||||
- Allowing duplicate interface name of ovs. RHBZ#1887349
|
||||
|
||||
* Tue Aug 18 2020 Gris Ge <fge@redhat.com> - 0.3.4-12
|
||||
- New patch: OVSDB: Allowing remove all OVS ports. RHBZ#1869345
|
||||
|
||||
* Tue Aug 18 2020 Gris Ge <fge@redhat.com> - 0.3.4-11
|
||||
- OVSDB: Allowing remove all OVS ports. RHBZ#1869345
|
||||
|
||||
* Thu Aug 06 2020 Gris Ge <fge@redhat.com> - 0.3.4-10
|
||||
- OVSDB: Preserv old external_ids. RHBZ#1866269
|
||||
|
||||
* Tue Aug 04 2020 Gris Ge <fge@redhat.com> - 0.3.4-9
|
||||
- Fix converting memory only profile to persistent. RHBZ#1859844
|
||||
|
||||
* Mon Aug 03 2020 Gris Ge <fge@redhat.com> - 0.3.4-8
|
||||
- Fix failure when adding ovs bond to existing bridge. RHBZ#1858758
|
||||
|
||||
* Thu Jul 30 2020 Gris Ge <fge@redhat.com> - 0.3.4-7
|
||||
- Remove existing inactivate NM profiles. RHBZ#1862025
|
||||
|
||||
* Wed Jul 29 2020 Gris Ge <fge@redhat.com> - 0.3.4-6
|
||||
- New build to retrigger the CI gating.
|
||||
|
||||
* Wed Jul 29 2020 Gris Ge <fge@redhat.com> - 0.3.4-5
|
||||
- Use new patch. RHBZ#1861668
|
||||
|
||||
* Wed Jul 29 2020 Gris Ge <fge@redhat.com> - 0.3.4-4
|
||||
- Ignore unknown interface. RHBZ#1861668
|
||||
|
||||
* Tue Jul 28 2020 Gris Ge <fge@redhat.com> - 0.3.4-3
|
||||
- Add support NetworkManaged exteranl managed interface. RHBZ#1861263
|
||||
|
||||
* Tue Jul 28 2020 Gris Ge <fge@redhat.com> - 0.3.4-2
|
||||
- Hide MTU for OVS patch port. RHBZ#1858762
|
||||
|
||||
* Sat Jul 25 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.4-1
|
||||
- Upgrade to 0.3.4
|
||||
|
||||
* Fri Jul 24 2020 Gris Ge <fge@redhat.com> - 0.3.3-3
|
||||
- Allowing child been marked absent. RHBZ#1859148
|
||||
|
||||
* Mon Jul 06 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.3-2
|
||||
- Fix bug 1850698
|
||||
|
||||
* Thu Jul 02 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.3-1
|
||||
- Upgrade to 0.3.3
|
||||
|
||||
* Mon Jun 29 2020 Gris Ge <fge@redhat.com> - 0.3.2-6
|
||||
- Improve performance by remove unneeded calls. RHBZ#1820009
|
||||
|
||||
* Mon Jun 29 2020 Gris Ge <fge@redhat.com> - 0.3.2-5
|
||||
- Sort the pretty state with priority. RHBZ#1806474
|
||||
|
||||
* Mon Jun 29 2020 Gris Ge <fge@redhat.com> - 0.3.2-4
|
||||
- Canonicalize IP address. RHBZ#1816612
|
||||
|
||||
* Mon Jun 29 2020 Gris Ge <fge@redhat.com> - 0.3.2-3
|
||||
- Improve VLAN MTU error message. RHBZ#1788763
|
||||
|
||||
* Mon Jun 29 2020 Gris Ge <fge@redhat.com> - 0.3.2-2
|
||||
- Fix bug 1850698
|
||||
|
||||
* Mon Jun 15 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.2-1
|
||||
- Upgrade to 0.3.2
|
||||
- Sync. up with upstream spec file
|
||||
|
||||
* Thu Jun 11 2020 Gris Ge <fge@redhat.com> - 0.3.1-1
|
||||
- Upgrade to 0.3.1
|
||||
|
||||
* Wed May 13 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.3.0-1
|
||||
- Upgrade to 0.3.0
|
||||
- Sync. up with upstream spec file.
|
||||
- Update signature verification.
|
||||
|
||||
* Tue Mar 31 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.9-1
|
||||
- Upgrade to 0.2.9
|
||||
|
||||
* Wed Mar 25 2020 Gris Ge <fge@redhat.com> - 0.2.6-6
|
||||
- Support 3+ DNS name server(IPv4 only or IPv6 only). RHBZ #1816043
|
||||
|
||||
* Fri Mar 20 2020 Gris Ge <fge@redhat.com> - 0.2.6-5
|
||||
- Support static DNS with DHCP. RHBZ #1815112
|
||||
|
||||
* Thu Mar 12 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.6-4.8
|
||||
- Fix bond mac and options regression. RHBZ #1809330
|
||||
|
||||
* Mon Mar 09 2020 Gris Ge <fge@redhat.com> - 0.2.6-3.8
|
||||
- Fix change bond mode. RHBZ #1809330
|
||||
|
||||
* Mon Mar 02 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.6-2.7
|
||||
- Fix cmd stuck when trying to create ovs-bond. RHBZ #1806249.
|
||||
|
||||
* Tue Feb 25 2020 Gris Ge <fge@redhat.com> - 0.2.6-1
|
||||
- Upgrade to 0.2.6
|
||||
|
||||
* Thu Feb 20 2020 Gris Ge <fge@redhat.com> - 0.2.5-1
|
||||
- Upgrade to 0.2.5
|
||||
|
||||
* Thu Feb 13 2020 Gris Ge <fge@redhat.com> - 0.2.4-2
|
||||
- Fix failure when editing existing OVS interface. RHBZ #1786935
|
||||
|
||||
* Thu Feb 13 2020 Gris Ge <fge@redhat.com> - 0.2.4-1
|
||||
- Upgrade to 0.2.4
|
||||
|
||||
* Wed Feb 05 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.3-1
|
||||
- Upgrade to 0.2.3
|
||||
|
||||
* Tue Feb 04 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.2-3
|
||||
- Fix the incorrect source
|
||||
|
||||
* Tue Feb 04 2020 Fernando Fernandez Mancera <ferferna@redhat.com> - 0.2.2-2
|
||||
- Upgrade to 0.2.2
|
||||
|
||||
* Wed Jan 22 2020 Gris Ge <fge@redhat.com> - 0.2.0-3.1
|
||||
- Fix the memeory leak of NM.Client. RHBZ #1784707
|
||||
|
||||
* Mon Dec 02 2019 Gris Ge <fge@redhat.com> - 0.2.0-2
|
||||
- Fix the incorrect source tarbal.
|
||||
|
||||
* Mon Dec 02 2019 Gris Ge <fge@redhat.com> - 0.2.0-1
|
||||
- Upgrade to nmstate 0.2.0
|
||||
|
||||
* Mon Dec 02 2019 Gris Ge <fge@redhat.com> - 0.1.1-4
|
||||
- Fix the problem found by CI gating.
|
||||
|
||||
* Mon Dec 02 2019 Gris Ge <fge@redhat.com> - 0.1.1-3
|
||||
- Bump dist number as RHEL 8.1.1 took 0.1.1-2.
|
||||
|
||||
* Mon Dec 02 2019 Gris Ge <fge@redhat.com> - 0.1.1-2
|
||||
- Upgrade to nmstate 0.1.1.
|
||||
|
||||
* Tue Sep 10 2019 Gris Ge <fge@redhat.com> - 0.0.8-15
|
||||
- Detach slaves without deleting them: RHBZ #1749632
|
||||
|
||||
* Fri Sep 06 2019 Gris Ge <fge@redhat.com> - 0.0.8-14
|
||||
- Preserve (dynamic) IPv6 address base on MAC address: RHBZ #1748825
|
||||
|
||||
* Fri Sep 06 2019 Gris Ge <fge@redhat.com> - 0.0.8-13
|
||||
- Prioritize master interfaces activaction: RHBZ #1749314
|
||||
|
||||
* Mon Sep 02 2019 Gris Ge <fge@redhat.com> - 0.0.8-12
|
||||
- Fix slave activatoin race: RHBZ #1741440
|
||||
|
||||
* Mon Sep 02 2019 Gris Ge <fge@redhat.com - 0.0.8-11
|
||||
- Add NetworkManager-config-server dependency: Fix RHBZ #1740085
|
||||
|
||||
* Thu Aug 15 2019 Gris Ge <fge@redhat.com> - 0.0.8-10
|
||||
- Fix RHBZ #1740125
|
||||
|
||||
* Wed Aug 14 2019 Gris Ge <fge@redhat.com> - 0.0.8-9
|
||||
- Fix RHBZ #1741049
|
||||
|
||||
* Wed Aug 14 2019 Gris Ge <fge@redhat.com> - 0.0.8-8
|
||||
- Fix RHBZ #1740584
|
||||
|
||||
* Tue Aug 13 2019 Gris Ge <fge@redhat.com> - 0.0.8-7
|
||||
- Fix RHBZ #1740554
|
||||
|
||||
* Tue Aug 13 2019 Gris Ge <fge@redhat.com> - 0.0.8-6
|
||||
- Bump release tag as CNV took the -5.
|
||||
|
||||
* Tue Aug 13 2019 Gris Ge <fge@redhat.com> - 0.0.8-5
|
||||
- Bump release tag as CNV took the -4.
|
||||
|
||||
* Tue Aug 13 2019 Gris Ge <fge@redhat.com> - 0.0.8-4
|
||||
- Disable reapply on ipv6 to fix bug 1738101.
|
||||
|
||||
* Fri Jul 26 2019 Gris Ge <fge@redhat.com> - 0.0.8-3
|
||||
- Fix the license to meet Fedora/RHEL guideline.
|
||||
|
||||
* Fri Jul 26 2019 Gris Ge <fge@redhat.com> - 0.0.8-2
|
||||
- Relicense to LGPL2.1+.
|
||||
|
||||
* Fri Jul 26 2019 Gris Ge <fge@redhat.com> - 0.0.8-1
|
||||
- Upgrade to 0.0.8.
|
||||
|
||||
* Fri Jun 14 2019 Gris Ge <fge@redhat.com> - 0.0.7-1
|
||||
- Upgrade to 0.0.7.
|
||||
|
||||
* Mon Apr 22 2019 Gris Ge <fge@redhat.com> - 0.0.5-3
|
||||
- Add missing runtime dependency.
|
||||
|
||||
* Thu Mar 21 2019 Gris Ge <fge@redhat.com> - 0.0.5-2
|
||||
- Rebuild to enable CI testing.
|
||||
|
||||
* Mon Mar 18 2019 Gris Ge <fge@redhat.com> - 0.0.5-1
|
||||
- Initial release
|
Loading…
Reference in New Issue
Block a user