blob: e6d71fd0f75086def6c8266184b2b125b356172e [file] [log] [blame]
#!/bin/bash
#
# Installs node manager on the local machine.
#
# Specifically:
#
# 1. Fetches the binaries required for a node manager installation from a few
# possible sources.
#
# 2. Sets up the helper with setuid. The helper binary needs to be owned by
# root and have the suid bit set, to enable the node manager to run binaries
# under different system accounts than itself.
#
# 3. Runs the self-install command on the node manager.
#
# Usage:
#
# # Gets binaries from local repository
# ./nminstall <install parent dir>
#
# # Gets binaries from local filesystem
# ./nminstall <install parent dir> /path/to/binaries
#
# # Gets binaries from HTTP server
# ./nminstall <install parent dir> http://host/path
set -e
usage() {
echo "usage:"
echo "./nminstall <install parent dir> [<binary source>]"
}
readonly BIN_NAMES=(noded suidhelper agentd)
###############################################################################
# Copies one binary from source to destination.
# Arguments:
# name of the binary
# source dir of binary
# destination dir of binary
# Returns:
# None
###############################################################################
copy_binary() {
local -r BIN_NAME="$1"
local -r BIN_SRC_DIR="$2"
local -r BIN_DEST_DIR="$3"
local -r SOURCE="${BIN_SRC_DIR}/${BIN_NAME}"
if [[ -x "${SOURCE}" ]]; then
local -r DESTINATION="${BIN_DEST_DIR}/${BIN_NAME}"
cp "${SOURCE}" "${DESTINATION}"
chmod 700 "${DESTINATION}"
else
echo "couldn't find ${SOURCE}"
exit 1
fi
}
###############################################################################
# Fetches binaries needed by node manager installation.
# Globals:
# BIN_NAMES
# VEYRON_ROOT
# Arguments:
# destination for binaries
# source of binaries
# Returns:
# None
###############################################################################
get_binaries() {
local -r BIN_INSTALL="$1"
local -r BIN_SOURCE="$2"
local bin_names_str=""
for bin_name in "${BIN_NAMES[@]}"; do
bin_names_str+=" ${bin_name}"
done
# If source is not specified, try to look for it in the repository.
if [[ -z "${BIN_SOURCE}" ]]; then
if [[ -z "${VEYRON_ROOT}" ]]; then
echo 'ERROR: binary source not specified and no local repository available'
exit 1
fi
local -r REPO_BIN_DIR="${VEYRON_ROOT}/veyron/go/bin"
echo "Fetching binaries:${bin_names_str} from build repository: ${REPO_BIN_DIR} ..."
for bin_name in "${BIN_NAMES[@]}"; do
copy_binary "${bin_name}" "${REPO_BIN_DIR}" "${BIN_INSTALL}"
done
return
fi
# If the source is specified as an existing local filesystem path,
# look for the binaries there.
if [[ -d "${BIN_SOURCE}" ]]; then
echo "Fetching binaries:${bin_names_str} locally from: ${BIN_SOURCE} ..."
for bin_name in "${BIN_NAMES[@]}"; do
copy_binary "${bin_name}" "${BIN_SOURCE}" "${BIN_INSTALL}"
done
return
fi
# If the source looks like a URL, use HTTP to fetch.
local -r URL_REGEXP='^(https?|ftp|file)://'
if [[ "${BIN_SOURCE}" =~ ${URL_REGEXP} ]]; then
echo "Fetching binaries:${bin_names_str} remotely from: ${BIN_SOURCE} ..."
for bin_name in "${BIN_NAMES[@]}"; do
local DEST="${BIN_INSTALL}/${bin_name}"
curl -f -o "${DEST}" "${BIN_SOURCE}/${bin_name}"
chmod 700 "${DEST}"
done
return
fi
echo 'ERROR: couldn'"'"'t fetch binaries.'
exit 1
}
main() {
local -r INSTALL_PARENT_DIR="$1"
if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
echo 'No local install destination specified!'
usage
exit 1
fi
if [[ ! -d "${INSTALL_PARENT_DIR}" ]]; then
echo "${INSTALL_PARENT_DIR} is not a directory!"
exit 1
fi
local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/node_manager"
# TODO(caprita): Check that the node manager is not already installed before
# proceeding. We should require an explicit uninstall to avoid wiping away
# the node manager accidentally.
sudo rm -rf "${INSTALL_DIR}"
mkdir -m 700 "${INSTALL_DIR}"
local -r BIN_INSTALL="${INSTALL_DIR}/bin"
mkdir -m 700 "${BIN_INSTALL}"
# Fetch the binaries.
local -r BIN_SOURCE="$2"
get_binaries "${BIN_INSTALL}" "${BIN_SOURCE}"
for bin_name in "${BIN_NAMES[@]}"; do
local BINARY="${BIN_INSTALL}/${bin_name}"
if [[ ! -s "${BINARY}" ]]; then
echo "${BINARY} is empty."
exit 1
fi
done
echo "Binaries are in ${BIN_INSTALL}."
# Set up the suidhelper.
echo "Configuring suidhelper ..."
local -r SETUID_SCRIPT="${BIN_INSTALL}/suidhelper"
sudo bash -c "chown root:root \"${SETUID_SCRIPT}\"; chmod 4551 \"${SETUID_SCRIPT}\""
echo "Suidhelper configured."
# Tell the node manager to install itself.
local -r NM_ROOT="${INSTALL_DIR}/nmroot"
echo "Installing node manager under ${NM_ROOT} ..."
local -r PUBLISH=$(hostname)
VEYRON_NM_CURRENT="${INSTALL_DIR}/noded.curr" VEYRON_NM_ROOT="${NM_ROOT}" VEYRON_NM_HELPER="${SETUID_SCRIPT}" "${BIN_INSTALL}/noded" --install_self --name="${PUBLISH}"
echo "Node manager installed."
local -r SECURITY_DIR="${INSTALL_DIR}/security"
mkdir -m 700 "${SECURITY_DIR}"
local -r PRINCIPAL_DIR="${SECURITY_DIR}/principal"
mkdir -m 700 "${PRINCIPAL_DIR}"
local -r AGENT_KEY_DIR="${SECURITY_DIR}/keys"
mkdir -m 700 "${AGENT_KEY_DIR}"
# Run node manager under the security agent.
echo
echo "Running:"
echo "VEYRON_CREDENTIALS=\"${PRINCIPAL_DIR}\" \"${BIN_INSTALL}/agentd\" --additional_principals=\"${AGENT_KEY_DIR}\" \"${INSTALL_DIR}/noded.curr\""
echo
# NOTE: If you update the command below, please also update the command echoed
# above to keep the two in sync.
VEYRON_CREDENTIALS="${PRINCIPAL_DIR}" "${BIN_INSTALL}/agentd" --additional_principals="${AGENT_KEY_DIR}" "${INSTALL_DIR}/noded.curr"
}
main "$@"