Bump base image (#538)
[discourse_docker.git] / discourse-doctor
CommitLineData
24b887f2
JP
1#!/usr/bin/env bash
2LOG_FILE="/tmp/discourse-debug.txt"
3WORKING_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4
5log() {
6 if [ "$1" == "-e" ]
7 then
8 shift
9 echo -e "$*" | tee -a "$LOG_FILE"
10 else
11 echo "$*" | tee -a "$LOG_FILE"
12 fi
13}
14
15check_root() {
16 if [[ $EUID -ne 0 ]]; then
17 log "This script must be run as root. Please sudo or log in as root first." 1>&2
18 exit 1
19 fi
20}
21
22##
23## Check whether a connection to HOSTNAME ($1) on PORT ($2) is possible
24##
25connect_to_port() {
26 HOST="$1"
27 PORT="$2"
28 VERIFY=$(date +%s | sha256sum | base64 | head -c 20)
29 echo -e "HTTP/1.1 200 OK\n\n $VERIFY" | nc -w 4 -l -p $PORT >/dev/null 2>&1 &
30 if curl --proto =http -s $HOST:$PORT --connect-timeout 3 | grep $VERIFY >/dev/null 2>&1 &
31 then
32 return 0
33 else
34 return 1
35 fi
36}
37
38check_ip_match() {
39 HOST="$1"
40 log
41 log Checking your domain name . . .
42 if connect_to_port $HOST 443
43 then
44 log
45 log "Connection to $HOST succeeded."
46 else
47 log WARNING:: This server does not appear to be accessible at $HOST:443.
48 log
49 if connect_to_port $HOST 80
50 then
51 log A connection to port 80 succeeds, however.
52 log This suggests that your DNS settings are correct,
53 log but something is keeping traffic to port 443 from getting to your server.
54 log Check your networking configuration to see that connections to port 443 are allowed.
55 else
56 log "A connection to http://$HOST (port 80) also fails."
57 log
58 log This suggests that $HOST resolves to the wrong IP address
59 log or that traffic is not being routed to your server.
60 fi
61 log
62 log Google: \"open ports YOUR CLOUD SERVICE\" for information for resolving this problem.
63 log
64 log This test might not work for all situations,
65 log so if you can access Discourse at http://$HOST, this might not indicate a problem.
66 sleep 3
67 fi
68}
69
70check_docker_is_installed() {
71 log -e "\n==================== DOCKER INFO ===================="
72 docker_path="$(which docker.io || which docker)"
73 if [ -z $docker_path ]; then
74 log "Docker is not installed. Have you installed Discourse at all?"
75 log "Perhaps you're looking for ./discourse-setup ."
76 log "There is no point in continuing."
77 exit
78 else
79 log -e "DOCKER VERSION: $(docker --version)"
80 log -e "\nDOCKER PROCESSES (docker ps -a)\n\n$(sudo docker ps -a)\n"
81 fi
82}
83
84get_OS() {
85 log -e "OS: $(uname -s)"
86}
87
88check_disk_and_memory() {
89 log -e "\n\n==================== MEMORY INFORMATION ===================="
90 os_type=$(get_OS)
91 if [ "$os_type" == "Darwin" ]; then
92 log -e "RAM: $( free -m | awk '/Mem:/ {print $2}' ) \n"
93 else
94 log -e "RAM (MB): $( free -m --si | awk ' /Mem:/ {print $2} ')\n"
95 fi
96 log "$(free -m)"
97
98 log -e "\n==================== DISK SPACE CHECK ===================="
99 log "---------- OS Disk Space ----------"
100 log "$(df -h / /var/discourse /var/lib/docker /var/lib/docker/* | uniq)"
101
102 if [ "$version" != "NOT FOUND" ]
103 then
104 log
105 log "---------- Container Disk Space ----------"
106 log "$(sudo docker exec -w /var/www/discourse -i $app_name df -h / /shared/ /shared/postgres_data /shared/redis_data /shared/backups /var/log | uniq)"
107 fi
108
109 log -e "\n==================== DISK INFORMATION ===================="
110 log "$( fdisk -l )"
111 log -e "\n==================== END DISK INFORMATION ===================="
112
113 free_disk="$(df /var | tail -n 1 | awk '{print $4}')"
114 # Arguably ./launcher is doing this so discourse-doctor does not need to . . .
115 if [ "$free_disk" -lt 5000 ]; then
116 log "\n\n==================== DISK SPACE PROBLEM ===================="
117 log "WARNING: you appear to have very low disk space."
118 log "This could be the cause of problems running your site."
119 log "Please free up some space, or expand your disk, before continuing."
120 log
121 log "Run \'apt-get autoremove && apt-get autoclean\' to clean up unused"
122 log "packages and \'./launcher cleanup\' to remove stale Docker containers."
123 exit 1
124 fi
125}
126
127get_discourse_version() {
128 version=""
129 version=$(wget -q --timeout=3 https://$VERSION_HOSTNAME/privacy -O -|grep generator|head -1 |cut -d "=" -f 3|cut -d '-' -f 1 |cut -d '"' -f 2) &> /dev/null
130 if ! echo $version | grep Discourse
131 then
132 version=$(wget -q --timeout=3 http://$VERSION_HOSTNAME/privacy -O -|grep generator|head -1 |cut -d "=" -f 3|cut -d '-' -f 1 |cut -d '"' -f 2) &> /dev/null
133 fi
134 if [ -z "$version" ]
135 then
136 version="NOT FOUND"
137 fi
138 log "Discourse version at $VERSION_HOSTNAME: $version"
139}
140
141check_if_hostname_resolves_here() {
142 log "========================================"
143 VERSION_HOSTNAME=$DISCOURSE_HOSTNAME
144 get_discourse_version
145 DISCOURSE_VERSION="$version"
146 VERSION_HOSTNAME=localhost
147 get_discourse_version
148 LOCALHOST_VERSION="$version"
149 if [ "$DISCOURSE_VERSION" != "$LOCALHOST_VERSION" ]
150 then
151 log "==================== DNS PROBLEM ===================="
152 log "This server reports $LOCALHOST_VERSION, but $DISCOURSE_HOSTNAME reports $DISCOURSE_VERSION."
153 log "This suggests that you have a DNS problem or that an intermediate proxy is to blame."
154 log "If you are using Cloudflare, or a CDN, it may be improperly configured."
155 fi
156}
157
158##
159## get discourse configuration values from YML file
160##
161get_discourse_config() {
162 log -e "\n==================== YML SETTINGS ===================="
163 read_config "DISCOURSE_HOSTNAME"
164 DISCOURSE_HOSTNAME=$read_config_result
165 log DISCOURSE_HOSTNAME=$DISCOURSE_HOSTNAME
166 read_config "DISCOURSE_SMTP_ADDRESS"
167 SMTP_ADDRESS=$read_config_result
168 log SMTP_ADDRESS=$SMTP_ADDRESS
169 read_config "DISCOURSE_DEVELOPER_EMAILS"
170 DEVELOPER_EMAILS=$read_config_result
171 log DEVELOPER_EMAILS=$DEVELOPER_EMAILS
172 read_config "DISCOURSE_SMTP_PASSWORD"
173 SMTP_PASSWORD=$read_config_result
174 log SMTP_PASSWORD=$read_config_result
175 read_config "DISCOURSE_SMTP_PORT"
176 SMTP_PORT=$read_config_result
177 log SMTP_PORT=$read_config_result
178 read_config "DISCOURSE_SMTP_USER_NAME"
179 SMTP_USER_NAME=$read_config_result
180 log SMTP_USER_NAME=$read_config_result
181 read_config "LETSENCRYPT_ACCOUNT_EMAIL"
182 letsencrypt_account_email=$read_config_result
183 log "LETSENCRYPT_ACCOUNT_EMAIL=$letsencrypt_account_email"
184}
185
186check_plugins() {
187 log -e "\n\n==================== PLUGINS ===================="
6ffca0c2 188 log -e "$(grep 'git clone' containers/$app_name.yml)"
24b887f2
JP
189 grep git containers/$app_name.yml > /tmp/$PPID.grep
190
191 if grep -cv "github.com/discourse" /tmp/$PPID.grep > /dev/null
192 then
193 log -e "\nWARNING:"
194 log You have what appear to be non-official plugins.
195 log "If you are having trouble, you should disable them and try rebuilding again."
196 else
197 log -e "\nNo non-official plugins detected."
198 fi
199 log -e "\nSee https://github.com/discourse/discourse/blob/master/lib/plugin/metadata.rb for the official list.\n"
200}
201
202dump_yaml() {
203 log -e "\n\n==================== YML DUMP ===================="
204 log Dumping $app_name.yml
205 log -e "\n\n"
206}
207
208##
209## read a variable from the config file and stick it in read_config_result
210##
211read_config() {
212 config_line=$(egrep "^ #?$1:" $web_file)
06aa4ddb 213 read_config_result=$(echo $config_line | awk -F ":" '{print $2}')
24b887f2
JP
214 read_config_result=$(echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g")
215}
216
217##
218## call rake emails:test inside the container
219##
220check_email() {
221 log -e "\n==================== MAIL TEST ===================="
222 log "For a robust test, get an address from http://www.mail-tester.com/"
223 echo "Or just send a test message to yourself."
224 EMAIL=$(echo $DEVELOPER_EMAILS |cut -d , -f 1)
225 read -p "Email address for mail test? ('n' to skip) [$EMAIL]: " new_value
226 if [ ! -z "$new_value" ]
227 then
228 EMAIL="$new_value"
229 fi
230 if [ "$new_value" != "n" ] && [ "$new_value" != "N" ]
231 then
232 log "Sending mail to $EMAIL. . . "
233 log "$(sudo docker exec -w /var/www/discourse -i $app_name rake emails:test[$EMAIL])"
234 else
235 log "Mail test skipped."
236 fi
237}
238
239get_yml_file() {
240 app_name=""
241 if [ -f containers/app.yml ]
242 then
243 app_name="app"
244 web_file=containers/$app_name.yml
245 log "Found $web_file"
246 elif [ -f containers/web_only.yml ]
247 then
248 log "YML=web_only.yml"
249 app_name="web_only"
250 web_file=containers/$app_name.yml
251 log "Found $web_file"
252 else
82b2979d 253 log "Can't find app.yml or web_only.yml."
24b887f2
JP
254 log "Giving up."
255 exit
256 fi
257}
258
259check_docker() {
260 docker ps | tail -n +2 > /tmp/$UUID-docker.txt
261
262 if grep $app_name /tmp/$UUID-docker.txt
263 then
264 log -e "\nDiscourse container $app_name is running"
265 else
266 log "==================== SERIOUS PROBLEM!!!! ===================="
267 log "$app_name not running!"
268 log "Attempting to rebuild"
269 log "==================== REBUILD LOG ===================="
270 # too hard to pass STDERR of ./launcher to log()
271 ./launcher rebuild $app_name 2>&1 | tee -a $LOG_FILE
272 log "==================== END REBUILD LOG ===================="
e9db29df 273 docker ps | tail -n +2 > /tmp/$UUID-docker.txt
24b887f2
JP
274 if grep $app_name /tmp/$UUID-docker.txt
275 then
276 log -e "\nDiscourse container $app_name is now running."
277 log ". . . waiting 30 seconds for container to crank up. . . "
278 sleep 30
279 else
2312f4cc 280 log "Failed to rebuild $app_name."
24b887f2
JP
281 # check_ip_match checks if curl to $DISCOURSE_HOSTNAME gets to this server
282 # It works only if ports 80 and 443 are free
283 check_ip_match $DISCOURSE_HOSTNAME
284 log "You should probably remove any non-standard plugins and rebuild."
285 NO_CONTAINER='y'
2312f4cc
JP
286 log "Attempting to restart existing container. . . "
287 ./launcher start $app_name 2>&1 | tee -a $LOG_FILE
e9db29df 288 docker ps | tail -n +2 > /tmp/$UUID-docker.txt
2312f4cc
JP
289 if grep $app_name /tmp/$UUID-docker.txt
290 then
291 log "Restarted the container."
292 NO_CONTAINER='n'
293 else
294 log "Failed to restart the container."
295 fi
24b887f2
JP
296 fi
297 fi
298}
299
300##
301## redact passwords and email addresses from log file
302##
303clean_up_log_file() {
304 for VAR
305 in SMTP_PASSWORD LETSENCRYPT_ACCOUNT_EMAIL DEVELOPER_EMAILS DISCOURSE_DB_PASSWORD 'Sending mail to'
306 do
307 echo "Replacing: $VAR"
308 sed -i -e 's/'"$VAR"'\([=: ]\)\S*/'"$VAR"'\1REDACTED /g' $LOG_FILE
309 done
310}
311
312print_done() {
313 log
314 log "==================== DONE! ===================="
315 DOCTOR_FILE=$(date +%s | sha256sum | base64 | head -c 20).txt
316
317 if [ $app_name == 'app' ] && [ "$NO_CONTAINER" != 'y' ]
318 then
b0c92bac
JD
319 read -p "Would you like to serve a publicly available version of this file? (Y/n)" serve
320 if [ $serve == 'Y' ]
321 then
322 cp $LOG_FILE shared/standalone/log/var-log/$DOCTOR_FILE
323 sudo docker exec -w /var/www/discourse -i $app_name cp /var/log/$DOCTOR_FILE public
324 log "The output of this program may be available at http://$DISCOURSE_HOSTNAME/$DOCTOR_FILE"
325 log "You should inspect that file carefully before sharing the URL."
326 else
327 log "Publicly available log not generated."
328 fi
24b887f2
JP
329 fi
330 # The following is not in the web log file since it was copied above, which seems corect
331 log
332 log "You can examine the output of this script with "
333 log "LESS=-Ri less $LOG_FILE"
334 log
335 log "BUT FIRST, make sure that you know the first three commands below!!!"
336 log
337 log "Commands to know when viewing the file with the above command (called 'less'): "
338 log "q -- quit"
339 log "/error<ENTER> -- search for the word 'error'"
340 log "n -- search for the next occurrence"
341 log "g -- go to the beginning of the file"
342 log "f -- go forward a page"
343 log "b -- go back a page"
344 log "G -- go to the end of the file"
345}
346
347initialize_log_file() {
348 rm -f $LOG_FILE
349 touch $LOG_FILE
350 log DISCOURSE DOCTOR $(date)
351 log -e "OS: $(uname -a)\n\n"
352}
353
354##
355## END FUNCTION DECLARATION
356##
357
358check_root
359cd $WORKING_DIR || exit
360initialize_log_file
361get_yml_file
362get_discourse_config
363check_docker_is_installed
364check_docker
365check_plugins
366check_if_hostname_resolves_here
367check_disk_and_memory
368check_email
369clean_up_log_file
370print_done