def got_server_uuid(server_uuid): warning = "Couldn't determine which hash=>id database to use: %s" if server_uuid is None: logging.warning(warning % "server UUID not available") return None try: lsb_release_info = parse_lsb_release(self.lsb_release_filename) except IOError as error: logging.warning(warning % str(error)) return None try: codename = lsb_release_info["code-name"] except KeyError: logging.warning(warning % "missing code-name key in %s" % self.lsb_release_filename) return None arch = self._facade.get_arch() if not arch: # The Apt code should always return a non-empty string, # so this branch shouldn't get executed at all. However # this check is kept as an extra paranoia sanity check. logging.warning(warning % "unknown dpkg architecture") return None return os.path.join(self._config.hash_id_directory, "%s_%s_%s" % (server_uuid, codename, arch))
def test_parse_lsb_release_with_missing_or_extra_fields(self): """ L{parse_lsb_release} ignores lines not matching the map of known keys, and returns only keys with an actual value. """ lsb_release_filename = self.makeFile("DISTRIB_ID=Ubuntu\n" "FOO=Bar\n") self.assertEqual(parse_lsb_release(lsb_release_filename), {"distributor-id": "Ubuntu"})
def got_server_uuid(server_uuid): warning = "Couldn't determine which hash=>id database to use: %s" if server_uuid is None: logging.warning(warning % "server UUID not available") return None try: lsb_release_info = parse_lsb_release(self.lsb_release_filename) except IOError, error: logging.warning(warning % str(error)) return None
def test_parse_lsb_release(self): """ L{parse_lsb_release} returns a C{dict} holding information from the given LSB release file. """ lsb_release_filename = self.makeFile("DISTRIB_ID=Ubuntu\n" "DISTRIB_RELEASE=6.06\n" "DISTRIB_CODENAME=dapper\n" "DISTRIB_DESCRIPTION=" "\"Ubuntu 6.06.1 LTS\"\n") self.assertEqual( parse_lsb_release(lsb_release_filename), { "distributor-id": "Ubuntu", "description": "Ubuntu 6.06.1 LTS", "release": "6.06", "code-name": "dapper" })
def handle_release_upgrade(self, message): """Fetch the upgrade-tool, verify it and run it. @param message: A message of type C{"release-upgrade"}. """ target_code_name = message["code-name"] operation_id = message["operation-id"] lsb_release_info = parse_lsb_release(self.lsb_release_filename) current_code_name = lsb_release_info["code-name"] if target_code_name == current_code_name: message = self.make_operation_result_message( operation_id, FAILED, "The system is already running %s." % target_code_name, 1) logging.info("Queuing message with release upgrade failure to " "exchange urgently.") return self._send_message(message) tarball_url = message["upgrade-tool-tarball-url"] signature_url = message["upgrade-tool-signature-url"] allow_third_party = message.get("allow-third-party", False) debug = message.get("debug", False) directory = self._config.upgrade_tool_directory tarball_filename = url_to_filename(tarball_url, directory=directory) signature_filename = url_to_filename(signature_url, directory=directory) result = self.fetch(tarball_url, signature_url) result.addCallback( lambda x: self.verify(tarball_filename, signature_filename)) result.addCallback(lambda x: self.extract(tarball_filename)) result.addCallback(lambda x: self.tweak(current_code_name)) result.addCallback( lambda x: self.upgrade(target_code_name, operation_id, allow_third_party=allow_third_party, debug=debug)) result.addCallback(lambda x: self.finish()) result.addErrback(self.abort, operation_id) return result
def _compute_packages_changes(self): """Analyse changes in the universe of known packages. This method will verify if there are packages that: - are now installed, and were not; - are now available, and were not; - are now locked, and were not; - were previously available but are not anymore; - were previously installed but are not anymore; - were previously locked but are not anymore; Additionally it will report package locks that: - are now set, and were not; - were previously set but are not anymore; Also, packages coming from the security pocket will be reported as such. In all cases, the server is notified of the new situation with a "packages" message. @return: A deferred resulting in C{True} if package changes were detected with respect to the previous run, or C{False} otherwise. """ self._facade.ensure_channels_reloaded() old_installed = set(self._store.get_installed()) old_available = set(self._store.get_available()) old_upgrades = set(self._store.get_available_upgrades()) old_locked = set(self._store.get_locked()) old_autoremovable = set(self._store.get_autoremovable()) old_security = set(self._store.get_security()) current_installed = set() current_available = set() current_upgrades = set() current_locked = set() current_autoremovable = set() current_security = set() lsb = parse_lsb_release(LSB_RELEASE_FILENAME) backports_archive = "{}-backports".format(lsb["code-name"]) security_archive = "{}-security".format(lsb["code-name"]) for package in self._facade.get_packages(): # Don't include package versions from the official backports # archive. The backports archive is enabled by default since # xenial with a pinning policy of 100. Ideally we would # support pinning, but we don't yet. In the mean time, we # ignore backports, so that packages don't get automatically # upgraded to the backports version. backport_origins = [ origin for origin in package.origins if origin.archive == backports_archive] if backport_origins and ( len(backport_origins) == len(package.origins)): # Ignore the version if it's only in the official # backports archive. If it's somewhere else as well, # e.g. a PPA, we assume it was added manually and the # user wants to get updates from it. continue hash = self._facade.get_package_hash(package) id = self._store.get_hash_id(hash) if id is not None: if self._facade.is_package_installed(package): current_installed.add(id) if self._facade.is_package_available(package): current_available.add(id) if self._facade.is_package_autoremovable(package): current_autoremovable.add(id) else: current_available.add(id) # Are there any packages that this package is an upgrade for? if self._facade.is_package_upgrade(package): current_upgrades.add(id) # Is this package present in the security pocket? security_origins = any( origin for origin in package.origins if origin.archive == security_archive) if security_origins: current_security.add(id) for package in self._facade.get_locked_packages(): hash = self._facade.get_package_hash(package) id = self._store.get_hash_id(hash) if id is not None: current_locked.add(id) new_installed = current_installed - old_installed new_available = current_available - old_available new_upgrades = current_upgrades - old_upgrades new_locked = current_locked - old_locked new_autoremovable = current_autoremovable - old_autoremovable new_security = current_security - old_security not_installed = old_installed - current_installed not_available = old_available - current_available not_upgrades = old_upgrades - current_upgrades not_locked = old_locked - current_locked not_autoremovable = old_autoremovable - current_autoremovable not_security = old_security - current_security message = {} if new_installed: message["installed"] = \ list(sequence_to_ranges(sorted(new_installed))) if new_available: message["available"] = \ list(sequence_to_ranges(sorted(new_available))) if new_upgrades: message["available-upgrades"] = \ list(sequence_to_ranges(sorted(new_upgrades))) if new_locked: message["locked"] = \ list(sequence_to_ranges(sorted(new_locked))) if new_autoremovable: message["autoremovable"] = list( sequence_to_ranges(sorted(new_autoremovable))) if not_autoremovable: message["not-autoremovable"] = list( sequence_to_ranges(sorted(not_autoremovable))) if new_security: message["security"] = list( sequence_to_ranges(sorted(new_security))) if not_security: message["not-security"] = list( sequence_to_ranges(sorted(not_security))) if not_installed: message["not-installed"] = \ list(sequence_to_ranges(sorted(not_installed))) if not_available: message["not-available"] = \ list(sequence_to_ranges(sorted(not_available))) if not_upgrades: message["not-available-upgrades"] = \ list(sequence_to_ranges(sorted(not_upgrades))) if not_locked: message["not-locked"] = \ list(sequence_to_ranges(sorted(not_locked))) if not message: return succeed(False) message["type"] = "packages" result = self.send_message(message) logging.info( "Queuing message with changes in known packages: " "%(installed)d installed, %(available)d available, " "%(upgrades)d available upgrades, %(locked)d locked, " "%(auto)d autoremovable, %(security)d security, " "%(not_installed)d not installed, " "%(not_available)d not available, " "%(not_upgrades)d not available upgrades, " "%(not_locked)d not locked, " "%(not_auto)d not autoremovable, " "%(not_security)d not security.", dict( installed=len(new_installed), available=len(new_available), upgrades=len(new_upgrades), locked=len(new_locked), auto=len(new_autoremovable), not_installed=len(not_installed), not_available=len(not_available), not_upgrades=len(not_upgrades), not_locked=len(not_locked), not_auto=len(not_autoremovable), security=len(new_security), not_security=len(not_security))) def update_currently_known(result): if new_installed: self._store.add_installed(new_installed) if not_installed: self._store.remove_installed(not_installed) if new_available: self._store.add_available(new_available) if new_locked: self._store.add_locked(new_locked) if new_autoremovable: self._store.add_autoremovable(new_autoremovable) if not_available: self._store.remove_available(not_available) if new_upgrades: self._store.add_available_upgrades(new_upgrades) if not_upgrades: self._store.remove_available_upgrades(not_upgrades) if not_locked: self._store.remove_locked(not_locked) if not_autoremovable: self._store.remove_autoremovable(not_autoremovable) if new_security: self._store.add_security(new_security) if not_security: self._store.remove_security(not_security) # Something has changed wrt the former run, let's update the # timestamp and return True. stamp_file = self._config.detect_package_changes_stamp touch_file(stamp_file) return True result.addCallback(update_currently_known) return result
def _get_distribution_info(self): """Get details about the distribution.""" message = {} message.update(parse_lsb_release(self._lsb_release_filename)) return message