github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/integration/functions.sh (about) 1 # Functions for setting up Trillian integration tests 2 3 if [[ -z "${TMPDIR}" ]]; then 4 TMPDIR=/tmp 5 fi 6 readonly TMPDIR 7 declare -a RPC_SERVER_PIDS 8 declare -a LOG_SIGNER_PIDS 9 declare -a TO_KILL 10 declare -a TO_DELETE 11 HTTP_SERVER_1='' 12 RPC_SERVER_1='' 13 RPC_SERVERS='' 14 ETCD_OPTS='' 15 ETCD_PID='' 16 ETCD_DB_DIR='' 17 readonly TRILLIAN_PATH=$(go list -f '{{.Dir}}' github.com/google/trillian) 18 19 # run_test runs the given test with additional output messages. 20 run_test() { 21 local name=$1 22 shift 23 echo "=== RUN ${name}" 24 "$@" 25 rc=$? 26 if [ $rc -ne 0 ]; then 27 echo "--- FAIL: ${name}" 28 else 29 echo "--- PASS: ${name}" 30 fi 31 return $rc 32 } 33 34 # wait_for_server_startup pauses until there is a response on the given port. 35 wait_for_server_startup() { 36 # The server will 404 the request as there's no handler for it. This error doesn't matter 37 # as the test will fail if the server is really not up. 38 local port=$1 39 set +e 40 wget -q --spider --retry-connrefused --waitretry=1 -t 10 localhost:${port} 41 # Wait a bit more to give it a chance to become actually available e.g. if Travis is slow 42 sleep 2 43 wget -q --spider -t 1 localhost:${port} 44 local rc=$? 45 set -e 46 # wget emits rc=8 for server issuing an error response (e.g. 404) 47 if [ ${rc} != 0 -a ${rc} != 8 ]; then 48 echo "Failed to get response on localhost:${port}" 49 exit 1 50 fi 51 } 52 53 # pick_unused_port selects an apparently unused port. 54 pick_unused_port() { 55 local avoid=${1:-0} 56 local base=6962 57 local port 58 for (( port = "${base}" ; port <= 61000 ; port++ )); do 59 if [[ $port == $avoid ]]; then 60 continue 61 fi 62 if ! lsof -i :$port > /dev/null; then 63 echo $port 64 break 65 fi 66 done 67 } 68 69 # kill_pid tries to kill the given pid, first softly then more aggressively. 70 kill_pid() { 71 local pid=$1 72 set +e 73 local count=0 74 while kill -INT ${pid} > /dev/null 2>&1; do 75 sleep 1 76 ((count++)) 77 if ! ps -p ${pid} > /dev/null ; then 78 break 79 fi 80 if [ $count -gt 5 ]; then 81 echo "Now do kill -KILL ${pid}" 82 kill -KILL ${pid} 83 break 84 fi 85 echo "Retry kill -INT ${pid}" 86 done 87 set -e 88 } 89 90 # log_prep_test prepares a set of running processes for a Trillian log test. 91 # Parameters: 92 # - number of log servers to run 93 # - number of log signers to run 94 # Populates: 95 # - HTTP_SERVER_1 : first HTTP server 96 # - RPC_SERVER_1 : first RPC server 97 # - RPC_SERVERS : RPC target, either comma-separated list of RPC addresses or etcd service 98 # - RPC_SERVER_PIDS : bash array of RPC server pids 99 # - LOG_SIGNER_PIDS : bash array of signer pids 100 # - ETCD_OPTS : common option to configure etcd location 101 # If the ETCD_DIR var points to a valid etcd, also populates: 102 # - ETCD_PID : etcd pid 103 # - ETCD_DB_DIR : location of etcd database 104 # If WITH_PKCS11 is set, also populates: 105 # - SOFTHSM_CONF : location of the SoftHSM configuration file 106 log_prep_test() { 107 # Default to one of each. 108 local rpc_server_count=${1:-1} 109 local log_signer_count=${2:-1} 110 111 echo "Building Trillian log code" 112 go build ${GOFLAGS} github.com/google/trillian/server/trillian_log_server/ 113 go build ${GOFLAGS} github.com/google/trillian/server/trillian_log_signer/ 114 115 # Wipe the test database 116 yes | "${TRILLIAN_PATH}/scripts/resetdb.sh" 117 118 local logserver_opts='' 119 local logsigner_opts='' 120 local has_etcd=0 121 122 # Start a local etcd instance (if configured). 123 if [[ -x "${ETCD_DIR}/etcd" ]]; then 124 has_etcd=1 125 local etcd_port=2379 126 local etcd_server="localhost:${etcd_port}" 127 echo "Starting local etcd server on ${etcd_server}" 128 ${ETCD_DIR}/etcd & 129 ETCD_PID=$! 130 ETCD_OPTS="--etcd_servers=${etcd_server}" 131 ETCD_DB_DIR=default.etcd 132 wait_for_server_startup ${etcd_port} 133 logserver_opts="${logserver_opts} --etcd_http_service=trillian-logserver-http --etcd_service=trillian-logserver --quota_system=etcd" 134 logsigner_opts="${logsigner_opts} --etcd_http_service=trillian-logsigner-http --quota_system=etcd" 135 else 136 if [[ ${log_signer_count} > 1 ]]; then 137 echo "*** Warning: running multiple signers with no etcd instance ***" 138 fi 139 logsigner_opts="${logsigner_opts} --force_master" 140 fi 141 142 if [[ "${WITH_PKCS11}" == "true" ]]; then 143 export SOFTHSM_CONF=${TMPDIR}/softhsm.conf 144 local pkcs11_opts="--pkcs11_module_path ${PKCS11_MODULE:-/usr/lib/softhsm/libsofthsm.so}" 145 fi 146 147 # Start a set of Log RPC servers. 148 for ((i=0; i < rpc_server_count; i++)); do 149 port=$(pick_unused_port) 150 RPC_SERVERS="${RPC_SERVERS},localhost:${port}" 151 http=$(pick_unused_port ${port}) 152 153 echo "Starting Log RPC server on localhost:${port}, HTTP on localhost:${http}" 154 ./trillian_log_server ${ETCD_OPTS} ${pkcs11_opts} ${logserver_opts} \ 155 --rpc_endpoint="localhost:${port}" \ 156 --http_endpoint="localhost:${http}" \ 157 ${LOGGING_OPTS} \ 158 & 159 pid=$! 160 RPC_SERVER_PIDS+=(${pid}) 161 wait_for_server_startup ${port} 162 163 # Use the first Log server as the Admin server (any would do) 164 if [[ $i -eq 0 ]]; then 165 HTTP_SERVER_1="localhost:${http}" 166 RPC_SERVER_1="localhost:${port}" 167 fi 168 done 169 RPC_SERVERS="${RPC_SERVERS:1}" 170 171 # Setup etcd quotas, if applicable 172 if [[ ${has_etcd} -eq 1 ]]; then 173 setup_etcd_quotas "${HTTP_SERVER_1}" 174 fi 175 176 # Start a set of signers. 177 for ((i=0; i < log_signer_count; i++)); do 178 http=$(pick_unused_port) 179 echo "Starting Log signer, HTTP on localhost:${http}" 180 ./trillian_log_signer ${ETCD_OPTS} ${pkcs11_opts} ${logsigner_opts} \ 181 --sequencer_interval="1s" \ 182 --batch_size=500 \ 183 --http_endpoint="localhost:${http}" \ 184 --num_sequencers 2 \ 185 ${LOGGING_OPTS} \ 186 & 187 pid=$! 188 LOG_SIGNER_PIDS+=(${pid}) 189 wait_for_server_startup ${http} 190 done 191 192 if [[ ! -z "${ETCD_OPTS}" ]]; then 193 RPC_SERVERS="trillian-logserver" 194 echo "Registered log servers @${RPC_SERVERS}/" 195 ETCDCTL_API=3 etcdctl get ${RPC_SERVERS}/ --prefix 196 echo "Registered HTTP endpoints" 197 ETCDCTL_API=3 etcdctl get trillian-logserver-http/ --prefix 198 ETCDCTL_API=3 etcdctl get trillian-logsigner-http/ --prefix 199 fi 200 } 201 202 # log_stop_tests closes down a set of running processes for a log test. 203 # Assumes the following variables are set: 204 # - LOG_SIGNER_PIDS : bash array of signer pids 205 # - RPC_SERVER_PIDS : bash array of RPC server pids 206 # - ETCD_PID : etcd pid 207 log_stop_test() { 208 for pid in "${LOG_SIGNER_PIDS[@]}"; do 209 echo "Stopping Log signer (pid ${pid})" 210 kill_pid ${pid} 211 done 212 for pid in "${RPC_SERVER_PIDS[@]}"; do 213 echo "Stopping Log RPC server (pid ${pid})" 214 kill_pid ${pid} 215 done 216 if [[ "${ETCD_PID}" != "" ]]; then 217 echo "Stopping local etcd server (pid ${ETCD_PID})" 218 kill_pid ${ETCD_PID} 219 fi 220 } 221 222 # setup_etcd_quotas creates the etcd quota configurations used by tests. 223 # 224 # Parameters: 225 # - server : HTTP endpoint for the quota API (eg, logserver http port) 226 # 227 # Outputs: 228 # DELETE and POST responses. 229 # 230 # Returns: 231 # 0 if success, non-zero otherwise. 232 setup_etcd_quotas() { 233 local server="$1" 234 local name='quotas/global/write/config' 235 236 # Remove the config before creating. It's OK if it doesn't exist. 237 local delete_output=$(curl -s -X DELETE "${server}/v1beta1/${name}") 238 printf 'DELETE %s: %s\n' "${name}" "${delete_output}" 239 240 local create_output=$(curl \ 241 -d '@-' \ 242 -s \ 243 -H 'Content-Type: application/json' \ 244 -X POST \ 245 "${server}/v1beta1/${name}" <<EOF 246 { 247 "name": "${name}", 248 "config": { 249 "state": "ENABLED", 250 "max_tokens": 1000, 251 "sequencing_based": { 252 } 253 } 254 } 255 EOF 256 ) 257 printf 'POST %s: %s\n' "${name}" "${create_output}" 258 259 # Success responses have the config name in them 260 echo "${create_output}" | grep '"name":' > /dev/null 261 } 262 263 # map_prep_test prepares a set of running processes for a Trillian map test. 264 # Parameters: 265 # - number of map servers to run 266 # Populates: 267 # - RPC_SERVER_1 : first RPC server 268 # - RPC_SERVERS : RPC target, either comma-separated list of RPC addresses or etcd service 269 # - RPC_SERVER_PIDS : bash array of RPC server pids 270 map_prep_test() { 271 # Default to one map server. 272 local rpc_server_count=${1:-1} 273 274 echo "Building Trillian map code" 275 go build ${GOFLAGS} github.com/google/trillian/server/trillian_map_server/ 276 277 # Wipe the test database 278 yes | "${TRILLIAN_PATH}/scripts/resetdb.sh" 279 280 # Start a set of Map RPC servers. 281 for ((i=0; i < rpc_server_count; i++)); do 282 port=$(pick_unused_port) 283 RPC_SERVERS="${RPC_SERVERS},localhost:${port}" 284 http=$(pick_unused_port ${port}) 285 286 echo "Starting Map RPC server on localhost:${port}, HTTP on localhost:${http}" 287 ./trillian_map_server \ 288 --rpc_endpoint="localhost:${port}" \ 289 --http_endpoint="localhost:${http}" \ 290 --alsologtostderr \ 291 & 292 pid=$! 293 RPC_SERVER_PIDS+=(${pid}) 294 wait_for_server_startup ${port} 295 296 # Use the first Map server as the Admin server (any would do) 297 if [[ $i -eq 0 ]]; then 298 RPC_SERVER_1="localhost:${port}" 299 fi 300 done 301 RPC_SERVERS="${RPC_SERVERS:1}" 302 } 303 304 # map_stop_tests closes down a set of running processes for a map test. 305 # Assumes the following variables are set: 306 # - RPC_SERVER_PIDS : bash array of RPC server pids 307 map_stop_test() { 308 for pid in "${RPC_SERVER_PIDS[@]}"; do 309 echo "Stopping Map RPC server (pid ${pid})" 310 kill_pid ${pid} 311 done 312 } 313 314 # map_provision creates new Trillian maps 315 # Parameters: 316 # - location of admin server instance 317 # - number of maps to provision (default: 1) 318 # Populates: 319 # - MAP_IDS: comma-separated list of tree IDs for provisioned maps 320 map_provision() { 321 local admin_server="$1" 322 local count=${2:-1} 323 324 echo 'Building createtree' 325 go build ${GOFLAGS} github.com/google/trillian/cmd/createtree/ 326 327 for ((i=0; i < count; i++)); do 328 local map_id=$(./createtree \ 329 --logtostderr \ 330 --admin_server="${admin_server}" \ 331 --tree_type=MAP \ 332 --hash_strategy=TEST_MAP_HASHER \ 333 --private_key_format=PrivateKey \ 334 --pem_key_path=${GOPATH}/src/github.com/google/trillian/testdata/map-rpc-server.privkey.pem \ 335 --pem_key_password=towel \ 336 --signature_algorithm=ECDSA) 337 echo "Created map ${tree_id}" 338 if [[ $i -eq 0 ]]; then 339 MAP_IDS="${map_id}" 340 else 341 MAP_IDS="${MAP_IDS},${map_id}" 342 fi 343 done 344 } 345 346 # on_exit will clean up anything in ${TO_KILL} and ${TO_DELETE}. 347 on_exit() { 348 local pid=0 349 for pid in "${TO_KILL[@]}"; do 350 echo "Killing ${pid} on exit" 351 kill_pid "${pid}" 352 done 353 local file="" 354 for file in "${TO_DELETE[@]}"; do 355 echo "Deleting ${file} on exit" 356 rm -rf ${file} 357 done 358 } 359 360 trap on_exit EXIT