summaryrefslogtreecommitdiff
path: root/python/vyos/configtree.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos/configtree.py')
-rw-r--r--python/vyos/configtree.py120
1 files changed, 103 insertions, 17 deletions
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index e9cdb69e4..09cfd43d3 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -1,5 +1,5 @@
# configtree -- a standalone VyOS config file manipulation library (Python bindings)
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2018-2022 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;
@@ -12,10 +12,11 @@
# 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 os
import re
import json
-from ctypes import cdll, c_char_p, c_void_p, c_int
+from ctypes import cdll, c_char_p, c_void_p, c_int, c_bool
LIBPATH = '/usr/lib/libvyosconfig.so.0'
@@ -59,7 +60,7 @@ class ConfigTree(object):
self.__get_error.restype = c_char_p
self.__to_string = self.__lib.to_string
- self.__to_string.argtypes = [c_void_p]
+ self.__to_string.argtypes = [c_void_p, c_bool]
self.__to_string.restype = c_char_p
self.__to_commands = self.__lib.to_commands
@@ -147,6 +148,8 @@ class ConfigTree(object):
self.__config = address
self.__version = ''
+ self.__migration = os.environ.get('VYOS_MIGRATION')
+
def __del__(self):
if self.__config is not None:
self.__destroy(self.__config)
@@ -157,8 +160,8 @@ class ConfigTree(object):
def _get_config(self):
return self.__config
- def to_string(self):
- config_string = self.__to_string(self.__config).decode()
+ def to_string(self, ordered_values=False):
+ config_string = self.__to_string(self.__config, ordered_values).decode()
config_string = "{0}\n{1}".format(config_string, self.__version)
return config_string
@@ -191,17 +194,35 @@ class ConfigTree(object):
else:
self.__set_add_value(self.__config, path_str, str(value).encode())
+ if self.__migration:
+ print(f"- op: set path: {path} value: {value} replace: {replace}")
+
def delete(self, path):
check_path(path)
path_str = " ".join(map(str, path)).encode()
- self.__delete(self.__config, path_str)
+ res = self.__delete(self.__config, path_str)
+ if (res != 0):
+ raise ConfigTreeError(f"Path doesn't exist: {path}")
+
+ if self.__migration:
+ print(f"- op: delete path: {path}")
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())
+ res = self.__delete_value(self.__config, path_str, value.encode())
+ if (res != 0):
+ if res == 1:
+ raise ConfigTreeError(f"Path doesn't exist: {path}")
+ elif res == 2:
+ raise ConfigTreeError(f"Value doesn't exist: '{value}'")
+ else:
+ raise ConfigTreeError()
+
+ if self.__migration:
+ print(f"- op: delete_value path: {path} value: {value}")
def rename(self, path, new_name):
check_path(path)
@@ -216,6 +237,9 @@ class ConfigTree(object):
if (res != 0):
raise ConfigTreeError("Path [{}] doesn't exist".format(path))
+ if self.__migration:
+ print(f"- op: rename old_path: {path} new_path: {new_path}")
+
def copy(self, old_path, new_path):
check_path(old_path)
check_path(new_path)
@@ -227,7 +251,11 @@ class ConfigTree(object):
raise ConfigTreeError()
res = self.__copy(self.__config, oldpath_str, newpath_str)
if (res != 0):
- raise ConfigTreeError("Path [{}] doesn't exist".format(old_path))
+ msg = self.__get_error().decode()
+ raise ConfigTreeError(msg)
+
+ if self.__migration:
+ print(f"- op: copy old_path: {old_path} new_path: {new_path}")
def exists(self, path):
check_path(path)
@@ -303,6 +331,72 @@ class ConfigTree(object):
subt = ConfigTree(address=res)
return subt
+def show_diff(left, right, path=[], commands=False, libpath=LIBPATH):
+ if left is None:
+ left = ConfigTree(config_string='\n')
+ if right is None:
+ right = ConfigTree(config_string='\n')
+ if not (isinstance(left, ConfigTree) and isinstance(right, ConfigTree)):
+ raise TypeError("Arguments must be instances of ConfigTree")
+ if path:
+ if (not left.exists(path)) and (not right.exists(path)):
+ raise ConfigTreeError(f"Path {path} doesn't exist")
+
+ check_path(path)
+ path_str = " ".join(map(str, path)).encode()
+
+ __lib = cdll.LoadLibrary(libpath)
+ __show_diff = __lib.show_diff
+ __show_diff.argtypes = [c_bool, c_char_p, c_void_p, c_void_p]
+ __show_diff.restype = c_char_p
+ __get_error = __lib.get_error
+ __get_error.argtypes = []
+ __get_error.restype = c_char_p
+
+ res = __show_diff(commands, path_str, left._get_config(), right._get_config())
+ res = res.decode()
+ if res == "#1@":
+ msg = __get_error().decode()
+ raise ConfigTreeError(msg)
+
+ return res
+
+def union(left, right, libpath=LIBPATH):
+ if left is None:
+ left = ConfigTree(config_string='\n')
+ if right is None:
+ right = ConfigTree(config_string='\n')
+ if not (isinstance(left, ConfigTree) and isinstance(right, ConfigTree)):
+ raise TypeError("Arguments must be instances of ConfigTree")
+
+ __lib = cdll.LoadLibrary(libpath)
+ __tree_union = __lib.tree_union
+ __tree_union.argtypes = [c_void_p, c_void_p]
+ __tree_union.restype = c_void_p
+ __get_error = __lib.get_error
+ __get_error.argtypes = []
+ __get_error.restype = c_char_p
+
+ res = __tree_union( left._get_config(), right._get_config())
+ tree = ConfigTree(address=res)
+
+ return tree
+
+def reference_tree_to_json(from_dir, to_file, libpath=LIBPATH):
+ try:
+ __lib = cdll.LoadLibrary(libpath)
+ __reference_tree_to_json = __lib.reference_tree_to_json
+ __reference_tree_to_json.argtypes = [c_char_p, c_char_p]
+ __get_error = __lib.get_error
+ __get_error.argtypes = []
+ __get_error.restype = c_char_p
+ res = __reference_tree_to_json(from_dir.encode(), to_file.encode())
+ except Exception as e:
+ raise ConfigTreeError(e)
+ if res == 1:
+ msg = __get_error().decode()
+ raise ConfigTreeError(msg)
+
class DiffTree:
def __init__(self, left, right, path=[], libpath=LIBPATH):
if left is None:
@@ -326,10 +420,6 @@ class DiffTree:
self.__diff_tree.argtypes = [c_char_p, c_void_p, c_void_p]
self.__diff_tree.restype = c_void_p
- self.__trim_tree = self.__lib.trim_tree
- self.__trim_tree.argtypes = [c_void_p, c_void_p]
- self.__trim_tree.restype = c_void_p
-
check_path(path)
path_str = " ".join(map(str, path)).encode()
@@ -343,11 +433,7 @@ class DiffTree:
self.add = self.full.get_subtree(['add'])
self.sub = self.full.get_subtree(['sub'])
self.inter = self.full.get_subtree(['inter'])
-
- # trim sub(-tract) tree to get delete tree for commands
- ref = self.right.get_subtree(path, with_node=True) if path else self.right
- res = self.__trim_tree(self.sub._get_config(), ref._get_config())
- self.delete = ConfigTree(address=res)
+ self.delete = self.full.get_subtree(['del'])
def to_commands(self):
add = self.add.to_commands()