-
Notifications
You must be signed in to change notification settings - Fork 989
/
foreman-debug
executable file
·403 lines (359 loc) · 12.1 KB
/
foreman-debug
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
255
256
257
258
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
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#!/bin/bash
# vim:sw=2:ts=2:et
export SCLNAME=tfm
usage() {
cat <<USAGE
$0 - configuration and log data collector
USAGE: $0 [options]
Collects configuration and log data for Foreman, Smart Proxies, backend
services and system information while removing security information like
passwords, tokens and keys.
This program can be used on Foreman instances, Smart Proxy instances or
backend services separately.
OPTIONS:
-d DIR Directory to place the tarball in (default /var/tmp/foreman-XYZ)
-g Skip generic info (CPU, memory, firewall etc.)
-a Keep directory and do not generate a compressed tarball
-s SIZE Maximum log set size in MB (current+rotated files, defaults to 10 MB)
-j PRG Filter with provided program when creating a tarball
-p Additionally print password patterns being filtered out
-q Quiet mode
-v Verbose mode
-h Shows this message
USAGE
}
# Filter for patterns like password=XYZ, -storepass XYZ or secret: XYZ
FILTER_WORDS=(
password
PASSWORD
default_password
oauth_consumer_key
secret
token
keystorePass
truststorePass
storepass
)
FILTER_WORDS_STR=$(IFS=$'|'; echo "${FILTER_WORDS[*]}")
FILTER="s/($FILTER_WORDS_STR)(\"?\s*[:=]?\s*)\S+/\1\2+FILTERED+/g"
error() {
echo "$*" >&2
}
qprintf() {
[ $QUIET -ne 1 ] && printf "$@"
}
printv() {
[ $QUIET -ne 1 ] && [ $VERBOSE -eq 1 ] && echo "[$SECONDS]" $*
}
clean_stdin() {
while read -e -t 0.1; do : ; done
}
# add outout of the command and redirect possible errors there
add_cmd() {
CMD=$1
OUT=$2
printv " - $OUT"
echo -e "COMMAND> $CMD\n" > "$DIR/$OUT"
eval $CMD >> "$DIR/$OUT" 2>&1
}
# add and filter file of known MIME type, calculate size
add_file() {
FILE=$1
SIZE=$(stat -c "%s" $FILE)
MIME=$(file -bi "$FILE" | cut -d\; -f1)
case $MIME in
application/x-gzip)
OUTFILE="$DIR${FILE/%.gz/}"
zcat "$FILE" | sed -r "$FILTER" > "$OUTFILE"
touch -c -r "$FILE" "$OUTFILE"
;;
application/x-bzip2)
OUTFILE="$DIR${FILE/%.bz2/}"
bzcat "$FILE" | sed -r "$FILTER" > "$OUTFILE"
touch -c -r "$FILE" "$OUTFILE"
;;
application/x-xz)
OUTFILE="$DIR${FILE/%.xz/}"
xzcat "$FILE" | sed -r "$FILTER" > "$OUTFILE"
touch -c -r "$FILE" "$OUTFILE"
;;
text/plain | application/xml)
OUTFILE="$DIR$FILE"
sed -r "$FILTER" "$FILE" > "$OUTFILE"
[ $PRINTPASS -eq 1 ] && grep -H "+FILTERED+" "$OUTFILE"
touch -c -r "$FILE" "$OUTFILE"
;;
*)
echo "Skipping file $FILE: unknown MIME type $MIME" >> "$DIR/skipped_files"
SIZE=0 # don't count the size to collected files
;;
esac
}
# add files (from newest to oldest) that are non zero, readable, regular file or symlink, until $MAXSIZE limit is reached
add_files() {
SUMSIZE=0
# sort regular+symlink readable nonempty files per modification time, newest first - assuming no space in a filename
for FILE in $(find -L $* -type f -readable -size +0b -printf "%T@ %p\n" 2> /dev/null | sort -nr | cut -d' ' -f2 2> /dev/null); do
# if we are over size limit, skip rest older files
if [ \( $SUMSIZE -gt $MAXSIZE \) -a \( $MAXSIZE -gt 0 \) ]; then
printv " - $FILE (skipped due to size)"
else
printv " - $FILE"
SUBDIR=$(dirname $FILE)
[ ! -d "$DIR$SUBDIR" ] && mkdir -p "$DIR$SUBDIR"
# if the file is symlink, copy source and add target
if [ -h $FILE ]; then
cp -a "$FILE" "$DIR$FILE"
FILE=$(readlink -f $FILE)
fi
add_file $FILE
SUMSIZE=$(($((SUMSIZE))+$((SIZE))))
fi
touch -c -r "$SUBDIR" "$DIR$SUBDIR"
done
}
# default values
DIR=""
NOGENERIC=0
NOTAR=0
MAXSIZE=10485760 # 10 MB in bytes
COMPRESS=""
PRINTPASS=0
QUIET=0
VERBOSE=0
DEBUG=0
if type -p xz >/dev/null; then
COMPRESS="xz -1"
EXTENSION=".xz"
elif type -p bzip2 >/dev/null; then
COMPRESS="bzip2 -1"
EXTENSION=".bz2"
elif type -p gzip >/dev/null; then
COMPRESS="gzip -5"
EXTENSION=".gz"
else
COMPRESS="cat"
EXTENSION=""
fi
# read optional configuration file with user-defined defaults
CONF_FILE=/usr/share/foreman/config/foreman-debug.conf
test -f $CONF_FILE && source $CONF_FILE
while getopts "d:gam:s:j:uqpvhx" opt; do
case $opt in
d)
DIR="$OPTARG"
;;
g)
NOGENERIC=1
;;
a)
NOTAR=1
;;
p)
PRINTPASS=1
;;
q)
QUIET=1
;;
v)
VERBOSE=1
;;
m)
error "Warning: -m option has no effect, use -s option"
;;
j)
COMPRESS="$OPTARG"
EXTENSION=".$(echo "$OPTARG" | awk '{ print $1 }')"
;;
s)
#read the value and convert from MB to bytes
MAXSIZE="$OPTARG"
MAXSIZE=$((MAXSIZE*1024*1024))
;;
x)
# this option is not docummented - use for extra output,
# skip slow items and to disable root check
DEBUG=1
;;
h)
usage
exit
;;
?)
error "Invalid option: $OPTARG"
usage
exit
;;
esac
done
[ $DEBUG -eq 0 -a $EUID -ne 0 ] && error "This script must be run as root" && exit 1
# some tasks take long time, print a banner (unless quiet mode was selected)
qprintf "Processing... (takes a while)\n"
# determine distribution family
if [ -f /etc/debian_version ]; then
OS=debian
OS_RELEASE=$(head -n1 /etc/debian_version)
elif [ -f /etc/redhat-release ]; then
OS=redhat
OS_RELEASE=$(head -n1 /etc/redhat-release)
elif type -p lsb_release >/dev/null; then
OS=$(lsb_release -si 2>/dev/null)
OS_RELEASE=$(lsb_release -sr 2>/dev/null)
elif type -p rpm >/dev/null; then
OS=$(rpm -q --whatprovides redhat-release --queryformat '%{NAME}')
OS_RELEASE=$(rpm -q --whatprovides redhat-release --queryformat '%{VERSION}')
else
OS=$(uname -s)
OS_RELEASE="Unknown"
fi
printv "Determined $OS distribution"
clean_temp() {
# prevent from removing anything user-defined
if [[ "$NOTAR" -eq 0 && "$DIR" == /var/tmp* ]]; then
printv "Cleaning $DIR"
rm -rf "$DIR"
fi
if [[ "$TMPDIR" == /var/tmp* ]]; then
printv "Cleaning $TMPDIR"
rm -rf "$TMPDIR"
fi
}
install_clean_trap() {
trap clean_temp EXIT
}
if [ -z "$DIR" ]; then
DIR=$(mktemp -d $(basename $0)-XXXXX -p /var/tmp)
else
[ ! -d "$DIR" ] && mkdir -p "$DIR"
fi
export TMPDIR=$(mktemp -d foreman-debug-auxtmp-XXXXX -p /var/tmp)
install_clean_trap
printv "Created $DIR and $TMPDIR"
TARBALL="$DIR.tar$EXTENSION"
# GENERIC ARTIFACTS
if [ $NOGENERIC -eq 0 ]; then
printv "Collecting generic system information"
add_cmd "date" "date"
add_cmd "lsb_release -a" "lsb_release"
add_cmd "uname -a" "uname"
add_cmd "cat /proc/cpuinfo" "cpuinfo"
add_cmd "cat /proc/meminfo" "meminfo"
add_cmd "ulimit -a" "ulimit"
add_cmd "lsmod" "lsmod"
add_cmd "iptables -L -v -n" "iptables"
add_cmd "ifconfig -a" "ifconfig"
add_cmd "route -n" "route"
add_cmd "netstat -putna" "netstat"
add_cmd "ip a" "ip_a"
add_cmd "ip r" "ip_r"
add_cmd "ss -putna" "ss"
add_cmd "cat /etc/hosts" "hosts"
add_cmd "ping -c1 -W1 localhost" "ping_localhost"
add_cmd "ping -c1 -W1 $(hostname)" "ping_hostname"
add_cmd "ping -c1 -W1 $(hostname -f)" "ping_hostname_full"
add_cmd "host $(hostname -f)" "hostname_dns_check"
type scl &>/dev/null && \
add_cmd "scl -l" "software_collections"
add_cmd "ps auxwwwZ" "process_list"
add_files /var/log/messages*
add_files /var/log/audit/audit.log*
add_files /var/log/syslog*
add_cmd "getenforce" "selinux_state"
add_cmd "ausearch -m AVC -m USER_AVC -m SELINUX_ERR | head -n 100" "selinux_first_denials.log"
add_cmd "ausearch -m AVC -m USER_AVC -m SELINUX_ERR || grep AVC /var/log/audit/audit.log" "selinux_denials.log"
if [ -f /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
[[ -f /var/lib/sepolgen/interface_info ]] || sepolgen-ifgen &>/dev/null
add_cmd "audit2allow -Ra || audit2allow -a" "selinux_audit2allow"
add_cmd "semodule -l" "selinux_modules"
add_cmd "semanage boolean -l" "selinux_booleans"
add_cmd "semanage fcontext -l" "selinux_fcontext"
fi
if [ "$OS" = "redhat" ]; then
[ $DEBUG -eq 0 ] && add_cmd "rpm -qa" "installed_packages"
elif [ "$OS" = "debian" ]; then
[ $DEBUG -eq 0 ] && add_cmd "dpkg --list" "installed_packages"
fi
add_cmd "virt-who -dop" "virt_who"
fi
# FOREMAN RELATED ARTIFACTS
printv "Collecting Foreman-related information"
add_cmd "rpm -qa '*foreman*' || dpkg -l '*foreman*' | sort" "foreman_packages"
add_cmd "ruby --version" "version_ruby"
add_cmd "puppet --version" "version_puppet"
add_cmd "gem list" "gem_list"
add_cmd "scl enable $SCLNAME 'gem list'" "gem_list_scl"
add_cmd "bundle --local --gemfile=/usr/share/foreman/Gemfile" "bundle_list"
add_cmd "facter" "facts"
add_files /var/log/foreman/apipie_cache*.log*
add_files /var/log/foreman/cron*.log*
add_files /var/log/foreman/db_migrate*.log*
add_files /var/log/foreman/db_seed*.log*
add_files /var/log/foreman/production.log-*
add_files /var/log/foreman/production.log
add_files /var/log/foreman/dynflow_executor.output*
add_files /var/log/foreman-proxy-certs-generate.*log
# Dynflow Sidekiq
add_files /etc/foreman/dynflow/*
add_cmd "systemctl list-units dynflow*" "dynflow_units"
add_cmd "journalctl -u dynflow-sidekiq@*" "dynflow_sidekiq_logs"
add_cmd 'systemctl status "system-dynflow\x2dsidekiq.slice"' "dynflow_sidekiq_status"
# exclude *key.pem files and encryption_key.rb
add_files /etc/foreman/*.{yml,yaml,conf} /etc/foreman/plugins/*.yaml
add_files /etc/foreman-installer/scenarios.d/{*,*/*,*/.*}
add_files /var/log/foreman-installer/
add_files /var/log/foreman-maintain/
add_files /etc/foreman-installer/custom-hiera.yaml
add_files /var/log/foreman-selinux-install.log
add_files /usr/share/foreman/Gemfile*
add_cmd "virsh list" "virsh_list"
add_files /etc/libvirt/* /etc/libvirt/storage/* /etc/libvirt/qemu/* /etc/libvirt/qemu/networks
add_files /var/lib/pgsql/data/*.conf
add_files /var/lib/puppet/ssl/certs/$(hostname -f).pem /var/lib/puppet/ssl/certs/ca.pem
add_files /etc/{httpd,apache2}/conf/*
add_files /etc/{httpd,apache2}/conf.d/*
add_files /etc/{httpd,apache2}/conf.d/*/*
add_files /var/log/{httpd,apache2}/*error_log*
add_files /var/log/{httpd,apache2}/foreman-ssl_access_ssl.log*
add_cmd "echo \"select id,name,value from settings where name not similar to '%(pass|key|secret)'\" | su postgres -c 'psql foreman'" "foreman_settings_table"
add_cmd "echo 'select type,name,host,port,account,base_dn,attr_login,onthefly_register,tls from auth_sources' | su postgres -c 'psql foreman'" "foreman_auth_table"
add_cmd "foreman-selinux-relabel -nv" "foreman_filecontexts"
add_files /etc/{sysconfig,default}/foreman
add_files /etc/{sysconfig,default}/libvirt*
add_files /etc/sysconfig/pgsql
add_files /var/lib/pgsql/data/pg_log/*
add_cmd "passenger-status --show=pool" "passenger_status_pool"
add_cmd "passenger-status --show=requests" "passenger_status_requests"
add_cmd "passenger-status --show=backtraces" "passenger_status_backtraces"
add_cmd "passenger-memory-stats" "passenger_memory"
# Look for any debug extensions provided by plugins
if [ -d "/usr/share/foreman/script/foreman-debug.d" ]; then
for extension in /usr/share/foreman/script/foreman-debug.d/* ; do
if [ -x "$extension" ]; then
printv "Processing extension $extension"
source "$extension" 2>/dev/null
# install cleanup trap again just in case it got overwritten
install_clean_trap
fi
done
fi
qprintf "\n\n"
qprintf "%10s %s\n" "HOSTNAME:" "$(hostname -f 2>/dev/null)"
qprintf "%10s %s\n" "OS:" "$OS"
qprintf "%10s %s\n" "RELEASE:" "$OS_RELEASE"
qprintf "%10s %s\n" "FOREMAN:" "$(cat /usr/share/foreman/VERSION 2>/dev/null)"
qprintf "%10s %s\n" "RUBY:" "$(ruby --version 2>/dev/null)"
qprintf "%10s %s\n" "PUPPET:" "$(puppet --version 2>/dev/null)"
test -f /var/log/audit/audit.log && \
qprintf "%10s %s\n" "DENIALS:" "$(ausearch -m AVC -r | wc -l)"
qprintf "\n\n"
if [ "$NOTAR" -eq 0 ]; then
pushd "$DIR" >/dev/null
printv "Compressing directory structure"
tar -c ../$(basename $DIR) 2>/dev/null | $COMPRESS > "$TARBALL"
popd >/dev/null
qprintf "%s: %s\n\n" "A debug file has been created" "$TARBALL ($(stat -c %s "$TARBALL") bytes)"
else
qprintf "%s: %s\n\n" "A debug directory has been created" "$DIR"
fi
printv "Finished in $SECONDS seconds"
exit 0