diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/setup.py | 2 | ||||
-rw-r--r-- | python/vyos/config.py | 57 | ||||
-rw-r--r-- | python/vyos/configdict.py | 13 | ||||
-rw-r--r-- | python/vyos/ifconfig/__init__.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/section.py | 33 | ||||
-rw-r--r-- | python/vyos/util.py | 25 |
6 files changed, 115 insertions, 16 deletions
diff --git a/python/setup.py b/python/setup.py index ac7d0b573..9440e7fe7 100644 --- a/python/setup.py +++ b/python/setup.py @@ -3,7 +3,7 @@ from setuptools import setup setup( name = "vyos", - version = "1.2.0", + version = "1.3.0", author = "VyOS maintainers and contributors", author_email = "maintainers@vyos.net", description = ("VyOS configuration libraries."), diff --git a/python/vyos/config.py b/python/vyos/config.py index 54cb518c3..56353c322 100644 --- a/python/vyos/config.py +++ b/python/vyos/config.py @@ -68,6 +68,7 @@ import re import json import subprocess +import vyos.util import vyos.configtree @@ -100,23 +101,33 @@ class Config(object): # once the config system is initialized during boot; # before initialization, set to empty string if os.path.isfile('/tmp/vyos-config-status'): - running_config_text = self._run([self._cli_shell_api, '--show-active-only', '--show-show-defaults', '--show-ignore-edit', 'showConfig']) + try: + running_config_text = self._run([self._cli_shell_api, '--show-active-only', '--show-show-defaults', '--show-ignore-edit', 'showConfig']) + except VyOSError: + running_config_text = '' else: running_config_text = '' # Session config ("active") only exists in conf mode. # In op mode, we'll just use the same running config for both active and session configs. if self.in_session(): - session_config_text = self._run([self._cli_shell_api, '--show-working-only', '--show-show-defaults', '--show-ignore-edit', 'showConfig']) + try: + session_config_text = self._run([self._cli_shell_api, '--show-working-only', '--show-show-defaults', '--show-ignore-edit', 'showConfig']) + except VyOSError: + session_config_text = '' else: session_config_text = running_config_text - self._session_config = vyos.configtree.ConfigTree(session_config_text) if running_config_text: self._running_config = vyos.configtree.ConfigTree(running_config_text) else: self._running_config = None + if session_config_text: + self._session_config = vyos.configtree.ConfigTree(session_config_text) + else: + self._session_config = None + def _make_command(self, op, path): args = path.split() cmd = [self._cli_shell_api, op] + args @@ -193,6 +204,8 @@ class Config(object): This function cannot be used outside a configuration sessions. In operational mode scripts, use ``exists_effective``. """ + if not self._session_config: + return False if self._session_config.exists(self._make_path(path)): return True else: @@ -275,7 +288,7 @@ class Config(object): self.__session_env = save_env return(default) - def get_config_dict(self, path=[], effective=False): + def get_config_dict(self, path=[], effective=False, key_mangling=None): """ Args: path (str list): Configuration tree path, can be empty Returns: a dict representation of the config @@ -287,6 +300,15 @@ class Config(object): else: config_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]) + return config_dict def is_multi(self, path): @@ -362,9 +384,12 @@ class Config(object): This function cannot be used outside a configuration session. In operational mode scripts, use ``return_effective_value``. """ - try: - value = self._session_config.return_value(self._make_path(path)) - except vyos.configtree.ConfigTreeError: + if self._session_config: + try: + value = self._session_config.return_value(self._make_path(path)) + except vyos.configtree.ConfigTreeError: + value = None + else: value = None if not value: @@ -387,9 +412,12 @@ class Config(object): This function cannot be used outside a configuration session. In operational mode scripts, use ``return_effective_values``. """ - try: - values = self._session_config.return_values(self._make_path(path)) - except vyos.configtree.ConfigTreeError: + if self._session_config: + try: + values = self._session_config.return_values(self._make_path(path)) + except vyos.configtree.ConfigTreeError: + values = [] + else: values = [] if not values: @@ -408,9 +436,12 @@ class Config(object): string list: child node names """ - try: - nodes = self._session_config.list_nodes(self._make_path(path)) - except vyos.configtree.ConfigTreeError: + if self._session_config: + try: + nodes = self._session_config.list_nodes(self._make_path(path)) + except vyos.configtree.ConfigTreeError: + nodes = [] + else: nodes = [] if not nodes: diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 4708d3b50..973fbdd8b 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -87,6 +87,19 @@ def retrieve_config(path_hash, base_path, config): return config_hash +def dict_merge(source, destination): + """ Merge two dictionaries. Only keys which are not present in destination + will be copied from source, anything else will be kept untouched. Function + will return a new dict which has the merged key/value pairs. """ + from copy import deepcopy + tmp = deepcopy(destination) + + for key, value in source.items(): + if key not in tmp.keys(): + tmp[key] = value + + return tmp + def list_diff(first, second): """ Diff two dictionaries and return only unique items diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index 1757adf26..a7cdeadd1 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -31,6 +31,7 @@ from vyos.ifconfig.macvlan import MACVLANIf from vyos.ifconfig.vxlan import VXLANIf from vyos.ifconfig.wireguard import WireGuardIf from vyos.ifconfig.vtun import VTunIf +from vyos.ifconfig.vti import VTIIf from vyos.ifconfig.pppoe import PPPoEIf from vyos.ifconfig.tunnel import GREIf from vyos.ifconfig.tunnel import GRETapIf diff --git a/python/vyos/ifconfig/section.py b/python/vyos/ifconfig/section.py index 926c22e8a..173a90bb4 100644 --- a/python/vyos/ifconfig/section.py +++ b/python/vyos/ifconfig/section.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see <http://www.gnu.org/licenses/>. +import re import netifaces @@ -103,12 +104,42 @@ class Section: yield ifname @classmethod + def _sort_interfaces(cls, generator): + """ + return a list of the sorted interface by number, vlan, qinq + """ + def key(ifname): + value = 0 + parts = re.split(r'([^0-9]+)([0-9]+)[.]?([0-9]+)?[.]?([0-9]+)?', ifname) + length = len(parts) + name = parts[1] if length >= 3 else parts[0] + # the +1 makes sure eth0.0.0 after eth0.0 + number = int(parts[2]) + 1 if length >= 4 and parts[2] is not None else 0 + vlan = int(parts[3]) + 1 if length >= 5 and parts[3] is not None else 0 + qinq = int(parts[4]) + 1 if length >= 6 and parts[4] is not None else 0 + + # so that "lo" (or short names) are handled (as "loa") + for n in (name + 'aaa')[:3]: + value *= 100 + value += (ord(n) - ord('a')) + value += number + # vlan are 16 bits, so this can not overflow + value = (value << 16) + vlan + value = (value << 16) + qinq + return value + + l = list(generator) + l.sort(key=key) + return l + + @classmethod def interfaces(cls, section=''): """ return a list of the name of the configured interface which are under a section if no section is provided, then it returns all configured interfaces """ - return list(cls._intf_under_section(section)) + + return cls._sort_interfaces(cls._intf_under_section(section)) @classmethod def _intf_with_feature(cls, feature=''): diff --git a/python/vyos/util.py b/python/vyos/util.py index c93f8d3f0..0ddc14963 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -1,4 +1,4 @@ -# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -14,6 +14,7 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. import os +import re import sys # @@ -340,6 +341,28 @@ def colon_separated_to_dict(data_string, uniquekeys=False): return data +def mangle_dict_keys(data, regex, replacement): + """ Mangles dict keys according to a regex and replacement character. + Some libraries like Jinja2 do not like certain characters in dict keys. + This function can be used for replacing all offending characters + with something acceptable. + + Args: + data (dict): Original dict to mangle + + Returns: dict + """ + new_dict = {} + for key in data.keys(): + new_key = re.sub(regex, replacement, key) + + value = data[key] + if isinstance(value, dict): + new_dict[new_key] = mangle_dict_keys(value, regex, replacement) + else: + new_dict[new_key] = value + + return new_dict def process_running(pid_file): """ Checks if a process with PID in pid_file is running """ |