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