I wanted to write a bash script that would start a Datasette server running, run a request against it using curl
, then stop the server again.
It should then return an exit code indicating if the curl
request was succesful or not.
Research notes in this issue - here's the final script I came up with:
#!/bin/bash
# Generate certificates
python -m trustme
# This creates server.pem, server.key, client.pem
# Start the server in the background
datasette --memory \
--ssl-keyfile=server.key \
--ssl-certfile=server.pem \
-p 8152 &
# Store the background process ID in a variable
server_pid=$!
# Wait for the server to start
sleep 2
# Make a test request using curl
curl -f --cacert client.pem 'https://localhost:8152/_memory.json'
# Save curl's exit code (-f option causes it to return one on HTTP errors)
curl_exit_code=$?
# Shut down the server
kill $server_pid
sleep 1
# Clean up the certificates
rm server.pem server.key client.pem
echo $curl_exit_code
exit $curl_exit_code
There are a few additional tricks in this - it's running python -m trustme
to create self-signed certificates in the current directory which are used for the test - but the key parts are these:
datasette ... &
- starts Datasette running as a background processserver_pid=$!
- records the PID of the server we just started so we can shut it down latercurl -f ...
- makes a curl
request, but returns an exit code that indicates if the request succeeded or was a 404 or 500 error or similarcurl_exit_code=$?
- records that exit code for laterkill $server_id
- causes the server to exit - I then did a sleep 1
to provide time for it to output its shutdown text to the terminalexit $curl_exit_code
- the exit code for the Bash script is now the same as the exit code returned by curl
I'm running this script in CI in GitHub Actions.
Jan Lehnardt submitted a pull request with this improved version:
#!/bin/bash
# Generate certificates
python -m trustme
# This creates server.pem, server.key, client.pem
cleanup () {
rm server.pem server.key client.pem
}
# Start the server in the background
datasette --memory \
--ssl-keyfile=server.key \
--ssl-certfile=server.pem \
-p 8152 &
# Store the background process ID in a variable
server_pid=$!
test_url='https://localhost:8152/_memory.json'
# Wait for the server to start
# h/t https://github.com/pouchdb/pouchdb/blob/25db22fb0ff025b8d2c698da30c6c409066baa0c/bin/run-test.sh#L102-L113
waiting=0
until $(curl --output /dev/null --silent --insecure --head --fail --max-time 2 $test_url); do
if [ $waiting -eq 4 ]; then
echo "$test_url can not be reached, server failed to start"
cleanup
exit 1
fi
let waiting=waiting+1
sleep 1
done
# Make a test request using curl
curl -f --cacert client.pem $test_url
# Save curl's exit code (-f option causes it to return one on HTTP errors)
curl_exit_code=$?
# Shut down the server
kill $server_pid
waiting=0
# show all pids
# | find just the $server_pid
# | | don’t match on the previous grep
# | | | we don’t need the output
# | | | |
until ( ! ps ax | grep $server_pid | grep -v grep > /dev/null ); do
if [ $waiting -eq 4 ]; then
echo "$server_pid does still exist, server failed to stop"
cleanup
exit 1
fi
let waiting=waiting+1
sleep 1
done
# Clean up the certificates
cleanup
echo $curl_exit_code
exit $curl_exit_code
There's not much extra commentary I can add to this - Jan's inline comments are fantastic!
I really like the waiting=0
pattern here for retrying up to 4 times.
Worth breaking down the curl
command here a bit:
curl --output /dev/null --silent --insecure --head --fail --max-time 2 $test_url
It's avoiding any output at all with a combination of writing output to /dev/null
and using --silent
to turn off logging.
It uses --insecure
because our server is running with a self-signed certificate, which will produce errors without this option - and here we just want to poll until the server is up and running.
--max-time
ensures each poll waits a maximum of two seconds.
And as before, --fail
causes curl
to return an exit code that indicates if the request was successful or not.
Jan used this as the impetus to start a new library of shell utility functions.
Created 2022-12-17T18:59:07-08:00, updated 2023-01-24T17:47:49-08:00 · History · Edit