blob: 2e5e5b66cfc44ec0fcc5e44ec8407a107527ce53 [file] [log] [blame]
#!/bin/bash
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
FACTORY_DIR="$(readlink -f "${SCRIPT_DIR}/../..")"
FACTORY_PRIVATE_DIR="${FACTORY_DIR}/../factory-private"
. "${FACTORY_DIR}/devtools/mk/common.sh" || exit 1
. "${FACTORY_DIR}/devtools/aufs/shflags" || exit 1
. "${FACTORY_PRIVATE_DIR}/config/probe_info_service/config.sh" || exit 1
PROBE_INFO_SERVICE_DIR="${FACTORY_DIR}/py/probe_info_service"
VENV_PYTHON_NAME="python3"
VENV_PYTHON_RELPATH="./bin/${VENV_PYTHON_NAME}"
: "${LOCAL_DEPLOYMENT_DIR:=/tmp/probe_info_service}"
LOCAL_DEPLOYMENT_VENV_PATH="${LOCAL_DEPLOYMENT_DIR}/venv"
LOCAL_DEPLOYMENT_VENV_PYTHON_PATH="\
${LOCAL_DEPLOYMENT_VENV_PATH}/bin/${VENV_PYTHON_NAME}"
LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH="${LOCAL_DEPLOYMENT_DIR}/project_root"
LOCAL_DEPLOYMENT_SERVICE_SIDS=()
# Following variables will be assigned by `load_config <DEPLOYMENT_TYPE>`
GCP_PROJECT=
run_in_dir() {
local working_dir="$1"
shift
(cd "${working_dir}"; "$@")
}
do_deploy() {
local deployment_type="$1"
if ! load_config "${deployment_type}"; then
die "Unsupported deployment type: \"${deployment_type}\"."
fi
info "Create a temporary directory to hold files to deploy."
local tmpdir="$(mktemp -d)"
if [ ! -d "${tmpdir}" ]; then
die "Failed to create a temporary placeholder for files to deploy."
fi
add_temp "${tmpdir}"
info "Prepare the files to deploy."
make -C "${PROBE_INFO_SERVICE_DIR}" PACK_DEST_DIR="${tmpdir}" _pack
info "Deploy the app engine."
run_in_dir "${tmpdir}" gcloud --project="${GCP_PROJECT}" app deploy app.yaml
}
local_deployment_define_flags() {
DEFINE_boolean clean "${FLAGS_FALSE}" \
"Clean-up 'PROBE_INFO_SERVICE_VNEV_PATH' gracefully first."
}
local_deployment_prepare() {
load_config "staging" # Leverage the staging config for GCP_PROJECT ID.
if [ "${FLAGS_clean}" == "${FLAGS_TRUE}" ]; then
if [[ -f "${LOCAL_DEPLOYMENT_VENV_PYTHON_PATH}" ]]; then
info "Drop the existing venv."
rm -rf "${LOCAL_DEPLOYMENT_VENV_PATH}"
fi
if [[ -d "${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}" ]]; then
info "Drop the existing project root dir."
rm -rf "${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}"
fi
fi
if [ ! -f "${LOCAL_DEPLOYMENT_VENV_PYTHON_PATH}" ]; then
info "Initialize venv for local instance."
python3 -m virtualenv \
--python="${VENV_PYTHON_NAME}" "${LOCAL_DEPLOYMENT_VENV_PATH}"
fi
info "Copy resources into venv path."
make -C "${PROBE_INFO_SERVICE_DIR}" \
PACK_DEST_DIR="${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}" _pack
info "Install dependent package/modules."
local_deployment_run_venv_python -m pip install -r \
"${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}/requirements.txt"
info "Start the dependent services."
local sid="$(setsid bash -c "gcloud --project='${GCP_PROJECT}' beta \
emulators datastore start --no-store-on-disk 2>/dev/null >/dev/null \
& echo \$\$")"
sleep 3 # ensure the datastore emulator is ready
LOCAL_DEPLOYMENT_SERVICE_SIDS+=("${sid}")
$(gcloud --project="${GCP_PROJECT}" beta emulators datastore env-init)
}
local_deployment_stop() {
info "Stop all dependent services."
local pid
for pid in "${LOCAL_DEPLOYMENT_SERVICE_SIDS[@]}"; do
pkill -s "${pid}"
done
}
local_deployment_run_venv_python() {
run_in_dir "${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}" \
exec "${LOCAL_DEPLOYMENT_VENV_PYTHON_PATH}" "$@"
}
local_deployment_find_all_test_modules() {
local find_output="$(find "${LOCAL_DEPLOYMENT_PROJECT_ROOT_PATH}" -type f \
-name "*_*test.py" -printf "%P\\n")"
local path_name=
IFS=$'\n'
for path_name in ${find_output}; do
local path_name_no_ext="${path_name%.py}"
echo "${path_name_no_ext//\//.}"
done
}
local_deployment_create_log_dir() {
local log_type="$1"
local timestamp="$(date +%Y%m%d_%H%M%S)"
local log_dir="${LOCAL_DEPLOYMENT_DIR}/logs.${log_type}.${timestamp}.d"
local log_linkpath="${LOCAL_DEPLOYMENT_DIR}/logs.${log_type}.latest.d"
mkdir -p "${log_dir}"
rm "${log_linkpath}" || true
ln -s "$(basename "${log_dir}")" "${log_linkpath}"
echo "${log_dir}"
}
do_run_local() {
set +e # Temporary turns off non-zero status check for the shflags library.
local_deployment_define_flags
FLAGS "$@" || die $?
set -e
local_deployment_prepare
info "Start the local instance."
local_deployment_run_venv_python \
-m cros.factory.probe_info_service.app_engine.main || true
local_deployment_stop
}
do_run_tests() {
set +e # Temporary turns off non-zero status check for the shflags library.
local_deployment_define_flags
DEFINE_boolean dump_logs "${FLAGS_FALSE}" "Dump logs of the failure tests."
FLAGS_HELP="USAGE: $0 [flags] [<test_modules>...]"
FLAGS "$@" || die $?
set -e
local_deployment_prepare
eval local "test_modules=(${FLAGS_ARGV})"
if [ "${#test_modules[@]}" -eq 0 ]; then
info "Discover all test modules."
test_modules=($(local_deployment_find_all_test_modules))
info "Found ${#test_modules[@]} test modules."
fi
local failed_test_modules=()
local log_dir="$(local_deployment_create_log_dir "test")"
local test_module=
for test_module in "${test_modules[@]}"; do
info "Run test \"${test_module}\"."
local logfile_path="${log_dir}/${test_module}.log"
if ! local_deployment_run_venv_python -m "${test_module}" \
>"${logfile_path}" 2>&1; then
failed_test_modules+=("${test_module}")
fi
done
local_deployment_stop
if [ ${#failed_test_modules[@]} -eq 0 ]; then
info "All tests are passed!"
return
fi
error "Following ${#failed_test_modules[@]} test(s) are failed:"
for test_module in "${failed_test_modules[@]}"; do
local logfile_path="${log_dir}/${test_module}.log"
echo "- ${test_module}, logfile path: ${logfile_path}"
if [ "${FLAGS_dump_logs}" == "${FLAGS_TRUE}" ]; then
echo "========== BEGIN: LOG =========="
cat "${logfile_path}"
echo "========== END: LOG =========="
fi
done
die "Fail rate ${#failed_test_modules[@]}/${#test_modules[@]} > 0."
}
print_usage() {
cat << __EOF__
Chrome OS Probe Info Service Deployment Script
commands:
$0 help
Shows this help message.
$0 deploy [prod|staging]
Deploys Probe Info Service to the given environment by gcloud command.
$0 run [<args...>]
Runs Probe Info Service locally. The command prepares the virtualenv and
the source code to deploy in 'LOCAL_DEPLOYMENT_DIR' (default to
/tmp/probe_info_service/) first. Then it starts the server instance
locally.
$0 test [<args...>]
Runs the specified/all tests. The command prepares the virtualenv and
the source code to deploy in 'LOCAL_DEPLOYMENT_DIR' (default to
/tmp/probe_info_service/) first. Then it runs the targets locally.
To get the detail usages of the sub-commands, please run
$0 <sub-command> --help
__EOF__
}
main() {
local subcmd="$1"
shift || true
case "${subcmd}" in
help)
print_usage
;;
deploy)
do_deploy "$1"
;;
run)
do_run_local "$@"
;;
test)
do_run_tests "$@"
;;
*)
die "Unknown sub-command: \"${subcmd}\". Run \`${0} help\` to print" \
"the usage."
;;
esac
mk_success
}
main "$@"