summaryrefslogtreecommitdiff
path: root/python/vyos
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos')
-rw-r--r--python/vyos/config.py57
-rw-r--r--python/vyos/configdict.py13
-rw-r--r--python/vyos/ifconfig/__init__.py1
-rw-r--r--python/vyos/ifconfig/section.py33
-rw-r--r--python/vyos/util.py25
5 files changed, 114 insertions, 15 deletions
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 """