mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
setup: Make additional info available for force upgrading
This includes list of packages for which conffile prompts will be shown. For each package current version of the package, new version of the package and list of configuration files that were modified. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
7862325bb6
commit
ec68eb3d89
@ -172,35 +172,49 @@ def subcommand_filter_conffile_packages(arguments):
|
||||
apt_pkg.init() # Read configuration that will be used later.
|
||||
packages = set(arguments.packages)
|
||||
|
||||
status_hashes = _get_conffile_hashes_from_status_file(packages)
|
||||
status_hashes, current_versions = _get_conffile_hashes_from_status_file(
|
||||
packages)
|
||||
|
||||
mismatched_hashes = _filter_matching_package_hashes(status_hashes)
|
||||
|
||||
downloaded_files = _download_packages(packages)
|
||||
|
||||
new_package_hashes = _get_conffile_hashes_from_downloaded_files(
|
||||
new_package_hashes, new_versions = _get_conffile_hashes_from_downloaded_files(
|
||||
packages, downloaded_files, status_hashes, mismatched_hashes)
|
||||
|
||||
conffile_packages = [
|
||||
package for package in packages if _is_conffile_prompt_pending(
|
||||
packages_info = {}
|
||||
for package in packages:
|
||||
modified_conffiles = _get_modified_conffiles(
|
||||
status_hashes[package], mismatched_hashes[package],
|
||||
new_package_hashes[package])
|
||||
]
|
||||
print(json.dumps(conffile_packages))
|
||||
if not modified_conffiles:
|
||||
continue
|
||||
|
||||
package_info = {
|
||||
'current_version': current_versions[package],
|
||||
'new_version': new_versions[package],
|
||||
'modified_conffiles': modified_conffiles
|
||||
}
|
||||
packages_info[package] = package_info
|
||||
|
||||
print(json.dumps(packages_info))
|
||||
|
||||
|
||||
def _is_conffile_prompt_pending(status_hashes, mismatched_hashes,
|
||||
new_package_hashes):
|
||||
"""Return whether upgrading the package requires a conffile prompt."""
|
||||
def _get_modified_conffiles(status_hashes, mismatched_hashes,
|
||||
new_package_hashes):
|
||||
"""Return list of conffiles that will cause prompts for a package."""
|
||||
modified_conffiles = []
|
||||
for conffile, hash_value in mismatched_hashes.items():
|
||||
if conffile not in new_package_hashes:
|
||||
# Modified configuration file not present new package
|
||||
continue
|
||||
|
||||
if status_hashes[conffile] != new_package_hashes[conffile]:
|
||||
if status_hashes[conffile] == new_package_hashes[conffile]:
|
||||
# Configuration file is same in both versions of package. Conffile
|
||||
# prompt is not triggered even if the file is modified on disk.
|
||||
return True
|
||||
continue
|
||||
|
||||
modified_conffiles.append(conffile)
|
||||
|
||||
for conffile, hash_value in new_package_hashes.items():
|
||||
if conffile in status_hashes:
|
||||
@ -218,9 +232,9 @@ def _is_conffile_prompt_pending(status_hashes, mismatched_hashes,
|
||||
#
|
||||
# If existing file is a directory, unattended-upgrades allows it,
|
||||
# we still treat it as a conffile prompt. This should be okay.
|
||||
return True
|
||||
modified_conffiles.append(conffile)
|
||||
|
||||
return False
|
||||
return modified_conffiles
|
||||
|
||||
|
||||
def _get_conffile_hashes_from_status_file(packages):
|
||||
@ -231,6 +245,7 @@ def _get_conffile_hashes_from_status_file(packages):
|
||||
|
||||
"""
|
||||
package_hashes = defaultdict(dict)
|
||||
package_versions = defaultdict(lambda: None)
|
||||
|
||||
status_file = apt_pkg.config.find('Dir::State::status')
|
||||
with apt_pkg.TagFile(status_file) as tag_file:
|
||||
@ -241,8 +256,9 @@ def _get_conffile_hashes_from_status_file(packages):
|
||||
|
||||
hashes = _parse_conffiles_value(section.get('Conffiles', ''))
|
||||
package_hashes[package] = hashes
|
||||
package_versions[package] = section.get('Version')
|
||||
|
||||
return package_hashes
|
||||
return package_hashes, package_versions
|
||||
|
||||
|
||||
def _parse_conffiles_value(value):
|
||||
@ -335,16 +351,19 @@ def _get_conffile_hashes_from_downloaded_files(
|
||||
packages, downloaded_files, status_hashes, mismatched_hashes):
|
||||
"""Retrieve the conffile hashes from downloaded .deb files."""
|
||||
new_hashes = defaultdict(dict)
|
||||
new_versions = defaultdict(lambda: None)
|
||||
for downloaded_file in downloaded_files:
|
||||
try:
|
||||
package_name, hashes = _get_conffile_hashes_from_downloaded_file(
|
||||
package_name, hashes, new_version = \
|
||||
_get_conffile_hashes_from_downloaded_file(
|
||||
packages, downloaded_file, status_hashes, mismatched_hashes)
|
||||
except (LookupError, apt_pkg.Error, ValueError):
|
||||
continue
|
||||
|
||||
new_hashes[package_name] = hashes
|
||||
new_versions[package_name] = new_version
|
||||
|
||||
return new_hashes
|
||||
return new_hashes, new_versions
|
||||
|
||||
|
||||
def _get_conffile_hashes_from_downloaded_file(
|
||||
@ -359,6 +378,8 @@ def _get_conffile_hashes_from_downloaded_file(
|
||||
if package_name not in packages:
|
||||
raise ValueError
|
||||
|
||||
new_version = section['Version']
|
||||
|
||||
conffiles = deb_file.control.extractdata('conffiles')
|
||||
conffiles = conffiles.decode().strip().split()
|
||||
|
||||
@ -376,7 +397,7 @@ def _get_conffile_hashes_from_downloaded_file(
|
||||
md5sum = apt_pkg.md5sum(conffile_data)
|
||||
hashes[conffile] = md5sum
|
||||
|
||||
return package_name, hashes
|
||||
return package_name, hashes, new_version
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@ -104,7 +104,7 @@ def setup(helper, old_version=None):
|
||||
helper.call('post', actions.superuser_run, 'bind', ['setup'])
|
||||
|
||||
|
||||
def force_upgrade(helper):
|
||||
def force_upgrade(helper, _packages):
|
||||
"""Force upgrade the managed packages to resolve conffile prompt."""
|
||||
helper.install(managed_packages, force_configuration='old')
|
||||
|
||||
|
||||
@ -186,8 +186,13 @@ def refresh_package_lists():
|
||||
transaction.refresh_package_lists()
|
||||
|
||||
|
||||
def filter_conffile_prompts(packages):
|
||||
"""Return a filtered list of packages that require conffile prompts."""
|
||||
def filter_conffile_prompt_packages(packages):
|
||||
"""Return a filtered info on packages that require conffile prompts.
|
||||
|
||||
Information for each package includes: current_version, new_version and
|
||||
list of modified_conffiles.
|
||||
|
||||
"""
|
||||
response = actions.superuser_run(
|
||||
'packages',
|
||||
['filter-conffile-packages', '--packages'] + list(packages))
|
||||
|
||||
@ -501,17 +501,13 @@ class ForceUpgrader():
|
||||
|
||||
apps = self._get_list_of_apps_to_force_upgrade()
|
||||
logger.info('Apps needing conffile upgrades: %s',
|
||||
', '.join([app.name for app in apps]))
|
||||
', '.join([str(app.name) for app in apps]))
|
||||
|
||||
need_retry = False
|
||||
for app in apps:
|
||||
for app, packages in apps.items():
|
||||
try:
|
||||
logger.info('Force upgrading app: %s', app.name)
|
||||
# XXX: Try to send information about package versions being
|
||||
# upgraded and the configuration files that have lead to the
|
||||
# force upgrade. This can be picked up from the 'packages
|
||||
# filter-conffile-packages' that does all the relevant work.
|
||||
app.force_upgrade(app.setup_helper)
|
||||
app.force_upgrade(app.setup_helper, packages)
|
||||
logger.info('Successfully force upgraded app: %s', app.name)
|
||||
except Exception as exception:
|
||||
logger.exception('Error running force upgrade: %s', exception)
|
||||
@ -525,7 +521,7 @@ class ForceUpgrader():
|
||||
"""Return a list of app modules on which to run force upgrade."""
|
||||
packages = self._get_list_of_upgradable_packages()
|
||||
if not packages: # No packages to upgrade
|
||||
return []
|
||||
return {}
|
||||
|
||||
package_names = [package.name for package in packages]
|
||||
logger.info('Packages available for upgrade: %s',
|
||||
@ -534,15 +530,17 @@ class ForceUpgrader():
|
||||
managed_packages, package_apps_map = self._filter_managed_packages(
|
||||
package_names)
|
||||
if not managed_packages:
|
||||
return []
|
||||
return {}
|
||||
|
||||
conffile_packages = package.filter_conffile_prompts(managed_packages)
|
||||
conffile_packages = package.filter_conffile_prompt_packages(
|
||||
managed_packages)
|
||||
logger.info('Packages that need conffile upgrades: %s',
|
||||
conffile_packages)
|
||||
|
||||
apps = set()
|
||||
apps = defaultdict(list)
|
||||
for package_name in conffile_packages:
|
||||
apps.update(package_apps_map[package_name])
|
||||
for app in package_apps_map[package_name]:
|
||||
apps[app].append(conffile_packages[package_name])
|
||||
|
||||
return apps
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user