summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/openvpn/server.conf.j22
-rw-r--r--interface-definitions/dns-forwarding.xml.in19
-rw-r--r--interface-definitions/include/radius-server-ipv4-ipv6.xml.i22
-rw-r--r--interface-definitions/include/source-address-ipv4-ipv6-multi.xml.i22
-rw-r--r--interface-definitions/system-login.xml.in16
-rw-r--r--python/vyos/progressbar.py33
-rw-r--r--python/vyos/remote.py43
-rw-r--r--python/vyos/utils/io.py10
-rwxr-xr-xsrc/migration-scripts/firewall/12-to-132
-rwxr-xr-xsrc/migration-scripts/policy/6-to-72
-rwxr-xr-xsrc/op_mode/generate_firewall_rule-resequence.py4
11 files changed, 77 insertions, 98 deletions
diff --git a/data/templates/openvpn/server.conf.j2 b/data/templates/openvpn/server.conf.j2
index 746155c37..c02411904 100644
--- a/data/templates/openvpn/server.conf.j2
+++ b/data/templates/openvpn/server.conf.j2
@@ -79,7 +79,7 @@ server {{ subnet | address_from_cidr }} {{ subnet | netmask_from_cidr }} {{ 'nop
{% if server.push_route is vyos_defined %}
{% for route, route_config in server.push_route.items() %}
{% if route | is_ipv4 %}
-push "route {{ route | address_from_cidr }} {{ route | netmask_from_cidr }} {{ subnet | first_host_address ~ ' ' ~ route_config.metric if route_config.metric is vyos_defined }}"
+push "route {{ route | address_from_cidr }} {{ route | netmask_from_cidr }} {{ 'vpn_gateway' ~ ' ' ~ route_config.metric if route_config.metric is vyos_defined }}"
{% elif route | is_ipv6 %}
push "route-ipv6 {{ route }}"
{% endif %}
diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in
index c4295317a..5ca02acef 100644
--- a/interface-definitions/dns-forwarding.xml.in
+++ b/interface-definitions/dns-forwarding.xml.in
@@ -684,25 +684,8 @@
<defaultValue>1500</defaultValue>
</leafNode>
#include <include/name-server-ipv4-ipv6-port.xml.i>
+ #include <include/source-address-ipv4-ipv6-multi.xml.i>
<leafNode name="source-address">
- <properties>
- <help>Local addresses from which to send DNS queries</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
- </completionHelp>
- <valueHelp>
- <format>ipv4</format>
- <description>IPv4 address from which to send traffic</description>
- </valueHelp>
- <valueHelp>
- <format>ipv6</format>
- <description>IPv6 address from which to send traffic</description>
- </valueHelp>
- <multi/>
- <constraint>
- <validator name="ip-address"/>
- </constraint>
- </properties>
<defaultValue>0.0.0.0 ::</defaultValue>
</leafNode>
<leafNode name="system">
diff --git a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
index a0cdcd7c3..e454b9025 100644
--- a/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
+++ b/interface-definitions/include/radius-server-ipv4-ipv6.xml.i
@@ -25,27 +25,7 @@
#include <include/radius-server-auth-port.xml.i>
</children>
</tagNode>
- <leafNode name="source-address">
- <properties>
- <help>Source IP address used to initiate connection</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
- </completionHelp>
- <valueHelp>
- <format>ipv4</format>
- <description>IPv4 source address</description>
- </valueHelp>
- <valueHelp>
- <format>ipv6</format>
- <description>IPv6 source address</description>
- </valueHelp>
- <constraint>
- <validator name="ipv4-address"/>
- <validator name="ipv6-address"/>
- </constraint>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/source-address-ipv4-ipv6-multi.xml.i>
<leafNode name="security-mode">
<properties>
<help>Security mode for RADIUS authentication</help>
diff --git a/interface-definitions/include/source-address-ipv4-ipv6-multi.xml.i b/interface-definitions/include/source-address-ipv4-ipv6-multi.xml.i
new file mode 100644
index 000000000..d56ca5be6
--- /dev/null
+++ b/interface-definitions/include/source-address-ipv4-ipv6-multi.xml.i
@@ -0,0 +1,22 @@
+<!-- include start from source-address-ipv4-ipv6-multi.xml.i -->
+<leafNode name="source-address">
+ <properties>
+ <help>Source IP address used to initiate connection</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_local_ips.sh --both</script>
+ </completionHelp>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 source address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 source address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-address"/>
+ </constraint>
+ <multi/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/system-login.xml.in b/interface-definitions/system-login.xml.in
index 30fea91b0..a2f8beead 100644
--- a/interface-definitions/system-login.xml.in
+++ b/interface-definitions/system-login.xml.in
@@ -244,21 +244,7 @@
</leafNode>
</children>
</tagNode>
- <leafNode name="source-address">
- <properties>
- <help>Source IP used to communicate with TACACS+ server</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_local_ips.sh --ipv4</script>
- </completionHelp>
- <valueHelp>
- <format>ipv4</format>
- <description>IPv4 source address</description>
- </valueHelp>
- <constraint>
- <validator name="ipv4-address"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/source-address-ipv4.xml.i>
<leafNode name="security-mode">
<properties>
<help>Security mode for TACACS+ authentication</help>
diff --git a/python/vyos/progressbar.py b/python/vyos/progressbar.py
index 1793c445b..7bc9d9856 100644
--- a/python/vyos/progressbar.py
+++ b/python/vyos/progressbar.py
@@ -19,26 +19,35 @@ 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
self.step = step
+ # Silently ignore all calls if terminal capabilities are lacking.
+ # This will also prevent the output from littering Ansible logs,
+ # as `ansible.netcommon.network_cli' coaxes the terminal into believing
+ # it is interactive.
+ self._dumb = is_dumb_terminal()
def __enter__(self):
- # Recalculate terminal width with every window resize.
- signal.signal(signal.SIGWINCH, lambda signum, frame: self._update_cols())
- # Disable line wrapping to prevent the staircase effect.
- subprocess.run(['tput', 'rmam'], check=False)
- self._update_cols()
- # Print an empty progressbar with entry.
- self.progress(0, 1)
+ if not self._dumb:
+ # Recalculate terminal width with every window resize.
+ signal.signal(signal.SIGWINCH, lambda signum, frame: self._update_cols())
+ # Disable line wrapping to prevent the staircase effect.
+ subprocess.run(['tput', 'rmam'], check=False)
+ self._update_cols()
+ # Print an empty progressbar with entry.
+ self.progress(0, 1)
return self
def __exit__(self, exc_type, kexc_val, exc_tb):
- # Revert to the default SIGWINCH handler (ie nothing).
- signal.signal(signal.SIGWINCH, signal.SIG_DFL)
- # Reenable line wrapping.
- subprocess.run(['tput', 'smam'], check=False)
+ if not self._dumb:
+ # Revert to the default SIGWINCH handler (ie nothing).
+ signal.signal(signal.SIGWINCH, signal.SIG_DFL)
+ # Reenable line wrapping.
+ subprocess.run(['tput', 'smam'], check=False)
def _update_cols(self):
# `os.get_terminal_size()' is fast enough for our purposes.
self.col = max(os.get_terminal_size().columns - 15, 20)
@@ -60,7 +69,7 @@ class Progressbar:
Stateless progressbar taking no input at init and current progress with
final size at callback (for SSH)
"""
- if done <= total:
+ if done <= total and not self._dumb:
length = math.ceil(self.col * done / total)
percentage = str(math.ceil(100 * done / total)).rjust(3)
# Carriage return at the end will make sure the line will get overwritten.
diff --git a/python/vyos/remote.py b/python/vyos/remote.py
index 1ca8a9530..4be477d24 100644
--- a/python/vyos/remote.py
+++ b/python/vyos/remote.py
@@ -34,6 +34,7 @@ from requests.packages.urllib3 import PoolManager
from vyos.progressbar import Progressbar
from vyos.utils.io import ask_yes_no
+from vyos.utils.io import is_interactive
from vyos.utils.io import print_error
from vyos.utils.misc import begin
from vyos.utils.process import cmd
@@ -49,7 +50,7 @@ class InteractivePolicy(MissingHostKeyPolicy):
def missing_host_key(self, client, hostname, key):
print_error(f"Host '{hostname}' not found in known hosts.")
print_error('Fingerprint: ' + key.get_fingerprint().hex())
- if sys.stdout.isatty() and ask_yes_no('Do you wish to continue?'):
+ if is_interactive() and ask_yes_no('Do you wish to continue?'):
if client._host_keys_filename\
and ask_yes_no('Do you wish to permanently add this host/key pair to known hosts?'):
client._host_keys.add(hostname, key.get_name(), key)
@@ -250,7 +251,6 @@ class HttpC:
allow_redirects=True,
timeout=self.timeout) as r:
# Abort early if the destination is inaccessible.
- print('pre-3')
r.raise_for_status()
# If the request got redirected, keep the last URL we ended up with.
final_urlstring = r.url
@@ -323,17 +323,25 @@ def urlc(urlstring, *args, **kwargs):
except KeyError:
raise ValueError(f'Unsupported URL scheme: "{url.scheme}"')
-def download(local_path, urlstring, *args, **kwargs):
+def download(local_path, urlstring, progressbar=False, check_space=False,
+ source_host='', source_port=0, timeout=10.0):
try:
- urlc(urlstring, *args, **kwargs).download(local_path)
+ progressbar = progressbar and is_interactive()
+ urlc(urlstring, progressbar, check_space, source_host, source_port, timeout).download(local_path)
except Exception as err:
print_error(f'Unable to download "{urlstring}": {err}')
+ except KeyboardInterrupt:
+ print_error('\nDownload aborted by user.')
-def upload(local_path, urlstring, *args, **kwargs):
+def upload(local_path, urlstring, progressbar=False,
+ source_host='', source_port=0, timeout=10.0):
try:
- urlc(urlstring, *args, **kwargs).upload(local_path)
+ progressbar = progressbar and is_interactive()
+ urlc(urlstring, progressbar, source_host, source_port, timeout).upload(local_path)
except Exception as err:
print_error(f'Unable to upload "{urlstring}": {err}')
+ except KeyboardInterrupt:
+ print_error('\nUpload aborted by user.')
def get_remote_config(urlstring, source_host='', source_port=0):
"""
@@ -346,26 +354,3 @@ def get_remote_config(urlstring, source_host='', source_port=0):
return f.read()
finally:
os.remove(temp)
-
-def friendly_download(local_path, urlstring, source_host='', source_port=0):
- """
- Download with a progress bar, reassuring messages and free space checks.
- """
- try:
- print_error('Downloading...')
- download(local_path, urlstring, True, True, source_host, source_port)
- except KeyboardInterrupt:
- print_error('\nDownload aborted by user.')
- sys.exit(1)
- except:
- import traceback
- print_error(f'Failed to download {urlstring}.')
- # There are a myriad different reasons a download could fail.
- # SSH errors, FTP errors, I/O errors, HTTP errors (403, 404...)
- # We omit the scary stack trace but print the error nevertheless.
- exc_type, exc_value, exc_traceback = sys.exc_info()
- traceback.print_exception(exc_type, exc_value, None, 0, None, False)
- sys.exit(1)
- else:
- print_error('Download complete.')
- sys.exit(0)
diff --git a/python/vyos/utils/io.py b/python/vyos/utils/io.py
index 5fffa62f8..8790cbaac 100644
--- a/python/vyos/utils/io.py
+++ b/python/vyos/utils/io.py
@@ -62,3 +62,13 @@ def ask_yes_no(question, default=False) -> bool:
stdout.write("Please respond with yes/y or no/n\n")
except EOFError:
stdout.write("\nPlease respond with yes/y or no/n\n")
+
+def is_interactive():
+ """Try to determine if the routine was called from an interactive shell."""
+ import os, sys
+ return os.getenv('TERM', default=False) and sys.stderr.isatty() and sys.stdout.isatty()
+
+def is_dumb_terminal():
+ """Check if the current TTY is dumb, so that we can disable advanced terminal features."""
+ import os
+ return os.getenv('TERM') in ['vt100', 'dumb']
diff --git a/src/migration-scripts/firewall/12-to-13 b/src/migration-scripts/firewall/12-to-13
index c2b34b2d8..4eaae779b 100755
--- a/src/migration-scripts/firewall/12-to-13
+++ b/src/migration-scripts/firewall/12-to-13
@@ -70,7 +70,7 @@ for family in ['ipv4', 'ipv6', 'bridge']:
state_value = config.return_value(base + [family, hook, priority, 'rule', rule, 'state', state])
config.delete(base + [family, hook, priority, 'rule', rule, 'state', state])
if state_value == 'enable':
- config.set(base + [family, hook, priority, 'rule', rule, 'state', state])
+ config.set(base + [family, hook, priority, 'rule', rule, 'state'], value=state, replace=False)
flag_enable = 'True'
if flag_enable == 'False':
config.delete(base + [family, hook, priority, 'rule', rule, 'state'])
diff --git a/src/migration-scripts/policy/6-to-7 b/src/migration-scripts/policy/6-to-7
index 1f955aa02..727b8487a 100755
--- a/src/migration-scripts/policy/6-to-7
+++ b/src/migration-scripts/policy/6-to-7
@@ -66,7 +66,7 @@ for family in ['route', 'route6']:
state_value = config.return_value(base + [family, policy_name, 'rule', rule, 'state', state])
config.delete(base + [family, policy_name, 'rule', rule, 'state', state])
if state_value == 'enable':
- config.set(base + [family, policy_name, 'rule', rule, 'state', state])
+ config.set(base + [family, policy_name, 'rule', rule, 'state'], value=state, replace=False)
flag_enable = 'True'
if flag_enable == 'False':
config.delete(base + [family, policy_name, 'rule', rule, 'state'])
diff --git a/src/op_mode/generate_firewall_rule-resequence.py b/src/op_mode/generate_firewall_rule-resequence.py
index eb82a1a0a..21441f689 100755
--- a/src/op_mode/generate_firewall_rule-resequence.py
+++ b/src/op_mode/generate_firewall_rule-resequence.py
@@ -41,6 +41,10 @@ def convert_to_set_commands(config_dict, parent_key=''):
commands.extend(
convert_to_set_commands(value, f"{current_key} "))
+ elif isinstance(value, list):
+ for item in value:
+ commands.append(f"set {current_key} '{item}'")
+
elif isinstance(value, str):
commands.append(f"set {current_key} '{value}'")