diff options
28 files changed, 735 insertions, 153 deletions
diff --git a/data/templates/dynamic-dns/ddclient.conf.tmpl b/data/templates/dynamic-dns/ddclient.conf.tmpl index 22cb38f4e..9c7219230 100644 --- a/data/templates/dynamic-dns/ddclient.conf.tmpl +++ b/data/templates/dynamic-dns/ddclient.conf.tmpl @@ -1,10 +1,7 @@ - ### Autogenerated by dynamic_dns.py ### daemon=1m syslog=yes ssl=yes -pid={{ pid_file }} -cache={{ cache_file }} {% for interface in interfaces -%} diff --git a/op-mode-definitions/ipoe-server.xml b/op-mode-definitions/ipoe-server.xml index c05e2d2c1..c20d3aa2a 100644 --- a/op-mode-definitions/ipoe-server.xml +++ b/op-mode-definitions/ipoe-server.xml @@ -12,24 +12,33 @@ <help>Clear ipoe-server session</help> </properties> <children> - <leafNode name="username"> + <tagNode name="username"> <properties> <help>Clear ipoe-server session by username</help> <completionHelp> - <script>/usr/bin/accel-cmd -p 2002 show sessions username | sed -e 's/ \r//g' | tail -n +3</script> + <script>${vyos_completion_dir}/list_ipoe.py --selector="username"</script> </completionHelp> </properties> - <command>/usr/bin/accel-cmd -p 2002 terminate username $5</command> - </leafNode> - <leafNode name="sid"> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="terminate" --selector="username" --target="$5"</command> + </tagNode> + <tagNode name="sid"> <properties> - <help>Clear ipoe-server session by sid</help> + <help>Clear ipoe-server session by Session ID</help> <completionHelp> - <script>/usr/bin/accel-cmd -p 2002 show sessions sid | sed -e 's/ \r//g' | tail -n +3</script> + <script>${vyos_completion_dir}/list_ipoe.py --selector="sid"</script> </completionHelp> </properties> - <command>/usr/bin/accel-cmd -p 2002 terminate sid $5</command> - </leafNode> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="terminate" --selector="sid" --target="$5"</command> + </tagNode> + <tagNode name="interface"> + <properties> + <help>Clear ipoe-server session by interface</help> + <completionHelp> + <script>${vyos_completion_dir}/list_ipoe.py --selector="ifname"</script> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="terminate" --selector="if" --target="$5"</command> + </tagNode> </children> </node> </children> @@ -47,13 +56,13 @@ <properties> <help>Show active IPoE server sessions</help> </properties> - <command>/usr/bin/accel-cmd -p 2002 show sessions ifname,username,called-sid,calling-sid,ip,ip6,ip6-dp,rate-limit,state,uptime,sid</command> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="show_sessions"</command> </leafNode> <leafNode name="statistics"> <properties> <help>Show IPoE server statistics</help> </properties> - <command>/usr/bin/accel-cmd -p 2002 show stat</command> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="show_stat"</command> </leafNode> </children> </node> @@ -65,7 +74,7 @@ <properties> <help>show ipoe-server status</help> </properties> - <command>if [ -e /var/run/accel_ipoe.pid ]; then /usr/bin/accel-cmd restart -p 2002; else echo "ipoe-server not running"; fi</command> + <command>${vyos_op_scripts_dir}/ipoe-control.py --action="restart"</command> </leafNode> </children> </node> diff --git a/op-mode-definitions/show-ip-bgp.xml b/op-mode-definitions/show-ip-bgp.xml new file mode 100644 index 000000000..5eb2ae56e --- /dev/null +++ b/op-mode-definitions/show-ip-bgp.xml @@ -0,0 +1,342 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="ip"> + <children> + <node name="bgp"> + <properties> + <help>Show Border Gateway Protocol (BGP) information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp"</command> + <children> + <leafNode name="attribute-info"> + <properties> + <help>Show BGP attribute information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp attribute-info"</command> + </leafNode> + <leafNode name="cidr-only"> + <properties> + <help>Display only routes with non-natural netmasks</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp cidr-only"</command> + </leafNode> + <node name="community"> + <properties> + <help>Show BGP routes matching the communities</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp community"</command> + </node> + <tagNode name="community"> + <properties> + <help>Display routes matching the specified communities</help> + <completionHelp> + <list><AA:NN> local-AS no-advertise no-export</list> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp community $5"</command> + </tagNode> + <leafNode name="community-info"> + <properties> + <help>List all bgp community information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp community-info"</command> + </leafNode> + <tagNode name="community-list"> + <properties> + <help>Show BGP routes matching specified community list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp community-list $5"</command> + <children> + <leafNode name="exact-match"> + <properties> + <help>Show BGP routes exactly matching specified community list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp community-list $5 exact-match"</command> + </leafNode> + </children> + </tagNode> + <leafNode name="dampened-paths"> + <properties> + <help>Show dampened BGP paths</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp dampening dampened-paths"</command> + </leafNode> + <tagNode name="filter-list"> + <properties> + <help>Show BGP information for specified word</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp filter-list $5"</command> + </tagNode> + <leafNode name="flap-statistics"> + <properties> + <help>Show flap statistics of routes</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp dampening flap-statistics"</command> + </leafNode> + <node name="ipv4"> + <properties> + <help>Show BGP IPv4 information</help> + </properties> + <children> + <node name="unicast"> + <properties> + <help>Show BGP IPv4 unicast information</help> + </properties> + <children> + <leafNode name="cidr-only"> + <properties> + <help>Display only routes with non-natural netmasks</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast cidr-only"</command> + </leafNode> + <node name="community"> <!-- START new code --> + <properties> + <help>Show BGP routes matching the communities</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community"</command> + </node> + <tagNode name="community"> + <properties> + <help>Display routes matching the specified communities</help> + <completionHelp> + <list><AA:NN> local-AS no-advertise no-export</list> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community $7"</command> + </tagNode> + <tagNode name="community-list"> + <properties> + <help>Show BGP routes matching specified community list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community-list $7"</command> + <children> + <leafNode name="exact-match"> + <properties> + <help>Show BGP routes exactly matching specified community list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast community-list $7 exact-match"</command> + </leafNode> + </children> + </tagNode> + <tagNode name="filter-list"> + <properties> + <help>Show BGP information for specified word</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp filter-list $5"</command> + </tagNode> + <tagNode name="neighbors"> + <properties> + <help>Show detailed BGP IPv4 unicast neighbor information</help> + <completionHelp> + <script>vtysh -c "show ip bgp ipv4 unicast summary" | awk '{print $1}' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"</script> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbors $7"</command> + <children> + <leafNode name="advertised-routes"> + <properties> + <help>Show routes advertised to a BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 advertised-routes"</command> + </leafNode> + <leafNode name="prefix-counts"> + <properties> + <help>Show detailed prefix count information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 prefix-counts"</command> + </leafNode> + <leafNode name="received-routes"> + <properties> + <help>Show the received routes from neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 received-routes"</command> + </leafNode> + <leafNode name="routes"> + <properties> + <help>Show routes learned from neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast neighbor $7 routes"</command> + </leafNode> + </children> + </tagNode> + <leafNode name="paths"> + <properties> + <help>Show BGP path information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast paths"</command> + </leafNode> + <tagNode name="prefix-list"> + <properties> + <help>Show BGP routes matching the specified prefix list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast prefix-list $7"</command> + </tagNode> + <tagNode name="regexp"> + <properties> + <help>Show BGP routes matching the specified AS path regular expression</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp ipv4 unicast regexp $5"</command> + </tagNode> + <tagNode name="route-map"> + <properties> + <help>Show BGP routes matching the specified route map</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp route-map $5"</command> + </tagNode> + <leafNode name="summary"> + <properties> + <help>Show summary of BGP information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp summary"</command> + </leafNode> + </children> + </node> + <tagNode name="unicast"> + <properties> + <help>Show BGP information for specified IP address or prefix</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x></list> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp $6"</command> + </tagNode> + </children> + </node> + <node name="large-community"> + <properties> + <help>Show BGP routes matching the specified large-communities</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp large-community"</command> + </node> + <leafNode name="large-community-info"> + <properties> + <help>Show BGP large-community information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp large-community-info"</command> + </leafNode> + <tagNode name="large-community-list"> + <properties> + <help>Show BGP routes matching the specified large-community list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp large-community-list $5"</command> + </tagNode> + <leafNode name="memory"> + <properties> + <help>Show BGP memory usage</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp memory"</command> + </leafNode> + <tagNode name="neighbors"> + <properties> + <help>Show detailed BGP IPv4 unicast neighbor information</help> + <completionHelp> + <script>vtysh -c "show ip bgp summary" | awk '{print $1}' | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"</script> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbors $5"</command> + <children> + <leafNode name="advertised-routes"> + <properties> + <help>Show routes advertised to a BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 advertised-routes"</command> + </leafNode> + <leafNode name="dampened-routes"> + <properties> + <help>Show dampened routes received from BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 dampened-routes"</command> + </leafNode> + <leafNode name="flap-statistics"> + <properties> + <help>Show flap statistics of the routes learned from BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 flap-statistics"</command> + </leafNode> + <leafNode name="prefix-counts"> + <properties> + <help>Show detailed prefix count information for BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 prefix-counts"</command> + </leafNode> + <node name="received"> + <properties> + <help>Show information received from BGP neighbor</help> + </properties> + <children> + <leafNode name="prefix-filter"> + <properties> + <help>Show prefixlist filter</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 received prefix-filter"</command> + </leafNode> + </children> + </node> + <leafNode name="received-routes"> + <properties> + <help>Show received routes from BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 received-routes"</command> + </leafNode> + <leafNode name="routes"> + <properties> + <help>Show routes learned from BGP neighbor</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp neighbor $5 routes"</command> + </leafNode> + </children> + </tagNode> + <leafNode name="paths"> + <properties> + <help>Show BGP path information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp paths"</command> + </leafNode> + <tagNode name="prefix-list"> + <properties> + <help>Show BGP routes matching the specified prefix list</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp prefix-list $5"</command> + </tagNode> + <tagNode name="regexp"> + <properties> + <help>Show BGP routes matching the specified AS path regular expression</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp regexp $5"</command> + </tagNode> + <tagNode name="route-map"> + <properties> + <help>Show BGP routes matching the specified route map</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp route-map $5"</command> + </tagNode> + <leafNode name="statistics"> + <properties> + <help>Show summary of BGP information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp statistics"</command> + </leafNode> + <leafNode name="summary"> + <properties> + <help>Show summary of BGP information</help> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp summary"</command> + </leafNode> + </children> + </node> + <tagNode name="bgp"> + <properties> + <help>Show BGP information for specified IP address or prefix</help> + <completionHelp> + <list><x.x.x.x> <x.x.x.x/x></list> + </completionHelp> + </properties> + <command>/usr/bin/vtysh -c "show ip bgp $4"</command> + </tagNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/python/vyos/airbag.py b/python/vyos/airbag.py index 664974d5f..b0565192d 100644 --- a/python/vyos/airbag.py +++ b/python/vyos/airbag.py @@ -19,10 +19,10 @@ import logging import logging.handlers from datetime import datetime +from vyos import debug from vyos.config import Config from vyos.version import get_version from vyos.util import run -from vyos.util import debug # we allow to disable the extra logging @@ -77,8 +77,7 @@ def bug_report(dtype, value, trace): # reach the end of __main__ and was not intercepted def intercepter(dtype, value, trace): bug_report(dtype, value, trace) - # debug returns either '' or 'developer' if debuging is enabled - if debug('developer'): + if debug.enabled('developer'): import pdb pdb.pm() diff --git a/python/vyos/debug.py b/python/vyos/debug.py new file mode 100644 index 000000000..20090fb85 --- /dev/null +++ b/python/vyos/debug.py @@ -0,0 +1,182 @@ +# Copyright 2019 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 +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# 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, see <http://www.gnu.org/licenses/>. + +import os +import sys + + +def message(message, flag='', destination=sys.stdout): + """ + print a debug message line on stdout if debugging is enabled for the flag + also log it to a file if the flag 'log' is enabled + + message: the message to print + flag: which flag must be set for it to print + destination: which file like object to write to (default: sys.stdout) + + returns if any message was logged or not + """ + enable = enabled(flag) + if enable: + destination.write(_format(flag,message)) + + # the log flag is special as it logs all the commands + # executed to a log + logfile = _logfile('log', '/tmp/developer-log') + if not logfile: + return enable + + try: + # at boot the file is created as root:vyattacfg + # at runtime the file is created as user:vyattacfg + # the default permission are 644 + mask = os.umask(0o113) + + with open(logfile, 'a') as f: + f.write(_format('log', message)) + finally: + os.umask(mask) + + return enable + + +def enabled(flag): + """ + a flag can be set by touching the file in /tmp or /config + + The current flags are: + - developer: the code will drop into PBD on un-handled exception + - log: the code will log all command to a file + - ifconfig: when modifying an interface, + prints command with result and sysfs access on stdout for interface + - command: print command run with result + + Having the flag setup on the filesystem is required to have + debuging at boot time, however, setting the flag via environment + does not require a seek to the filesystem and is more efficient + it can be done on the shell on via .bashrc for the user + + The function returns an empty string if the flag was not set otherwise + the function returns either the file or environment name used to set it up + """ + + # this is to force all new flags to be registered here to be + # documented both here and a reminder to update readthedocs :-) + if flag not in ['developer', 'log', 'ifconfig', 'command']: + return '' + + return _fromenv(flag) or _fromfile(flag) + + +def _format(flag, message): + """ + format a log message + """ + return f'DEBUG/{flag.upper():<7} {message}\n' + + +def _fromenv(flag): + """ + check if debugging is set for this flag via environment + + For a given debug flag named "test" + The presence of the environment VYOS_TEST_DEBUG (uppercase) enables it + + return empty string if not + return content of env value it is + """ + + flagname = f'VYOS_{flag.upper()}_DEBUG' + flagenv = os.environ.get(flagname, None) + + if flagenv is None: + return '' + return flagenv + + +def _fromfile(flag): + """ + Check if debug exist for a given debug flag name + + Check is a debug flag was set by the user. the flag can be set either: + - in /tmp for a non-persistent presence between reboot + - in /config for always on (an existence at boot time) + + For a given debug flag named "test" + The presence of the file vyos.test.debug (all lowercase) enables it + + The function returns an empty string if the flag was not set otherwise + the function returns the full flagname + """ + + for folder in ('/tmp', '/config'): + flagfile = f'{folder}/vyos.{flag}.debug' + if os.path.isfile(flagfile): + return flagfile + + return '' + + +def _contentenv(flag): + return os.environ.get(f'VYOS_{flag.upper()}_DEBUG', '').strip() + + +def _contentfile(flag): + """ + Check if debug exist for a given debug flag name + + Check is a debug flag was set by the user. the flag can be set either: + - in /tmp for a non-persistent presence between reboot + - in /config for always on (an existence at boot time) + + For a given debug flag named "test" + The presence of the file vyos.test.debug (all lowercase) enables it + + The function returns an empty string if the flag was not set otherwise + the function returns the full flagname + """ + + for folder in ('/tmp', '/config'): + flagfile = f'{folder}/vyos.{flag}.debug' + if not os.path.isfile(flagfile): + continue + with open(flagfile) as f: + return f.readline().strip() + + return '' + + +def _logfile(flag, default): + """ + return the name of the file to use for logging when the flag 'log' is set + if it could not be established or the location is invalid it returns + an empty string + """ + + # For log we return the location of the log file + log_location = _contentenv(flag) or _contentfile(flag) + + # it was not set + if not log_location: + return '' + + # Make sure that the logs can only be in /tmp, /var/log, or /tmp + if not log_location.startswith('/tmp/') and \ + not log_location.startswith('/config/') and \ + not log_location.startswith('/var/log/'): + return default + if '..' in log_location: + return default + return log_location diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index 464cd585e..7bb63beed 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -16,8 +16,9 @@ import os -from vyos.util import debug, debug_msg -from vyos.util import popen, cmd +from vyos import debug +from vyos.util import popen +from vyos.util import cmd from vyos.ifconfig.section import Section @@ -35,10 +36,10 @@ class Control(Section): # if debug is not explicitely disabled the the config, enable it self.debug = '' if kargs.get('debug', True): - self.debug = debug('ifconfig') + self.debug = debug.enabled('ifconfig') def _debug_msg (self, message): - return debug_msg(message, self.debug) + return debug.message(message, self.debug) def _popen(self, command): return popen(command, self.debug) diff --git a/python/vyos/util.py b/python/vyos/util.py index 14020e2d9..49c47cd85 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -21,48 +21,7 @@ from subprocess import PIPE from subprocess import STDOUT from subprocess import DEVNULL - -def debug(flag): - """ - Check is a debug flag was set by the user. - a flag can be set by touching the file /tmp/vyos.flag.debug - with flag being the flag name, the current flags are: - - developer: the code will drop into PBD on un-handled exception - - ifconfig: prints command and sysfs access on stdout for interface - The function returns an empty string if the flag was not set, - """ - - # this is to force all new flags to be registered here to be documented: - if flag not in ['developer', 'ifconfig']: - return '' - for folder in ('/tmp', '/config'): - if os.path.isfile(f'{folder}/vyos.{flag}.debug'): - return flag - return '' - - -def debug_msg(message, flag=''): - """ - print a debug message line on stdout if debugging is enabled for the flag - """ - - if debug(flag): - print(f'DEBUG/{flag:<6} {message}') - - if not debug('developer'): - return - - logfile = '/tmp/full-log' - existed = os.path.exists(logfile) - - with open(logfile, 'a') as f: - f.write(f'DEBUG/{flag:<6} {message}\n') - if not existed: - # at boot the file is created as root:vyattacfg - # at runtime the file is created as user:vyattacfg - # do not use run/cmd to not have a recursive call to this code - os.system(f'chmod g+w {logfile}') - +from vyos import debug # There is many (too many) ways to run command with python # os.system, subprocess.Popen, subproces.{run,call,check_output} @@ -98,7 +57,14 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None, to get both stdout, and stderr: popen('command', stdout=PIPE, stderr=STDOUT) to discard stdout and get stderr: popen('command', stdout=DEVNUL, stderr=PIPE) """ - debug_msg(f"cmd '{command}'", flag) + + # log if the flag is set, otherwise log if command is set + if not debug.enabled(flag): + flag = 'command' + + cmd_msg = f"cmd '{command}'" + debug.message(cmd_msg, flag) + use_shell = shell stdin = None if shell is None: @@ -129,7 +95,8 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None, nl = '\n' if decoded1 and decoded2 else '' decoded = decoded1 + nl + decoded2 if decoded: - debug_msg(f"returned:\n{decoded}", flag) + ret_msg = f"returned:\n{decoded}" + debug.message(ret_msg, flag) return decoded, p.returncode diff --git a/src/completion/list_ipoe.py b/src/completion/list_ipoe.py new file mode 100755 index 000000000..c386b46a2 --- /dev/null +++ b/src/completion/list_ipoe.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import argparse +from vyos.util import popen + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--selector', help='Selector: username|ifname|sid', required=True) + args = parser.parse_args() + + output, err = popen("accel-cmd -p 2002 show sessions {0}".format(args.selector)) + if not err: + res = output.split("\r\n") + # Delete header from list + del res[:2] + print(' '.join(res)) diff --git a/src/conf_mode/bcast_relay.py b/src/conf_mode/bcast_relay.py index 0069218f6..a3bc76ef8 100755 --- a/src/conf_mode/bcast_relay.py +++ b/src/conf_mode/bcast_relay.py @@ -146,7 +146,7 @@ def generate(relay): def apply(relay): # first stop all running services - call('sudo systemctl stop udp-broadcast-relay@{1..99}') + call('systemctl stop udp-broadcast-relay@{1..99}.service') if (relay is None) or relay['disabled']: return None @@ -156,7 +156,7 @@ def apply(relay): # Don't start individual instance when it's disabled if r['disabled']: continue - call('sudo systemctl start udp-broadcast-relay@{0}'.format(r['id'])) + call('systemctl start udp-broadcast-relay@{0}.service'.format(r['id'])) return None diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py index a7b12fa01..567dfa4b3 100755 --- a/src/conf_mode/dns_forwarding.py +++ b/src/conf_mode/dns_forwarding.py @@ -31,7 +31,7 @@ parser = argparse.ArgumentParser() parser.add_argument("--dhclient", action="store_true", help="Started from dhclient-script") -config_file = r'/etc/powerdns/recursor.conf' +config_file = r'/run/powerdns/recursor.conf' default_config_data = { 'allow_from': [], @@ -152,17 +152,21 @@ def generate(dns): if dns is None: return None + dirname = os.path.dirname(config_file) + if not os.path.exists(dirname): + os.mkdir(dirname) + render(config_file, 'dns-forwarding/recursor.conf.tmpl', dns, trim_blocks=True) return None def apply(dns): if dns is None: # DNS forwarding is removed in the commit - call("systemctl stop pdns-recursor") + call("systemctl stop pdns-recursor.service") if os.path.isfile(config_file): os.unlink(config_file) else: - call("systemctl restart pdns-recursor") + call("systemctl restart pdns-recursor.service") if __name__ == '__main__': args = parser.parse_args() diff --git a/src/conf_mode/dynamic_dns.py b/src/conf_mode/dynamic_dns.py index b76503419..038f77cf9 100755 --- a/src/conf_mode/dynamic_dns.py +++ b/src/conf_mode/dynamic_dns.py @@ -25,10 +25,7 @@ from vyos import ConfigError from vyos.util import call from vyos.template import render - -config_file = r'/etc/ddclient/ddclient.conf' -cache_file = r'/var/cache/ddclient/ddclient.cache' -pid_file = r'/var/run/ddclient/ddclient.pid' +config_file = r'/run/ddclient/ddclient.conf' # Mapping of service name to service protocol default_service_protocol = { @@ -47,9 +44,7 @@ default_service_protocol = { default_config_data = { 'interfaces': [], - 'cache_file': cache_file, - 'deleted': False, - 'pid_file': pid_file + 'deleted': False } def get_config(): @@ -220,39 +215,27 @@ def verify(dyndns): def generate(dyndns): # bail out early - looks like removal from running config if dyndns['deleted']: - if os.path.exists(config_file): - os.unlink(config_file) - return None - dirname = os.path.dirname(dyndns['pid_file']) - if not os.path.exists(dirname): - os.mkdir(dirname) - dirname = os.path.dirname(config_file) if not os.path.exists(dirname): os.mkdir(dirname) render(config_file, 'dynamic-dns/ddclient.conf.tmpl', dyndns) - + # Config file must be accessible only by its owner os.chmod(config_file, S_IRUSR | S_IWUSR) return None def apply(dyndns): - if os.path.exists(dyndns['cache_file']): - os.unlink(dyndns['cache_file']) - - if os.path.exists('/etc/ddclient.conf'): - os.unlink('/etc/ddclient.conf') - if dyndns['deleted']: - call('/etc/init.d/ddclient stop') - if os.path.exists(dyndns['pid_file']): - os.unlink(dyndns['pid_file']) + call('systemctl stop ddclient.service') + if os.path.exists(config_file): + os.unlink(config_file) + else: - call('/etc/init.d/ddclient restart') + call('systemctl restart ddclient.service') return None diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py index 3320075fb..1354488ac 100755 --- a/src/conf_mode/flow_accounting_conf.py +++ b/src/conf_mode/flow_accounting_conf.py @@ -346,9 +346,9 @@ def apply(config): command = None # Check if flow-accounting was removed and define command if not config['flow-accounting-configured']: - command = '/usr/bin/sudo /bin/systemctl stop uacctd' + command = 'systemctl stop uacctd.service' else: - command = '/usr/bin/sudo /bin/systemctl restart uacctd' + command = 'systemctl restart uacctd.service' # run command to start or stop flow-accounting cmd(command, raising=ConfigError, message='Failed to start/stop flow-accounting') diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py index 7c2f79abc..dd5819f9f 100755 --- a/src/conf_mode/host_name.py +++ b/src/conf_mode/host_name.py @@ -173,7 +173,7 @@ def apply(config): # restart pdns if it is used ret = run('/usr/bin/rec_control ping') if ret == 0: - call('/etc/init.d/pdns-recursor restart >/dev/null') + call('systemctl restart pdns-recursor.service') return None diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index b42765586..6733623c6 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -79,7 +79,7 @@ default_config_data = { 'server_push_route': [], 'server_reject_unconfigured': False, 'server_subnet': '', - 'server_topology': 'net30', + 'server_topology': '', 'shared_secret_file': '', 'tls': False, 'tls_auth': '', @@ -124,13 +124,10 @@ def getDefaultServer(network, topology, devtype): Logic from openvpn's src/openvpn/helper.c. Returns a dict with addresses or False if the input parameters were incorrect. """ - if not (topology and devtype): - return False - if not (devtype == 'tun' or devtype == 'tap'): return False - if not network.prefixlen: + if not network.version == 4: return False elif (devtype == 'tun' and network.prefixlen > 29) or (devtype == 'tap' and network.prefixlen > 30): return False @@ -345,6 +342,7 @@ def get_config(): openvpn['server_topology'] = conf.return_value('server topology') # Server-mode subnet (from which client IPs are allocated) + server_network = None if conf.exists('server subnet'): # server_network is used later in this function server_network = IPv4Network(conf.return_value('server subnet')) @@ -476,25 +474,31 @@ def get_config(): if not openvpn['tls_dh'] and openvpn['tls_key'] and checkCertHeader('-----BEGIN EC PRIVATE KEY-----', openvpn['tls_key']): openvpn['tls_dh'] = 'none' + # set default server topology to net30 + if openvpn['mode'] == 'server' and not openvpn['server_topology']: + openvpn['server_topology'] = 'net30' + # Set defaults where necessary. - # If any of the input parameters are missing or wrong, + # If any of the input parameters are wrong, # this will return False and no defaults will be set. - default_server = getDefaultServer(server_network, openvpn['server_topology'], openvpn['type']) - if default_server: - # server-bridge doesn't require a pool so don't set defaults for it - if not openvpn['bridge_member']: - openvpn['server_pool'] = True - if not openvpn['server_pool_start']: - openvpn['server_pool_start'] = default_server['pool_start'] - - if not openvpn['server_pool_stop']: - openvpn['server_pool_stop'] = default_server['pool_stop'] - - if not openvpn['server_pool_netmask']: - openvpn['server_pool_netmask'] = default_server['pool_netmask'] - - for client in openvpn['client']: - client['remote_netmask'] = default_server['client_remote_netmask'] + if server_network and openvpn['server_topology'] and openvpn['type']: + default_server = None + default_server = getDefaultServer(server_network, openvpn['server_topology'], openvpn['type']) + if default_server: + # server-bridge doesn't require a pool so don't set defaults for it + if not openvpn['bridge_member']: + openvpn['server_pool'] = True + if not openvpn['server_pool_start']: + openvpn['server_pool_start'] = default_server['pool_start'] + + if not openvpn['server_pool_stop']: + openvpn['server_pool_stop'] = default_server['pool_stop'] + + if not openvpn['server_pool_netmask']: + openvpn['server_pool_netmask'] = default_server['pool_netmask'] + + for client in openvpn['client']: + client['remote_netmask'] = default_server['client_remote_netmask'] return openvpn diff --git a/src/conf_mode/le_cert.py b/src/conf_mode/le_cert.py index 4b365a566..2db31d3fc 100755 --- a/src/conf_mode/le_cert.py +++ b/src/conf_mode/le_cert.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019 VyOS maintainers and contributors +# Copyright (C) 2019-2020 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,8 +13,6 @@ # # 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 os @@ -25,7 +23,6 @@ from vyos import ConfigError from vyos.util import cmd from vyos.util import call - vyos_conf_scripts_dir = vyos.defaults.directories['conf_mode'] dependencies = [ @@ -86,17 +83,17 @@ def generate(cert): # certbot will attempt to reload nginx, even with 'certonly'; # start nginx if not active - ret = call('systemctl is-active --quiet nginx.ervice') + ret = call('systemctl is-active --quiet nginx.service') if ret: - call('sudo systemctl start nginx.service') + call('systemctl start nginx.service') request_certbot(cert) def apply(cert): if cert is not None: - call('sudo systemctl restart certbot.timer') + call('systemctl restart certbot.timer') else: - call('sudo systemctl stop certbot.timer') + call('systemctl stop certbot.timer') return None for dep in dependencies: diff --git a/src/conf_mode/mdns_repeater.py b/src/conf_mode/mdns_repeater.py index bca1a537e..a652553f7 100755 --- a/src/conf_mode/mdns_repeater.py +++ b/src/conf_mode/mdns_repeater.py @@ -25,7 +25,6 @@ from vyos import ConfigError from vyos.util import call from vyos.template import render - config_file = r'/etc/default/mdns-repeater' default_config_data = { @@ -86,11 +85,11 @@ def generate(mdns): def apply(mdns): if (mdns is None) or mdns['disabled']: - call('sudo systemctl stop mdns-repeater') + call('systemctl stop mdns-repeater.service') if os.path.exists(config_file): os.unlink(config_file) else: - call('sudo systemctl restart mdns-repeater') + call('systemctl restart mdns-repeater.service') return None diff --git a/src/conf_mode/system-syslog.py b/src/conf_mode/system-syslog.py index 7d93ffdd5..9da3d9157 100755 --- a/src/conf_mode/system-syslog.py +++ b/src/conf_mode/system-syslog.py @@ -244,8 +244,8 @@ def verify(c): def apply(c): if not c: - return run('systemctl stop syslog') - return run('systemctl restart syslog') + return run('systemctl stop syslog.service') + return run('systemctl restart syslog.service') if __name__ == '__main__': try: diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py index 229202304..94c8bcf03 100755 --- a/src/conf_mode/tftp_server.py +++ b/src/conf_mode/tftp_server.py @@ -106,7 +106,7 @@ def generate(tftpd): def apply(tftpd): # stop all services first - then we will decide - call('systemctl stop tftpd@{0..20}') + call('systemctl stop tftpd@{0..20}.service') # bail out early - e.g. service deletion if tftpd is None: diff --git a/src/etc/systemd/system/pdns-recursor.service.d/override.conf b/src/etc/systemd/system/pdns-recursor.service.d/override.conf new file mode 100644 index 000000000..602d7b774 --- /dev/null +++ b/src/etc/systemd/system/pdns-recursor.service.d/override.conf @@ -0,0 +1,5 @@ +[Service] +WorkingDirectory= +WorkingDirectory=/run/powerdns +ExecStart= +ExecStart=/usr/sbin/pdns_recursor --daemon=no --write-pid=no --disable-syslog --log-timestamp=no --config-dir=/run/powerdns diff --git a/src/op_mode/dns_forwarding_restart.sh b/src/op_mode/dns_forwarding_restart.sh index 8e556f2f0..64cc92115 100755 --- a/src/op_mode/dns_forwarding_restart.sh +++ b/src/op_mode/dns_forwarding_restart.sh @@ -2,7 +2,7 @@ if cli-shell-api existsEffective service dns forwarding; then echo "Restarting the DNS forwarding service" - systemctl restart pdns-recursor + systemctl restart pdns-recursor.service else echo "DNS forwarding is not configured" fi diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py index 405dd9f04..e4e5043d5 100755 --- a/src/op_mode/dynamic_dns.py +++ b/src/op_mode/dynamic_dns.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018 VyOS maintainers and contributors +# Copyright (C) 2018-2020 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 @@ -23,8 +23,7 @@ import time from vyos.config import Config from vyos.util import call - -cache_file = r'/var/cache/ddclient/ddclient.cache' +cache_file = r'/run/ddclient/ddclient.cache' OUT_TMPL_SRC = """ {%- for entry in hosts -%} @@ -86,9 +85,9 @@ def show_status(): def update_ddns(): - call('systemctl stop ddclient') + call('systemctl stop ddclient.service') os.remove(cache_file) - call('systemctl start ddclient') + call('systemctl start ddclient.service') def main(): diff --git a/src/op_mode/flow_accounting_op.py b/src/op_mode/flow_accounting_op.py index 71fdfc288..bf8c39fd6 100755 --- a/src/op_mode/flow_accounting_op.py +++ b/src/op_mode/flow_accounting_op.py @@ -70,7 +70,7 @@ def _is_host(host): # check if flow-accounting running def _uacctd_running(): - command = '/usr/bin/sudo /bin/systemctl status uacctd > /dev/null' + command = 'systemctl status uacctd.service > /dev/null' return run(command) == 0 # get list of interfaces @@ -195,7 +195,7 @@ if not _uacctd_running(): # restart pmacct daemon if cmd_args.action == 'restart': # run command to restart flow-accounting - cmd('/usr/bin/sudo /bin/systemctl restart uacctd', + cmd('systemctl restart uacctd.service', message='Failed to restart flow-accounting') # clear in-memory collected flows diff --git a/src/op_mode/generate_ssh_server_key.py b/src/op_mode/generate_ssh_server_key.py index f65d383c0..cbc9ef973 100755 --- a/src/op_mode/generate_ssh_server_key.py +++ b/src/op_mode/generate_ssh_server_key.py @@ -14,14 +14,13 @@ # 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 - +from sys import exit from vyos.util import ask_yes_no from vyos.util import cmd if not ask_yes_no('Do you really want to remove the existing SSH host keys?'): - sys.exit(0) + exit(0) -cmd('sudo rm -v /etc/ssh/ssh_host_*') -cmd('sudo dpkg-reconfigure openssh-server') -cmd('sudo systemctl restart ssh') +cmd('rm -v /etc/ssh/ssh_host_*') +cmd('dpkg-reconfigure openssh-server') +cmd('systemctl restart ssh.service') diff --git a/src/op_mode/ipoe-control.py b/src/op_mode/ipoe-control.py new file mode 100755 index 000000000..7111498b2 --- /dev/null +++ b/src/op_mode/ipoe-control.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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 sys +import argparse + +from vyos.config import Config +from vyos.util import popen, run + +cmd_dict = { + 'cmd_base' : '/usr/bin/accel-cmd -p 2002 ', + 'selector' : ['if', 'username', 'sid'], + 'actions' : { + 'show_sessions' : 'show sessions', + 'show_stat' : 'show stat', + 'terminate' : 'teminate' + } +} + +def is_ipoe_configured(): + if not Config().exists_effective('service ipoe-server'): + print("Service IPoE is not configured") + sys.exit(1) + +def main(): + #parese args + parser = argparse.ArgumentParser() + parser.add_argument('--action', help='Control action', required=True) + parser.add_argument('--selector', help='Selector username|ifname|sid', required=False) + parser.add_argument('--target', help='Target must contain username|ifname|sid', required=False) + args = parser.parse_args() + + + # Check is IPoE configured + is_ipoe_configured() + + if args.action == "restart": + run(cmd_dict['cmd_base'] + "restart") + sys.exit(0) + + if args.action in cmd_dict['actions']: + if args.selector in cmd_dict['selector'] and args.target: + run(cmd_dict['cmd_base'] + "{0} {1} {2}".format(args.action, args.selector, args.target)) + else: + output, err = popen(cmd_dict['cmd_base'] + cmd_dict['actions'][args.action], decode='utf-8') + if not err: + print(output) + else: + print("IPoE server is not running") + +if __name__ == '__main__': + main() diff --git a/src/op_mode/restart_dhcp_relay.py b/src/op_mode/restart_dhcp_relay.py index 66dc435b3..af4fb2d15 100755 --- a/src/op_mode/restart_dhcp_relay.py +++ b/src/op_mode/restart_dhcp_relay.py @@ -39,7 +39,7 @@ if __name__ == '__main__': if not c.exists_effective('service dhcp-relay'): print("DHCP relay service not configured") else: - call('sudo systemctl restart isc-dhcp-relay.service') + call('systemctl restart isc-dhcp-server.service') sys.exit(0) elif args.ipv6: @@ -47,7 +47,7 @@ if __name__ == '__main__': if not c.exists_effective('service dhcpv6-relay'): print("DHCPv6 relay service not configured") else: - call('sudo systemctl restart isc-dhcpv6-relay.service') + call('systemctl restart isc-dhcp-server6.service') sys.exit(0) else: diff --git a/src/op_mode/show_dhcp.py b/src/op_mode/show_dhcp.py index a79033f69..c49e604b7 100755 --- a/src/op_mode/show_dhcp.py +++ b/src/op_mode/show_dhcp.py @@ -193,7 +193,7 @@ if __name__ == '__main__': sys.exit(0) # if dhcp server is down, inactive leases may still be shown as active, so warn the user. - if call('systemctl -q is-active isc-dhcpv4-server.service') != 0: + if call('systemctl -q is-active isc-dhcp-server.service') != 0: print("WARNING: DHCP server is configured but not started. Data may be stale.") if args.leases: diff --git a/src/op_mode/show_dhcpv6.py b/src/op_mode/show_dhcpv6.py index 18baa5517..d686defc0 100755 --- a/src/op_mode/show_dhcpv6.py +++ b/src/op_mode/show_dhcpv6.py @@ -179,7 +179,7 @@ if __name__ == '__main__': sys.exit(0) # if dhcp server is down, inactive leases may still be shown as active, so warn the user. - if call('systemctl -q is-active isc-dhcpv6-server.service') != 0: + if call('systemctl -q is-active isc-dhcp-server6.service') != 0: print("WARNING: DHCPv6 server is configured but not started. Data may be stale.") if args.leases: diff --git a/src/systemd/ddclient.service b/src/systemd/ddclient.service new file mode 100644 index 000000000..a4d55827a --- /dev/null +++ b/src/systemd/ddclient.service @@ -0,0 +1,14 @@ +[Unit] +Description=Dynamic DNS Update Client +RequiresMountsFor=/run +ConditionPathExists=/run/ddclient/ddclient.conf +After=vyos-router.service + +[Service] +WorkingDirectory=/run/ddclient +Type=forking +PIDFile=/run/ddclient/ddclient.pid +ExecStart=/usr/sbin/ddclient -cache /run/ddclient/ddclient.cache -pid /run/ddclient/ddclient.pid -file /run/ddclient/ddclient.conf + +[Install] +WantedBy=multi-user.target |