def test_dumb_update(self): """Test that our dumb ``apt-get update`` wrapper works.""" if os.getuid() != 0: return self.skipTest("root privileges required to opt in") updater = AptMirrorUpdater() # Remove all existing package lists. updater.clear_package_lists() # Verify that package lists aren't available. assert not have_package_lists() # Run `apt-get update' to download the package lists. updater.dumb_update() # Verify that package lists are again available. assert have_package_lists()
def test_smart_update(self): """ Test that our smart ``apt-get update`` wrapper works. Currently this test simply ensures coverage of the happy path. Ideally it will evolve to test the handled edge cases as well. """ if os.getuid() != 0: return self.skipTest("root privileges required to opt in") updater = AptMirrorUpdater() # Remove all existing package lists. updater.clear_package_lists() # Verify that package lists aren't available. assert not have_package_lists() # Run `apt-get update' to download the package lists. updater.smart_update() # Verify that package lists are again available. assert have_package_lists()
def test_debian_lts_eol_date(self): """ Regression test for `issue #5`_. .. _issue #5: https://github.com/xolox/python-apt-mirror-updater/issues/5 """ updater = AptMirrorUpdater( distributor_id='debian', distribution_codename='jessie', architecture='amd64', ) eol_expected = (time.time() >= 1593468000) assert updater.release_is_eol == eol_expected
def test_best_mirror_selection(self): """Test the selection of a "best" mirror.""" updater = AptMirrorUpdater() assert is_mirror_url(updater.best_mirror)
def test_mirror_ranking(self): """Test the ranking of discovered mirrors.""" updater = AptMirrorUpdater() # Make sure that multiple discovered mirrors are available. assert sum(m.is_available for m in updater.ranked_mirrors) > 10
def test_adaptive_mirror_discovery(self): """Test the discovery of mirrors for the current type of system.""" updater = AptMirrorUpdater() assert len(updater.available_mirrors) > 10 assert all(is_mirror_url(c.mirror_url) for c in updater.available_mirrors)
def test_adaptive_mirror_discovery(self): """Test the discovery of mirrors for the current type of system.""" updater = AptMirrorUpdater() assert len(updater.available_mirrors) > 10 for candidate in updater.available_mirrors: self.check_mirror_url(candidate.mirror_url)
def main(): """Command line interface for the ``apt-mirror-updater`` program.""" # Initialize logging to the terminal and system log. coloredlogs.install(syslog=True) # Command line option defaults. context = LocalContext() updater = AptMirrorUpdater(context=context) limit = MAX_MIRRORS actions = [] # Parse the command line arguments. try: options, arguments = getopt.getopt(sys.argv[1:], 'r:fblc:aux:m:vqh', [ 'remote-host=', 'find-current-mirror', 'find-best-mirror', 'list-mirrors', 'change-mirror', 'auto-change-mirror', 'update', 'update-package-lists', 'exclude=', 'max=', 'verbose', 'quiet', 'help', ]) for option, value in options: if option in ('-r', '--remote-host'): if actions: msg = "The %s option should be the first option given on the command line!" raise Exception(msg % option) context = RemoteContext(value) updater = AptMirrorUpdater(context=context) elif option in ('-f', '--find-current-mirror'): actions.append( functools.partial(report_current_mirror, updater)) elif option in ('-b', '--find-best-mirror'): actions.append(functools.partial(report_best_mirror, updater)) elif option in ('-l', '--list-mirrors'): actions.append( functools.partial(report_available_mirrors, updater)) elif option in ('-c', '--change-mirror'): actions.append(functools.partial(updater.change_mirror, value)) elif option in ('-a', '--auto-change-mirror'): actions.append(updater.change_mirror) elif option in ('-u', '--update', '--update-package-lists'): actions.append(updater.smart_update) elif option in ('-x', '--exclude'): actions.insert(0, functools.partial(updater.ignore_mirror, value)) elif option in ('-m', '--max'): limit = int(value) elif option in ('-v', '--verbose'): coloredlogs.increase_verbosity() elif option in ('-q', '--quiet'): coloredlogs.decrease_verbosity() elif option in ('-h', '--help'): usage(__doc__) return else: assert False, "Unhandled option!" if not actions: usage(__doc__) return # Propagate options to the Python API. updater.max_mirrors = limit except Exception as e: warning("Error: Failed to parse command line arguments! (%s)" % e) sys.exit(1) # Perform the requested action(s). try: for callback in actions: callback() except Exception: logger.exception("Encountered unexpected exception! Aborting ..") sys.exit(1)
def update_package_lists(self): """Run ``apt-get update`` (with compensation if things break).""" AptMirrorUpdater(context=self.context).smart_update()
def upgrade_remote_system(context, force_reboot=False): """ Perform standard system maintenance tasks on a remote Debian or Ubuntu system. :param context: An execution context created by :mod:`executor.contexts`. This function performs the following system maintenance tasks: 1. The ``apt-get update`` command is run (using the Python API of the :pypi:`apt-mirror-updater` program). 2. The ``apt-get dist-upgrade`` command is run [1]_. 3. The ``apt-get clean`` command is run. 4. If the file ``/var/run/reboot-required`` exists (indicating that a reboot is required due to security updates) the remote system is rebooted using the Python API of the ``reboot-remote-system`` program, to enable automatic unlocking of remote root disk encryption. 5. Old kernel packages are removed (using the Python API of the ``debuntu-kernel-manager`` program). If more than one meta package is installed a warning message is logged but no exception is raised. 6. The ``apt-get autoremove --purge`` command is run to optionally [1]_ remove any 'auto-removable' system packages. .. [1] Because the ``apt-get`` option ``--yes`` is not used, the operator will be asked to confirm using an interactive confirmation prompt. """ # Run 'apt-get update' (with compensation if things break). updater = AptMirrorUpdater(context=context) updater.smart_update() # Run 'apt-get dist-upgrade'. logger.info("Upgrading system packages on %s ..", context) context.execute('apt-get', 'dist-upgrade', sudo=True, tty=True) # Run 'apt-get clean'. logger.info("Cleaning up downloaded archives on %s ..", context) context.execute('apt-get', 'clean', sudo=True) # Use debuntu-kernel-manager to detect when a reboot is required by package # upgrades or because the system isn't running on the newest kernel yet. kernel_manager = KernelPackageManager( apt_options=['--yes'], context=context, ) if force_reboot: reboot_helper(kernel_manager, "Rebooting %s as requested by operator ..") elif kernel_manager.reboot_required: reboot_helper( kernel_manager, "Rebooting %s because this is required by package upgrades ..") elif not kernel_manager.running_newest_kernel: reboot_helper( kernel_manager, "Rebooting %s because it's not yet running the newest kernel ..") # Cleanup old kernel packages after rebooting, when we're # most likely (average case) running on the newest kernel. try: kernel_manager.cleanup_packages() except CleanupError as e: # Don't error out when multiple meta packages are installed. logger.warning(e) # Interactively prompt to remove packages that seem to no longer be needed # (but never assume this to be correct: the operator needs to confirm). logger.info("Removing 'auto-removable' system packages ..") context.execute('apt-get', 'autoremove', '--purge', sudo=True, tty=True) logger.info("Done!")