From faaad2e029fd3520b62983dd78c7692434138360 Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Wed, 22 Jul 2020 23:36:44 +0100 Subject: xml: T2582: use xml for is_tag and is_leaf --- python/vyos/xml/__init__.py | 15 +++++++++++++++ python/vyos/xml/definition.py | 23 +++++++++++++++++++---- python/vyos/xml/test_xml.py | 2 +- 3 files changed, 35 insertions(+), 5 deletions(-) (limited to 'python/vyos/xml') diff --git a/python/vyos/xml/__init__.py b/python/vyos/xml/__init__.py index 6e0e73b1b..0f914fed2 100644 --- a/python/vyos/xml/__init__.py +++ b/python/vyos/xml/__init__.py @@ -35,6 +35,18 @@ def load_configuration(cache=[]): return xml +# def is_multi(lpath): +# return load_configuration().is_multi(lpath) + + +def is_tag(lpath): + return load_configuration().is_tag(lpath) + + +def is_leaf(lpath, flat=True): + return load_configuration().is_leaf(lpath, flat) + + def defaults(lpath, flat=False): return load_configuration().defaults(lpath, flat) @@ -42,3 +54,6 @@ def defaults(lpath, flat=False): if __name__ == '__main__': print(defaults(['service'], flat=True)) print(defaults(['service'], flat=False)) + + print(is_tag(["system", "login", "user", "vyos", "authentication", "public-keys"])) + print(is_tag(['protocols', 'static', 'multicast', 'route', '0.0.0.0/0', 'next-hop'])) diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py index b0339b228..098e64f7e 100644 --- a/python/vyos/xml/definition.py +++ b/python/vyos/xml/definition.py @@ -126,10 +126,12 @@ class XML(dict): elif word: if data_node != kw.plainNode or len(passed) == 1: self.options = [_ for _ in self.tree if _.startswith(word)] + self.options.sort() else: self.options = [] else: self.options = named_options + self.options.sort() self.plain = not is_dataNode @@ -143,6 +145,7 @@ class XML(dict): self.word = '' if self.tree.get(kw.node,'') not in (kw.tagNode, kw.leafNode): self.options = [_ for _ in self.tree if not kw.found(_)] + self.options.sort() def checks(self, cmd): # as we move thought the named node twice @@ -300,16 +303,28 @@ class XML(dict): return tree def _get(self, lpath, tag, with_tag=True): - return self._tree(lpath + [tag], with_tag) + tree = self._tree(lpath, with_tag) + if tree is None: + return None + return tree.get(tag, None) def is_multi(self, lpath, with_tag=True): - return self._get(lpath, kw.multi, with_tag) is True + tree = self._get(lpath, kw.multi, with_tag) + if tree is None: + return None + return tree is True def is_tag(self, lpath, with_tag=True): - return self._get(lpath, kw.node, with_tag) == kw.tagNode + tree = self._get(lpath, kw.node, with_tag) + if tree is None: + return None + return tree == kw.tagNode def is_leaf(self, lpath, with_tag=True): - return self._get(lpath, kw.node, with_tag) == kw.leafNode + tree = self._get(lpath, kw.node, with_tag) + if tree is None: + return None + return tree == kw.leafNode def exists(self, lpath, with_tag=True): return self._get(lpath, kw.node, with_tag) is not None diff --git a/python/vyos/xml/test_xml.py b/python/vyos/xml/test_xml.py index ac0620d99..ff55151d2 100644 --- a/python/vyos/xml/test_xml.py +++ b/python/vyos/xml/test_xml.py @@ -33,7 +33,7 @@ class TestSearch(TestCase): last = self.xml.traverse("") self.assertEqual(last, '') self.assertEqual(self.xml.inside, []) - self.assertEqual(self.xml.options, ['protocols', 'service', 'system', 'firewall', 'interfaces', 'vpn', 'nat', 'vrf', 'high-availability']) + self.assertEqual(self.xml.options, ['firewall', 'high-availability', 'interfaces', 'nat', 'protocols', 'service', 'system', 'vpn', 'vrf']) self.assertEqual(self.xml.filling, False) self.assertEqual(self.xml.word, last) self.assertEqual(self.xml.check, False) -- cgit v1.2.3 From b40c52682a25664f7018ab8b4e5ba6f467f10d17 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Sun, 30 Aug 2020 08:22:32 -0500 Subject: config: T2636: get_config_dict() returns a list on multi node by default Unless no_multi_convert is True, a single valued multi node will be returned as a list by get_config_dict(). Modification of Thomas Mangin's version. --- python/vyos/config.py | 61 ++++++++++++++++++++++++++----------------- python/vyos/configdiff.py | 4 +-- python/vyos/xml/__init__.py | 4 +++ python/vyos/xml/definition.py | 17 ++++++++++++ 4 files changed, 60 insertions(+), 26 deletions(-) (limited to 'python/vyos/xml') diff --git a/python/vyos/config.py b/python/vyos/config.py index 884d6d947..de79a3654 100644 --- a/python/vyos/config.py +++ b/python/vyos/config.py @@ -67,6 +67,7 @@ import re import json from copy import deepcopy +import vyos.xml import vyos.util import vyos.configtree from vyos.configsource import ConfigSource, ConfigSourceSession @@ -193,50 +194,62 @@ class Config(object): """ return self._config_source.show_config(path, default, effective) - def get_cached_dict(self, effective=False): + def get_cached_root_dict(self, effective=False): cached = self._dict_cache.get(effective, {}) if cached: - config_dict = cached + return cached + + if effective: + config = self._running_config else: - config_dict = {} + config = self._session_config - if effective: - if self._running_config: - config_dict = json.loads((self._running_config).to_json()) - else: - if self._session_config: - config_dict = json.loads((self._session_config).to_json()) + if config: + config_dict = json.loads(config.to_json()) + else: + config_dict = {} - self._dict_cache[effective] = config_dict + self._dict_cache[effective] = config_dict return config_dict - def get_config_dict(self, path=[], effective=False, key_mangling=None, get_first_key=False): + def get_config_dict(self, path=[], effective=False, key_mangling=None, + get_first_key=False, no_multi_convert=False): """ Args: path (str list): Configuration tree path, can be empty effective=False: effective or session config key_mangling=None: mangle dict keys according to regex and replacement get_first_key=False: if k = path[:-1], return sub-dict d[k] instead of {k: d[k]} + no_multi_convert=False: if convert, return single value of multi node as list Returns: a dict representation of the config under path """ - config_dict = self.get_cached_dict(effective) + lpath = self._make_path(path) + root_dict = self.get_cached_root_dict(effective) + conf_dict = vyos.util.get_sub_dict(root_dict, lpath, get_first_key) - config_dict = vyos.util.get_sub_dict(config_dict, self._make_path(path), get_first_key) + if not key_mangling and no_multi_convert: + return deepcopy(conf_dict) - if key_mangling: - if not (isinstance(key_mangling, tuple) and \ - (len(key_mangling) == 2) and \ - isinstance(key_mangling[0], str) and \ - isinstance(key_mangling[1], str)): - raise ValueError("key_mangling must be a tuple of two strings") - else: - config_dict = vyos.util.mangle_dict_keys(config_dict, key_mangling[0], key_mangling[1]) - else: - config_dict = deepcopy(config_dict) + xmlpath = lpath if get_first_key else lpath[:-1] - return config_dict + if not key_mangling: + conf_dict = vyos.xml.multi_to_list(xmlpath, conf_dict) + return conf_dict + + if no_multi_convert is False: + conf_dict = vyos.xml.multi_to_list(xmlpath, conf_dict) + + if not (isinstance(key_mangling, tuple) and \ + (len(key_mangling) == 2) and \ + isinstance(key_mangling[0], str) and \ + isinstance(key_mangling[1], str)): + raise ValueError("key_mangling must be a tuple of two strings") + + conf_dict = vyos.util.mangle_dict_keys(conf_dict, key_mangling[0], key_mangling[1]) + + return conf_dict def is_multi(self, path): """ diff --git a/python/vyos/configdiff.py b/python/vyos/configdiff.py index b79893507..0e41fbe27 100644 --- a/python/vyos/configdiff.py +++ b/python/vyos/configdiff.py @@ -82,8 +82,8 @@ class ConfigDiff(object): """ def __init__(self, config, key_mangling=None): self._level = config.get_level() - self._session_config_dict = config.get_cached_dict() - self._effective_config_dict = config.get_cached_dict(effective=True) + self._session_config_dict = config.get_cached_root_dict(effective=False) + self._effective_config_dict = config.get_cached_root_dict(effective=True) self._key_mangling = key_mangling # mirrored from Config; allow path arguments relative to level diff --git a/python/vyos/xml/__init__.py b/python/vyos/xml/__init__.py index 0f914fed2..0ef0c85ce 100644 --- a/python/vyos/xml/__init__.py +++ b/python/vyos/xml/__init__.py @@ -51,6 +51,10 @@ def defaults(lpath, flat=False): return load_configuration().defaults(lpath, flat) +def multi_to_list(lpath, conf): + return load_configuration().multi_to_list(lpath, conf) + + if __name__ == '__main__': print(defaults(['service'], flat=True)) print(defaults(['service'], flat=False)) diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py index 098e64f7e..6d6fcb5c7 100644 --- a/python/vyos/xml/definition.py +++ b/python/vyos/xml/definition.py @@ -281,6 +281,23 @@ class XML(dict): return _flatten(lpath, len(lpath), d) + def multi_to_list(self, lpath, conf): + r = {} + for k in conf: + # key mangling could also be done here + # it would prevent two parsing of the config tree + # under = k.replace('-','_') + under = k + fpath = lpath + [k] + if isinstance(conf[k],dict): + r[under] = self.multi_to_list(fpath, conf[k]) + continue + value = conf[k] + if self.is_multi(fpath) and not isinstance(value, list): + value = [value] + r[under] = value + return r + # from functools import lru_cache # @lru_cache(maxsize=100) # XXX: need to use cachetool instead - for later -- cgit v1.2.3 From 0ddca9de00b7ae3969f718c2cd2f081506d5c222 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Tue, 1 Sep 2020 11:41:17 -0500 Subject: xml: T2849: vyos.xml.defaults should return a list on multi nodes --- python/vyos/xml/definition.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'python/vyos/xml') diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py index 6d6fcb5c7..a25fc50c5 100644 --- a/python/vyos/xml/definition.py +++ b/python/vyos/xml/definition.py @@ -254,6 +254,9 @@ class XML(dict): d = d.get(k, {}) if not flat: + # _flatten will make this conversion + d = self.multi_to_list(lpath, d) + r = {} for k in d: under = k.replace('-','_') -- cgit v1.2.3