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