distro: set the repository checksum dynamically

Instead of having a static repository checksum, set it dynamically from
the metadata that osbuild-composer last saw. This is implemented in
dnf-json, which returns the checksums for each repository on every call.

This enables the use of repositories that change over time, such as
fedora-updates. Note that the osbuild pipeline will break when such a
repository changes. This is intentional: pipelines have to be
reproducible.
This commit is contained in:
Lars Karlitski 2019-12-07 23:01:44 +01:00
parent 75218ad2d9
commit d3a0b788a2
20 changed files with 184 additions and 95 deletions

View file

@ -2,6 +2,7 @@
import datetime
import dnf
import hashlib
import json
import sys
@ -24,7 +25,7 @@ def dnfrepo(desc, parent_conf=None):
elif "metalink" in desc:
repo.metalink = desc["metalink"]
elif "mirrorlist" in desc:
repo.metalink = desc["mirrorlist"]
repo.mirrorlist = desc["mirrorlist"]
else:
assert False
@ -46,6 +47,30 @@ def exit_with_dnf_error(kind: str, reason: str):
sys.exit(DNF_ERROR_EXIT_CODE)
def repo_checksums(base):
checksums = {}
for repo in base.repos.iter_enabled():
# Uses the same algorithm as libdnf to find cache dir:
# https://github.com/rpm-software-management/libdnf/blob/master/libdnf/repo/Repo.cpp#L1288
if repo.metalink:
url = repo.metalink
elif repo.mirrorlist:
url = repo.mirrorlist
elif repo.baseurl:
url = repo.baseurl[0]
else:
assert False
digest = hashlib.sha256(url.encode()).hexdigest()[:16]
with open(f"{base.conf.cachedir}/{repo.id}-{digest}/repodata/repomd.xml", "rb") as f:
repomd = f.read()
checksums[repo.id] = "sha256:" + hashlib.sha256(repomd).hexdigest()
return checksums
call = json.load(sys.stdin)
command = call["command"]
arguments = call.get("arguments", {})
@ -66,7 +91,10 @@ if command == "dump":
"buildtime": timestamp_to_rfc3339(package.buildtime),
"license": package.license
})
json.dump(packages, sys.stdout)
json.dump({
"checksums": repo_checksums(base),
"packages": packages
}, sys.stdout)
elif command == "depsolve":
base = create_base(arguments.get("repos", {}))
@ -82,13 +110,16 @@ elif command == "depsolve":
except dnf.exceptions.DepsolveError as e:
exit_with_dnf_error("DepsolveError", f"There was a problem depsolving {arguments['package-specs']}: {e}")
packages = []
dependencies = []
for package in base.transaction.install_set:
packages.append({
dependencies.append({
"name": package.name,
"epoch": package.epoch,
"version": package.version,
"release": package.release,
"arch": package.arch
})
json.dump(packages, sys.stdout)
json.dump({
"checksums": repo_checksums(base),
"dependencies": dependencies
}, sys.stdout)