| #!/bin/bash |
| |
| # This script exports a common::run function which builds |
| # and runs mounttables and other daemons needed to run and |
| # test the Veyron Browser. |
| # The ports on which to run these services should be passed |
| # as arguments to the function. |
| # This script shuts down these services on exit. |
| # TODO(aghassemi) This script is becoming too complicated and |
| # big for shell scripting, switch to a JavaScript or Go implementation |
| |
| source "${VEYRON_ROOT}/scripts/lib/shell.sh" |
| |
| trap 'terminate force' INT TERM |
| trap 'terminate' EXIT |
| |
| # PIDS is a file that keeps track of PIDS of spawned services (one PID per line). |
| PIDS=$(shell::tmp_file) |
| |
| # TERMINATING is a file that keeps track of whether we are in the the middle of terminating the script. |
| TERMINATING=$(shell::tmp_file) |
| echo "false" > "${TERMINATING}" |
| |
| # We use temporary files to keep track if PIDs since subshells are isolated and |
| # can not access variables in parent's scope and we like to run services in subshells |
| # so we can easily track if they have exited or not. |
| |
| # terminate is automatically called when receiving a signal or can be manually |
| # called from other functions to exit the script |
| # The string 'force' can be provided as the first argument to indicate whether |
| # we should kill the process and exit with an non-zero error code instead of |
| # the default behavior which is to wait for termination and exit with exit code 0 |
| terminate() { |
| # Indicate that we are terminating, reset the trap so it won't get called again and |
| # throw out further output. |
| echo "true" > "${TERMINATING}" |
| trap - EXIT INT TERM |
| exec &> /dev/null |
| |
| # Kill all the spawned processes. |
| while read ID; do |
| kill -KILL "${ID}" || true |
| done < "${PIDS}" |
| |
| wait |
| shell::at_exit |
| |
| # Exit successfully or terminate. |
| local -r FORCE="${1-}" |
| if [[ "${FORCE}" = "force" ]]; then |
| kill -KILL $$ || true |
| else |
| exit 0 |
| fi |
| } |
| |
| # build is used to install binaries needed to run services. |
| build() { |
| export GOPATH="${VEYRON_ROOT}/veyron-browser/go:${PATH}" |
| export GOBIN="${VEYRON_ROOT}/veyron-browser/go/bin" |
| |
| veyron go install veyron.io/veyron/veyron/services/mounttable/mounttabled |
| veyron go install veyron.io/veyron/veyron/services/proxy/proxyd |
| veyron go install veyron.io/veyron/veyron/services/mgmt/binary/binaryd |
| veyron go install veyron.io/veyron/veyron/services/mgmt/build/buildd |
| veyron go install veyron.io/veyron/veyron/tools/principal |
| veyron go install veyron.io/wspr/veyron/services/wsprd |
| veyron go install sample/sampled |
| } |
| |
| # common::fail will output a red FAILED message along with and optional message given |
| # as first argument and an optional LOGFILE location to output as second argument. |
| # This function will also exit the shell with an exit code of 1. |
| common::fail() { |
| local -r MESSAGE="${1-}" |
| local -r LOG_FILE="${2-}" |
| |
| echo -e "\033[91m\033[1mFAIL ${MESSAGE}\033[0m" |
| |
| if [[ -e "${LOG_FILE}" ]]; then |
| cat "${LOG_FILE}" |
| fi |
| |
| terminate force |
| } |
| |
| # fail_on_exit will call common::fail when the PID given as the first argument exits abruptly. |
| # (e.g. not being terminated by the scripts itself) |
| # It practically ensures if a service fails to start or crash during the run, we are notified. |
| fail_on_exit() { |
| # Temporarily ignore stderr or we will see messages like "Killed xxx" when a service |
| # is terminated by our script at the end. |
| exec 6>&2 2>/dev/null |
| |
| local -r PID="$1" |
| local -r NAME="$2" |
| local -r LOGFILE="$3" |
| |
| # Keep the PID so we can shut down the service later on exit. |
| echo "${PID}" >> "${PIDS}" |
| |
| # Ensure the service is still running. |
| while sleep 0.5; do |
| ps -p "${PID}" &> /dev/null || break |
| done |
| |
| # Service no longer running. |
| # Ignore if we are already terminating, this is necessary to differentiate between |
| # a process exiting/not starting during the run vs. being shutdown by the script itself. |
| if [[ ! -e "${TERMINATING}" ]] || [[ $(cat ${TERMINATING}) = true ]]; then |
| return |
| fi |
| |
| # Re-enable stderr and fail. |
| exec 2>&6 |
| common::fail "${NAME} service did not start or crashed, see log below for details" "${LOGFILE}" |
| } |
| |
| # common::run is used to run the services needed to test and demon veyron browser |
| # run will exit the shell if a process fails to start or panics and it will display |
| # an error message along with the log file for the misbehaving service. |
| common::run() { |
| build || common::fail "failed to build the binaries" |
| cd "${GOBIN}" |
| |
| local -r ROOT_MOUNTTABLE_PORT="$1" |
| local -r HOUSE_MOUNTTABLE_PORT="$2" |
| local -r COTTAGE_MOUNTTABLE_PORT="$3" |
| local -r WSPR_PORT="$4" |
| local -r PROXY_PORT="$5" |
| local -r IDENTITY_DIR="$6" |
| local -r SEEK_BLESSSING="$7" |
| |
| local -r PROXY_ADDR=127.0.0.1:"${PROXY_PORT}" |
| local -r IDENTITY_SERVER=/proxy.envyor.com:8101/identity/veyron-test/google |
| |
| # Get credentials |
| export VEYRON_CREDENTIALS="${IDENTITY_DIR}"; |
| |
| if [[ ! -e "${IDENTITY_DIR}" ]] || [[ ! "$(ls -A ${IDENTITY_DIR})" ]]; then |
| ./principal create "${IDENTITY_DIR}" "veyron-browser" |
| if [[ "${SEEK_BLESSSING}" = true ]]; then |
| ./principal seekblessings |
| fi |
| fi |
| |
| # Run each server in a sub shell so we can call common::fail if process fails to start |
| # or panics as it is running. |
| |
| # Allowed seconds for each service to start |
| local -r SRV_TIMEOUT=2 |
| local -r TIMEDOUT_MSG="Timed out waiting for:" |
| |
| # Run mounttables. |
| local -r ROOT_MTLOG="${TMPDIR}/mt_root.log" |
| local -r MTLOG_MESSAGE="Mount table service at" |
| cat /dev/null > "${ROOT_MTLOG}" |
| ( |
| ./mounttabled --veyron.tcp.address="localhost:${ROOT_MOUNTTABLE_PORT}" &> "${ROOT_MTLOG}" & |
| fail_on_exit $! "root mounttable" "${ROOT_MTLOG}" |
| ) & |
| shell::timed_wait_for "${SRV_TIMEOUT}" "${ROOT_MTLOG}" "${MTLOG_MESSAGE}" || common::fail "${TIMEDOUT_MSG} mounttable root" |
| |
| export NAMESPACE_ROOT=/localhost:"${ROOT_MOUNTTABLE_PORT}"; |
| |
| local -r HOUSE_MTLOG="${TMPDIR}/mt_house.log" |
| cat /dev/null > "${HOUSE_MTLOG}" |
| ( |
| ./mounttabled --veyron.tcp.address="localhost:${HOUSE_MOUNTTABLE_PORT}" --name="house" &> "${HOUSE_MTLOG}" & |
| fail_on_exit $! "house mounttable" "${HOUSE_MTLOG}" |
| ) & |
| shell::timed_wait_for "${SRV_TIMEOUT}" "${HOUSE_MTLOG}" "${MTLOG_MESSAGE}" || common::fail "${TIMEDOUT_MSG} house mounttable" |
| |
| local -r COTTAGE_MTLOG="${TMPDIR}/mt_cottage.log" |
| cat /dev/null > "${COTTAGE_MTLOG}" |
| ( |
| ./mounttabled --veyron.tcp.address="localhost:${COTTAGE_MOUNTTABLE_PORT}" --name="cottage" &> "${COTTAGE_MTLOG}" & |
| fail_on_exit $! "cottage mounttable" "${COTTAGE_MTLOG}" |
| ) & |
| shell::timed_wait_for "${SRV_TIMEOUT}" "${COTTAGE_MTLOG}" "${MTLOG_MESSAGE}" || common::fail "${TIMEDOUT_MSG} cottage mounttable" |
| |
| # Run proxies. |
| local -r PROXYLOG="${TMPDIR}/proxy.log" |
| cat /dev/null > "${PROXYLOG}" |
| ( |
| ./proxyd --v=1 --http=":0" -address="${PROXY_ADDR}" &> "${PROXYLOG}" & |
| fail_on_exit $! "proxy" "${PROXYLOG}" |
| ) & |
| shell::timed_wait_for "${SRV_TIMEOUT}" "${PROXYLOG}" "Proxy listening on" || common::fail "${TIMEDOUT_MSG} proxy" |
| |
| local -r WSPRLOG="${TMPDIR}/wspr.log" |
| cat /dev/null > "${WSPRLOG}" |
| ( |
| ./wsprd --v=1 --new_security_model=true --veyron.proxy="${PROXY_ADDR}" --port="${WSPR_PORT}" --identd="${IDENTITY_SERVER}" &> "${WSPRLOG}" & |
| fail_on_exit $! "wspr" "${WSPRLOG}" |
| ) & |
| shell::timed_wait_for "${SRV_TIMEOUT}" "${WSPRLOG}" "Listening at" || common::fail "${TIMEDOUT_MSG} wspr" |
| |
| # Run some veyron services for demo and integration testing. |
| local -r SAMPLEDLOG="${TMPDIR}/sampled.log" |
| cat /dev/null > "${SAMPLEDLOG}" |
| ( |
| ./sampled &> "${SAMPLEDLOG}" & |
| fail_on_exit $! "sampled" "${SAMPLEDLOG}" |
| ) & |
| } |