Page MenuHomeVyOS Platform

configtree.py
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

configtree.py

# configtree -- a standalone VyOS config file manipulation library (Python bindings)
# Copyright (C) 2018 VyOS maintainers and contributors
#
# This library is free software; you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software Foundation;
# either version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with this library;
# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import re
import json
from ctypes import cdll, c_char_p, c_void_p, c_int
def escape_backslash(string: str) -> str:
"""Escape single backslashes in string that are not in escape sequence"""
p = re.compile(r'(?<!\\)[\\](?!b|f|n|r|t|\\[^bfnrt])')
result = p.sub(r'\\\\', string)
return result
def extract_version(s):
""" Extract the version string from the config string """
t = re.split('(^//)', s, maxsplit=1, flags=re.MULTILINE)
return (s, ''.join(t[1:]))
def check_path(path):
# Necessary type checking
if not isinstance(path, list):
raise TypeError("Expected a list, got a {}".format(type(path)))
else:
pass
class ConfigTreeError(Exception):
pass
class ConfigTree(object):
def __init__(self, config_string, libpath='/usr/lib/libvyosconfig.so.0'):
self.__config = None
self.__lib = cdll.LoadLibrary(libpath)
# Import functions
self.__from_string = self.__lib.from_string
self.__from_string.argtypes = [c_char_p]
self.__from_string.restype = c_void_p
self.__get_error = self.__lib.get_error
self.__get_error.argtypes = []
self.__get_error.restype = c_char_p
self.__to_string = self.__lib.to_string
self.__to_string.argtypes = [c_void_p]
self.__to_string.restype = c_char_p
self.__to_commands = self.__lib.to_commands
self.__to_commands.argtypes = [c_void_p]
self.__to_commands.restype = c_char_p
self.__to_json = self.__lib.to_json
self.__to_json.argtypes = [c_void_p]
self.__to_json.restype = c_char_p
self.__to_json_ast = self.__lib.to_json_ast
self.__to_json_ast.argtypes = [c_void_p]
self.__to_json_ast.restype = c_char_p
self.__set_add_value = self.__lib.set_add_value
self.__set_add_value.argtypes = [c_void_p, c_char_p, c_char_p]
self.__set_add_value.restype = c_int
self.__delete_value = self.__lib.delete_value
self.__delete_value.argtypes = [c_void_p, c_char_p, c_char_p]
self.__delete_value.restype = c_int
self.__delete = self.__lib.delete_node
self.__delete.argtypes = [c_void_p, c_char_p]
self.__delete.restype = c_int
self.__rename = self.__lib.rename_node
self.__rename.argtypes = [c_void_p, c_char_p, c_char_p]
self.__rename.restype = c_int
self.__copy = self.__lib.copy_node
self.__copy.argtypes = [c_void_p, c_char_p, c_char_p]
self.__copy.restype = c_int
self.__set_replace_value = self.__lib.set_replace_value
self.__set_replace_value.argtypes = [c_void_p, c_char_p, c_char_p]
self.__set_replace_value.restype = c_int
self.__set_valueless = self.__lib.set_valueless
self.__set_valueless.argtypes = [c_void_p, c_char_p]
self.__set_valueless.restype = c_int
self.__exists = self.__lib.exists
self.__exists.argtypes = [c_void_p, c_char_p]
self.__exists.restype = c_int
self.__list_nodes = self.__lib.list_nodes
self.__list_nodes.argtypes = [c_void_p, c_char_p]
self.__list_nodes.restype = c_char_p
self.__return_value = self.__lib.return_value
self.__return_value.argtypes = [c_void_p, c_char_p]
self.__return_value.restype = c_char_p
self.__return_values = self.__lib.return_values
self.__return_values.argtypes = [c_void_p, c_char_p]
self.__return_values.restype = c_char_p
self.__is_tag = self.__lib.is_tag
self.__is_tag.argtypes = [c_void_p, c_char_p]
self.__is_tag.restype = c_int
self.__set_tag = self.__lib.set_tag
self.__set_tag.argtypes = [c_void_p, c_char_p]
self.__set_tag.restype = c_int
self.__destroy = self.__lib.destroy
self.__destroy.argtypes = [c_void_p]
config_section, version_section = extract_version(config_string)
config_section = escape_backslash(config_section)
config = self.__from_string(config_section.encode())
if config is None:
msg = self.__get_error().decode()
raise ValueError("Failed to parse config: {0}".format(msg))
else:
self.__config = config
self.__version = version_section
def __del__(self):
if self.__config is not None:
self.__destroy(self.__config)
def __str__(self):
return self.to_string()
def to_string(self):
config_string = self.__to_string(self.__config).decode()
config_string = "{0}\n{1}".format(config_string, self.__version)
return config_string
def to_commands(self):
return self.__to_commands(self.__config).decode()
def to_json(self):
return self.__to_json(self.__config).decode()
def to_json_ast(self):
return self.__to_json_ast(self.__config).decode()
def set(self, path, value=None, replace=True):
"""Set new entry in VyOS configuration.
path: configuration path e.g. 'system dns forwarding listen-address'
value: value to be added to node, e.g. '172.18.254.201'
replace: True: current occurance will be replaced
False: new value will be appended to current occurances - use
this for adding values to a multi node
"""
check_path(path)
path_str = " ".join(map(str, path)).encode()
if value is None:
self.__set_valueless(self.__config, path_str)
else:
if replace:
self.__set_replace_value(self.__config, path_str, str(value).encode())
else:
self.__set_add_value(self.__config, path_str, str(value).encode())
def delete(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
self.__delete(self.__config, path_str)
def delete_value(self, path, value):
check_path(path)
path_str = " ".join(map(str, path)).encode()
self.__delete_value(self.__config, path_str, value.encode())
def rename(self, path, new_name):
check_path(path)
path_str = " ".join(map(str, path)).encode()
newname_str = new_name.encode()
# Check if a node with intended new name already exists
new_path = path[:-1] + [new_name]
if self.exists(new_path):
raise ConfigTreeError()
res = self.__rename(self.__config, path_str, newname_str)
if (res != 0):
raise ConfigTreeError("Path [{}] doesn't exist".format(path))
def copy(self, old_path, new_path):
check_path(old_path)
check_path(new_path)
oldpath_str = " ".join(map(str, old_path)).encode()
newpath_str = " ".join(map(str, new_path)).encode()
# Check if a node with intended new name already exists
if self.exists(new_path):
raise ConfigTreeError()
res = self.__copy(self.__config, oldpath_str, newpath_str)
if (res != 0):
raise ConfigTreeError("Path [{}] doesn't exist".format(old_path))
def exists(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res = self.__exists(self.__config, path_str)
if (res == 0):
return False
else:
return True
def list_nodes(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res_json = self.__list_nodes(self.__config, path_str).decode()
res = json.loads(res_json)
if res is None:
raise ConfigTreeError("Path [{}] doesn't exist".format(path_str))
else:
return res
def return_value(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res_json = self.__return_value(self.__config, path_str).decode()
res = json.loads(res_json)
if res is None:
raise ConfigTreeError("Path [{}] doesn't exist".format(path_str))
else:
return res
def return_values(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res_json = self.__return_values(self.__config, path_str).decode()
res = json.loads(res_json)
if res is None:
raise ConfigTreeError("Path [{}] doesn't exist".format(path_str))
else:
return res
def is_tag(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res = self.__is_tag(self.__config, path_str)
if (res >= 1):
return True
else:
return False
def set_tag(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
res = self.__set_tag(self.__config, path_str)
if (res == 0):
return True
else:
raise ConfigTreeError("Path [{}] doesn't exist".format(path_str))

File Metadata

Mime Type
text/x-script.python
Expires
Mon, Dec 15, 9:08 PM (2 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3057537
Default Alt Text
configtree.py (9 KB)

Event Timeline