From ea34f8f454a7a865fc013df4690bc9129649f2d3 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 28 Jul 2020 02:08:29 -0400 Subject: [PATCH] import nmstate-0.3.2-6.el8 --- .gitignore | 4 +- .nmstate.metadata | 4 +- ...88763_improve_vlan_mtu_error_message.patch | 217 ++++++++++++++++++ ...6474-sort-pretty-state-with-priority.patch | 171 ++++++++++++++ .../BZ_1816612_canonicalize-IP-address.patch | 176 ++++++++++++++ ...BZ_1820009_only_reapply_if_activated.patch | 63 +++++ ...ove_duplicate_call_of_is_ovs_running.patch | 68 ++++++ .../BZ_1850698-Fix-remove-dns-config.patch | 60 +++++ SOURCES/nmstate-0.2.0.tar.gz.asc | 17 -- SOURCES/nmstate-0.3.2.tar.gz.asc | 16 ++ SPECS/nmstate.spec | 105 ++++++++- 11 files changed, 874 insertions(+), 27 deletions(-) create mode 100644 SOURCES/BZ_1788763_improve_vlan_mtu_error_message.patch create mode 100644 SOURCES/BZ_1806474-sort-pretty-state-with-priority.patch create mode 100644 SOURCES/BZ_1816612_canonicalize-IP-address.patch create mode 100644 SOURCES/BZ_1820009_only_reapply_if_activated.patch create mode 100644 SOURCES/BZ_1820009_remove_duplicate_call_of_is_ovs_running.patch create mode 100644 SOURCES/BZ_1850698-Fix-remove-dns-config.patch delete mode 100644 SOURCES/nmstate-0.2.0.tar.gz.asc create mode 100644 SOURCES/nmstate-0.3.2.tar.gz.asc diff --git a/.gitignore b/.gitignore index 23b2588..5b1c88a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg -SOURCES/nmstate-0.2.0.tar.gz +SOURCES/nmstate-0.3.2.tar.gz +SOURCES/nmstate.gpg diff --git a/.nmstate.metadata b/.nmstate.metadata index 847393c..3eb8b95 100644 --- a/.nmstate.metadata +++ b/.nmstate.metadata @@ -1,2 +1,2 @@ -7bcc63976a8d449b3adc57f40d7a476106889042 SOURCES/gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg -33afae47f344d5908b7772fbfd33fef26eb88ffb SOURCES/nmstate-0.2.0.tar.gz +5f07dbfc599578c7b90fd3efd044bf01f7aa7c4c SOURCES/nmstate-0.3.2.tar.gz +c3efe2931425e910002e11ff34ef102fbfa0b9de SOURCES/nmstate.gpg diff --git a/SOURCES/BZ_1788763_improve_vlan_mtu_error_message.patch b/SOURCES/BZ_1788763_improve_vlan_mtu_error_message.patch new file mode 100644 index 0000000..441c8e1 --- /dev/null +++ b/SOURCES/BZ_1788763_improve_vlan_mtu_error_message.patch @@ -0,0 +1,217 @@ +From 83a9a81c38463c66ad512aacccfe627aa2b5a17e Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Tue, 23 Jun 2020 10:18:51 +0200 +Subject: [PATCH 1/3] base_iface: rename iface_type property to type + +In order to follow the property naming, it makes sense to rename +"iface_type" property to "type". + +Signed-off-by: Fernando Fernandez Mancera +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/base_iface.py | 4 ++-- + libnmstate/ifaces/ifaces.py | 9 ++++----- + libnmstate/ifaces/ovs.py | 4 ++-- + libnmstate/plugins/nmstate_plugin_ovsdb.py | 4 ++-- + 4 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py +index 56a1115..6c55f6a 100644 +--- a/libnmstate/ifaces/base_iface.py ++++ b/libnmstate/ifaces/base_iface.py +@@ -152,7 +152,7 @@ class BaseIface: + return self._name + + @property +- def iface_type(self): ++ def type(self): + return self._info.get(Interface.TYPE, InterfaceType.UNKNOWN) + + @property +@@ -285,7 +285,7 @@ class BaseIface: + if self.is_master and not self.is_absent: + for slave_name in self.slaves: + slave_iface = ifaces[slave_name] +- slave_iface.set_master(self.name, self.iface_type) ++ slave_iface.set_master(self.name, self.type) + + def update(self, info): + self._info.update(info) +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index 9c254ac..e85123c 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -74,7 +74,7 @@ class Ifaces: + + if iface_info.get(Interface.TYPE) is None: + if cur_iface: +- iface_info[Interface.TYPE] = cur_iface.iface_type ++ iface_info[Interface.TYPE] = cur_iface.type + elif iface.is_up: + raise NmstateValueError( + f"Interface {iface.name} has no type defined " +@@ -82,7 +82,7 @@ class Ifaces: + ) + iface = _to_specific_iface_obj(iface_info, save_to_disk) + if ( +- iface.iface_type == InterfaceType.UNKNOWN ++ iface.type == InterfaceType.UNKNOWN + # Allowing deletion of down profiles + and not iface.is_absent + ): +@@ -147,7 +147,7 @@ class Ifaces: + When OVS patch peer does not exist or is down, raise an error. + """ + for iface in self._ifaces.values(): +- if iface.iface_type == InterfaceType.OVS_INTERFACE and iface.is_up: ++ if iface.type == InterfaceType.OVS_INTERFACE and iface.is_up: + if iface.peer: + peer_iface = self._ifaces.get(iface.peer) + if not peer_iface or not peer_iface.is_up: +@@ -156,8 +156,7 @@ class Ifaces: + "be up" + ) + elif ( +- not peer_iface.iface_type +- == InterfaceType.OVS_INTERFACE ++ not peer_iface.type == InterfaceType.OVS_INTERFACE + or not peer_iface.is_patch_port + ): + raise NmstateValueError( +diff --git a/libnmstate/ifaces/ovs.py b/libnmstate/ifaces/ovs.py +index 0a5abe9..cd04cef 100644 +--- a/libnmstate/ifaces/ovs.py ++++ b/libnmstate/ifaces/ovs.py +@@ -84,7 +84,7 @@ class OvsBridgeIface(BridgeIface): + slave_iface.update( + {BridgeIface.BRPORT_OPTIONS_METADATA: port_config} + ) +- if slave_iface.iface_type == InterfaceType.OVS_INTERFACE: ++ if slave_iface.type == InterfaceType.OVS_INTERFACE: + slave_iface.parent = self.name + super().gen_metadata(ifaces) + +@@ -101,7 +101,7 @@ class OvsBridgeIface(BridgeIface): + } + ) + slave_iface.mark_as_changed() +- slave_iface.set_master(self.name, self.iface_type) ++ slave_iface.set_master(self.name, self.type) + slave_iface.parent = self.name + return slave_iface + +diff --git a/libnmstate/plugins/nmstate_plugin_ovsdb.py b/libnmstate/plugins/nmstate_plugin_ovsdb.py +index a0cfbc0..83965e1 100644 +--- a/libnmstate/plugins/nmstate_plugin_ovsdb.py ++++ b/libnmstate/plugins/nmstate_plugin_ovsdb.py +@@ -168,9 +168,9 @@ class NmstateOvsdbPlugin(NmstatePlugin): + continue + if not iface.is_up: + continue +- if iface.iface_type == OVSBridge.TYPE: ++ if iface.type == OVSBridge.TYPE: + table_name = "Bridge" +- elif iface.iface_type == OVSInterface.TYPE: ++ elif iface.type == OVSInterface.TYPE: + table_name = "Interface" + else: + continue +-- +2.27.0 + + +From 80a0a200fc198d9f2f31cfa67fbd3d2c776256df Mon Sep 17 00:00:00 2001 +From: Adwait Thattey +Date: Thu, 18 Jun 2020 23:11:33 +0530 +Subject: [PATCH 2/3] iface: add setter method for mtu of interface + +Signed-off-by: Adwait Thattey +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/base_iface.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py +index 6c55f6a..edccb1f 100644 +--- a/libnmstate/ifaces/base_iface.py ++++ b/libnmstate/ifaces/base_iface.py +@@ -298,6 +298,10 @@ class BaseIface: + def mtu(self): + return self._info.get(Interface.MTU) + ++ @mtu.setter ++ def mtu(self, value): ++ self._info[Interface.MTU] = value ++ + def _capitalize_mac(self): + if self.mac: + self._info[Interface.MAC] = self.mac.upper() +-- +2.27.0 + + +From 60ef20b6b4a4cd76b47b5fa8f989eee2ca2608fd Mon Sep 17 00:00:00 2001 +From: Adwait Thattey +Date: Thu, 18 Jun 2020 23:58:11 +0530 +Subject: [PATCH 3/3] vlan: validate mtu not greater than base iface + +A new validator is added that verifies that the +MTU of VLAN/VXLAN is not more than MTU of base iface + +If base iface MTU doesn't exist, set as vlan MTU + +Multiple tests are added to check if appropriate errors are thrown + +Signed-off-by: Adwait Thattey +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/ifaces.py | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/libnmstate/ifaces/ifaces.py b/libnmstate/ifaces/ifaces.py +index e85123c..c216dd8 100644 +--- a/libnmstate/ifaces/ifaces.py ++++ b/libnmstate/ifaces/ifaces.py +@@ -123,6 +123,7 @@ class Ifaces: + + def _pre_edit_validation_and_cleanup(self): + self._validate_over_booked_slaves() ++ self._validate_vlan_mtu() + self._handle_master_slave_list_change() + self._match_child_iface_state_with_parent() + self._mark_orphen_as_absent() +@@ -164,6 +165,31 @@ class Ifaces: + " patch port" + ) + ++ def _validate_vlan_mtu(self): ++ """ ++ Validate that mtu of vlan or vxlan is less than ++ or equal to it's base interface's MTU ++ ++ If base MTU is not present, set same as vlan MTU ++ """ ++ for iface in self._ifaces.values(): ++ ++ if ( ++ iface.type in [InterfaceType.VLAN, InterfaceType.VXLAN] ++ and iface.is_up ++ and iface.mtu ++ ): ++ base_iface = self._ifaces.get(iface.parent) ++ if not base_iface.mtu: ++ base_iface.mtu = iface.mtu ++ if iface.mtu > base_iface.mtu: ++ raise NmstateValueError( ++ f"Interface {iface.name} has bigger " ++ f"MTU({iface.mtu}) " ++ f"than its base interface: {iface.parent} " ++ f"MTU({base_iface.mtu})" ++ ) ++ + def _handle_master_slave_list_change(self): + """ + * Mark slave interface as changed if master removed. +-- +2.27.0 + diff --git a/SOURCES/BZ_1806474-sort-pretty-state-with-priority.patch b/SOURCES/BZ_1806474-sort-pretty-state-with-priority.patch new file mode 100644 index 0000000..532272e --- /dev/null +++ b/SOURCES/BZ_1806474-sort-pretty-state-with-priority.patch @@ -0,0 +1,171 @@ +From d0bfae4171f0d280241949a928654c84e63ed006 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Mon, 29 Jun 2020 22:30:03 +0800 +Subject: [PATCH] pretty state: Dumping state in the sorted order with priority + +For OVS bond port, we would like the `name` been shown before other +properties. + +To achieve that, we sort the dict keys and honoring the priority list which +means keys in `PRIORITY_LIST` will be shown before others. + +Currently the `PRIORITY_LIST` is: +`("name", "type", "state", "enabled", "dns", "route-rules", "routes", + "interfaces")` + +Test cases added. + +Signed-off-by: Gris Ge +Signed-off-by: Till Maas +--- + libnmstate/prettystate.py | 94 ++++++++++++++++++--------------------- + 1 file changed, 43 insertions(+), 51 deletions(-) + +diff --git a/libnmstate/prettystate.py b/libnmstate/prettystate.py +index da57618..10e22d6 100644 +--- a/libnmstate/prettystate.py ++++ b/libnmstate/prettystate.py +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2018-2019 Red Hat, Inc. ++# Copyright (c) 2018-2020 Red Hat, Inc. + # + # This file is part of nmstate + # +@@ -17,15 +17,29 @@ + # along with this program. If not, see . + # + +-from collections import OrderedDict ++from collections.abc import Mapping ++from collections.abc import Sequence + from copy import deepcopy + import difflib + import json +-from operator import itemgetter + + import yaml + +-from libnmstate.schema import Constants ++from .schema import DNS ++from .schema import Route ++from .schema import RouteRule ++from .schema import Interface ++ ++PRIORITY_LIST = ( ++ "name", ++ "type", ++ "state", ++ "enabled", ++ DNS.KEY, ++ RouteRule.KEY, ++ Route.KEY, ++ Interface.KEY, ++) + + + def format_desired_current_state_diff(desired_state, current_state): +@@ -57,8 +71,8 @@ def format_desired_current_state_diff(desired_state, current_state): + + class PrettyState: + def __init__(self, state): +- yaml.add_representer(OrderedDict, represent_ordereddict) +- self.state = order_state(deepcopy(state)) ++ yaml.add_representer(dict, represent_dict) ++ self.state = _sort_with_priority(state) + + @property + def yaml(self): +@@ -71,35 +85,18 @@ class PrettyState: + return json.dumps(self.state, indent=4, separators=(",", ": ")) + + +-def represent_ordereddict(dumper, data): ++def represent_dict(dumper, data): ++ """ ++ Represent dictionary with insert order + """ +- Represent OrderedDict as regular dictionary +- +- Source: https://stackoverflow.com/questions/16782112/can-pyyaml-dump-dict-items-in-non-alphabetical-order +- """ # noqa: E501 + value = [] + + for item_key, item_value in data.items(): + node_key = dumper.represent_data(item_key) + node_value = dumper.represent_data(item_value) +- + value.append((node_key, node_value)) + +- return yaml.nodes.MappingNode(u"tag:yaml.org,2002:map", value) +- +- +-def order_state(state): +- iface_states = state.pop(Constants.INTERFACES, None) +- +- state = order_iface_state(state) +- +- if iface_states is not None: +- state[Constants.INTERFACES] = [ +- order_iface_state(iface_state) +- for iface_state in sorted(iface_states, key=itemgetter("name")) +- ] +- +- return state ++ return yaml.nodes.MappingNode("tag:yaml.org,2002:map", value) + + + def represent_unicode(_, data): +@@ -112,30 +109,25 @@ def represent_unicode(_, data): + """ + + return yaml.ScalarNode( +- tag=u"tag:yaml.org,2002:str", value=data.encode("utf-8") ++ tag="tag:yaml.org,2002:str", value=data.encode("utf-8") + ) + + +-def order_iface_state(iface_state): +- ordered_state = OrderedDict() +- +- for setting in ("name", "type", "state"): +- try: +- ordered_state[setting] = iface_state.pop(setting) +- except KeyError: +- pass +- +- for key, value in order_dict(iface_state).items(): +- ordered_state[key] = value +- +- return ordered_state +- +- +-def order_dict(dict_): +- ordered_dict = OrderedDict() +- for key, value in sorted(dict_.items()): +- if isinstance(value, dict): +- value = order_dict(value) +- ordered_dict[key] = value +- +- return ordered_dict ++def _sort_with_priority(data): ++ if isinstance(data, Sequence) and not isinstance(data, str): ++ return [_sort_with_priority(item) for item in data] ++ elif isinstance(data, Mapping): ++ new_data = {} ++ for key in sorted(data.keys(), key=_sort_with_priority_key_func): ++ new_data[key] = _sort_with_priority(data[key]) ++ return new_data ++ else: ++ return deepcopy(data) ++ ++ ++def _sort_with_priority_key_func(key): ++ try: ++ priority = PRIORITY_LIST.index(key) ++ except ValueError: ++ priority = len(PRIORITY_LIST) ++ return (priority, key) +-- +2.27.0 + diff --git a/SOURCES/BZ_1816612_canonicalize-IP-address.patch b/SOURCES/BZ_1816612_canonicalize-IP-address.patch new file mode 100644 index 0000000..bfe7b2b --- /dev/null +++ b/SOURCES/BZ_1816612_canonicalize-IP-address.patch @@ -0,0 +1,176 @@ +From c3a924203e8f0d3d6d6fc7882f006d60e7d8d985 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Fri, 19 Jun 2020 10:14:25 +0800 +Subject: [PATCH] ip: canonicalize IP address + +Canonicalize these IP addresses: + * `InterfaceIP.ADDRESS_IP` + * `Route.DESTINATION` + * `Route.NEXT_HOP_ADDRESS` + * `RouteRule.IP_FROM` + * `RouteRule.IP_TO` + +Introduced two functions to `libnmstate/iplib.py`: + * `canonicalize_ip_network()` returns address with prefix + * `canonicalize_ip_address()` returns address without prefix + +Unit test cases added. + +Signed-off-by: Gris Ge +--- + libnmstate/ifaces/base_iface.py | 19 +++++++------------ + libnmstate/iplib.py | 14 ++++++++++++++ + libnmstate/route.py | 12 ++++++++++++ + libnmstate/route_rule.py | 14 +++++++------- + 4 files changed, 40 insertions(+), 19 deletions(-) + +diff --git a/libnmstate/ifaces/base_iface.py b/libnmstate/ifaces/base_iface.py +index 33da69d..56a1115 100644 +--- a/libnmstate/ifaces/base_iface.py ++++ b/libnmstate/ifaces/base_iface.py +@@ -20,13 +20,12 @@ + from collections.abc import Mapping + from copy import deepcopy + import logging +-from ipaddress import ip_address + from operator import itemgetter + + from libnmstate.error import NmstateInternalError + from libnmstate.error import NmstateValueError +-from libnmstate.iplib import is_ipv6_address + from libnmstate.iplib import is_ipv6_link_local_addr ++from libnmstate.iplib import canonicalize_ip_address + from libnmstate.schema import Interface + from libnmstate.schema import InterfaceIP + from libnmstate.schema import InterfaceIPv6 +@@ -44,7 +43,7 @@ class IPState: + self._info = info + self._remove_stack_if_disabled() + self._sort_addresses() +- self._canonicalize_ipv6_addr() ++ self._canonicalize_ip_addr() + self._canonicalize_dynamic() + + def _canonicalize_dynamic(self): +@@ -61,15 +60,11 @@ class IPState: + ): + self._info.pop(dhcp_option, None) + +- def _canonicalize_ipv6_addr(self): +- """ +- Convert full IPv6 address to abbreviated address. +- """ +- if self._family == Interface.IPV6: +- for addr in self.addresses: +- address = addr[InterfaceIP.ADDRESS_IP] +- if is_ipv6_address(address): +- addr[InterfaceIP.ADDRESS_IP] = str(ip_address(address)) ++ def _canonicalize_ip_addr(self): ++ for addr in self.addresses: ++ addr[InterfaceIP.ADDRESS_IP] = canonicalize_ip_address( ++ addr[InterfaceIP.ADDRESS_IP] ++ ) + + def _sort_addresses(self): + self.addresses.sort(key=itemgetter(InterfaceIP.ADDRESS_IP)) +diff --git a/libnmstate/iplib.py b/libnmstate/iplib.py +index 57fffd7..183b81b 100644 +--- a/libnmstate/iplib.py ++++ b/libnmstate/iplib.py +@@ -52,3 +52,17 @@ def ip_address_full_to_tuple(addr): + raise NmstateValueError(f"Invalid IP address, error: {err}") + + return f"{net.network_address}", net.prefixlen ++ ++ ++def canonicalize_ip_network(address): ++ try: ++ return ipaddress.ip_network(address, strict=False).with_prefixlen ++ except ValueError as e: ++ raise NmstateValueError(f"Invalid IP network address: {e}") ++ ++ ++def canonicalize_ip_address(address): ++ try: ++ return ipaddress.ip_address(address).compressed ++ except ValueError as e: ++ raise NmstateValueError(f"Invalid IP address: {e}") +diff --git a/libnmstate/route.py b/libnmstate/route.py +index 6534182..a182f99 100644 +--- a/libnmstate/route.py ++++ b/libnmstate/route.py +@@ -22,6 +22,8 @@ from collections import defaultdict + from libnmstate.error import NmstateValueError + from libnmstate.error import NmstateVerificationError + from libnmstate.iplib import is_ipv6_address ++from libnmstate.iplib import canonicalize_ip_network ++from libnmstate.iplib import canonicalize_ip_address + from libnmstate.prettystate import format_desired_current_state_diff + from libnmstate.schema import Interface + from libnmstate.schema import Route +@@ -44,6 +46,7 @@ class RouteEntry(StateEntry): + # TODO: Convert IPv6 full address to abbreviated address + self.complement_defaults() + self._invalid_reason = None ++ self._canonicalize_ip_address() + + @property + def is_ipv6(self): +@@ -148,6 +151,15 @@ class RouteEntry(StateEntry): + return False + return True + ++ def _canonicalize_ip_address(self): ++ if not self.absent: ++ if self.destination: ++ self.destination = canonicalize_ip_network(self.destination) ++ if self.next_hop_address: ++ self.next_hop_address = canonicalize_ip_address( ++ self.next_hop_address ++ ) ++ + + class RouteState: + def __init__(self, ifaces, des_route_state, cur_route_state): +diff --git a/libnmstate/route_rule.py b/libnmstate/route_rule.py +index 8b45367..f35d59c 100644 +--- a/libnmstate/route_rule.py ++++ b/libnmstate/route_rule.py +@@ -6,7 +6,7 @@ from libnmstate.error import NmstateVerificationError + from libnmstate.error import NmstateValueError + from libnmstate.iplib import KERNEL_MAIN_ROUTE_TABLE_ID + from libnmstate.iplib import is_ipv6_address +-from libnmstate.iplib import to_ip_address_full ++from libnmstate.iplib import canonicalize_ip_network + from libnmstate.prettystate import format_desired_current_state_diff + from libnmstate.schema import Interface + from libnmstate.schema import RouteRule +@@ -23,7 +23,7 @@ class RouteRuleEntry(StateEntry): + self.priority = route_rule.get(RouteRule.PRIORITY) + self.route_table = route_rule.get(RouteRule.ROUTE_TABLE) + self._complement_defaults() +- self._append_prefix_length_for_host_only_ip() ++ self._canonicalize_ip_network() + + def _complement_defaults(self): + if self.ip_from is None: +@@ -38,11 +38,11 @@ class RouteRuleEntry(StateEntry): + ): + self.route_table = KERNEL_MAIN_ROUTE_TABLE_ID + +- def _append_prefix_length_for_host_only_ip(self): +- if self.ip_from and "/" not in self.ip_from: +- self.ip_from = to_ip_address_full(self.ip_from) +- if self.ip_to and "/" not in self.ip_to: +- self.ip_to = to_ip_address_full(self.ip_to) ++ def _canonicalize_ip_network(self): ++ if self.ip_from: ++ self.ip_from = canonicalize_ip_network(self.ip_from) ++ if self.ip_to: ++ self.ip_to = canonicalize_ip_network(self.ip_to) + + def _keys(self): + return (self.ip_from, self.ip_to, self.priority, self.route_table) +-- +2.27.0 + diff --git a/SOURCES/BZ_1820009_only_reapply_if_activated.patch b/SOURCES/BZ_1820009_only_reapply_if_activated.patch new file mode 100644 index 0000000..64fa364 --- /dev/null +++ b/SOURCES/BZ_1820009_only_reapply_if_activated.patch @@ -0,0 +1,63 @@ +From 26ca4e3a1a96829ca115f436872d4a575490cce6 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 24 Jun 2020 15:27:42 +0800 +Subject: [PATCH] nm/device: Only invoke reapply on activated device + +Only invoke `NM.Device.reapply_async()` on activated device. + +Signed-off-by: Gris Ge +--- + libnmstate/nm/device.py | 32 ++++++++++++++++++-------------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/libnmstate/nm/device.py b/libnmstate/nm/device.py +index 92447b0..528f57d 100644 +--- a/libnmstate/nm/device.py ++++ b/libnmstate/nm/device.py +@@ -53,25 +53,29 @@ def delete(context, dev): + con_profile.delete() + + +-def modify(context, dev, connection_profile): ++def modify(context, nm_dev, connection_profile): + """ + Modify the given connection profile on the device. + Implemented by the reapply operation with a fallback to the + connection profile activation. + """ +- version_id = 0 +- flags = 0 +- action = f"Reapply device config: {dev.get_iface()}" +- context.register_async(action) +- user_data = context, dev, action +- dev.reapply_async( +- connection_profile, +- version_id, +- flags, +- context.cancellable, +- _modify_callback, +- user_data, +- ) ++ nm_ac = nm_dev.get_active_connection() ++ if connection.is_activated(nm_ac, nm_dev): ++ version_id = 0 ++ flags = 0 ++ action = f"Reapply device config: {nm_dev.get_iface()}" ++ context.register_async(action) ++ user_data = context, nm_dev, action ++ nm_dev.reapply_async( ++ connection_profile, ++ version_id, ++ flags, ++ context.cancellable, ++ _modify_callback, ++ user_data, ++ ) ++ else: ++ _activate_async(context, nm_dev) + + + def _modify_callback(src_object, result, user_data): +-- +2.27.0 + diff --git a/SOURCES/BZ_1820009_remove_duplicate_call_of_is_ovs_running.patch b/SOURCES/BZ_1820009_remove_duplicate_call_of_is_ovs_running.patch new file mode 100644 index 0000000..b06dcb8 --- /dev/null +++ b/SOURCES/BZ_1820009_remove_duplicate_call_of_is_ovs_running.patch @@ -0,0 +1,68 @@ +From 69bed0e79bd951b4e5496cae6b3738649030b5ae Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 23 Jun 2020 20:28:30 +0800 +Subject: [PATCH] ovs: Eliminate the repeat call of is_ovs_running() + +The `validate_interface_capabilities()` is invoking `is_ovs_running()` +on every interface. Fixed by using `set()` for interface types for +duplicate types and also caching ovs daemon status. + +The `NetworkManagerPlugin.get_interfaces()` is invoking +`is_ovs_running()` on every interface. Fixed by caching ovs daemon +status. + +Signed-off-by: Gris Ge +--- + libnmstate/nm/plugin.py | 3 ++- + libnmstate/validator.py | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/libnmstate/nm/plugin.py b/libnmstate/nm/plugin.py +index 20fa77e..4032359 100644 +--- a/libnmstate/nm/plugin.py ++++ b/libnmstate/nm/plugin.py +@@ -97,6 +97,7 @@ class NetworkManagerPlugin(NmstatePlugin): + + def get_interfaces(self): + info = [] ++ capabilities = self.capabilities + + devices_info = [ + (dev, nm_device.get_device_common_info(dev)) +@@ -122,7 +123,7 @@ 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 NmstatePlugin.OVS_CAPABILITY in self.capabilities: ++ 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 +diff --git a/libnmstate/validator.py b/libnmstate/validator.py +index ee30166..02890b4 100644 +--- a/libnmstate/validator.py ++++ b/libnmstate/validator.py +@@ -47,9 +47,10 @@ def validate_capabilities(state, capabilities): + + + def validate_interface_capabilities(ifaces_state, capabilities): +- ifaces_types = [iface_state.get("type") for iface_state in ifaces_state] ++ ifaces_types = {iface_state.get("type") for iface_state in ifaces_state} + has_ovs_capability = NmstatePlugin.OVS_CAPABILITY in capabilities + has_team_capability = NmstatePlugin.TEAM_CAPABILITY in capabilities ++ ovs_is_running = is_ovs_running() + for iface_type in ifaces_types: + is_ovs_type = iface_type in ( + InterfaceType.OVS_BRIDGE, +@@ -57,7 +58,7 @@ def validate_interface_capabilities(ifaces_state, capabilities): + InterfaceType.OVS_PORT, + ) + if is_ovs_type and not has_ovs_capability: +- if not is_ovs_running(): ++ if not ovs_is_running: + raise NmstateDependencyError( + "openvswitch service is not started." + ) +-- +2.27.0 + diff --git a/SOURCES/BZ_1850698-Fix-remove-dns-config.patch b/SOURCES/BZ_1850698-Fix-remove-dns-config.patch new file mode 100644 index 0000000..0d6787d --- /dev/null +++ b/SOURCES/BZ_1850698-Fix-remove-dns-config.patch @@ -0,0 +1,60 @@ +From 54e49943b636eab9453189381e93c68050c1e423 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Sun, 28 Jun 2020 20:05:08 +0800 +Subject: [PATCH] dns: Fix remove dns config + +Current code raise NmstateVerificationError when user not providing +the full state: + DNS.CONFIG: {DNS.SERVER: [], DNS.SEARCH: []} + +Now supporting remove static DNS config via: + * DNS.CONFIG: {} + * DNS.CONFIG: {DNS.SERVER: []} + * DNS.CONFIG: {DNS.SEARCH: []} + * DNS.CONFIG: {DNS.SERVER: [], DNS.SEARCH: []} + +Test case updated for this. + +Signed-off-by: Gris Ge +--- + libnmstate/dns.py | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/libnmstate/dns.py b/libnmstate/dns.py +index 3196fc4..1ec0d81 100644 +--- a/libnmstate/dns.py ++++ b/libnmstate/dns.py +@@ -33,14 +33,16 @@ class DnsState: + + def __init__(self, des_dns_state, cur_dns_state): + self._config_changed = False +- if des_dns_state: ++ if des_dns_state is None or des_dns_state.get(DNS.CONFIG) is None: ++ # Use current config if DNS.KEY not defined or DNS.CONFIG not ++ # defined. ++ self._dns_state = cur_dns_state or {} ++ else: + self._dns_state = des_dns_state + self._validate() + self._config_changed = _is_dns_config_changed( + des_dns_state, cur_dns_state + ) +- else: +- self._dns_state = cur_dns_state or {} + self._cur_dns_state = deepcopy(cur_dns_state) if cur_dns_state else {} + + @property +@@ -179,7 +181,9 @@ class DnsState: + + def verify(self, cur_dns_state): + cur_dns = DnsState(des_dns_state=None, cur_dns_state=cur_dns_state,) +- if self.config != cur_dns.config: ++ if self.config.get(DNS.SERVER) != cur_dns.config.get( ++ DNS.SERVER ++ ) or self.config.get(DNS.SEARCH) != cur_dns.config.get(DNS.SEARCH): + raise NmstateVerificationError( + format_desired_current_state_diff( + {DNS.KEY: self.config}, {DNS.KEY: cur_dns.config}, +-- +2.27.0 + diff --git a/SOURCES/nmstate-0.2.0.tar.gz.asc b/SOURCES/nmstate-0.2.0.tar.gz.asc deleted file mode 100644 index 5a24ce4..0000000 --- a/SOURCES/nmstate-0.2.0.tar.gz.asc +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.22 (GNU/Linux) - -iQIcBAABAgAGBQJd5R19AAoJEImQFMBGPBK7Q3QP/j0+keNS1M7i0LeCjv4r0/rU -3eqfGBwEUH8s8Jb8mSOyveWOZeVrNg8GXO8kv36DLWUBoCJ1r0iYtG+u5IuusUjp -AXuIS86jmIT1s3kuSXnOhybeD5ZQm8WS5mG/Kmd/I1m24oo+KDrQgkBfiXnqTNIm -OYPfI5hACK9b3AxAVATJHjDvF87YAKKa9xgpFPvUhJE0hjoJ4nx2aI9x09kWsxdT -aT5Mjc/3gu+ARabJdE0p2amNQW+lCs3O8TKU8ZOjYrBKV3VMD/V+rqLzqR3QvBcj -67VNHl5bq01r0PoN9U2MW/2g3sKpbGhtHEwwDxuzymxk/Z7Wyzjk8+9c3sFxL/VU -t/iezDgkT23IwU2clzP8V3Rjc2GKd+rq7M8G86mxV9ausaj8SZWfuUpnFkjStm8V -d2LNfuKiquR+0qhcSoFdeyKhIISlhNMymzkyBDucC3LRXKt7kfhXCwRx7RYDfVbZ -q/Yw+xzLtGmNjOz/hK+5V3wxonwZRob0JLOoRfsqi0BaXVq/Q/AcFIah9oZghBxT -AtDBLor9qM572PLSV7W8rPJ7fGlsFETIvF4erqC5yxzjZ4dgX/3zr3Zpwr/xE/RV -wDeiRjkkWo8i1lCQtS3Cd8yY4WZ/iI7egEMyLojWgrirz1uMNBZFtntwe+IoG9VH -2WTL8od4f/gk7xKPbCIY -=69KO ------END PGP SIGNATURE----- diff --git a/SOURCES/nmstate-0.3.2.tar.gz.asc b/SOURCES/nmstate-0.3.2.tar.gz.asc new file mode 100644 index 0000000..847ad25 --- /dev/null +++ b/SOURCES/nmstate-0.3.2.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEE8f1XsqXpyNthgIbGbM3lj+QeKP8FAl7nxvAACgkQbM3lj+Qe +KP/6yw/9GBET+XD86qCuzu9sxZt2vZTw3CIqvieuCPkzquqymoI2owJ2rCrNpnZy +jdhrobV992pt4qpHo12k8o8LubO38rzVkG6lXSJ8rlLrRkJc5c3APJPzeEnuWsrB +HL0JZ4Z2MA+q4TdLGPDNrN/XpnOEDphRZcuD6sFIa9nmiCbj6aI2BaQRriwr8bbh +W0LBzQ71u5tIXLVKo+Z3XYmQwFcjW8jQkxrfQbTYT80JORc2aC+yBdfayw+5GSsm +Us41H8cStfayv4m5t3Cvy8DMoxe1YC/GBY16sPDdmX+qTS43de8vtCgBho3KZrXx +cHi2V2/vlxo2Zra2a8wpwDFOU0nPbgRR+79R7w5/2f9U6g0sok3Qa4WLYjYE1tbK +l2gw/hdzHRLzq7UuVN8nchNDGmqQErtLJALvf7kWucVgN/u9VqrteEh6ZL7/eZ9G +AE3Dot2I+TWBgQ7D1feD9TGj7riY2/m3hNMMG5KeiyifHWDIo3tVqwO4WgaBU25h +L2AAQKtS0aBMp034cN1nFUxRAw0cFZPQmE52kSNaIbzQpy+3jR6o43IvLuTOVA4j +2FlGr9wGLk/Rom/mt2gGY6agiTnfkIV32Muesqwr0zr55ktbQ64xcIlXlXVpIL4j +ysbj8f2dBBR/4J/UrNTtzjEofTsDyO4+2NdXS3HuWTw3X74UFyY= +=EP3F +-----END PGP SIGNATURE----- diff --git a/SPECS/nmstate.spec b/SPECS/nmstate.spec index d2a65f7..e123eea 100644 --- a/SPECS/nmstate.spec +++ b/SPECS/nmstate.spec @@ -3,14 +3,20 @@ %define libname libnmstate Name: nmstate -Version: 0.2.0 -Release: 2%{?dist} +Version: 0.3.2 +Release: 6%{?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: gpgkey-F7910D93CA83D77348595C0E899014C0463C12BB.gpg +Source2: https://www.nmstate.io/nmstate.gpg +Patch1: BZ_1850698-Fix-remove-dns-config.patch +Patch2: BZ_1788763_improve_vlan_mtu_error_message.patch +Patch3: BZ_1816612_canonicalize-IP-address.patch +Patch4: BZ_1806474-sort-pretty-state-with-priority.patch +Patch5: BZ_1820009_remove_duplicate_call_of_is_ovs_running.patch +Patch6: BZ_1820009_only_reapply_if_activated.patch BuildArch: noarch BuildRequires: python3-devel BuildRequires: python3-setuptools @@ -27,21 +33,33 @@ provider support on the southbound. %package -n python3-%{libname} Summary: nmstate Python 3 API library -Requires: NetworkManager-libnm +Requires: NetworkManager-libnm >= 1:1.22.16 # 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 since it is only required for OVS support +# 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 -gpgv2 --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} +gpg2 --import --import-options import-export,import-minimal %{SOURCE2} > ./gpgkey-mantainers.gpg +gpgv2 --keyring ./gpgkey-mantainers.gpg %{SOURCE1} %{SOURCE0} %autosetup -p1 %build @@ -61,8 +79,83 @@ gpgv2 --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} %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 +* Mon Jun 29 2020 Gris Ge - 0.3.2-6 +- Improve performance by remove unneeded calls. RHBZ#1820009 + +* Mon Jun 29 2020 Gris Ge - 0.3.2-5 +- Sort the pretty state with priority. RHBZ#1806474 + +* Mon Jun 29 2020 Gris Ge - 0.3.2-4 +- Canonicalize IP address. RHBZ#1816612 + +* Mon Jun 29 2020 Gris Ge - 0.3.2-3 +- Improve VLAN MTU error message. RHBZ#1788763 + +* Mon Jun 29 2020 Gris Ge - 0.3.2-2 +- Fix bug 1850698 + +* Mon Jun 15 2020 Fernando Fernandez Mancera - 0.3.2-1 +- Upgrade to 0.3.2 +- Sync. up with upstream spec file + +* Thu Jun 11 2020 Gris Ge - 0.3.1-1 +- Upgrade to 0.3.1 + +* Wed May 13 2020 Fernando Fernandez Mancera - 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 - 0.2.9-1 +- Upgrade to 0.2.9 + +* Wed Mar 25 2020 Gris Ge - 0.2.6-6 +- Support 3+ DNS name server(IPv4 only or IPv6 only). RHBZ #1816043 + +* Fri Mar 20 2020 Gris Ge - 0.2.6-5 +- Support static DNS with DHCP. RHBZ #1815112 + +* Thu Mar 12 2020 Fernando Fernandez Mancera - 0.2.6-4.8 +- Fix bond mac and options regression. RHBZ #1809330 + +* Mon Mar 09 2020 Gris Ge - 0.2.6-3.8 +- Fix change bond mode. RHBZ #1809330 + +* Mon Mar 02 2020 Fernando Fernandez Mancera - 0.2.6-2.7 +- Fix cmd stuck when trying to create ovs-bond. RHBZ #1806249. + +* Tue Feb 25 2020 Gris Ge - 0.2.6-1 +- Upgrade to 0.2.6 + +* Thu Feb 20 2020 Gris Ge - 0.2.5-1 +- Upgrade to 0.2.5 + +* Thu Feb 13 2020 Gris Ge - 0.2.4-2 +- Fix failure when editing existing OVS interface. RHBZ #1786935 + +* Thu Feb 13 2020 Gris Ge - 0.2.4-1 +- Upgrade to 0.2.4 + +* Wed Feb 05 2020 Fernando Fernandez Mancera - 0.2.3-1 +- Upgrade to 0.2.3 + +* Tue Feb 04 2020 Fernando Fernandez Mancera - 0.2.2-3 +- Fix the incorrect source + +* Tue Feb 04 2020 Fernando Fernandez Mancera - 0.2.2-2 +- Upgrade to 0.2.2 + +* Wed Jan 22 2020 Gris Ge - 0.2.0-3.1 +- Fix the memeory leak of NM.Client. RHBZ #1784707 + * Mon Dec 02 2019 Gris Ge - 0.2.0-2 - Fix the incorrect source tarbal.