forked from rackerlabs/auter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auter.yumdnfModule
224 lines (190 loc) · 9.37 KB
/
auter.yumdnfModule
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/bin/bash
# This is a script that is intended to only be called by /usr/bin/auter and
# contains linux package manager specific code for auter.
# This is the yum/dnf version of this script intended for redhat/fedora/CentOS
# Exit if this script is executed directly
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
echo "ERROR: This script is used by auter and should not be executed directly. Exiting"
fi
function check_package_manager_lock() {
# Set default values if the variables are undefined
[[ "$PACKAGEMANAGERLOCKRETRIES" ]] || PACKAGEMANAGERLOCKRETRIES=5
[[ "$PACKAGEMANAGERLOCKRETRIES" -lt 1 ]] && PACKAGEMANAGERLOCKRETRIES=5
[[ "$PACKAGEMANAGERLOCKWAITTIME" ]] || PACKAGEMANAGERLOCKWAITTIME=60
[[ "$PACKAGEMANAGERLOCKWAITTIME" -lt 1 ]] && PACKAGEMANAGERLOCKWAITTIME=60
if [[ -f /var/run/yum.pid ]]; then
if { pgrep --pidfile /var/run/yum.pid &>/dev/null ; } ; then
for _lockcheckattempt in $(seq 1 $((PACKAGEMANAGERLOCKRETRIES + 1))); do
# If this has reached the retry limit configured then abort
if [[ $_lockcheckattempt -eq $((PACKAGEMANAGERLOCKRETRIES + 1)) ]]; then
logit "ERROR: Final attempt to wait for yum to release lock file failed. Aborting auter run"
quit 3
fi
logit "INFO: /var/run/yum.pid exists and process runnning. Waiting $PACKAGEMANAGERLOCKWAITTIME seconds for yum lock to be released: Attempt $_lockcheckattempt of $PACKAGEMANAGERLOCKRETRIES"
sleep $PACKAGEMANAGERLOCKWAITTIME
{ pgrep --pidfile /var/run/yum.pid &>/dev/null ; } || { logit "INFO: yum lock has been released" && break ; }
done
fi
fi
}
function prepare_updates() {
# Check for yum.lock file
check_package_manager_lock
local prepoutput
local -i rc
prepoutput="$(date '+%F %T')\\n"
# Run any pre-prep scripts
for _script in "$PREPREPSCRIPTDIR"/*; do
run_script "$_script" "Pre-Prep"
done
if [[ "$PREDOWNLOADUPDATES" == "yes" ]]; then
if [[ $("$PACKAGE_MANAGER" --help | grep -c downloadonly) -gt 0 ]]; then
# Remove the old rpms from the auter cache
[[ "$ONLYINSTALLFROMPREP" == "yes" ]] && rm -f "$DOWNLOADDIR"/"$CONFIGSET"/*.rpm
prepoutput+=$("$PACKAGE_MANAGER" check-update "${PACKAGEMANAGEROPTIONS[@]}" 2>&1)
rc=$?
# If check-update has an exit code of 100, updates are available.
if [[ "$rc" -eq 100 ]]; then
# Run any pre-prep scripts
sleep_delay=$((RANDOM % MAXDELAY))
[[ $sleep_delay -gt 1 ]] && logit "INFO: Sleeping for $sleep_delay seconds"
sleep $sleep_delay
if [[ "$ONLYINSTALLFROMPREP" == "yes" ]]; then
downloadoption=("--downloaddir=$DOWNLOADDIR/$CONFIGSET")
# DNF doesn't support downloaddir, so instead we download to the default
# location and copy out the way
if [[ "$PACKAGE_MANAGER" == "dnf" ]]; then
find /var/cache/dnf -name "*.rpm" -exec rm -f {} \;
downloadoption=()
fi
DOWNLOADLOGMSG=" to $DOWNLOADDIR/$CONFIGSET"
fi
if prepoutput+="$("$PACKAGE_MANAGER" "${PACKAGEMANAGEROPTIONS[@]}" "${downloadoption[@]}" update --downloadonly -y 2>&1)"; then
if [[ "$ONLYINSTALLFROMPREP" == "yes" && "$PACKAGE_MANAGER" == "dnf" ]]; then
find /var/cache/dnf -name "*.rpm" -exec mv {} "$DOWNLOADDIR/$CONFIGSET" \;
fi
logit "INFO: Updates downloaded$DOWNLOADLOGMSG"
read -d '\n' -ra pkglist <<< "$(awk '/Package.*Arch/,/Transaction Summary/{if ($2 ~ /x86|686|noarch/) print $1}' <<< "$prepoutput")"
prepoutput+="\\nSTATUS:SUCCESS:Package download complete:${#pkglist[@]}"
else
logit "ERROR: Updates could not be pre-downloaded$DOWNLOADLOGMSG. See the $DATADIR/last-prep-output-$CONFIGSET file for details."
prepoutput+="\\nSTATUS:FAILED:Package download failed"
fi
elif [[ "$rc" -eq 1 ]]; then
logit "ERROR: Exit status $rc returned by \`$PACKAGE_MANAGER ${PACKAGEMANAGEROPTIONS[*]} ${downloadoption[*]} update --downloadonly -y\`. Exiting."
prepoutput+="\\nSTATUS:FAILED:Yum failed with status $rc"
else
logit "INFO: No updates are available to be downloaded."
prepoutput+="\\nSTATUS:SUCCESS:No updates available"
fi
else
if [[ "${ONLYINSTALLFROMPREP}" == "yes" ]]; then
logit "ERROR: DOWNLOADOPTION set to 'yes' but the '--downloadonly' option is not available in the current version of $PACKAGE_MANAGER"
quit 3
else
logit "WARNING: downloadonly option is not available"
prepoutput+="\\nSTATUS:FAILED:Download only not available"
fi
fi
else
prepoutput+="$("$PACKAGE_MANAGER" "${PACKAGEMANAGEROPTIONS[@]}" check-update 2>&1)"
fi
rotate_file "$DATADIR/last-prep-output-$CONFIGSET"
[[ "$prepoutput" ]] && echo -e "$prepoutput" > "$DATADIR/last-prep-output-$CONFIGSET"
# Run any post-prep scripts
for _script in "$POSTPREPSCRIPTDIR"/*; do
run_script "$_script" "Post-Prep"
done
}
function apply_updates() {
# Default rc to 0 which means no updates are available
local -i rc=0
local applyoutput updateaction history_before history_after transactionid
applyoutput="$(date '+%F %T')\\n"
# Set the list of rpms to be installed
if [[ "$ONLYINSTALLFROMPREP" == "yes" ]]; then
# Check if there are updates staged for this configset
if [[ $(find "$DOWNLOADDIR/$CONFIGSET" -name "*.rpm" | wc -l) -gt 0 ]]; then
local rpms=()
# Check if the updates staged are still required
for _package in "$DOWNLOADDIR/$CONFIGSET"/*.rpm; do
# Check if the local rpm is an update to the installed package and if it is then add the file to rpms
# list. We are using rpm directly for this check because "yum check-update" does not support local rpm
# files. This also avoids connecting to the repos. And finally this avoids an issue when updating the
# kernel to the same version.
rpm -U --nodeps --test "$_package" &>/dev/null && rpms+=("$_package")
done
# We are manually setting the rc to 100 if there are updates to be applied. This is the return code that
# yum check-update would return if there were outstanding updates
[[ "${rpms[*]}" ]] && rc=100
fi
# When passing RPM files to dnf/yum, the update verb won't install any that aren't already
# installed (i.e. dependencies of other packages). Instead we need to use install.
updateaction="install"
else
applyoutput+=$("$PACKAGE_MANAGER" check-update "${PACKAGEMANAGEROPTIONS[@]}" 2>&1)
rc=$?
updateaction="update"
fi
# If check-update has an exit code of 100, updates are available.
if [[ "$rc" -eq 100 ]]; then
# Sleep before continuing with pre-scripts and updates
sleep_delay=$((RANDOM % MAXDELAY))
[[ $sleep_delay -gt 1 ]] && logit "INFO: Sleeping for $sleep_delay seconds"
sleep $sleep_delay
# Check for yum.lock file
check_package_manager_lock
for _script in "$PREAPPLYSCRIPTDIR"/*; do
run_script "$_script" "Pre-Apply"
done
logit "INFO: Applying updates"
history_before=$($PACKAGE_MANAGER history list)
# We don't want to allow the user to interrupt a yum/dnf transaction or Bad Things Happen.
trap '' SIGINT SIGTERM
rotate_file "$DATADIR/last-apply-output-$CONFIGSET"
if applyoutput+=$("$PACKAGE_MANAGER" "$updateaction" -y "${PACKAGEMANAGEROPTIONS[@]}" "${rpms[@]}" 2>&1); then
read -d '\n' -ra pkglist <<< "$( sed -r 's/^[[:space:]]+//g' <<< "$applyoutput" | awk '/(Updating|Upgrading|Installing)[[:space:]]+/{print $3}')"
applyoutput+="\\nSTATUS:SUCCESS:Package updates applied:${#pkglist[@]}"
else
applyoutput+="\\nSTATUS:FAILED:Package updates failed"
fi
default_signal_handling
echo -e "$applyoutput" > "$DATADIR/last-apply-output-$CONFIGSET"
history_after=$($PACKAGE_MANAGER history list)
for _script in "$POSTAPPLYSCRIPTDIR"/*; do
run_script "$_script" "Post-Apply"
done
if [[ "$history_before" == "$history_after" ]]; then
logit "ERROR: Updates failed. See the $DATADIR/last-apply-output-$CONFIGSET-$(date +%F) file for details. Exiting."
cp "$DATADIR/last-apply-output-$CONFIGSET" "$DATADIR/last-apply-output-$CONFIGSET-$(date +%F)"
quit 3
fi
transactionid=$($PACKAGE_MANAGER history info 2>&1 | grep "Transaction ID")
logit "INFO: Updates complete ($PACKAGE_MANAGER $transactionid). You may need to reboot for some updates to take effect"
log_last_run
# Excluding this check because the REBOOTCALL variable is used by the main auter script
# shellcheck disable=SC2034
if [[ "$AUTOREBOOT" == "yes" ]]; then
REBOOTCALL=1
elif [[ ! "$AUTOREBOOT" == "no" ]]; then
for _pkg in "${pkglist[@]}"; do
if [[ "${_pkg%-*-*}" =~ ^(${AUTOREBOOT// /\|})$ ]]; then
REBOOTCALL=1
break
fi
done
fi
# Remove the old rpms from the auter cache
[[ "$ONLYINSTALLFROMPREP" == "yes" ]] && rm -f "$DOWNLOADDIR/$CONFIGSET"/*.rpm
elif [[ "$rc" -eq 0 ]]; then
logit "INFO: No updates are available to be applied."
applyoutput+="\\nSTATUS:SUCCESS:No updates available"
echo -e "$applyoutput" > "$DATADIR/last-apply-output-$CONFIGSET"
log_last_run
else
logit "ERROR: Exit status $rc returned by \`$PACKAGE_MANAGER check-update ${PACKAGEMANAGEROPTIONS[*]}\`. Exiting."
applyoutput+="\\nSTATUS:FAILED:Yum failed with status $rc"
echo -e "$applyoutput" > "$DATADIR/last-apply-output-$CONFIGSET"
quit 3
fi
}