-
-
Save Gargravarr2112/696099726599fe1e7738a575be339fdc to your computer and use it in GitHub Desktop.
bionic | |
bionic-updates | |
bionic-backports | |
xenial | |
xenial-updates | |
xenial-backports |
#!/bin/bash | |
set -euo pipefail; | |
#A considerably simpler take on apt-mirror - parses the Packages files like apt-mirror, but then builds a file of .debs to download, which is then passed to rsync which does the rest. | |
#Saves the overhead of downloading each file over HTTP and considerably simpler to debug. Can now be configured using a file containing paths instead of running rsync many times in a loop. | |
#Just like apt-mirror, capable of running on only one Ubuntu release to save space. | |
#Author: Rob Johnson | |
#Date: 2017-09-20 | |
syncDate=$(date +%F); | |
#File to build a list of files to rsync from the remote mirror - will contain one line for every file in the dists/ to sync | |
filename=packages-$syncDate.txt; | |
#Assumes a 'master source' file in /etc/mirror-rsync.d named for the masterSource value below. The file contains newline-separated | |
#entries of which dists/ to sync. See example in other file here. | |
masterSource='gb.archive.ubuntu.com'; | |
#Adapt as necessary to your package mirror setup | |
localPackageStore="/srv/packagemirror/mirror/$masterSource/ubuntu"; | |
if [ ! -f /etc/mirror-rsync.d/$masterSource ]; then | |
echo "No master source file found at /etc/mirror-rsync.d/$masterSource, create one and add one line per dists/ entry to sync"; | |
exit 1; | |
fi | |
#Add a marker for a second APT mirror to look for - if the sync falls on its face, can drop this out of the pair and sync exclusively from the mirror until fixed | |
if [ -f /srv/packagemirror/lastSuccess ]; then | |
rm -v /srv/packagemirror/lastSuccess; | |
fi | |
echo "$syncDate $(date +%T) Starting, exporting to /tmp/$filename"; | |
#In case leftover from testing or failed previous run | |
if [[ -f /tmp/$filename ]]; then | |
rm -v "/tmp/$filename"; | |
fi | |
echo "$(date +%T) Syncing releases"; | |
rsync --no-motd --delete-during --archive --recursive --human-readable --files-from="/etc/mirror-rsync.d/$masterSource" $masterSource::ubuntu "$localPackageStore/"; | |
echo "$(date +%T) Generating package list"; | |
#rather than hard-coding, use a config file to run the loop. The same config file as used above to sync the releases | |
while read release; do | |
for repo in 'main' 'restricted' 'universe' 'multiverse'; do #Adapt if necessary | |
for arch in 'amd64' 'i386'; do #Adapt if necessary | |
if [[ ! -f $localPackageStore/$release/$repo/binary-$arch/Packages ]]; then #uncompressed file not found | |
echo "$(date +%T) Extracking $release $repo $arch Packages file from archive"; | |
gunzip --keep "$localPackageStore/$release/$repo/binary-$arch/Packages.gz"; | |
fi | |
echo "$(date +%T) Extracting packages from $release $repo $arch"; | |
if [[ -s $localPackageStore/$release/$repo/binary-$arch/Packages ]]; then | |
grep 'Filename: ' "$localPackageStore/$release/$repo/binary-$arch/Packages" | sed 's/Filename: //' >> "/tmp/$filename"; | |
else | |
echo "$(date +%T) Package list is empty, skipping"; | |
fi | |
done | |
done | |
done </etc/mirror-rsync.d/$masterSource | |
echo "$(date +%T) Deduplicating"; | |
sort --unique "/tmp/$filename" > "/tmp/$filename.sorted"; | |
rm -v "/tmp/$filename"; | |
mv -v "/tmp/$filename.sorted" "/tmp/$filename"; | |
echo "$(wc -l \"/tmp/$filename\" | awk '{print $1}') files to be sync'd"; | |
echo "$(date +%T) Running rsync"; | |
#rsync may error out due to excessive load on the source server, so try up to 3 times | |
set +e; | |
attempt=1; | |
exitCode=1; | |
while [[ $exitCode -gt 0 ]] && [[ $attempt -lt 4 ]]; | |
do | |
SECONDS=0; | |
rsync --copy-links --files-from="/tmp/$filename" --no-motd --delete-during --archive --recursive --human-readable $masterSource::ubuntu "$localPackageStore/" 2>&1; | |
exitCode=$?; | |
if [[ $exitCode -gt 0 ]]; then | |
waitTime=$((attempt*300)); #increasing wait time - 5, 10 and 15 minutes between attempts | |
echo "rsync attempt $attempt failed with exit code $exitCode, waiting $waitTime seconds to retry"; | |
sleep $waitTime; | |
let attempt+=1; | |
fi | |
done | |
set -e; | |
#Exiting here will stop the lastSuccess file being created, and will stop APT02 running its own sync | |
if [[ $exitCode -gt 0 ]]; then | |
echo "rsync failed all 3 attempts, erroring out"; | |
exit 2; | |
fi | |
echo "$(date +%T) Sync complete, runtime: $SECONDS s"; | |
echo "$(date +%T) Deleting obsolete packages"; | |
#Build a list of files that have been synced and delete any that are not in the list | |
find "$localPackageStore/pool/" -type f | { grep -Fvf "/tmp/$filename" || true; } | xargs --no-run-if-empty -I {} rm -v {}; # '|| true' used here to prevent grep causing pipefail if there are no packages to delete - grep normally returns 1 if no files are found | |
echo "$(date +%T) Complete"; | |
rm -v "/tmp/$filename"; | |
touch /srv/packagemirror/lastSuccess; |
So I tried your script there and ran into this problem.
rsync: link_stat "/bionic" (in ubuntu) failed: No such file or directory (2)
I'm not sure exactly how to resolve it, I don't understand where it's failing. all I did was remove the path part for the source file so it'd work from wherever and ofc the destination path. I get that same error if I run the rsync command directly after I replace the variables ofc.
@jms1989 you might want to use this script. It's a bit more robust for downloading mirrors.
@jms1989 probably best to do what @flavienbwk suggests, I don't recognise that error, nor do I use this script at the moment (don't have a use for it). I may revisit it in the future, but otherwise I'd be debugging it the same as you. You could try set -x
to see what commands are actually being run when it fails.
To anyone finding this script - I have restarted development on it for my own needs and have created a repo: https://github.com/Gargravarr2112/mirror-rsync
Updated code (that actually works!) and instructions can be found there.
@flavienbwk Sorry, didn't see your reply until now. Also, I see I was wrong - I forgot how I wrote my own script, sorry!
The config file needs to have as the filename the mirror source. In your case, this means you create a file named 'fr.archive.ubuntu.com'. Within that file you would list the releases, which are 'bionic', 'bionic-updates' and 'bionic-backports'. You could do the same for 'security.ubuntu.com' but I feel it is better to pull security updates directly from Ubuntu to avoid a rapid update being behind. Pulling the main packages from a local mirror will dramatically reduce your required bandwidth in any case. I've added the file I used. Hope this helps!