diff --git a/debian/changelog b/debian/changelog index 5c3cd8b53..82eaff86f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -46,6 +46,15 @@ yunohost (3.0.0~beta1) testing; urgency=low -- Alexandre Aubin Thu, 03 May 2018 03:04:45 +0000 +yunohost (2.7.13.6) testing; urgency=low + + * Misc fixes + * [stretch-migration] Disable predictable network interface names + + Fixes by Bram and Aleks + + -- Alexandre Aubin Fri, 15 Jun 2018 16:20:00 +0000 + yunohost (2.7.13.5) testing; urgency=low * [fix] a bug when log to be fetched is empty diff --git a/locales/en.json b/locales/en.json index 21aa67d8b..dc7a5203a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -238,7 +238,7 @@ "migration_0003_not_jessie": "The current debian distribution is not Jessie !", "migration_0003_system_not_fully_up_to_date": "Your system is not fully up to date. Please perform a regular upgrade before running the migration to stretch.", "migration_0003_still_on_jessie_after_main_upgrade": "Something wrong happened during the main upgrade : system is still on Jessie !? To investigate the issue, please look at {log} :s ...", - "migration_0003_general_warning": "Please note that this migration is a delicate operation. While the YunoHost team did its best to review and test it, the migration might still break parts of the system or apps.\n\nTherefore, we recommend you to :\n - Perform a backup of any critical data or app. More infos on https://yunohost.org/backup ;\n - Be patient after launching the migration : depending on your internet connection and hardware, it might take up to a few hours for everything to upgrade.\n\nAdditionally, the port for SMTP, used by external email clients like (Thunderbird or K9-Mail) was changed from 465 (SSL/TLS) to 587 (STARTTLS). The old port 465 will automatically be closed and the new port 587 will be opened in the firewall. You and your users *will* have to adapt the configuration of your email clients accordingly!", + "migration_0003_general_warning": "Please note that this migration is a delicate operation. While the YunoHost team did its best to review and test it, the migration might still break parts of the system or apps.\n\nTherefore, we recommend you to :\n - Perform a backup of any critical data or app. More infos on https://yunohost.org/backup ;\n - Be patient after launching the migration : depending on your internet connection and hardware, it might take up to a few hours for everything to upgrade.\n\nAdditionally, the port for SMTP, used by external email clients (like Thunderbird or K9-Mail) was changed from 465 (SSL/TLS) to 587 (STARTTLS). The old port 465 will automatically be closed and the new port 587 will be opened in the firewall. You and your users *will* have to adapt the configuration of your email clients accordingly!", "migration_0003_problematic_apps_warning": "Please note that the following possibly problematic installed apps were detected. It looks like those were not installed from an applist or are not flagged as 'working'. Consequently, we cannot guarantee that they will still work after the upgrade : {problematic_apps}", "migration_0003_modified_files": "Please note that the following files were found to be manually modified and might be overwritten at the end of the upgrade : {manually_modified_files}", "migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!", diff --git a/src/yunohost/data_migrations/0003_migrate_to_stretch.py b/src/yunohost/data_migrations/0003_migrate_to_stretch.py index f5a3ded30..104faf3fe 100644 --- a/src/yunohost/data_migrations/0003_migrate_to_stretch.py +++ b/src/yunohost/data_migrations/0003_migrate_to_stretch.py @@ -15,6 +15,7 @@ from yunohost.service import (_run_service_command, manually_modified_files_compared_to_debian_default) from yunohost.utils.filesystem import free_space_in_directory from yunohost.utils.packages import get_installed_version +from yunohost.utils.network import get_network_interfaces from yunohost.firewall import firewall_allow, firewall_disallow logger = getActionLogger('yunohost.migration') @@ -69,6 +70,8 @@ class MyMigration(Migration): self.apt_dist_upgrade(conf_flags=["new", "miss", "def"]) _run_service_command("restart", "fail2ban") + self.disable_predicable_interface_names() + # Clean the mess os.system("apt autoremove --assume-yes") os.system("apt clean --assume-yes") @@ -360,3 +363,20 @@ class MyMigration(Migration): # command showing in the terminal, since 'info' channel is only # enabled if the user explicitly add --verbose ... os.system(command) + + def disable_predicable_interface_names(self): + + # Try to see if currently used interface names are predictable ones or not... + # If we ain't using "eth0" or "wlan0", assume we are using predictable interface + # names and therefore they shouldnt be disabled + network_interfaces = get_network_interfaces().keys() + if "eth0" not in network_interfaces and "wlan0" not in network_interfaces: + return + + interfaces_config = read_file("/etc/network/interfaces") + if "eth0" not in interfaces_config and "wlan0" not in interfaces_config: + return + + # Disable predictive interface names + # c.f. https://unix.stackexchange.com/a/338730 + os.system("ln -s /dev/null /etc/systemd/network/99-default.link") diff --git a/src/yunohost/monitor.py b/src/yunohost/monitor.py index ed13d532d..fc10a4fbc 100644 --- a/src/yunohost/monitor.py +++ b/src/yunohost/monitor.py @@ -164,6 +164,7 @@ def monitor_network(units=None, human_readable=False): units = ['check', 'usage', 'infos'] # Get network devices and their addresses + # TODO / FIXME : use functions in utils/network.py to manage this devices = {} output = subprocess.check_output('ip addr show'.split()) for d in re.split('^(?:[0-9]+: )', output, flags=re.MULTILINE): @@ -213,6 +214,7 @@ def monitor_network(units=None, human_readable=False): elif u == 'infos': p_ipv4 = get_public_ip() or 'unknown' + # TODO / FIXME : use functions in utils/network.py to manage this l_ip = 'unknown' for name, addrs in devices.items(): if name == 'lo': diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 47bdd6f6b..d4912f140 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -709,7 +709,7 @@ def _tail(file, n): lines = f.read().splitlines() if len(lines) >= to_read or pos == 0: - return lines[-to_read] + return lines[-to_read:] avg_line_length *= 1.3 diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index e22d1644d..dec0384bf 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -19,10 +19,13 @@ """ import logging +import re +import subprocess from urllib import urlopen logger = logging.getLogger('yunohost.utils.network') + def get_public_ip(protocol=4): """Retrieve the public IP address from ip.yunohost.org""" @@ -37,3 +40,76 @@ def get_public_ip(protocol=4): return urlopen(url).read().strip() except IOError: return None + + +def get_network_interfaces(): + + # Get network devices and their addresses (raw infos from 'ip addr') + devices_raw = {} + output = subprocess.check_output('ip addr show'.split()) + for d in re.split('^(?:[0-9]+: )', output, flags=re.MULTILINE): + # Extract device name (1) and its addresses (2) + m = re.match('([^\s@]+)(?:@[\S]+)?: (.*)', d, flags=re.DOTALL) + if m: + devices_raw[m.group(1)] = m.group(2) + + # Parse relevant informations for each of them + devices = {name: _extract_inet(addrs) for name, addrs in devices_raw.items() if name != "lo"} + + return devices + + +def get_gateway(): + + output = subprocess.check_output('ip route show'.split()) + m = re.search('default via (.*) dev ([a-z]+[0-9]?)', output) + if not m: + return None + + addr = _extract_inet(m.group(1), True) + return addr.popitem()[1] if len(addr) == 1 else None + + +############################################################################### + + +def _extract_inet(string, skip_netmask=False, skip_loopback=True): + """ + Extract IP addresses (v4 and/or v6) from a string limited to one + address by protocol + + Keyword argument: + string -- String to search in + skip_netmask -- True to skip subnet mask extraction + skip_loopback -- False to include addresses reserved for the + loopback interface + + Returns: + A dict of {protocol: address} with protocol one of 'ipv4' or 'ipv6' + + """ + ip4_pattern = '((25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}' + ip6_pattern = '(((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)' + ip4_pattern += '/[0-9]{1,2})' if not skip_netmask else ')' + ip6_pattern += '/[0-9]{1,3})' if not skip_netmask else ')' + result = {} + + for m in re.finditer(ip4_pattern, string): + addr = m.group(1) + if skip_loopback and addr.startswith('127.'): + continue + + # Limit to only one result + result['ipv4'] = addr + break + + for m in re.finditer(ip6_pattern, string): + addr = m.group(1) + if skip_loopback and addr == '::1': + continue + + # Limit to only one result + result['ipv6'] = addr + break + + return result