-
Notifications
You must be signed in to change notification settings - Fork 0
/
perun
executable file
·254 lines (204 loc) · 7.86 KB
/
perun
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
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
252
253
254
#!/bin/bash
NAME='perunv3'
SCRIPTS_DIR=`dirname $0`
LOCK_DIR=${LOCK_DIR:=/var/lock}
SERVICE_BLACKLIST=() # syntax: (item1 item2 item3)
SERVICE_WHITELIST=()
if [ -f "/etc/${NAME}.conf" ]; then
. "/etc/${NAME}.conf"
fi
if [ -f "/etc/redhat-release" ]; then
PIDOF="/sbin/pidof"
else
PIDOF="/bin/pidof"
fi
# Temporarily set umask to 077 in order to have all temp configuration files private
umask 077
### Status codes
I_FINISHED=(0 'Service ${SERVICE} processing done')
I_PROTOCOL_MINOR_DIFF=(0 'Difference in protocol minor version')
I_SERVICE_DISABLED=(0 'Service ${SERVICE} is disabled')
E_WORK_DIR=(1 'Problem with working directory')
E_TAR_FILES=(2 'Problem with extracting received files')
E_LOCK_FILE=(3 'Lock file already exists')
E_DIFF_UPDATE=(4 'Diff between old and new file failed')
E_IO=(5 'IO operation failed')
E_CONCURRENT_PROCESS=(6 'Concurrent process is running right now')
E_LOCK_DELETE=(7 'Lock file cannot be deleted')
E_LOCK_PIDFILE=(8 'Lock pid file cannot be created')
E_PROTOCOL_VERSION=(200 'Wrong version of received files - (local=${PROTOCOL_VERSION},remote=${RECEIVED_PROTOCOL_VERSION})')
E_PROTOCOL_VERSION_FILE=(201 'Remote protocol version file missing')
E_PROTOCOL_VERSION_VARIABLE=(202 'PROTOCOL_VERSION variable not set')
E_UNSUPPORTED_SERVICE=(203 'Unsupported service')
E_MOVE_ERROR=(205 'Could not move ${SRC} to ${DST}')
E_PERL_UNIQUE=(206 'Perl uniq program failed')
E_NEW_TO_OLD=(207 'Critical error! File with old state can not t be replaced with new one. Do this manually or the service will be in incosistent state! Files: OLD=${OLD} NEW=${NEW}')
E_NEW_FILE=(208 'New file (to diff_update) does not exists or it is not readable')
E_DESTINATION_FILE=(209 'Destination file (to diff_update) does not exists or do not have right persmissions')
E_PERMISSIONS=(210 'Cannot set permissions')
### Functions
function log_msg {
CODE=`eval echo '${'$1'[0]}'`
TEXT=`eval echo '${'$1'[1]}'`
TEXT=`eval echo \"${TEXT}\"` # expand variables in message
CODE=${CODE:=255}
TEXT=${TEXT:=Unknown error $1}
if [ "${CODE}" -eq 0 ]; then
MSG="Info: ${TEXT}"
echo "${MSG}"
logger -t "${NAME}" -p daemon.info "${MSG}" &>/dev/null
else
MSG="Error $1 (code=${CODE}): ${TEXT}"
echo "${MSG}" >&2
logger -t "${NAME}" -p daemon.error "${MSG}" &>/dev/null
exit "${CODE}"
fi
}
function catch_error {
ERROR_NAME="$1"
shift
"$@" || log_msg ${ERROR_NAME}
}
function create_lock {
if mkdir "${LOCK_FILE}"; then
trap 'rm -r -f "${WORK_DIR}" "${LOCK_FILE}"' EXIT
catch_error E_LOCK_PIDFILE echo $$ > "$LOCK_PIDFILE"
else
# lock file exists, check for existence of concurrent process
if $PIDOF perun | grep "\(^\| \)`cat $LOCK_PIDFILE`\( \|$\)"; then
# concurrent process is running - this skript must terminate
log_msg E_CONCURRENT_PROCESS
else
# lock is not valid; it should be deleted
catch_error E_LOCK_DELETE rm -r "$LOCK_FILE"
echo "Invalid lock file found and deleted: $LOCK_FILE" >&2
catch_error E_LOCK_FILE mkdir "${LOCK_FILE}"
trap 'rm -r -f "${WORK_DIR}" "${LOCK_FILE}"' EXIT
catch_error E_LOCK_PIDFILE echo $$ > "$LOCK_PIDFILE"
fi
fi
}
function version_check {
SERVICE_VERSION_FILE="${WORK_DIR}/VERSION"
[ -n "${PROTOCOL_VERSION}" ] || log_msg E_PROTOCOL_VERSION_VARIABLE
[ -r "$SERVICE_VERSION_FILE" ] || log_msg E_PROTOCOL_VERSION_FILE
RECEIVED_PROTOCOL_VERSION=`head -n 1 "$SERVICE_VERSION_FILE"`
[ "${RECEIVED_PROTOCOL_VERSION%.*}" = "${PROTOCOL_VERSION%.*}" ] || log_msg E_PROTOCOL_VERSION
[ ${RECEIVED_PROTOCOL_VERSION} = ${PROTOCOL_VERSION} ] || log_msg I_PROTOCOL_MINOR_DIFF
}
function diff_mv {
SRC="$1"
DST="$2"
diff -q "${SRC}" "${DST}" &>/dev/null || {
# Read permissions of the destination file
if [ -f "${DST}" ]; then
DST_PERM=`stat -c %a "${DST}"`
# Set the original permissions on the source file
catch_error E_PERMISSIONS chmod $DST_PERM "${SRC}"
fi
catch_error E_MOVE_ERROR mv -f "${SRC}" "${DST}"
# If SElinux is present and set to enforcing then restore contexts
which sestatus > /dev/null 2>&1 && if [ `sestatus | grep "SELinux status" | grep -c enabled` -eq 1 -a `sestatus | grep "Current mode" | grep -c enforcing` -eq 1 ]; then
restorecon "${DST}"
fi
return 0
}
return 1
}
function mv_chmod {
SRC="$1"
DST="$2"
# Read permissions of the destination file
if [ -f "${DST}" ]; then
DST_PERM=`stat -c %a "${DST}"`
# Set the original permissions on the source file
catch_error E_PERMISSIONS chmod $DST_PERM "${SRC}"
fi
diff_mv "${SRC}" "${DST}"
return $?
}
function in_array {
ITEM=$1
shift
for ELEMENT in "$@"; do
[ "x${ITEM}" == "x${ELEMENT}" ] && return 0
done
return 1
}
# Params: file_with_old_state file_with_new_state destination_file
# This function do diff between OLD and NEW and then apply changes to destination. After that move NEW to OLD (to ensure rigth state for another calling).
function diff_update {
OLD="$1"
NEW="$2"
DESTINATION="$3"
TMP_DIFF_FILE="${WORK_DIR}/diff_update-old_new_diff"
TMP_TO_REMOVE_FILE="${WORK_DIR}/diff_update-to_remove"
TMP_TO_ADD_FILE="${WORK_DIR}/diff_update-to_add"
TMP_DESTINATION_FILE="${WORK_DIR}/diff_update-destination"
[ -r "$NEW" ] || log_msg E_NEW_FILE
[ -r "$DESTINATION" -a -w "$DESTINATION" ] || log_msg E_DESTINATION_FILE
catch_error E_IO touch "$TMP_DIFF_FILE" "$TMP_TO_REMOVE_FILE" "$TMP_TO_ADD_FILE" "$TMP_DESTINATION_FILE"
diff -w -N "$OLD" "$NEW" > "$TMP_DIFF_FILE"
grep '^>' "$TMP_DIFF_FILE" | sed -e 's/^..//' > "$TMP_TO_ADD_FILE"
grep '^<' "$TMP_DIFF_FILE" | sed -e 's/^..//' > "$TMP_TO_REMOVE_FILE"
if [ $? -ne 0 ]; then
#nothing to remove, just add
catch_error E_IO cat "$DESTINATION" "$TMP_TO_ADD_FILE" >> "$TMP_DESTINATION_FILE"
else
#remove from second argument (file) or stdin lines which are contained in first agrument (file)
# run with -n switch!
PERL_UNIQUE='
BEGIN {
open TOREMOVE, shift @ARGV || die $!;
%toRemove = map { $_ => 1 } <TOREMOVE>;
}
s/^\s+(.*?)\s+$/$1\n/g;
print if($toRemove{$_} != 1);'
catch_error E_PERL_UNIQUE perl -n -e "$PERL_UNIQUE" "$TMP_TO_REMOVE_FILE" "$DESTINATION" > "$TMP_DESTINATION_FILE"
catch_error E_IO cat "$TMP_TO_ADD_FILE" >> "$TMP_DESTINATION_FILE"
fi
catch_error E_NEW_TO_OLD mv "$NEW" "$OLD"
diff_mv "$TMP_DESTINATION_FILE" "$DESTINATION"
}
function run_pre_hooks {
for F in `ls "${SCRIPTS_DIR}/${SERVICE}.d"/pre_* 2>/dev/null` ;do . $F ; done
}
function run_mid_hooks {
for F in `ls "${SCRIPTS_DIR}/${SERVICE}.d"/mid_* 2>/dev/null` ;do . $F ; done
}
function run_post_hooks {
for F in `ls "${SCRIPTS_DIR}/${SERVICE}.d"/post_* 2>/dev/null` ;do . $F ; done
}
#################################################
WORK_DIR=`mktemp -d ${TMPDIR:-/tmp}/${NAME}.XXXXXXXXXX`
[ $? -ne 0 ] && log_msg E_WORK_DIR
trap 'rm -r -f "${WORK_DIR}"' EXIT
### Receive and process data
catch_error E_TAR_FILES tar --no-same-owner --no-same-permissions -x -C "${WORK_DIR}" <&0
SERVICE=`head -n 1 "${WORK_DIR}/SERVICE"`
LOCK_FILE="${LOCK_DIR}/${NAME}-${SERVICE}.lock"
LOCK_PIDFILE="$LOCK_FILE/pid"
# check if the service is not disabled
if [ "${#SERVICE_WHITELIST[@]}" -gt 0 ]; then
if in_array "${SERVICE}" "${SERVICE_WHITELIST[@]}"; then
true
else
log_msg I_SERVICE_DISABLED
exit 0;
fi
fi
if [ "${#SERVICE_BLACKLIST[@]}" -gt 0 ]; then
if in_array "${SERVICE}" "${SERVICE_BLACKLIST[@]}"; then
log_msg I_SERVICE_DISABLED
exit 0;
fi
fi
case "${SERVICE}" in
'fedcloud_export') . ${SCRIPTS_DIR}/process-fedcloud_export.sh ;;
*) log_msg E_UNSUPPORTED_SERVICE;;
esac
version_check #check the received version with version from slave script
run_pre_hooks
process #execute slave skript (e.g. runs function process in process-passwd.sh script)
run_post_hooks
log_msg I_FINISHED