summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/vyos/configquery.py44
-rw-r--r--python/vyos/configsession.py7
-rw-r--r--python/vyos/configverify.py4
-rw-r--r--python/vyos/defaults.py5
-rw-r--r--python/vyos/ifconfig/l2tpv3.py24
-rw-r--r--python/vyos/ifconfig/vti.py7
-rw-r--r--python/vyos/template.py15
-rw-r--r--python/vyos/util.py23
-rw-r--r--python/vyos/xml/load.py10
9 files changed, 109 insertions, 30 deletions
diff --git a/python/vyos/configquery.py b/python/vyos/configquery.py
index ed7346f1f..1cdcbcf39 100644
--- a/python/vyos/configquery.py
+++ b/python/vyos/configquery.py
@@ -18,9 +18,16 @@ A small library that allows querying existence or value(s) of config
settings from op mode, and execution of arbitrary op mode commands.
'''
+import re
+import json
+from copy import deepcopy
from subprocess import STDOUT
-from vyos.util import popen
+import vyos.util
+import vyos.xml
+from vyos.config import Config
+from vyos.configtree import ConfigTree
+from vyos.configsource import ConfigSourceSession
class ConfigQueryError(Exception):
pass
@@ -51,32 +58,59 @@ class CliShellApiConfigQuery(GenericConfigQuery):
def exists(self, path: list):
cmd = ' '.join(path)
- (_, err) = popen(f'cli-shell-api existsActive {cmd}')
+ (_, err) = vyos.util.popen(f'cli-shell-api existsActive {cmd}')
if err:
return False
return True
def value(self, path: list):
cmd = ' '.join(path)
- (out, err) = popen(f'cli-shell-api returnActiveValue {cmd}')
+ (out, err) = vyos.util.popen(f'cli-shell-api returnActiveValue {cmd}')
if err:
raise ConfigQueryError('No value for given path')
return out
def values(self, path: list):
cmd = ' '.join(path)
- (out, err) = popen(f'cli-shell-api returnActiveValues {cmd}')
+ (out, err) = vyos.util.popen(f'cli-shell-api returnActiveValues {cmd}')
if err:
raise ConfigQueryError('No values for given path')
return out
+class ConfigTreeQuery(GenericConfigQuery):
+ def __init__(self):
+ super().__init__()
+
+ config_source = ConfigSourceSession()
+ self.configtree = Config(config_source=config_source)
+
+ def exists(self, path: list):
+ return self.configtree.exists(path)
+
+ def value(self, path: list):
+ return self.configtree.return_value(path)
+
+ def values(self, path: list):
+ return self.configtree.return_values(path)
+
+ def list_nodes(self, path: list):
+ return self.configtree.list_nodes(path)
+
+ def get_config_dict(self, path=[], effective=False, key_mangling=None,
+ get_first_key=False, no_multi_convert=False,
+ no_tag_node_value_mangle=False):
+ return self.configtree.get_config_dict(path, effective=effective,
+ key_mangling=key_mangling, get_first_key=get_first_key,
+ no_multi_convert=no_multi_convert,
+ no_tag_node_value_mangle=no_tag_node_value_mangle)
+
class VbashOpRun(GenericOpRun):
def __init__(self):
super().__init__()
def run(self, path: list, **kwargs):
cmd = ' '.join(path)
- (out, err) = popen(f'. /opt/vyatta/share/vyatta-op/functions/interpreter/vyatta-op-run; _vyatta_op_run {cmd}', stderr=STDOUT, **kwargs)
+ (out, err) = vyos.util.popen(f'. /opt/vyatta/share/vyatta-op/functions/interpreter/vyatta-op-run; _vyatta_op_run {cmd}', stderr=STDOUT, **kwargs)
if err:
raise ConfigQueryError(out)
return out
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py
index 670e6c7fc..f28ad09c5 100644
--- a/python/vyos/configsession.py
+++ b/python/vyos/configsession.py
@@ -10,14 +10,14 @@
# 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
+# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
import re
import sys
import subprocess
-from vyos.util import call
+from vyos.util import is_systemd_service_running
CLI_SHELL_API = '/bin/cli-shell-api'
SET = '/opt/vyatta/sbin/my_set'
@@ -73,8 +73,7 @@ def inject_vyos_env(env):
env['vyos_validators_dir'] = '/usr/libexec/vyos/validators'
# if running the vyos-configd daemon, inject the vyshim env var
- ret = call('systemctl is-active --quiet vyos-configd.service')
- if not ret:
+ if is_systemd_service_running('vyos-configd.service'):
env['vyshim'] = '/usr/sbin/vyshim'
return env
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 58028b604..4279e6982 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -344,7 +344,7 @@ def verify_accel_ppp_base_service(config):
# vertify auth settings
if dict_search('authentication.mode', config) == 'local':
if not dict_search('authentication.local_users', config):
- raise ConfigError('PPPoE local auth mode requires local users to be configured!')
+ raise ConfigError('Authentication mode local requires local users to be configured!')
for user in dict_search('authentication.local_users.username', config):
user_config = config['authentication']['local_users']['username'][user]
@@ -368,7 +368,7 @@ def verify_accel_ppp_base_service(config):
raise ConfigError(f'Missing RADIUS secret key for server "{server}"')
if 'gateway_address' not in config:
- raise ConfigError('PPPoE server requires gateway-address to be configured!')
+ raise ConfigError('Server requires gateway-address to be configured!')
if 'name_server_ipv4' in config:
if len(config['name_server_ipv4']) > 2:
diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py
index 9921e3b5f..03006c383 100644
--- a/python/vyos/defaults.py
+++ b/python/vyos/defaults.py
@@ -22,7 +22,10 @@ directories = {
"migrate": "/opt/vyatta/etc/config-migrate/migrate",
"log": "/var/log/vyatta",
"templates": "/usr/share/vyos/templates/",
- "certbot": "/config/auth/letsencrypt"
+ "certbot": "/config/auth/letsencrypt",
+ "api_schema": "/usr/libexec/vyos/services/api/graphql/graphql/schema/",
+ "api_templates": "/usr/libexec/vyos/services/api/graphql/recipes/templates/"
+
}
cfg_group = 'vyattacfg'
diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py
index 7ff0fdd0e..fcd1fbf81 100644
--- a/python/vyos/ifconfig/l2tpv3.py
+++ b/python/vyos/ifconfig/l2tpv3.py
@@ -13,8 +13,28 @@
# 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/>.
+from time import sleep
+from time import time
+from vyos.util import run
from vyos.ifconfig.interface import Interface
+def wait_for_add_l2tpv3(timeout=10, sleep_interval=1, cmd=None):
+ '''
+ In some cases, we need to wait until local address is assigned.
+ And only then can the l2tpv3 tunnel be configured.
+ For example when ipv6 address in tentative state
+ or we wait for some routing daemon for remote address.
+ '''
+ start_time = time()
+ test_command = cmd
+ while True:
+ if (start_time + timeout) < time():
+ return None
+ result = run(test_command)
+ if result == 0:
+ return True
+ sleep(sleep_interval)
+
@Interface.register
class L2TPv3If(Interface):
"""
@@ -43,7 +63,9 @@ class L2TPv3If(Interface):
cmd += ' encap {encapsulation}'
cmd += ' local {source_address}'
cmd += ' remote {remote}'
- self._cmd(cmd.format(**self.config))
+ c = cmd.format(**self.config)
+ # wait until the local/remote address is available, but no more 10 sec.
+ wait_for_add_l2tpv3(cmd=c)
# setup session
cmd = 'ip l2tp add session name {ifname}'
diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py
index a217d28ea..470ebbff3 100644
--- a/python/vyos/ifconfig/vti.py
+++ b/python/vyos/ifconfig/vti.py
@@ -33,7 +33,7 @@ class VTIIf(Interface):
# - https://man7.org/linux/man-pages/man8/ip-link.8.html
# - https://man7.org/linux/man-pages/man8/ip-tunnel.8.html
mapping = {
- 'source_interface' : 'dev',
+ 'source_interface' : 'dev',
}
if_id = self.ifname.lstrip('vti')
@@ -50,8 +50,3 @@ class VTIIf(Interface):
self._cmd(cmd.format(**self.config))
self.set_interface('admin_state', 'down')
-
- def set_admin_state(self, state):
- # function is not implemented for VTI interfaces as this is entirely
- # handled by the ipsec up/down scripts
- pass
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 6902d3720..08a5712af 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -29,13 +29,17 @@ _FILTERS = {}
# reuse Environments with identical settings to improve performance
@functools.lru_cache(maxsize=2)
-def _get_environment():
+def _get_environment(location=None):
+ if location is None:
+ loc_loader=FileSystemLoader(directories["templates"])
+ else:
+ loc_loader=FileSystemLoader(location)
env = Environment(
# Don't check if template files were modified upon re-rendering
auto_reload=False,
# Cache up to this number of templates for quick re-rendering
cache_size=100,
- loader=FileSystemLoader(directories["templates"]),
+ loader=loc_loader,
trim_blocks=True,
)
env.filters.update(_FILTERS)
@@ -63,7 +67,7 @@ def register_filter(name, func=None):
return func
-def render_to_string(template, content, formater=None):
+def render_to_string(template, content, formater=None, location=None):
"""Render a template from the template directory, raise on any errors.
:param template: the path to the template relative to the template folder
@@ -78,7 +82,7 @@ def render_to_string(template, content, formater=None):
package is build (recovering the load time and overhead caused by having the
file out of the code).
"""
- template = _get_environment().get_template(template)
+ template = _get_environment(location).get_template(template)
rendered = template.render(content)
if formater is not None:
rendered = formater(rendered)
@@ -93,6 +97,7 @@ def render(
permission=None,
user=None,
group=None,
+ location=None,
):
"""Render a template from the template directory to a file, raise on any errors.
@@ -109,7 +114,7 @@ def render(
# As we are opening the file with 'w', we are performing the rendering before
# calling open() to not accidentally erase the file if rendering fails
- rendered = render_to_string(template, content, formater)
+ rendered = render_to_string(template, content, formater, location)
# Write to file
with open(destination, "w") as file:
diff --git a/python/vyos/util.py b/python/vyos/util.py
index d5cd46a6c..8af46a6ee 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -562,12 +562,13 @@ def commit_in_progress():
# Since this will be used in scripts that modify the config outside of the CLI
# framework, those knowingly have root permissions.
# For everything else, we add a safeguard.
- from psutil import process_iter, NoSuchProcess
+ from psutil import process_iter
+ from psutil import NoSuchProcess
+ from getpass import getuser
from vyos.defaults import commit_lock
- idu = cmd('/usr/bin/id -u')
- if idu != '0':
- raise OSError("This functions needs root permissions to return correct results")
+ if getuser() != 'root':
+ raise OSError('This functions needs to be run as root to return correct results!')
for proc in process_iter():
try:
@@ -804,3 +805,17 @@ def make_incremental_progressbar(increment: float):
# Ignore further calls.
while True:
yield
+
+def is_systemd_service_active(service):
+ """ Test is a specified systemd service is activated.
+ Returns True if service is active, false otherwise.
+ Copied from: https://unix.stackexchange.com/a/435317 """
+ tmp = cmd(f'systemctl show --value -p ActiveState {service}')
+ return bool((tmp == 'active'))
+
+def is_systemd_service_running(service):
+ """ Test is a specified systemd service is actually running.
+ Returns True if service is running, false otherwise.
+ Copied from: https://unix.stackexchange.com/a/435317 """
+ tmp = cmd(f'systemctl show --value -p SubState {service}')
+ return bool((tmp == 'running'))
diff --git a/python/vyos/xml/load.py b/python/vyos/xml/load.py
index 37479c6e1..0578bef80 100644
--- a/python/vyos/xml/load.py
+++ b/python/vyos/xml/load.py
@@ -125,14 +125,20 @@ def _format_nodes(inside, conf, xml):
for node in nodes:
name = node.pop('@name')
into = inside + [name]
- r[name] = _format_node(into, node, xml)
+ if name in r:
+ r[name].update(_format_node(into, node, xml))
+ else:
+ r[name] = _format_node(into, node, xml)
r[name][kw.node] = nodename
xml[kw.tags].append(' '.join(into))
else:
node = nodes
name = node.pop('@name')
into = inside + [name]
- r[name] = _format_node(inside + [name], node, xml)
+ if name in r:
+ r[name].update(_format_node(inside + [name], node, xml))
+ else:
+ r[name] = _format_node(inside + [name], node, xml)
r[name][kw.node] = nodename
xml[kw.tags].append(' '.join(into))
return r