Newer
Older
#!/bin/bash
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
ACTION=$1
# Functions
function abort() {
echo "$1" >&2 && exit 1
}
function cn_config() {
# /opt/cn-config/cn-config.ldif is managed by kubernetes configmap
configsrc=/opt/cn-config/cn-config.ldif
if [ ! -f $configsrc ]; then
abort "$configsrc does not exist. Exiting."
fi
# always re-install config from latest repp
rm -rf ${LDAP_CONF_DIR}/*}
echo -e "slapadd -v -F ${LDAP_CONF_DIR} -bcn=config -l ${configsrc}"
slapadd -v -F ${LDAP_CONF_DIR} -bcn=config -l ${configsrc}
# test data load success
if [ "$?" -ne 0 ]; then
# remove restored data since config faulty, forcing reload on next boo
rm -rfv ${LDAP_MDB_DIR}/*.mdb
abort "Config data load did not succeed. Exiting."
fi
}
# Force to load from ldif
function ldif_load() {
echo -e "Assessing data state for ldap role: ${LDAP_ROLE}"
file_data=$(ls -t ${LDAP_BAK_DIR}/mdb/*.db-ldif 2>/dev/null | head -n 1)
if [[ ! -f "$file_data" ]] ; then
abort "No ldif file found in ${LDAP_BAK_DIR}/mdb. Exiting."
fi
echo "slapadd -q -F ${LDAP_CONF_DIR} -b dc=stanford,dc=edu -l ${file_data}"
rm -rf ${LDAP_MDB_DIR}/data.mdb
slapadd -q -F ${LDAP_CONF_DIR} -b dc=stanford,dc=edu -l ${file_data}
if [[ ${LDAP_ROLE} = "master" ]]; then
bakDataAccessLog=$(ls -t ${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb.[[:digit:]]* | head -n 1)
# restore snapshot of latest accesslog mdb iff it corresponds to most recent data snapshot,
# ie, it is tagged with the same timestamp, eg, <filename>.mdb.<timestamp>
if [[ ${bakData##*.} = ${bakDataAccessLog##*.} ]]; then
echo -e "Loading accesslog corresponding to most recent data snapshot"
stat --format "restoring snapshot of accesslog '%n' modified on %y" ${bakDataAccessLog}
cp -v ${bakDataAccessLog} ${LDAP_MDB_DIR}/accesslog/data.mdb
fi
fi
echo "Size of the ${LDAP_MDB_DIR}/data.mdb is:"
du -sh ${LDAP_MDB_DIR}/data.mdb
}

Xueshan Feng
committed
if [ -f ${LDAP_BAK_DIR}/force-reload ]; then
echo "${LDAP_BAK_DIR}/force-reload present, set LDAP_FORCE_RESTORE=true"
LDAP_FORCE_RESTORE="true"
else
LDAP_FORCE_RESTORE="false"
fi
echo -e "Assessing data state for ldap role: ${LDAP_ROLE}"
file_data=$(ls -t ${LDAP_BAK_DIR}/mdb/data.mdb* 2>/dev/null | head -n 1)
if [[ ( ! -f "$file_data" ) ]] ; then
abort "No mdb snapshot found in ${LDAP_BAK_DIR}/mdb. Exiting."
fi
# Get latest data.mdb in backup
bakData=$(ls -t ${LDAP_BAK_DIR}/mdb/data.mdb.[[:digit:]]* | head -n 1)
echo "Latest mdb file in backup: $bakData"
# Restore data and config if LDAP_FORCE_RESTORE is true or newer backup exists or size is smaller then usual.
echo "Comparing timestamps of $bakData and ${LDAP_MDB_DIR}/data.mdb"
if [[ ${LDAP_FORCE_RESTORE} = "true" ]] || [[ ${bakData} -nt ${LDAP_MDB_DIR}/data.mdb ]] \
|| du -sh ${LDAP_MDB_DIR}/data.mdb | grep -q 'M';
then
if [[ ${LDAP_FORCE_RESTORE} = "true" ]]; then
echo "Force restore from ${bakData}"
else
du -sh ${LDAP_MDB_DIR}/data.mdb
echo -e "\nLoading most recent data and config..."
fi
find ${LDAP_MDB_DIR} -type f -name '*.mdb' -delete
stat --format "Restoring snapshot '%n' modified on %y" ${bakData}
cp -v ${bakData} ${LDAP_MDB_DIR}/data.mdb
if [[ ${LDAP_ROLE} = "master" ]]; then
bakDataAccessLog=$(ls -t ${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb.[[:digit:]]* | head -n 1)
# restore snapshot of latest accesslog mdb iff it corresponds to most recent data snapshot,
# ie, it is tagged with the same timestamp, eg, <filename>.mdb.<timestamp>
if [[ ${bakData##*.} = ${bakDataAccessLog##*.} ]]; then
echo -e "Loading accesslog corresponding to most recent data snapshot"
stat --format "restoring snapshot of accesslog '%n' modified on %y" ${bakDataAccessLog}
cp -v ${bakDataAccessLog} ${LDAP_MDB_DIR}/accesslog/data.mdb
fi
fi
else
echo "${LDAP_MDB_DIR}/data.mdb is most recent data available."
fi
echo "Size of the ${LDAP_MDB_DIR}/data.mdb is:"
du -sh ${LDAP_MDB_DIR}/data.mdb
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
function mdb_dump() {
if [ ! $(which /usr/bin/mdb_copy) ]; then
abort "mdb_copy not installed. Exiting."
fi
timestamp=$(date "+%Y%m%d%H%M%S")
tmpdir=/tmp/$timestamp
mkdir -p $tmpdir
# data mdb
# Clean up old data, just in case
rm -rf ${LDAP_BAK_DIR}/mdb/data.mdb ${LDAP_BAK_DIR}/mdb/accesslog/data.mdb
echo "Performing snapshot using mdbcopy"
if ! /usr/bin/mdb_copy ${LDAP_MDB_DIR} ${LDAP_BAK_DIR}/mdb; then
abort "mdb_copy mdb failed. Existing."
else
mv ${LDAP_BAK_DIR}/mdb/data.mdb ${LDAP_BAK_DIR}/mdb/data.mdb.$timestamp
ls -lt ${LDAP_BAK_DIR}/mdb/data.mdb.${timestamp}
fi
# accesslog mdb
if [[ ${LDAP_ROLE} = "master" ]]; then
echo "Performing accesslog snapshot using mdbcopy"
if ! /usr/bin/mdb_copy ${LDAP_MDB_DIR}/accesslog ${LDAP_BAK_DIR}/mdb/accesslog; then
abort "mdb_copy accesslog failed. Existing."
else
mv ${LDAP_BAK_DIR}/mdb/accesslog/data.mdb \
${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb.${timestamp}
ls -lt ${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb.${timestamp}
fi
fi
# config
echo "Performing config dump using slapcat"
slapcat -F /etc/ldap/slapd.d -b cn=config > ${tmpdir}/config-${LDAP_ROLE}.ldif.$timestamp
# ensure slapcat issued no errors before copying config to backups
if [ "$?" -ne 0 ]; then
abort "Config dump did not succeed. Exiting."
fi
cp -v ${tmpdir}/config-${LDAP_ROLE}.ldif.$timestamp ${LDAP_BAK_DIR}/config
# clean up
rm -Rf ${tmpdir}
}
function ldif_dump() {
echo -e "Performing ldif dump for ${LDAP_ROLE} database"
# exit if backup directories not present
if [ ! -d ${LDAP_BAK_DIR}/ldif ]; then
abort "ldif dump directory not present: ${LDAP_BAK_DIR}/ldif"
fi
# wait for slapd process to exit before backing up
j=0
while pgrep -x slapd; do
sleep 3
j=$(($j+1))
if [ $j -gt 40 ]; then
abort "slapd shutdown is hung so backup cannot continue. Exiting."
fi
done
# dump and zip
timestamp=$(date "+%Y%m%d%H%M%S")
slapcat -v -b ${LDAP_BASE} > ${LDAP_BAK_DIR}/ldif/${LDAP_ROLE}-${timestamp}.db-ldif
# ensure slapcat issued no errors
if [ "$?" -ne 0 ]; then
abort "Database dump did not succeed. Exiting."
fi
gzip -v ${LDAP_BAK_DIR}/ldif/${LDAP_ROLE}-${timestamp}.db-ldif
}
function prune_dumpdir() {
# Clean up staled backup files (no timestamp suffix)
rm -rf ${LDAP_BAK_DIR}/mdb/data.mdb ${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb
files=($(ls -t ${LDAP_BAK_DIR}/mdb/data.mdb*))
file_count=${#files[@]}
trim_num=$(expr ${file_count} - ${MDB_BAK_HISTORY})
if [ $trim_num -gt 0 ]; then
for (( i=$MDB_BAK_HISTORY; i<=$(( $file_count -1 )); i++ ))
do
#echo -e "deleting file: ${files[$i]}\n"
rm -v ${files[$i]}
done
else
echo "No files to remove in ${LDAP_BAK_DIR}/mdb"
fi
files=($(ls -t ${LDAP_BAK_DIR}/mdb/accesslog/accesslog.mdb*))
file_count=${#files[@]}
trim_num=$(expr ${file_count} - ${MDB_BAK_HISTORY})
if [ $trim_num -gt 0 ]; then
for (( i=$MDB_BAK_HISTORY; i<=$(( $file_count -1 )); i++ ))
do
#echo -e "deleting file: ${files[$i]}\n"
rm -v ${files[$i]}
done
else
echo "No files to remove in ${LDAP_BAK_DIR}/mdb/accesslog"
fi
files=($(ls -t ${LDAP_BAK_DIR}/config/*.ldif*))
file_count=${#files[@]}
trim_num=$(expr ${file_count} - ${CONF_BAK_HISTORY})
if [ $trim_num -gt 0 ]; then
for (( i=$CONF_BAK_HISTORY; i<=$(( $file_count -1 )); i++ ))
do
#echo -e "deleting file: ${files[$i]}\n"
rm -v ${files[$i]}
done
else
echo "No files to remove in ${LDAP_BAK_DIR}/config"
fi
}
function krenew() {
echo "renewing kerberos tgt every $renew_secs seconds"
# sleep $renew_secs before first tkt renewal, since the initContainer obtains initial tkt
sleep $renew_secs
while true
do
kinit_svc
sleep $renew_secs
done
}
function kinit_svc() {
ccfile=${KRB5CCNAME#*:}
# Make the principal be the first component of HOSTNAME followed by
# 'stanford.edu'.
# Example 1. If HOSTNAME is 'ldap-test-smaster.cluster.local' then the
# principal will be 'ldap-test-smaster.stanford.edu'.
# Example 2. If HOSTNAME is 'ldap-test-sh.stanford.edu' then the
# principal will be 'ldap-test-sh.stanford.edu'.
principal=${HOSTNAME%%.*}.${REALM}
kinit -k -t $KRB5_KTNAME -c ${ccfile} ldap/${principal}
klist
}
# MAIN

Xueshan Feng
committed
# Run ldconfig to make sure our compiled slapd uses /lib, /usr/lib for its libraries path
ldconfig
# ensure data dump dirs present
mkdir -p ${LDAP_BAK_DIR}/mdb ${LDAP_BAK_DIR}/mdb/accesslog ${LDAP_BAK_DIR}/config ${LDAP_MDB_DIR}/accesslog

Xueshan Feng
committed
# set LDAP_FORCE_RESTORE to true if
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
case "${ACTION}" in
dump)
# Only do snaphost on one ldap server
pod_last_number=$(hostname -s | rev | cut -d "-" -f 1)
while true
do
sleep ${MDB_BAK_FREQ}
# Don't do dump if no-backup file exists
if [ -f ${LDAP_BAK_DIR}/no-backup ]; then
echo "${LDAP_BAK_DIR}/no-backup exists. Skip backup"
elif [ "$pod_last_number" = "0" ]; then
echo "making mdb_copy every ${MDB_BAK_FREQ} seconds"
echo "MDB backup stared."
mdb_dump && prune_dumpdir
echo "MDB backup ended."
next_backup=$(date -d "+$MDB_BAK_FREQ seconds")
echo "Next backup will start at $next_backup."
fi
done
;;
ldifdump)
ldif_dump
;;
kinit)
kinit_svc
;;
krenew)
shift
renew_secs=$1
krenew
;;
cn_config)
cn_config
;;
datapop)
cn_config && mdb_load
;;
# Generate cert hash files. Cert secret is mounted at /etc/ssl/ssl-certs
until [[ -f /etc/ssl/certs/server.pem ]] && [[ -f /etc/ssl/certs/ldap-cabundle.pem ]]
if [[ -f /etc/ssl/ssl-certs/server.pem ]] && [[ -f /etc/ssl/ssl-certs/ldap-cabundle.pem ]];
cp /etc/ssl/ssl-certs/server.pem /etc/ssl/certs
cp /etc/ssl/ssl-certs/ldap-cabundle.pem /etc/ssl/certs
c_rehash /etc/ssl/certs
fi
sleep 1
done
# Default slapd url, we should open ldaps as well for ldap+TLS
endpoints="ldap:/// ldaps:///"
if [[ "$ENABLE_SIMPLE" = "yes" ]]; then
# Simple bind needs saslauthd.
# Put the process PID in /var/run/saslauthd.
KRB5_KTNAME=/etc/krb5.keytab /usr/sbin/saslauthd -O /etc/saslauthd.conf \
if [[ "X${LDAP_LOG_FILE}" != "X/dev/null" ]]
then
if ! /usr/sbin/slapd -h "${endpoints}" -F /etc/ldap/slapd.d -d ${LDAP_LOG_LEVEL} > ${LDAP_LOG_FILE} 2>&1; then
echo "slapd failed to start. Wipe out local copy, forcing reload on next start."
rm -rfv ${LDAP_MDB_DIR}/*.mdb ${LDAP_MDB_DIR}/accesslog/*.mdb
fi
;;
stop)
if [[ -f /var/run/saslauthd/saslauthd.pid ]]; then
# Stop saslauthd
kill -9 `cat /var/run/saslauthd/saslauthd.pid`
fi
pid=$(cat /var/run/slapd.pid 2>/dev/null || pidof slapd)
retry=TERM/20/KILL/forever
if [ -n $pid ]; then
start-stop-daemon --stop --retry ${retry} --pid ${pid} 2>&1
else
start-stop-daemon --stop --retry ${retry} --exec /usr/sbin/slapd 2>&1
fi
;;
*)
abort "Usage: $0 (ldap|dump|ldifdump|krenew|kinit|cn_config|datapop|datapop-ldif)"