[Starlingx-discuss] [ Build ] Layered build challenges

Scott Little scott.little at windriver.com
Tue Mar 31 18:21:37 UTC 2020


Layered builds relies on an authoritative source (e.g. CENGN) publishing 
an RPM repo with all the RPMS produced by a single build, and an lst 
file enumerating those RPMS.  There are new config files describing the 
url's for those repos that use the latest_build symlink.  The client, a 
higher layer we wish to build, must download the new lst file and repo 
data, and use those to download all new/updates rpms.

Issue identified early on where.

1) The outputs of a specific build might not endure on CENGN as long as 
a designers build context.

2) The latest_build symlink might change in the middle of a download 
season.  Packages version may have changes during between builds.  The 
old version specified by the pre-update lst file might no longer be 
available.

So the next step is for CENGN to mirror those build outputs in a 
cumulative fashion, like any other repo.  It's a default for 
download_mirror.sh to look for a CENGN mirror of any url it uses, and 
its a default behavior for CENGN to mirror it.  The mirror would 
accumulate all the versions from all the builds.  So changing symlinks 
and deletion of old builds shouldn't impact the end user.

All this hinged on two assumptions.

1) If a package was not upversioned between builds, there would not be 
significant changes to the content of the RPM.

2) yum repodata has checksums and timestamps for all packages.  I 
expected yum to use that data to flag a changed rpm for re-download.

Recent experience has proven both assumptions turned out to be wrong.

1) Kernel modules were the first example of a violation of this 
asumption.  The mkod implicitly changes when the kernel changes. The 
most obvious is that the installation path to the kmod change, embedding 
the kernel version it was compiled against.  There are deeper 
differences not worth enumerating.

2) Yum will throw error over inconsistancies between new repodata and 
old, our new repodata and rpms already downloaded, but will not 
re-download the updated packages.  I have not been able to override this 
behavious with command line options, config files, or even cleaning all 
yum cache.  It appears to be a defense against mirrors that are slow to 
update, and perhaps against malicious hacks of an upstream repo.

The broken assumptions affected both the CENGN mirroring process, and 
the final download by upper layer builders.  Neither was updating rpms 
that have changed if the file name did not also change.

Is this only an important matter for kmods.  Exploration with rpmdiff 
reveals that the majority of RPMS change when rebuilt, even with zero 
source code changes to any package.  Excluding the timestamps on files 
embedded within the rpms lefts a list greater than 25% of the repo 
reporting differences.  Spent some time trying to figure out a way to 
filter out paths that embed the build time stamp, but the list remained 
stubbornly large.

So how to fix it.

Several methods have been explored.  Some solutions only apply if the 
downloader retains the file structure of the upstream repo, or if the 
download capture the entire repo.   True for the cengn mirror, not for 
the output of download_mirror.sh.

1) reposync: An rpm repo mirroring tool.  It's built on yum, and has the 
same behaviour as yum.  Can't use that.

2) verifytree:  This tool validates the checksums in the repodata vs the 
current set of rpms.  It's a tool aimed at rpm mirror operators. It 
requires that the download directory structure is a faithful replica of 
upstream.  So I can manually download the repodata, then validate it vs 
the previously downloaded set of rpms.  RPM's that it flags as having 
the wrong checksum need to be re-downloaded.  The actual re-download 
could be accomplished in two ways.

2a) Replicate the current repo in a temporary working directory, delete 
the updated rpms, use yum (either reposync or yumdownloader) with clean 
cache to re-download the missing files. Finally exchange the temporary 
directory with regular one.  This gives an atomic cutover to the new 
content.  This is what CENGN mirror is using now.

   This doesn't entirely solve the problem for downloaders that were 
actively updated their local snapshot when such a mirror update goes 
live.  Ideally the download_mirror tool has a retry loop.  If the last 
pass downloaded files, try again until a pass reports there are no 
further files to update.

2b) curl:  Use curl rather than yum.  Requires that we somehow know the 
URL for the rpm we intend to download.  'yumdownloader --url' can tell 
use the upstream url.

3) curl:  Use curl rather than yum, but do so directly without 
verifytree.  Rely entirely on timestamps.  If we can give curl the 
download url for the rpm, it can be given options that compare the local 
and remote file timestamps and only downloads if the remote copy is 
newer.  Also it preserves the file timestamp on download. We can use 
'yumdownloader --url' to tell us which repo to use, and what the 
download url is from that repo.

This was my solution for the download_mirror.sh users.

4) rsync: Requires CENGN to expose an rsync port to the world. Not my 
first choice.  File sharing pirates would love to compromise a machine 
with an open rsync port.


New issues.

1) 'yumdownloader --url' is SLOW.  It takes more than a second per 
package to produce an answer.  since lower layer rpms are handled by the 
same tools as all other rpms, we have over 2000 packages to check.  This 
slowness largely persists in batch mode where I query a large set of 
packages at once (3/4 sec per package).  It'll take an hour to process 
them all, even if the result is 'nothing to update'

2) As noted above, most rpms are showing subtle changes between builds 
even though the source has not changed.  This is undesirable, triggering 
a huge number of needless downloads.


New solutions?

1) Download rpms from lower layers using a different tool than 
'download_mirror.sh' or at least a different sub-function than dl-rpms.  
First, this mean that we only need to run 'yumdownloader -url' vs a 
smaller list of rpms.  Also this would allow us to use reposync and 
verify tree for the download functions, removing 'yumdownloader -url' 
entirely.

2) Use build avoidance.  Copies rpms from previous build into current 
build environment and then use an incremental build.  This avoids 
needlessly rebuilding rpms. RPMS retain the same checksum and timestamp 
if not rebuilt.  Cut the problem off at the source. Concern with this 
solution is that I still like to force a non-build avoidance build from 
time to time to ensure we haven't diverged from reality in some new and 
unexpected way.




More information about the Starlingx-discuss mailing list