diff options
-rw-r--r-- | python/vyos/config.py | 57 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bonding.py | 22 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_salt.py | 94 | ||||
-rwxr-xr-x | src/conf_mode/salt-minion.py | 2 | ||||
-rw-r--r-- | src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper | 2 |
5 files changed, 162 insertions, 15 deletions
diff --git a/python/vyos/config.py b/python/vyos/config.py index a5c1ad122..287fd2ed1 100644 --- a/python/vyos/config.py +++ b/python/vyos/config.py @@ -142,31 +142,41 @@ class Config(object): def exists(self, path): """ - Checks if a node with given path exists in the running or proposed config + Checks if a node or value with given path exists in the proposed config. + + Args: + path (str): Configuration tree path Returns: - True if node exists, False otherwise + True if node or value exists in the proposed config, False otherwise Note: - This function cannot be used outside a configuration sessions. + This function should not be used outside of configuration sessions. In operational mode scripts, use ``exists_effective``. """ - if not self._session_config: + if self._session_config is None: return False + + # Assume the path is a node path first if self._session_config.exists(self._make_path(path)): return True else: + # If that check fails, it may mean the path has a value at the end. # libvyosconfig exists() works only for _nodes_, not _values_ - # libvyattacfg one also worked for values, so we emulate that case here + # libvyattacfg also worked for values, so we emulate that case here if isinstance(path, str): path = re.split(r'\s+', path) path_without_value = path[:-1] - path_str = " ".join(path_without_value) try: - value = self._session_config.return_value(self._make_path(path_str)) - return (value == path[-1]) + # return_values() is safe to use with single-value nodes, + # it simply returns a single-item list in that case. + values = self._session_config.return_values(self._make_path(path_without_value)) + + # If we got this far, the node does exist and has values, + # so we need to check if it has the value in question among its values. + return (path[-1] in values) except vyos.configtree.ConfigTreeError: - # node doesn't exist at all + # Even the parent node doesn't exist at all return False def session_changed(self): @@ -380,7 +390,7 @@ class Config(object): def exists_effective(self, path): """ - Check if a node exists in the running (effective) config + Checks if a node or value exists in the running (effective) config. Args: path (str): Configuration tree path @@ -392,10 +402,31 @@ class Config(object): This function is safe to use in operational mode. In configuration mode, it ignores uncommited changes. """ - if self._running_config: - return(self._running_config.exists(self._make_path(path))) + if self._running_config is None: + return False + + # Assume the path is a node path first + if self._running_config.exists(self._make_path(path)): + return True + else: + # If that check fails, it may mean the path has a value at the end. + # libvyosconfig exists() works only for _nodes_, not _values_ + # libvyattacfg also worked for values, so we emulate that case here + if isinstance(path, str): + path = re.split(r'\s+', path) + path_without_value = path[:-1] + try: + # return_values() is safe to use with single-value nodes, + # it simply returns a single-item list in that case. + values = self._running_config.return_values(self._make_path(path_without_value)) + + # If we got this far, the node does exist and has values, + # so we need to check if it has the value in question among its values. + return (path[-1] in values) + except vyos.configtree.ConfigTreeError: + # Even the parent node doesn't exist at all + return False - return False def return_effective_value(self, path, default=None): """ diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index 4f2fe979a..9bb561275 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -165,5 +165,27 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase): self.cli_commit() + def test_bonding_uniq_member_description(self): + ethernet_path = ['interfaces', 'ethernet'] + for interface in self._interfaces: + for option in self._options.get(interface, []): + self.cli_set(self._base_path + [interface] + option.split()) + + self.cli_commit() + + # Add any changes on bonding members + # For example add description on separate ethX interfaces + for interface in self._interfaces: + for member in self._members: + self.cli_set(ethernet_path + [member, 'description', member + '_interface']) + + self.cli_commit() + + # verify config + for interface in self._interfaces: + slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split() + for member in self._members: + self.assertIn(member, slaves) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_service_salt.py b/smoketest/scripts/cli/test_service_salt.py new file mode 100755 index 000000000..5b328677e --- /dev/null +++ b/smoketest/scripts/cli/test_service_salt.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 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 +# published by the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# 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 unittest + +from socket import gethostname +from base_vyostest_shim import VyOSUnitTestSHIM + +from vyos.util import process_named_running +from vyos.util import read_file +from vyos.util import cmd + +PROCESS_NAME = 'salt-minion' +SALT_CONF = '/etc/salt/minion' +base_path = ['service', 'salt-minion'] + +class TestServiceSALT(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(TestServiceSALT, cls).setUpClass() + + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + + def tearDown(self): + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + # delete testing SALT config + self.cli_delete(base_path) + self.cli_commit() + + # For an unknown reason on QEMU systems (e.g. where smoketests are executed + # from the CI) salt-minion process is not killed by systemd. Apparently + # no issue on VMWare. + if cmd('systemd-detect-virt') != 'kvm': + self.assertFalse(process_named_running(PROCESS_NAME)) + + def test_default(self): + servers = ['192.0.2.1', '192.0.2.2'] + + for server in servers: + self.cli_set(base_path + ['master', server]) + + self.cli_commit() + + # commiconf = read_file() Check configured port + conf = read_file(SALT_CONF) + self.assertIn(f'- {server}', conf) + + # defaults + hostname = gethostname() + self.assertIn(f'hash_type: sha256', conf) + self.assertIn(f'id: {hostname}', conf) + self.assertIn(f'mine_interval: 60', conf) + + def test_options(self): + server = '192.0.2.3' + hash = 'sha1' + id = 'foo' + interval = '120' + + self.cli_set(base_path + ['master', server]) + self.cli_set(base_path + ['hash', hash]) + self.cli_set(base_path + ['id', id]) + self.cli_set(base_path + ['interval', interval]) + + self.cli_commit() + + # commiconf = read_file() Check configured port + conf = read_file(SALT_CONF) + self.assertIn(f'- {server}', conf) + + # defaults + self.assertIn(f'hash_type: {hash}', conf) + self.assertIn(f'id: {id}', conf) + self.assertIn(f'mine_interval: {interval}', conf) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/conf_mode/salt-minion.py b/src/conf_mode/salt-minion.py index 841bf6a39..5a8528741 100755 --- a/src/conf_mode/salt-minion.py +++ b/src/conf_mode/salt-minion.py @@ -39,7 +39,7 @@ default_config_data = { 'user': 'minion', 'group': 'vyattacfg', 'salt_id': gethostname(), - 'mine_interval': '60', + 'interval': '60', 'verify_master_pubkey_sign': 'false', 'master_key': '' } diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper index fc035766b..2bd2d1d22 100644 --- a/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper +++ b/src/etc/dhcp/dhclient-enter-hooks.d/03-vyos-ipwrapper @@ -23,7 +23,7 @@ function iptovtysh () { local VTYSH_GATEWAY="" local VTYSH_DEV="" local VTYSH_TAG="210" - local VTYSH_DISTANCE="" + local VTYSH_DISTANCE=$IF_METRIC # convert default route to 0.0.0.0/0 if [ "$4" == "default" ] ; then VTYSH_NETADDR="0.0.0.0/0" |