diff options
-rw-r--r-- | python/vyos/configsession.py | 6 | ||||
-rw-r--r-- | python/vyos/defaults.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig.py | 30 | ||||
-rwxr-xr-x | src/conf_mode/interface-bonding.py | 5 | ||||
-rwxr-xr-x | src/conf_mode/interface-wireguard.py | 26 | ||||
-rwxr-xr-x | src/helpers/vyos-boot-config-loader.py | 153 |
6 files changed, 171 insertions, 50 deletions
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index acbdd3d5f..09fae78a1 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -145,7 +145,8 @@ class ConfigSession(object): self.__run_command([COMMENT] + path + value) def commit(self): - self.__run_command([COMMIT]) + out = self.__run_command([COMMIT]) + return out def discard(self): self.__run_command([DISCARD]) @@ -157,4 +158,5 @@ class ConfigSession(object): return config_data def load_config(self, file_path): - self.__run_command(LOAD_CONFIG + [file_path]) + out = self.__run_command(LOAD_CONFIG + [file_path]) + return out diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py index 85d27d60d..dedb929b4 100644 --- a/python/vyos/defaults.py +++ b/python/vyos/defaults.py @@ -20,6 +20,7 @@ directories = { "config": "/opt/vyatta/etc/config", "current": "/opt/vyatta/etc/config-migrate/current", "migrate": "/opt/vyatta/etc/config-migrate/migrate", + "log": "/var/log/vyatta", } cfg_group = 'vyattacfg' diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 0793fad39..750a7cc70 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1057,6 +1057,36 @@ class BondIf(EthernetIf): def __init__(self, ifname): super().__init__(ifname, type='bond') + def remove(self): + """ + Remove interface from operating system. Removing the interface + deconfigures all assigned IP addresses and clear possible DHCP(v6) + client processes. + Example: + >>> from vyos.ifconfig import Interface + >>> i = Interface('eth0') + >>> i.remove() + """ + # when a bond member gets deleted, all members are placed in A/D state + # even when they are enabled inside CLI. This will make the config + # and system look async. + slave_list = [] + for s in self.get_slaves(): + slave = { + 'ifname' : s, + 'state': Interface(s).state + } + slave_list.append(slave) + + # remove bond master which places members in disabled state + super().remove() + + # replicate previous interface state before bond destruction back to + # physical interface + for slave in slave_list: + i = Interface(slave['ifname']) + i.state = slave['state'] + @property def xmit_hash_policy(self): """ diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interface-bonding.py index f0a33beff..ac3e1b867 100755 --- a/src/conf_mode/interface-bonding.py +++ b/src/conf_mode/interface-bonding.py @@ -279,11 +279,6 @@ def verify(bond): raise ConfigError('can not enslave interface {} which already ' \ 'belongs to {}'.format(intf, tmp)) - # we can not add disabled slave interfaces to our bond - if conf.exists('interfaces ethernet ' + intf + ' disable'): - raise ConfigError('can not enslave disabled interface {}' \ - .format(intf)) - # can not add interfaces with an assigned address to a bond if conf.exists('interfaces ethernet ' + intf + ' address'): raise ConfigError('can not enslave interface {} which has an address ' \ diff --git a/src/conf_mode/interface-wireguard.py b/src/conf_mode/interface-wireguard.py index d51a7a08d..4ae3251fe 100755 --- a/src/conf_mode/interface-wireguard.py +++ b/src/conf_mode/interface-wireguard.py @@ -26,12 +26,16 @@ from vyos.config import Config from vyos import ConfigError from vyos.ifconfig import WireGuardIf -ifname = str(os.environ['VYOS_TAGNODE_VALUE']) -intfc = WireGuardIf(ifname) +try: + ifname = str(os.environ['VYOS_TAGNODE_VALUE']) + intfc = WireGuardIf(ifname) +except KeyError: + print("Interface not specified") + sys.exit(1) kdir = r'/config/auth/wireguard' -def check_kmod(): +def _check_kmod(): if not os.path.exists('/sys/module/wireguard'): sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod") if os.system('sudo modprobe wireguard') != 0: @@ -39,6 +43,19 @@ def check_kmod(): raise ConfigError("modprobe wireguard failed") +def _migrate_default_keys(): + if os.path.exists('{}/private.key'.format(kdir)) and not os.path.exists('{}/default/private.key'.format(kdir)): + sl.syslog(sl.LOG_NOTICE, "migrate keypair to default") + old_umask = os.umask(0o027) + location = '{}/default'.format(kdir) + subprocess.call(['sudo mkdir -p ' + location], shell=True) + subprocess.call(['sudo chgrp vyattacfg ' + location], shell=True) + subprocess.call(['sudo chmod 750 ' + location], shell=True) + os.rename('{}/private.key'.format(kdir),'{}/private.key'.format(location)) + os.rename('{}/public.key'.format(kdir),'{}/public.key'.format(location)) + os.umask(old_umask) + + def get_config(): c = Config() if not c.exists('interfaces wireguard'): @@ -257,7 +274,8 @@ def apply(c): if __name__ == '__main__': try: - check_kmod() + _check_kmod() + _migrate_default_keys() c = get_config() verify(c) apply(c) diff --git a/src/helpers/vyos-boot-config-loader.py b/src/helpers/vyos-boot-config-loader.py index 06c95765f..7c81a4c3c 100755 --- a/src/helpers/vyos-boot-config-loader.py +++ b/src/helpers/vyos-boot-config-loader.py @@ -18,41 +18,72 @@ import os import sys +import pwd +import grp import subprocess import traceback +from datetime import datetime +from vyos.defaults import directories from vyos.configsession import ConfigSession, ConfigSessionError from vyos.configtree import ConfigTree STATUS_FILE = '/tmp/vyos-config-status' TRACE_FILE = '/tmp/boot-config-trace' -session = ConfigSession(os.getpid(), 'vyos-boot-config-loader') -env = session.get_session_env() +CFG_GROUP = 'vyattacfg' -default_file_name = env['vyatta_sysconfdir'] + '/config.boot.default' - -if len(sys.argv) < 1: - print("Must be called with argument.") - sys.exit(1) +if 'log' in directories: + LOG_DIR = directories['log'] else: - file_name = sys.argv[1] + LOG_DIR = '/var/log/vyatta' + +LOG_FILE = LOG_DIR + '/vyos-boot-config-loader.log' + +try: + with open('/proc/cmdline', 'r') as f: + cmdline = f.read() + if 'vyos-debug' in cmdline: + os.environ['VYOS_DEBUG'] = 'yes' +except Exception as e: + print('{0}'.format(e)) def write_config_status(status): - with open(STATUS_FILE, 'w') as f: - f.write('{0}\n'.format(status)) + try: + with open(STATUS_FILE, 'w') as f: + f.write('{0}\n'.format(status)) + except Exception as e: + print('{0}'.format(e)) def trace_to_file(trace_file_name): - with open(trace_file_name, 'w') as trace_file: - traceback.print_exc(file=trace_file) + try: + with open(trace_file_name, 'w') as trace_file: + traceback.print_exc(file=trace_file) + except Exception as e: + print('{0}'.format(e)) + +def failsafe(config_file_name): + fail_msg = """ + !!!!! + There were errors loading the configuration + Please examine the errors in + {0} + and correct + !!!!! + """.format(TRACE_FILE) + + print(fail_msg, file=sys.stderr) + + users = [x[0] for x in pwd.getpwall()] + if 'vyos' in users: + return -def failsafe(): try: - with open(default_file_name, 'r') as f: + with open(config_file_name, 'r') as f: config_file = f.read() except Exception as e: print("Catastrophic: no default config file " - "'{0}'".format(default_file_name)) + "'{0}'".format(config_file_name)) sys.exit(1) config = ConfigTree(config_file) @@ -73,29 +104,73 @@ def failsafe(): except subprocess.CalledProcessError as e: sys.exit("{0}".format(e)) - with open('/etc/motd', 'a+') as f: - f.write('\n\n') - f.write('!!!!!\n') - f.write('There were errors loading the initial configuration;\n') - f.write('please examine the errors in {0} and correct.' - '\n'.format(TRACE_FILE)) - f.write('!!!!!\n\n') +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Must specify boot config file.") + sys.exit(1) + else: + file_name = sys.argv[1] -try: - with open(file_name, 'r') as f: - config_file = f.read() -except Exception as e: - write_config_status(1) - failsafe() - trace_to_file(TRACE_FILE) - sys.exit("{0}".format(e)) + # Set user and group options, so that others will be able to commit + # Currently, the only caller does 'sg CFG_GROUP', but that may change + cfg_group = grp.getgrnam(CFG_GROUP) + os.setgid(cfg_group.gr_gid) -try: - session.load_config(file_name) - session.commit() - write_config_status(0) -except ConfigSessionError as e: - write_config_status(1) - failsafe() - trace_to_file(TRACE_FILE) - sys.exit(1) + # Need to set file permissions to 775 so that every vyattacfg group + # member has write access to the running config + os.umask(0o002) + + session = ConfigSession(os.getpid(), 'vyos-boot-config-loader') + env = session.get_session_env() + + default_file_name = env['vyatta_sysconfdir'] + '/config.boot.default' + + try: + with open(file_name, 'r') as f: + config_file = f.read() + except Exception: + write_config_status(1) + failsafe(default_file_name) + trace_to_file(TRACE_FILE) + sys.exit(1) + + try: + time_begin_load = datetime.now() + load_out = session.load_config(file_name) + time_end_load = datetime.now() + time_begin_commit = datetime.now() + commit_out = session.commit() + time_end_commit = datetime.now() + write_config_status(0) + except ConfigSessionError: + # If here, there is no use doing session.discard, as we have no + # recoverable config environment, and will only throw an error + write_config_status(1) + failsafe(default_file_name) + trace_to_file(TRACE_FILE) + sys.exit(1) + + time_elapsed_load = time_end_load - time_begin_load + time_elapsed_commit = time_end_commit - time_begin_commit + + try: + if not os.path.exists(LOG_DIR): + os.mkdir(LOG_DIR) + with open(LOG_FILE, 'a') as f: + f.write('\n\n') + f.write('{0} Begin config load\n' + ''.format(time_begin_load)) + f.write(load_out) + f.write('{0} End config load\n' + ''.format(time_end_load)) + f.write('Elapsed time for config load: {0}\n' + ''.format(time_elapsed_load)) + f.write('{0} Begin config commit\n' + ''.format(time_begin_commit)) + f.write(commit_out) + f.write('{0} End config commit\n' + ''.format(time_end_commit)) + f.write('Elapsed time for config commit: {0}\n' + ''.format(time_elapsed_commit)) + except Exception as e: + print('{0}'.format(e)) |