diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/vyos/airbag.py | 5 | ||||
-rw-r--r-- | python/vyos/authutils.py | 2 | ||||
-rw-r--r-- | python/vyos/debug.py | 182 | ||||
-rw-r--r-- | python/vyos/ifconfig/__init__.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/control.py | 13 | ||||
-rw-r--r-- | python/vyos/ifconfig/input.py | 31 | ||||
-rw-r--r-- | python/vyos/ifconfig/section.py (renamed from python/vyos/ifconfig/register.py) | 72 | ||||
-rw-r--r-- | python/vyos/ifconfig/tunnel.py | 14 | ||||
-rw-r--r-- | python/vyos/ifconfig/vti.py | 31 | ||||
-rw-r--r-- | python/vyos/remote.py | 15 | ||||
-rw-r--r-- | python/vyos/template.py | 22 | ||||
-rw-r--r-- | python/vyos/util.py | 144 |
12 files changed, 445 insertions, 87 deletions
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/authutils.py b/python/vyos/authutils.py index 90a46ffb4..66b5f4a74 100644 --- a/python/vyos/authutils.py +++ b/python/vyos/authutils.py @@ -22,7 +22,7 @@ def make_password_hash(password): """ Makes a password hash for /etc/shadow using mkpasswd """ mkpassword = 'mkpasswd --method=sha-512 --stdin' - return cmd(mkpassword, input=password.encode(), timeout=5) + return cmd(mkpassword, input=password, timeout=5) def split_ssh_public_key(key_string, defaultname=""): """ Splits an SSH public key into its components """ 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/__init__.py b/python/vyos/ifconfig/__init__.py index 1f9956af0..cd1696ca1 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -14,6 +14,7 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. +from vyos.ifconfig.section import Section from vyos.ifconfig.interface import Interface from vyos.ifconfig.bond import BondIf diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index c7a2fa2d6..7bb63beed 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -16,12 +16,13 @@ import os -from vyos.util import debug, debug_msg -from vyos.util import popen, cmd -from vyos.ifconfig.register import Register +from vyos import debug +from vyos.util import popen +from vyos.util import cmd +from vyos.ifconfig.section import Section -class Control(Register): +class Control(Section): _command_get = {} _command_set = {} @@ -35,10 +36,10 @@ class Control(Register): # 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/ifconfig/input.py b/python/vyos/ifconfig/input.py new file mode 100644 index 000000000..bfab36335 --- /dev/null +++ b/python/vyos/ifconfig/input.py @@ -0,0 +1,31 @@ +# Copyright 2020 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/>. + + +from vyos.ifconfig.interface import Interface + + +@Interface.register +class InputIf(Interface): + default = { + 'type': '', + } + definition = { + **Interface.definition, + **{ + 'section': 'input', + 'prefixes': ['ifb', ], + }, + } diff --git a/python/vyos/ifconfig/register.py b/python/vyos/ifconfig/section.py index c90782b70..ab340d247 100644 --- a/python/vyos/ifconfig/register.py +++ b/python/vyos/ifconfig/section.py @@ -16,9 +16,10 @@ import netifaces -class Register: +class Section: # the known interface prefixes _prefixes = {} + _classes = [] # class need to define: definition['prefixes'] # the interface prefixes declared by a class used to name interface with @@ -26,9 +27,16 @@ class Register: @classmethod def register(cls, klass): + """ + A function to use as decorator the interfaces classes + It register the prefix for the interface (eth, dum, vxlan, ...) + with the class which can handle it (EthernetIf, DummyIf,VXLANIf, ...) + """ if not klass.definition.get('prefixes',[]): raise RuntimeError(f'valid interface prefixes not defined for {klass.__name__}') + cls._classes.append(klass) + for ifprefix in klass.definition['prefixes']: if ifprefix in cls._prefixes: raise RuntimeError(f'only one class can be registered for prefix "{ifprefix}" type') @@ -38,7 +46,11 @@ class Register: @classmethod def _basename (cls, name, vlan): - # remove number from interface name + """ + remove the number at the end of interface name + name: name of the interface + vlan: if vlan is True, do not stop at the vlan number + """ name = name.rstrip('0123456789') name = name.rstrip('.') if vlan: @@ -47,15 +59,13 @@ class Register: @classmethod def section(cls, name, vlan=True): - # return the name of a section an interface should be under + """ + return the name of a section an interface should be under + name: name of the interface (eth0, dum1, ...) + vlan: should we try try to remove the VLAN from the number + """ name = cls._basename(name, vlan) - # XXX: To leave as long as vti and input are not moved to vyos - if name == 'vti': - return 'vti' - if name == 'ifb': - return 'input' - if name in cls._prefixes: return cls._prefixes[name].definition['section'] return '' @@ -68,15 +78,13 @@ class Register: raise ValueError(f'No type found for interface name: {name}') @classmethod - def _listing (cls,section=''): + def _intf_under_section (cls,section=''): + """ + return a generator with the name of the interface which are under a section + """ interfaces = netifaces.interfaces() for ifname in interfaces: - # XXX: Temporary hack as vti and input are not yet moved from vyatta to vyos - if ifname.startswith('vti') or ifname.startswith('input'): - yield ifname - continue - ifsection = cls.section(ifname) if not ifsection: continue @@ -87,9 +95,37 @@ class Register: yield ifname @classmethod - def listing(cls, section=''): - return list(cls._listing(section)) + def interfaces(cls, section=''): + """ + return a list of the name of the interface which are under a section + if no section is provided, then it returns all configured interfaces + """ + return list(cls._intf_under_section(section)) + @classmethod + def _intf_with_feature(cls, feature=''): + """ + return a generator with the name of the interface which have + a particular feature set in their definition such as: + bondable, broadcast, bridgeable, ... + """ + for klass in cls._classes: + if klass.definition[feature]: + yield klass.definition['section'] -# XXX: TODO - limit name for VRF interfaces + @classmethod + def feature(cls, feature=''): + """ + return list with the name of the interface which have + a particular feature set in their definition such as: + bondable, broadcast, bridgeable, ... + """ + return list(cls._intf_with_feature(feature)) + @classmethod + def reserved(cls): + """ + return list with the interface name prefixes + eth, lo, vxlan, dum, ... + """ + return list(cls._prefixes.keys()) diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 05060669a..009a53a82 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -143,7 +143,7 @@ class GREIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -167,7 +167,7 @@ class GRETapIf(_Tunnel): required = ['local', ] options = ['local', 'remote', ] - updates = [] + updates = ['mtu', ] create = 'ip link add {ifname} type {type}' change = '' @@ -193,7 +193,7 @@ class IP6GREIf(_Tunnel): 'hoplimit', 'tclass', 'flowlabel'] updates = ['local', 'remote', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname} mode {type}' @@ -227,7 +227,7 @@ class IPIPIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -252,7 +252,7 @@ class IPIP6If(_Tunnel): 'hoplimit', 'tclass', 'flowlabel'] updates = ['local', 'remote', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip -6 tunnel add {ifname} mode {type}' change = 'ip -6 tunnel cha {ifname}' @@ -288,7 +288,7 @@ class SitIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -309,7 +309,7 @@ class Sit6RDIf(SitIf): # TODO: check if key can really be used with 6RD options = ['remote', 'ttl', 'tos', 'key', '6rd-prefix', '6rd-relay-prefix'] updates = ['remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] def _create(self): # do not call _Tunnel.create, building fully here diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py new file mode 100644 index 000000000..56ebe01d1 --- /dev/null +++ b/python/vyos/ifconfig/vti.py @@ -0,0 +1,31 @@ +# Copyright 2020 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/>. + + +from vyos.ifconfig.interface import Interface + + +@Interface.register +class VTIIf(Interface): + default = { + 'type': 'vti', + } + definition = { + **Interface.definition, + **{ + 'section': 'vti', + 'prefixes': ['vti', ], + }, + } diff --git a/python/vyos/remote.py b/python/vyos/remote.py index f918461d1..1b4d3876e 100644 --- a/python/vyos/remote.py +++ b/python/vyos/remote.py @@ -18,7 +18,8 @@ import os import re import fileinput -from vyos.util import cmd, DEVNULL +from vyos.util import cmd +from vyos.util import DEVNULL def check_and_add_host_key(host_name): @@ -31,10 +32,10 @@ def check_and_add_host_key(host_name): mode = 0o600 os.mknod(known_hosts, 0o600) - keyscan_cmd = 'ssh-keyscan -t rsa {} 2>/dev/null'.format(host_name) + keyscan_cmd = 'ssh-keyscan -t rsa {}'.format(host_name) try: - host_key = cmd(keyscan_cmd, shell=True, stderr=DEVNULL) + host_key = cmd(keyscan_cmd, stderr=DEVNULL) except OSError: sys.exit("Can not get RSA host key") @@ -61,9 +62,9 @@ def check_and_add_host_key(host_name): print("Host key has changed!") print("If you trust the host key fingerprint below, continue.") - fingerprint_cmd = 'ssh-keygen -lf /dev/stdin <<< "{}"'.format(host_key) + fingerprint_cmd = 'ssh-keygen -lf /dev/stdin' try: - fingerprint = cmd(fingerprint_cmd, shell=True, stderr=DEVNULL) + fingerprint = cmd(fingerprint_cmd, stderr=DEVNULL, input=host_key) except OSError: sys.exit("Can not get RSA host key fingerprint.") @@ -125,7 +126,7 @@ def get_remote_config(remote_file): # Try header first, and look for 'OK' or 'Moved' codes: curl_cmd = 'curl {0} -q -I {1}'.format(redirect_opt, remote_file) try: - curl_output = cmd(curl_cmd, shell=True) + curl_output = cmd(curl_cmd) except OSError: sys.exit(1) @@ -142,6 +143,6 @@ def get_remote_config(remote_file): curl_cmd = 'curl {0} -# {1}'.format(redirect_opt, remote_file) try: - return cmd(curl_cmd, shell=True, stderr=None) + return cmd(curl_cmd, stderr=None) except OSError: return None diff --git a/python/vyos/template.py b/python/vyos/template.py index e559120c0..6c73ce753 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -22,10 +22,17 @@ from vyos.defaults import directories # reuse the same Environment to improve performance -_templates_env = Environment(loader=FileSystemLoader(directories['templates'])) -_templates_mem = {} +_templates_env = { + False: Environment(loader=FileSystemLoader(directories['templates'])), + True: Environment(loader=FileSystemLoader(directories['templates']), trim_blocks=True), +} +_templates_mem = { + False: {}, + True: {}, +} -def render(destination, template, content): + +def render(destination, template, content, trim_blocks=False, formater=None): """ render a template from the template directory, it will raise on any errors destination: the file where the rendered template must be saved @@ -41,15 +48,18 @@ def render(destination, template, content): # Setup a renderer for the given template # This is cached and re-used for performance - if template not in _templates_mem: - _templates_mem[template] = _templates_env.get_template(template) - template = _templates_mem[template] + if template not in _templates_mem[trim_blocks]: + _templates_mem[trim_blocks][template] = _templates_env[trim_blocks].get_template(template) + template = _templates_mem[trim_blocks][template] # As we are opening the file with 'w', we are performing the rendering # before calling open() to not accidentally erase the file if the # templating fails content = template.render(content) + if formater: + content = formater(content) + # Write client config file with open(destination, 'w') as f: f.write(content) diff --git a/python/vyos/util.py b/python/vyos/util.py index 291ce64ea..49c47cd85 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -16,67 +16,121 @@ import os import re import sys -from subprocess import Popen, PIPE, STDOUT, DEVNULL +from subprocess import Popen +from subprocess import PIPE +from subprocess import STDOUT +from subprocess import DEVNULL -def debug(flag): - # this is to force all new flags to be registered here so that - # they can be documented: - # - developer: the code will drop into PBD on un-handled exception - # - ifconfig: prints command and sysfs access on stdout for interface - if flag not in ['developer', 'ifconfig']: - return '' - return flag if os.path.isfile(f'/tmp/vyos.{flag}.debug') else '' +from vyos import debug +# There is many (too many) ways to run command with python +# os.system, subprocess.Popen, subproces.{run,call,check_output} +# which all have slighty different behaviour -def debug_msg(message, section=''): - if debug(section): - print(f'DEBUG/{section:<6} {message}') +def popen(command, flag='', shell=None, input=None, timeout=None, env=None, + stdout=PIPE, stderr=None, decode=None): + """ + popen is a wrapper helper aound subprocess.Popen + with it default setting it will return a tuple (out, err) + out: the output of the program run + err: the error code returned by the program + + it can be affected by the following flags: + shell: do not try to auto-detect if a shell is required + for example if a pipe (|) or redirection (>, >>) is used + input: data to sent to the child process via STDIN + the data should be bytes but string will be converted + timeout: time after which the command will be considered to have failed + env: mapping that defines the environment variables for the new process + stdout: define how the output of the program should be handled + - PIPE (default), sends stdout to the output + - DEVNULL, discard the output + stderr: define how the output of the program should be handled + - None (default), send/merge the data to/with stderr + - PIPE, popen will append it to output + - STDOUT, send the data to be merged with stdout + - DEVNULL, discard the output + decode: specify the expected text encoding (utf-8, ascii, ...) + + usage: + to get both stdout, and stderr: popen('command', stdout=PIPE, stderr=STDOUT) + to discard stdout and get stderr: popen('command', stdout=DEVNUL, stderr=PIPE) + """ + + # 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) -def popen(command, section='', shell=None, input=None, timeout=None, env=None, - universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None): - """ popen does not raise, returns the output and error code of command """ use_shell = shell + stdin = None if shell is None: - use_shell = True if ' ' in command else False + use_shell = False + if ' ' in command: + use_shell = True + if env: + use_shell = True + if input: + stdin = PIPE + input = input.encode() if type(input) is str else input p = Popen( command, - stdout=stdout, stderr=stderr, + stdin=stdin, stdout=stdout, stderr=stderr, env=env, shell=use_shell, - universal_newlines=universal_newlines, ) - tmp = p.communicate(input, timeout)[0].strip() - debug_msg(f"cmd '{command}'", section) - decoded = tmp.decode(decode) if decode else tmp.decode() + tmp = p.communicate(input, timeout) + out1 = b'' + out2 = b'' + if stdout == PIPE: + out1 = tmp[0] + if stderr == PIPE: + out2 += tmp[1] + decoded1 = out1.decode(decode) if decode else out1.decode() + decoded2 = out2.decode(decode) if decode else out2.decode() + decoded1 = decoded1.replace('\r\n', '\n').strip() + decoded2 = decoded2.replace('\r\n', '\n').strip() + nl = '\n' if decoded1 and decoded2 else '' + decoded = decoded1 + nl + decoded2 if decoded: - debug_msg(f"returned:\n{decoded}", section) + ret_msg = f"returned:\n{decoded}" + debug.message(ret_msg, flag) return decoded, p.returncode -def run(command, section='', shell=None, input=None, timeout=None, env=None, - universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None): - """ does not raise exception on error, returns error code """ +def run(command, flag='', shell=None, input=None, timeout=None, env=None, + stdout=DEVNULL, stderr=None, decode=None): + """ + A wrapper around vyos.util.popen, which discard the stdout and + will return the error code of a command + """ _, code = popen( - command, section, + command, flag, stdout=stdout, stderr=stderr, input=input, timeout=timeout, env=env, shell=shell, - universal_newlines=universal_newlines, decode=decode, ) return code -def cmd(command, section='', shell=None, input=None, timeout=None, env=None, - universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None, +def cmd(command, flag='', shell=None, input=None, timeout=None, env=None, + stdout=PIPE, stderr=None, decode=None, raising=None, message=''): - """ does raise exception, returns output of command """ + """ + A wrapper around vyos.util.popen, which returns the stdout and + will raise the error code of a command + + raising: specify which call should be used when raising (default is OSError) + the class should only require a string as parameter + """ decoded, code = popen( - command, section, + command, flag, stdout=stdout, stderr=stderr, input=input, timeout=timeout, env=env, shell=shell, - universal_newlines=universal_newlines, decode=decode, ) if code != 0: @@ -92,15 +146,17 @@ def cmd(command, section='', shell=None, input=None, timeout=None, env=None, return decoded -def call(command, section='', shell=None, input=None, timeout=None, env=None, - universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None): - """ does not raise exception on error, returns error code, print output """ +def call(command, flag='', shell=None, input=None, timeout=None, env=None, + stdout=PIPE, stderr=None, decode=None): + """ + A wrapper around vyos.util.popen, which print the stdout and + will return the error code of a command + """ out, code = popen( - command, section, + command, flag, stdout=stdout, stderr=stderr, input=input, timeout=timeout, env=env, shell=shell, - universal_newlines=universal_newlines, decode=decode, ) print(out) @@ -124,6 +180,16 @@ def chown(path, user, group): gid = getgrnam(group).gr_gid os.chown(path, uid, gid) + +def chmod_600(path): + """ make file only read/writable by owner """ + from stat import S_IRUSR, S_IWUSR + + if os.path.exists(path): + bitmask = S_IRUSR | S_IWUSR + os.chmod(path, bitmask) + + def chmod_750(path): """ make file/directory only executable to user and group """ from stat import S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP @@ -133,8 +199,8 @@ def chmod_750(path): os.chmod(path, bitmask) -def chmod_x(path): - """ make file executable """ +def chmod_755(path): + """ make file executable by all """ from stat import S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH if os.path.exists(path): |