blob: 443da9e1f316d3e8a45ffc50c31c8cdae5e65528 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
#!/bin/bash -x
# On container start, run an rsync to get a good copy of the tree.
# Then execute rsyncd; we will start serving once the sync completes.
# Then keep syncing in the background every 30m.
# Maintain 2 'partitions' of the tree.
# "serving" - This copy is served to users and is not mutated.
# "updating" - This copy is a shadow copy used for updates.
# Create the two partitions on startup.
PARTITION1=$(mktemp -d -p "${DEST_DIR}" XXXXXX)
PARTITION2=$(mktemp -d -p "${DEST_DIR}" XXXXXX)
# Function sync syncs dest ("${2}") from source ("${1}")
function sync() {
OPTS=(
--quiet
--recursive
--links
--perms
--times
--delete
--timeout=300
--progress
# NOTE(antarus): Checksum upsets some public mirror nodes; so don't use it for now.
# --checksum
)
SRC="${2}"
DST="${1}"
logger -t rsync "Started update at: $(date)"
logger -t rsync "re-rsyncing the gentoo-portage tree"
/usr/bin/rsync ${OPTS[@]} "${SRC}" "${DST}" >> $0.log 2>&1
err=$?
if [[ $err -ne 0 ]]; then
logger -t rsync "Failed to rsync tree: ${SRC}: $(date)"
return 1
fi
logger -t rsync "End: $(date)"
return 0
}
# Function init does a first sync, to populate the serving partition and
# setup symlinks, and begin serving data.
# Also, setup the tmpfs to be big enough.
# "${1}" is the serving partition. "${2}" is the update partition
function init() {
mount -t tmpfs -o size=1.3g tmpfs "${DEST_DIR}"
if [[ $? -ne 0 ]]; then
logger -t rsync "Init: Failed to resize tmpfs: ${DEST_DIR}"
return 1
fi
sync "${1}" "${SOURCE_MIRROR}" # this is synchronous.
# We serve out of ${DEST_DIR}/serving
ln -s "${1}" "serving"
# Setup the update partition
ln -s "${2}" "update"
# Then launch rsyncd; it will detach into the background and serve from serving.
rsync --daemon --config="/opt/rsync/rsyncd.conf"
return 0
}
# Function update syncs the 'update' partition and, if successful, swaps the partitions.
function update() {
update=$(readlink "${DEST_DIR}/update")
# If we fail to sync, just return false and avoid modifying the serving state.
if ! sync "${update}" "${SOURCE_MIRROR}"; then
return 1
fi
# Save the previous serving partition
old_serving=$(readlink "${DEST_DIR}/serving")
# Point the serving symlink at the update partition; now freshly updated.
mv -fT "${DEST_DIR}/update" "${DEST_DIR}/serving"
# Point the update partition at the old serving partition.
ln -sf "${old_serving}" "update"
}
function serve() {
while true
do
# TODO(antarus): Add exponential backoff.
sleep "${WAIT_TIME}"
update
done
}
# Partition1 starts as "serving", partition2 as "update"
init "${PARTITION1}" "${PARTITION2}"
if [[ $? -ne 0 ]]; then
exit 1
fi
# Serve forever
serve
|