summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/vyos/accel_ppp.py7
-rw-r--r--python/vyos/config.py4
-rw-r--r--python/vyos/config_mgmt.py17
-rw-r--r--python/vyos/configdict.py8
-rw-r--r--python/vyos/configdiff.py6
-rw-r--r--python/vyos/configsession.py19
-rw-r--r--python/vyos/configtree.py24
-rw-r--r--python/vyos/configverify.py134
-rw-r--r--python/vyos/ethtool.py1
-rw-r--r--python/vyos/firewall.py9
-rw-r--r--python/vyos/frr.py3
-rw-r--r--python/vyos/ifconfig/bond.py3
-rw-r--r--python/vyos/ifconfig/bridge.py7
-rw-r--r--python/vyos/ifconfig/interface.py19
-rw-r--r--python/vyos/ifconfig/vrrp.py4
-rw-r--r--python/vyos/ifconfig/vxlan.py5
-rw-r--r--python/vyos/ifconfig/wireguard.py3
-rw-r--r--python/vyos/iflag.py38
-rw-r--r--python/vyos/initialsetup.py4
-rw-r--r--python/vyos/ioctl.py5
-rw-r--r--python/vyos/kea.py3
-rw-r--r--python/vyos/opmode.py2
-rw-r--r--python/vyos/progressbar.py4
-rw-r--r--python/vyos/qos/priority.py3
-rw-r--r--python/vyos/range_regex.py5
-rw-r--r--python/vyos/system/compat.py22
-rw-r--r--python/vyos/system/grub.py14
-rw-r--r--python/vyos/template.py22
-rw-r--r--python/vyos/utils/network.py4
-rw-r--r--python/vyos/utils/system.py7
-rw-r--r--python/vyos/version.py6
-rwxr-xr-xpython/vyos/xml/generate.py7
-rw-r--r--python/vyos/xml/test_xml.py14
-rwxr-xr-xpython/vyos/xml_ref/generate_cache.py7
34 files changed, 251 insertions, 189 deletions
diff --git a/python/vyos/accel_ppp.py b/python/vyos/accel_ppp.py
index 0b4f8a9fe..a6f2ceb52 100644
--- a/python/vyos/accel_ppp.py
+++ b/python/vyos/accel_ppp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -13,14 +13,9 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import sys
-import vyos.opmode
from vyos.utils.process import rc_cmd
-
def get_server_statistics(accel_statistics, pattern, sep=':') -> dict:
import re
diff --git a/python/vyos/config.py b/python/vyos/config.py
index 7619ad367..cca65f0eb 100644
--- a/python/vyos/config.py
+++ b/python/vyos/config.py
@@ -1,4 +1,4 @@
-# Copyright 2017, 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2017-2024 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
@@ -60,12 +60,10 @@ In configuration mode, "base" functions like `exists`, `return_value` return val
while functions prefixed "effective" return values from the running config.
In operational mode, all functions return values from the running config.
-
"""
import re
import json
-from copy import deepcopy
from typing import Union
import vyos.configtree
diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py
index 28ccee769..fc51d781c 100644
--- a/python/vyos/config_mgmt.py
+++ b/python/vyos/config_mgmt.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 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
@@ -19,18 +19,23 @@ import sys
import gzip
import logging
-from typing import Optional, Tuple, Union
+from typing import Optional
+from typing import Tuple
from filecmp import cmp
from datetime import datetime
-from textwrap import dedent, indent
+from textwrap import dedent
from pathlib import Path
from tabulate import tabulate
from shutil import copy, chown
-from urllib.parse import urlsplit, urlunsplit
+from urllib.parse import urlsplit
+from urllib.parse import urlunsplit
from vyos.config import Config
-from vyos.configtree import ConfigTree, ConfigTreeError, show_diff
-from vyos.load_config import load, LoadConfigError
+from vyos.configtree import ConfigTree
+from vyos.configtree import ConfigTreeError
+from vyos.configtree import show_diff
+from vyos.load_config import load
+from vyos.load_config import LoadConfigError
from vyos.defaults import directories
from vyos.version import get_full_version_data
from vyos.utils.io import ask_yes_no
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 4111d7271..870d7cfda 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -203,8 +203,6 @@ def is_member(conf, interface, intftype=None):
empty -> Interface is not a member
key -> Interface is a member of this interface
"""
- from vyos.ifconfig import Section
-
ret_val = {}
intftypes = ['bonding', 'bridge']
@@ -633,7 +631,7 @@ def get_accel_dict(config, base, chap_secrets, with_pki=False):
Return a dictionary with the necessary interface config keys.
"""
- from vyos.utils.system import get_half_cpus
+ from vyos.cpu import get_core_count
from vyos.template import is_ipv4
dict = config.get_config_dict(base, key_mangling=('-', '_'),
@@ -643,7 +641,7 @@ def get_accel_dict(config, base, chap_secrets, with_pki=False):
with_pki=with_pki)
# set CPUs cores to process requests
- dict.update({'thread_count' : get_half_cpus()})
+ dict.update({'thread_count' : get_core_count()})
# we need to store the path to the secrets file
dict.update({'chap_secrets_file' : chap_secrets})
diff --git a/python/vyos/configdiff.py b/python/vyos/configdiff.py
index 03b06c6d9..f975df45d 100644
--- a/python/vyos/configdiff.py
+++ b/python/vyos/configdiff.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2024 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
@@ -13,12 +13,12 @@
# 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 enum import IntFlag, auto
+from enum import IntFlag
+from enum import auto
from vyos.config import Config
from vyos.configtree import DiffTree
from vyos.configdict import dict_merge
-from vyos.configdict import list_diff
from vyos.utils.dict import get_sub_dict
from vyos.utils.dict import mangle_dict_keys
from vyos.utils.dict import dict_search_args
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py
index 90842b749..ab7a631bb 100644
--- a/python/vyos/configsession.py
+++ b/python/vyos/configsession.py
@@ -176,6 +176,25 @@ class ConfigSession(object):
except (ValueError, ConfigSessionError) as e:
raise ConfigSessionError(e)
+ def set_section_tree(self, d: dict):
+ try:
+ if d:
+ for p in dict_to_paths(d):
+ self.set(p)
+ except (ValueError, ConfigSessionError) as e:
+ raise ConfigSessionError(e)
+
+ def load_section_tree(self, mask: dict, d: dict):
+ try:
+ if mask:
+ for p in dict_to_paths(mask):
+ self.delete(p)
+ if d:
+ for p in dict_to_paths(d):
+ self.set(p)
+ except (ValueError, ConfigSessionError) as e:
+ raise ConfigSessionError(e)
+
def comment(self, path, value=None):
if not value:
value = [""]
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index 423fe01ed..e4b282d72 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -401,6 +401,30 @@ def union(left, right, libpath=LIBPATH):
return tree
+def mask_inclusive(left, right, libpath=LIBPATH):
+ if not (isinstance(left, ConfigTree) and isinstance(right, ConfigTree)):
+ raise TypeError("Arguments must be instances of ConfigTree")
+
+ try:
+ __lib = cdll.LoadLibrary(libpath)
+ __mask_tree = __lib.mask_tree
+ __mask_tree.argtypes = [c_void_p, c_void_p]
+ __mask_tree.restype = c_void_p
+ __get_error = __lib.get_error
+ __get_error.argtypes = []
+ __get_error.restype = c_char_p
+
+ res = __mask_tree(left._get_config(), right._get_config())
+ except Exception as e:
+ raise ConfigTreeError(e)
+ if not res:
+ msg = __get_error().decode()
+ raise ConfigTreeError(msg)
+
+ tree = ConfigTree(address=res)
+
+ return tree
+
def reference_tree_to_json(from_dir, to_file, libpath=LIBPATH):
try:
__lib = cdll.LoadLibrary(libpath)
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 6508ccdd9..18642877a 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -23,8 +23,6 @@
from vyos import ConfigError
from vyos.utils.dict import dict_search
-from vyos.utils.dict import dict_search_recursive
-
# pattern re-used in ipsec migration script
dynamic_interface_pattern = r'(ppp|pppoe|sstpc|l2tp|ipoe)[0-9]+'
@@ -99,10 +97,17 @@ def verify_vrf(config):
Common helper function used by interface implementations to perform
recurring validation of VRF configuration.
"""
- from netifaces import interfaces
- if 'vrf' in config and config['vrf'] != 'default':
- if config['vrf'] not in interfaces():
- raise ConfigError('VRF "{vrf}" does not exist'.format(**config))
+ from vyos.utils.network import interface_exists
+ if 'vrf' in config:
+ vrfs = config['vrf']
+ if isinstance(vrfs, str):
+ vrfs = [vrfs]
+
+ for vrf in vrfs:
+ if vrf == 'default':
+ continue
+ if not interface_exists(vrf):
+ raise ConfigError(f'VRF "{vrf}" does not exist!')
if 'is_bridge_member' in config:
raise ConfigError(
@@ -162,43 +167,6 @@ def verify_tunnel(config):
if 'source_address' in config and is_ipv6(config['source_address']):
raise ConfigError('Can not use local IPv6 address is for mGRE tunnels')
-def verify_eapol(config):
- """
- Common helper function used by interface implementations to perform
- recurring validation of EAPoL configuration.
- """
- if 'eapol' in config:
- if 'certificate' not in config['eapol']:
- raise ConfigError('Certificate must be specified when using EAPoL!')
-
- if 'pki' not in config or 'certificate' not in config['pki']:
- raise ConfigError('Invalid certificate specified for EAPoL')
-
- cert_name = config['eapol']['certificate']
- if cert_name not in config['pki']['certificate']:
- raise ConfigError('Invalid certificate specified for EAPoL')
-
- cert = config['pki']['certificate'][cert_name]
-
- if 'certificate' not in cert or 'private' not in cert or 'key' not in cert['private']:
- raise ConfigError('Invalid certificate/private key specified for EAPoL')
-
- if 'password_protected' in cert['private']:
- raise ConfigError('Encrypted private key cannot be used for EAPoL')
-
- if 'ca_certificate' in config['eapol']:
- if 'ca' not in config['pki']:
- raise ConfigError('Invalid CA certificate specified for EAPoL')
-
- for ca_cert_name in config['eapol']['ca_certificate']:
- if ca_cert_name not in config['pki']['ca']:
- raise ConfigError('Invalid CA certificate specified for EAPoL')
-
- ca_cert = config['pki']['ca'][ca_cert_name]
-
- if 'certificate' not in ca_cert:
- raise ConfigError('Invalid CA certificate specified for EAPoL')
-
def verify_mirror_redirect(config):
"""
Common helper function used by interface implementations to perform
@@ -206,13 +174,13 @@ def verify_mirror_redirect(config):
It makes no sense to mirror traffic back at yourself!
"""
- import os
+ from vyos.utils.network import interface_exists
if {'mirror', 'redirect'} <= set(config):
raise ConfigError('Mirror and redirect can not be enabled at the same time!')
if 'mirror' in config:
for direction, mirror_interface in config['mirror'].items():
- if not os.path.exists(f'/sys/class/net/{mirror_interface}'):
+ if not interface_exists(mirror_interface):
raise ConfigError(f'Requested mirror interface "{mirror_interface}" '\
'does not exist!')
@@ -222,7 +190,7 @@ def verify_mirror_redirect(config):
if 'redirect' in config:
redirect_ifname = config['redirect']
- if not os.path.exists(f'/sys/class/net/{redirect_ifname}'):
+ if not interface_exists(redirect_ifname):
raise ConfigError(f'Requested redirect interface "{redirect_ifname}" '\
'does not exist!')
@@ -276,10 +244,10 @@ def verify_interface_exists(ifname, warning_only=False):
if the interface is defined on the CLI, if it's not found we try if
it exists at the OS level.
"""
- import os
from vyos.base import Warning
from vyos.configquery import ConfigTreeQuery
from vyos.utils.dict import dict_search_recursive
+ from vyos.utils.network import interface_exists
# Check if interface is present in CLI config
config = ConfigTreeQuery()
@@ -288,7 +256,7 @@ def verify_interface_exists(ifname, warning_only=False):
return True
# Interface not found on CLI, try Linux Kernel
- if os.path.exists(f'/sys/class/net/{ifname}'):
+ if interface_exists(ifname):
return True
message = f'Interface "{ifname}" does not exist!'
@@ -304,7 +272,7 @@ def verify_source_interface(config):
required by e.g. peth/MACvlan, MACsec ...
"""
import re
- from netifaces import interfaces
+ from vyos.utils.network import interface_exists
ifname = config['ifname']
if 'source_interface' not in config:
@@ -316,7 +284,7 @@ def verify_source_interface(config):
if tmp.match(src_ifname):
raise ConfigError(f'Can not source "{ifname}" from dynamic interface "{src_ifname}"!')
- if src_ifname not in interfaces():
+ if not interface_exists(src_ifname):
raise ConfigError(f'Specified source-interface {src_ifname} does not exist')
if 'source_interface_is_bridge_member' in config:
@@ -487,3 +455,69 @@ def verify_access_list(access_list, config, version=''):
# Check if the specified ACL exists, if not error out
if dict_search(f'policy.access-list{version}.{access_list}', config) == None:
raise ConfigError(f'Specified access-list{version} "{access_list}" does not exist!')
+
+def verify_pki_certificate(config: dict, cert_name: str, no_password_protected: bool=False):
+ """
+ Common helper function user by PKI consumers to perform recurring
+ validation functions for PEM based certificates
+ """
+ if 'pki' not in config:
+ raise ConfigError('PKI is not configured!')
+
+ if 'certificate' not in config['pki']:
+ raise ConfigError('PKI does not contain any certificates!')
+
+ if cert_name not in config['pki']['certificate']:
+ raise ConfigError(f'Certificate "{cert_name}" not found in configuration!')
+
+ pki_cert = config['pki']['certificate'][cert_name]
+ if 'certificate' not in pki_cert:
+ raise ConfigError(f'PEM certificate for "{cert_name}" missing in configuration!')
+
+ if 'private' not in pki_cert or 'key' not in pki_cert['private']:
+ raise ConfigError(f'PEM private key for "{cert_name}" missing in configuration!')
+
+ if no_password_protected and 'password_protected' in pki_cert['private']:
+ raise ConfigError('Password protected PEM private key is not supported!')
+
+def verify_pki_ca_certificate(config: dict, ca_name: str):
+ """
+ Common helper function user by PKI consumers to perform recurring
+ validation functions for PEM based CA certificates
+ """
+ if 'pki' not in config:
+ raise ConfigError('PKI is not configured!')
+
+ if 'ca' not in config['pki']:
+ raise ConfigError('PKI does not contain any CA certificates!')
+
+ if ca_name not in config['pki']['ca']:
+ raise ConfigError(f'CA Certificate "{ca_name}" not found in configuration!')
+
+ pki_cert = config['pki']['ca'][ca_name]
+ if 'certificate' not in pki_cert:
+ raise ConfigError(f'PEM CA certificate for "{cert_name}" missing in configuration!')
+
+def verify_pki_dh_parameters(config: dict, dh_name: str, min_key_size: int=0):
+ """
+ Common helper function user by PKI consumers to perform recurring
+ validation functions on DH parameters
+ """
+ from vyos.pki import load_dh_parameters
+
+ if 'pki' not in config:
+ raise ConfigError('PKI is not configured!')
+
+ if 'dh' not in config['pki']:
+ raise ConfigError('PKI does not contain any DH parameters!')
+
+ if dh_name not in config['pki']['dh']:
+ raise ConfigError(f'DH parameter "{dh_name}" not found in configuration!')
+
+ if min_key_size:
+ pki_dh = config['pki']['dh'][dh_name]
+ dh_params = load_dh_parameters(pki_dh['parameters'])
+ dh_numbers = dh_params.parameter_numbers()
+ dh_bits = dh_numbers.p.bit_length()
+ if dh_bits < min_key_size:
+ raise ConfigError(f'Minimum DH key-size is {min_key_size} bits!')
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index 5e241fc08..d45c9c272 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -13,7 +13,6 @@
# 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 os
import re
from json import loads
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index e70b4f0d9..0713eb370 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -30,7 +30,6 @@ from vyos.template import is_ipv4
from vyos.template import render
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
-from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import run
@@ -66,7 +65,7 @@ def fqdn_config_parse(firewall):
rule = path[4]
suffix = path[5][0]
set_name = f'{hook_name}_{priority}_{rule}_{suffix}'
-
+
if (path[0] == 'ipv4') and (path[1] == 'forward' or path[1] == 'input' or path[1] == 'output' or path[1] == 'name'):
firewall['ip_fqdn'][set_name] = domain
elif (path[0] == 'ipv6') and (path[1] == 'forward' or path[1] == 'input' or path[1] == 'output' or path[1] == 'name'):
@@ -85,7 +84,7 @@ def fqdn_resolve(fqdn, ipv6=False):
def find_nftables_rule(table, chain, rule_matches=[]):
# Find rule in table/chain that matches all criteria and return the handle
- results = cmd(f'sudo nft -a list chain {table} {chain}').split("\n")
+ results = cmd(f'sudo nft --handle list chain {table} {chain}').split("\n")
for line in results:
if all(rule_match in line for rule_match in rule_matches):
handle_search = re.search('handle (\d+)', line)
@@ -655,7 +654,7 @@ def geoip_update(firewall, force=False):
'ipv6_sets': ipv6_sets
})
- result = run(f'nft -f {nftables_geoip_conf}')
+ result = run(f'nft --file {nftables_geoip_conf}')
if result != 0:
print('Error: GeoIP failed to update firewall')
return False
diff --git a/python/vyos/frr.py b/python/vyos/frr.py
index c3703cbb4..e7743e9d5 100644
--- a/python/vyos/frr.py
+++ b/python/vyos/frr.py
@@ -1,4 +1,4 @@
-# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2024 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
@@ -69,7 +69,6 @@ import tempfile
import re
from vyos import ConfigError
-from vyos.utils.permission import chown
from vyos.utils.process import cmd
from vyos.utils.process import popen
from vyos.utils.process import STDOUT
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py
index 45e6e4c16..c6d0f1cff 100644
--- a/python/vyos/ifconfig/bond.py
+++ b/python/vyos/ifconfig/bond.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -16,7 +16,6 @@
import os
from vyos.ifconfig.interface import Interface
-from vyos.utils.process import cmd
from vyos.utils.dict import dict_search
from vyos.utils.assertion import assert_list
from vyos.utils.assertion import assert_positive
diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py
index 7936e3da5..917f962b7 100644
--- a/python/vyos/ifconfig/bridge.py
+++ b/python/vyos/ifconfig/bridge.py
@@ -13,13 +13,12 @@
# 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 netifaces import interfaces
-
from vyos.ifconfig.interface import Interface
from vyos.utils.assertion import assert_boolean
from vyos.utils.assertion import assert_list
from vyos.utils.assertion import assert_positive
from vyos.utils.dict import dict_search
+from vyos.utils.network import interface_exists
from vyos.configdict import get_vlan_ids
from vyos.configdict import list_diff
@@ -314,7 +313,7 @@ class BridgeIf(Interface):
# remove interface from bridge
tmp = dict_search('member.interface_remove', config)
for member in (tmp or []):
- if member in interfaces():
+ if interface_exists(member):
self.del_port(member)
# enable/disable VLAN Filter
@@ -345,7 +344,7 @@ class BridgeIf(Interface):
for interface, interface_config in tmp.items():
# if interface does yet not exist bail out early and
# add it later
- if interface not in interfaces():
+ if not interface_exists(interface):
continue
# Bridge lower "physical" interface
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 56dcde214..1b86982c4 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -35,7 +35,6 @@ from vyos.defaults import directories
from vyos.template import render
from vyos.utils.network import mac2eui64
from vyos.utils.dict import dict_search
-from vyos.utils.file import read_file
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_interface_namespace
from vyos.utils.network import is_netns_interface
@@ -415,7 +414,7 @@ class Interface(Control):
else:
nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ "{self.ifname}" }}'
# Check if deleting is possible first to avoid raising errors
- _, err = self._popen(f'nft -c {nft_del_element}')
+ _, err = self._popen(f'nft --check {nft_del_element}')
if not err:
# Remove map element
self._cmd(f'nft {nft_del_element}')
@@ -1375,15 +1374,19 @@ class Interface(Control):
ifname = self.ifname
config_base = directories['dhcp6_client_dir']
config_file = f'{config_base}/dhcp6c.{ifname}.conf'
+ script_file = f'/etc/wide-dhcpv6/dhcp6c.{ifname}.script' # can not live under /run b/c of noexec mount option
systemd_override_file = f'/run/systemd/system/dhcp6c@{ifname}.service.d/10-override.conf'
systemd_service = f'dhcp6c@{ifname}.service'
- # Rendered client configuration files require the apsolute config path
- self.config['dhcp6_client_dir'] = directories['dhcp6_client_dir']
+ # Rendered client configuration files require additional settings
+ config = deepcopy(self.config)
+ config['dhcp6_client_dir'] = directories['dhcp6_client_dir']
+ config['dhcp6_script_file'] = script_file
- if enable and 'disable' not in self.config:
- render(systemd_override_file, 'dhcp-client/ipv6.override.conf.j2', self.config)
- render(config_file, 'dhcp-client/ipv6.j2', self.config)
+ if enable and 'disable' not in config:
+ render(systemd_override_file, 'dhcp-client/ipv6.override.conf.j2', config)
+ render(config_file, 'dhcp-client/ipv6.j2', config)
+ render(script_file, 'dhcp-client/dhcp6c-script.j2', config, permission=0o755)
# Reload systemd unit definitons as some options are dynamically generated
self._cmd('systemctl daemon-reload')
@@ -1396,6 +1399,8 @@ class Interface(Control):
self._cmd(f'systemctl stop {systemd_service}')
if os.path.isfile(config_file):
os.remove(config_file)
+ if os.path.isfile(script_file):
+ os.remove(script_file)
return None
diff --git a/python/vyos/ifconfig/vrrp.py b/python/vyos/ifconfig/vrrp.py
index fde903a53..ee9336d1a 100644
--- a/python/vyos/ifconfig/vrrp.py
+++ b/python/vyos/ifconfig/vrrp.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -18,7 +18,6 @@ import json
import signal
from time import time
-from time import sleep
from tabulate import tabulate
from vyos.configquery import ConfigTreeQuery
@@ -155,4 +154,3 @@ class VRRP(object):
# add to the active list disabled instances
groups.extend(cls.disabled())
return(tabulate(groups, headers))
-
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index a2c4aad50..bdb48e303 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -13,9 +13,6 @@
# 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 json import loads
-
-from vyos import ConfigError
from vyos.configdict import list_diff
from vyos.ifconfig import Interface
from vyos.utils.assertion import assert_list
diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py
index 5704f8b64..5b5f25323 100644
--- a/python/vyos/ifconfig/wireguard.py
+++ b/python/vyos/ifconfig/wireguard.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -25,7 +25,6 @@ from hurry.filesize import alternative
from vyos.ifconfig import Interface
from vyos.ifconfig import Operational
from vyos.template import is_ipv6
-from vyos.base import Warning
class WireGuardOperational(Operational):
def _dump(self):
diff --git a/python/vyos/iflag.py b/python/vyos/iflag.py
index 7ff8e5623..3ce73c1bf 100644
--- a/python/vyos/iflag.py
+++ b/python/vyos/iflag.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -13,26 +13,24 @@
# 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 enum import Enum, unique, IntEnum
-
+from enum import IntEnum
class IFlag(IntEnum):
""" net/if.h interface flags """
- IFF_UP = 0x1 #: Interface up/down status
- IFF_BROADCAST = 0x2 #: Broadcast address valid
- IFF_DEBUG = 0x4, #: Debugging
- IFF_LOOPBACK = 0x8 #: Is loopback network
- IFF_POINTOPOINT = 0x10 #: Is point-to-point link
- IFF_NOTRAILERS = 0x20 #: Avoid use of trailers
- IFF_RUNNING = 0x40 #: Resources allocated
- IFF_NOARP = 0x80 #: No address resolution protocol
- IFF_PROMISC = 0x100 #: Promiscuous mode
- IFF_ALLMULTI = 0x200 #: Receive all multicast
- IFF_MASTER = 0x400 #: Load balancer master
- IFF_SLAVE = 0x800 #: Load balancer slave
- IFF_MULTICAST = 0x1000 #: Supports multicast
- IFF_PORTSEL = 0x2000 #: Media type adjustable
- IFF_AUTOMEDIA = 0x4000 #: Automatic media type enabled
- IFF_DYNAMIC = 0x8000 #: Is a dial-up device with dynamic address
-
+ IFF_UP = 0x1 #: Interface up/down status
+ IFF_BROADCAST = 0x2 #: Broadcast address valid
+ IFF_DEBUG = 0x4, #: Debugging
+ IFF_LOOPBACK = 0x8 #: Is loopback network
+ IFF_POINTOPOINT = 0x10 #: Is point-to-point link
+ IFF_NOTRAILERS = 0x20 #: Avoid use of trailers
+ IFF_RUNNING = 0x40 #: Resources allocated
+ IFF_NOARP = 0x80 #: No address resolution protocol
+ IFF_PROMISC = 0x100 #: Promiscuous mode
+ IFF_ALLMULTI = 0x200 #: Receive all multicast
+ IFF_MASTER = 0x400 #: Load balancer master
+ IFF_SLAVE = 0x800 #: Load balancer slave
+ IFF_MULTICAST = 0x1000 #: Supports multicast
+ IFF_PORTSEL = 0x2000 #: Media type adjustable
+ IFF_AUTOMEDIA = 0x4000 #: Automatic media type enabled
+ IFF_DYNAMIC = 0x8000 #: Is a dial-up device with dynamic address
diff --git a/python/vyos/initialsetup.py b/python/vyos/initialsetup.py
index 3b280dc6b..cb6b9e459 100644
--- a/python/vyos/initialsetup.py
+++ b/python/vyos/initialsetup.py
@@ -1,7 +1,7 @@
# initialsetup -- functions for setting common values in config file,
# for use in installation and first boot scripts
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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;
@@ -14,8 +14,6 @@
# 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 vyos.configtree
-
from vyos.utils.auth import make_password_hash
from vyos.utils.auth import split_ssh_public_key
diff --git a/python/vyos/ioctl.py b/python/vyos/ioctl.py
index cfa75aac6..51574c1db 100644
--- a/python/vyos/ioctl.py
+++ b/python/vyos/ioctl.py
@@ -1,4 +1,4 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -13,7 +13,6 @@
# 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 sys
import os
import socket
import fcntl
@@ -29,7 +28,7 @@ def get_terminal_size():
def get_interface_flags(intf):
""" Pull the SIOCGIFFLAGS """
- nullif = '\0'*256
+ nullif = '\0'*256
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
raw = fcntl.ioctl(sock.fileno(), SIOCGIFFLAGS, intf + nullif)
flags, = struct.unpack('H', raw[16:18])
diff --git a/python/vyos/kea.py b/python/vyos/kea.py
index 89ae7ca81..addfdba49 100644
--- a/python/vyos/kea.py
+++ b/python/vyos/kea.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 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
@@ -22,7 +22,6 @@ from vyos.template import isc_static_route
from vyos.template import netmask_from_cidr
from vyos.utils.dict import dict_search_args
from vyos.utils.file import file_permissions
-from vyos.utils.file import read_file
from vyos.utils.process import run
kea4_options = {
diff --git a/python/vyos/opmode.py b/python/vyos/opmode.py
index e1af1a682..8dab9a4ca 100644
--- a/python/vyos/opmode.py
+++ b/python/vyos/opmode.py
@@ -81,7 +81,7 @@ class InternalError(Error):
def _is_op_mode_function_name(name):
- if re.match(r"^(show|clear|reset|restart|add|update|delete|generate|set)", name):
+ if re.match(r"^(show|clear|reset|restart|add|update|delete|generate|set|renew)", name):
return True
else:
return False
diff --git a/python/vyos/progressbar.py b/python/vyos/progressbar.py
index 7bc9d9856..8d1042672 100644
--- a/python/vyos/progressbar.py
+++ b/python/vyos/progressbar.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 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
@@ -17,12 +17,10 @@ import math
import os
import signal
import subprocess
-import sys
from vyos.utils.io import is_dumb_terminal
from vyos.utils.io import print_error
-
class Progressbar:
def __init__(self, step=None):
self.total = 0.0
diff --git a/python/vyos/qos/priority.py b/python/vyos/qos/priority.py
index 8182400f9..7f0a67032 100644
--- a/python/vyos/qos/priority.py
+++ b/python/vyos/qos/priority.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-2024 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,7 +14,6 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
from vyos.qos.base import QoSBase
-from vyos.utils.dict import dict_search
class Priority(QoSBase):
_parent = 1
diff --git a/python/vyos/range_regex.py b/python/vyos/range_regex.py
index a8190d140..81e9d2e7e 100644
--- a/python/vyos/range_regex.py
+++ b/python/vyos/range_regex.py
@@ -22,7 +22,6 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
-import math
# coding=utf8
@@ -67,7 +66,7 @@ def regex_for_range(min_, max_):
min_ = 0
if max_ >= 0:
- positive_subpatterns = split_to_patterns(min_, max_)
+ positive_subpatterns = split_to_patterns(min_, max_)
negative_only_subpatterns = ['-' + val for val in negative_subpatterns if val not in positive_subpatterns]
positive_only_subpatterns = [val for val in positive_subpatterns if val not in negative_subpatterns]
@@ -139,4 +138,4 @@ def range_to_pattern(start, stop):
if any_digit_count > 1:
pattern += '{{{}}}'.format(any_digit_count)
- return pattern \ No newline at end of file
+ return pattern
diff --git a/python/vyos/system/compat.py b/python/vyos/system/compat.py
index 37b834ad6..1b487c1d2 100644
--- a/python/vyos/system/compat.py
+++ b/python/vyos/system/compat.py
@@ -198,11 +198,11 @@ def update_cfg_ver(root_dir:str = '') -> int:
return cfg_version
-def get_default(menu_entries: list, root_dir: str = '') -> Union[int, None]:
+def get_default(data: dict, root_dir: str = '') -> Union[int, None]:
"""Translate default version to menuentry index
Args:
- menu_entries (list): list of dicts of installed version boot data
+ data (dict): boot data
root_dir (str): an optional path to the root directory
Returns:
@@ -213,10 +213,22 @@ def get_default(menu_entries: list, root_dir: str = '') -> Union[int, None]:
grub_cfg_main = f'{root_dir}/{grub.GRUB_CFG_MAIN}'
+ menu_entries = data.get('versions', [])
+ console_type = data.get('console_type', 'tty')
+ console_num = data.get('console_num', '0')
image_name = image.get_default_image()
- sublist = list(filter(lambda x: x.get('version') == image_name,
- menu_entries))
+ sublist = list(filter(lambda x: (x.get('version') == image_name and
+ x.get('console_type') == console_type and
+ x.get('console_num') == console_num and
+ x.get('bootmode') == 'normal'),
+ menu_entries))
+ # legacy images added with legacy tools omitted 'ttyUSB'; if entry not
+ # available, default to initial entry of version
+ if not sublist:
+ sublist = list(filter(lambda x: x.get('version') == image_name,
+ menu_entries))
+
if sublist:
return menu_entries.index(sublist[0])
@@ -291,7 +303,7 @@ def grub_cfg_fields(root_dir: str = '') -> dict:
menu_entries = update_version_list(root_dir)
fields['versions'] = menu_entries
- default = get_default(menu_entries, root_dir)
+ default = get_default(fields, root_dir)
if default is not None:
fields['default'] = default
diff --git a/python/vyos/system/grub.py b/python/vyos/system/grub.py
index 864ed65aa..faf68c2d1 100644
--- a/python/vyos/system/grub.py
+++ b/python/vyos/system/grub.py
@@ -18,7 +18,6 @@ import platform
from pathlib import Path
from re import MULTILINE, compile as re_compile
from shutil import copy2
-from typing import Union
from uuid import uuid5, NAMESPACE_URL, UUID
from vyos.template import render
@@ -56,7 +55,7 @@ REGEX_KERNEL_CMDLINE: str = r'^BOOT_IMAGE=/(?P<boot_type>boot|live)/((?P<image_v
REGEX_GRUB_BOOT_OPTS: str = r'^\s*set boot_opts="(?P<boot_opts>[^$]+)"$'
-def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS') -> None:
+def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS', chroot : str = "") -> None:
"""Install GRUB for both BIOS and EFI modes (hybrid boot)
Args:
@@ -65,17 +64,22 @@ def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS') -> N
efi_dir (str): a path to '/boot/efi' directory
"""
+ if chroot:
+ chroot_cmd = f"chroot {chroot}"
+ else:
+ chroot_cmd = ""
+
efi_installation_arch = "x86_64"
if platform.machine() == "aarch64":
efi_installation_arch = "arm64"
elif platform.machine() == "x86_64":
cmd(
- f'grub-install --no-floppy --target=i386-pc \
+ f'{chroot_cmd} grub-install --no-floppy --target=i386-pc \
--boot-directory={boot_dir} {drive_path} --force'
)
cmd(
- f'grub-install --no-floppy --recheck --target={efi_installation_arch}-efi \
+ f'{chroot_cmd} grub-install --no-floppy --recheck --target={efi_installation_arch}-efi \
--force-extra-removable --boot-directory={boot_dir} \
--efi-directory={efi_dir} --bootloader-id="{id}" \
--no-uefi-secure-boot'
@@ -374,7 +378,7 @@ def create_structure(root_dir: str = '') -> None:
if not root_dir:
root_dir = disk.find_persistence()
- Path(f'{root_dir}/GRUB_DIR_VYOS_VERS').mkdir(parents=True, exist_ok=True)
+ Path(f'{root_dir}/{GRUB_DIR_VYOS_VERS}').mkdir(parents=True, exist_ok=True)
def set_console_type(console_type: str, root_dir: str = '') -> None:
diff --git a/python/vyos/template.py b/python/vyos/template.py
index ab06c7752..ac77e8a3d 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -32,8 +32,21 @@ _TESTS = {}
# reuse Environments with identical settings to improve performance
@functools.lru_cache(maxsize=2)
def _get_environment(location=None):
+ from os import getenv
+
if location is None:
- loc_loader=FileSystemLoader(directories["templates"])
+ # Sometimes functions that rely on templates need to be executed outside of VyOS installations:
+ # for example, installer functions are executed for image builds,
+ # and anything may be invoked for testing from a developer's machine.
+ # This environment variable allows running any unmodified code
+ # with a custom template location.
+ location_env_var = getenv("VYOS_TEMPLATE_DIR")
+ if location_env_var:
+ print(f"Using environment variable {location_env_var}")
+ template_dir = location_env_var
+ else:
+ template_dir = directories["templates"]
+ loc_loader=FileSystemLoader(template_dir)
else:
loc_loader=FileSystemLoader(location)
env = Environment(
@@ -294,7 +307,8 @@ def network_from_ipv4(address):
@register_filter('is_interface')
def is_interface(interface):
""" Check if parameter is a valid local interface name """
- return os.path.exists(f'/sys/class/net/{interface}')
+ from vyos.utils.network import interface_exists
+ return interface_exists(interface)
@register_filter('is_ip')
def is_ip(addr):
@@ -794,7 +808,7 @@ def kea_address_json(addresses):
out = []
for address in addresses:
- ifname = is_addr_assigned(address, return_ifname=True)
+ ifname = is_addr_assigned(address, return_ifname=True, include_vrf=True)
if not ifname:
continue
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index cac59475d..829124b57 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -310,7 +310,7 @@ def is_ipv6_link_local(addr):
return False
-def is_addr_assigned(ip_address, vrf=None, return_ifname=False) -> bool | str:
+def is_addr_assigned(ip_address, vrf=None, return_ifname=False, include_vrf=False) -> bool | str:
""" Verify if the given IPv4/IPv6 address is assigned to any interface """
from netifaces import interfaces
from vyos.utils.network import get_interface_config
@@ -321,7 +321,7 @@ def is_addr_assigned(ip_address, vrf=None, return_ifname=False) -> bool | str:
# case there is no need to proceed with this data set - continue loop
# with next element
tmp = get_interface_config(interface)
- if dict_search('master', tmp) != vrf:
+ if dict_search('master', tmp) != vrf and not include_vrf:
continue
if is_intf_addr_assigned(interface, ip_address):
diff --git a/python/vyos/utils/system.py b/python/vyos/utils/system.py
index 5d41c0c05..55813a5f7 100644
--- a/python/vyos/utils/system.py
+++ b/python/vyos/utils/system.py
@@ -79,13 +79,6 @@ def sysctl_apply(sysctl_dict: dict[str, str], revert: bool = True) -> bool:
# everything applied
return True
-def get_half_cpus():
- """ return 1/2 of the numbers of available CPUs """
- cpu = os.cpu_count()
- if cpu > 1:
- cpu /= 2
- return int(cpu)
-
def find_device_file(device):
""" Recurively search /dev for the given device file and return its full path.
If no device file was found 'None' is returned """
diff --git a/python/vyos/version.py b/python/vyos/version.py
index 1c5651c83..b5ed2705b 100644
--- a/python/vyos/version.py
+++ b/python/vyos/version.py
@@ -1,4 +1,4 @@
-# Copyright 2017-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2017-2024 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
@@ -30,7 +30,7 @@ Example of the version data dict::
"""
import os
-import json
+
import requests
import vyos.defaults
@@ -40,10 +40,8 @@ from vyos.utils.process import popen
from vyos.utils.process import run
from vyos.utils.process import DEVNULL
-
version_file = os.path.join(vyos.defaults.directories['data'], 'version.json')
-
def get_version_data(fname=version_file):
"""
Get complete version data
diff --git a/python/vyos/xml/generate.py b/python/vyos/xml/generate.py
index dfbbadd74..267cb84f6 100755
--- a/python/vyos/xml/generate.py
+++ b/python/vyos/xml/generate.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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,17 +12,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 sys
import pprint
import argparse
-from vyos.xml import kw
from vyos.xml import load
-
# import json
# def save_json(fname, loaded):
# with open(fname, 'w') as w:
diff --git a/python/vyos/xml/test_xml.py b/python/vyos/xml/test_xml.py
index 3a6f0132d..50fdc7470 100644
--- a/python/vyos/xml/test_xml.py
+++ b/python/vyos/xml/test_xml.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -13,22 +13,14 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-
-import os
-import unittest
-from unittest import TestCase, mock
+from unittest import TestCase
from vyos.xml import load_configuration
-import sys
-
-
class TestSearch(TestCase):
def setUp(self):
self.xml = load_configuration()
-
+
def test_(self):
last = self.xml.traverse("")
self.assertEqual(last, '')
diff --git a/python/vyos/xml_ref/generate_cache.py b/python/vyos/xml_ref/generate_cache.py
index d1ccb0f81..5f3f84dee 100755
--- a/python/vyos/xml_ref/generate_cache.py
+++ b/python/vyos/xml_ref/generate_cache.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -13,19 +13,14 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#
import sys
import json
from argparse import ArgumentParser
from argparse import ArgumentTypeError
-from os import getcwd
-from os import makedirs
from os.path import join
from os.path import abspath
from os.path import dirname
-from os.path import basename
from xmltodict import parse
_here = dirname(__file__)