0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-15 10:04:15 +00:00
netdata_netdata/claim/netdata-claim.sh.in
Andrew Moss fe722cb2a4
Improve the behavior of claiming ()
The default cloud url has been updated to app.netdata.cloud ready for the release. The claiming process now checks the current user executing claiming and refuses to perform the claim for the wrong user. If the current UID is 0 then claiming proceeds but the file ownership is adjusted to be the correct netdata user. The default expected user is `netdata` unless the script can identify the user from the current configuration. After the claiming script is executed the CLI is used to reload the claiming state.
2020-03-31 13:07:24 +02:00

315 lines
10 KiB
Bash
Executable file

#!/usr/bin/env bash
# netdata
# real-time performance and health monitoring, done right!
# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
# SPDX-License-Identifier: GPL-3.0-or-later
# Exit code: 0 - Success
# Exit code: 1 - Unknown argument
# Exit code: 2 - Problems with claiming working directory
# Exit code: 3 - Missing dependencies
# Exit code: 4 - Failure to connect to endpoint
# Exit code: 5 - Unknown HTTP error message
# Exit code: 6 - The CLI didn't work
# Exit code: 7 - Wrong user
#
# OK: Agent claimed successfully
# HTTP Status code: 204
# Exit code: 0
#
# Error: The agent id is invalid; it does not fulfill the constraints
# HTTP Status code: 422
# Error key: "ErrInvalidNodeID"
# Error message: "invalid node id"
# Exit code: 6
# Error: The agent hostname is invalid; it does not fulfill the constraints
# HTTP Status code: 422
# Error key: "ErrInvalidNodeName"
# Error message: "invalid node name"
# Exit code: 7
#
# Error: At least one of the given rooms ids is invalid; it does not fulfill the constraints
# HTTP Status code: 422
# Error key: "ErrInvalidRoomID"
# Error message: "invalid room id"
# Exit code: 8
#
# Error: Invalid public key; the public key is empty or not present
# HTTP Status code: 422
# Error key: "ErrInvalidPublicKey"
# Error message: "invalid public key"
# Exit code: 9
#
# Error: Expired, missing or invalid token
# HTTP Status code: 403
# Error key: "ErrForbidden"
# Error message: "token expired" | "token not found" | "invalid token"
# Exit code: 10
#
# Error: Duplicate agent id; an agent with the same id is already registered in the cloud
# HTTP Status code: 409
# Error key: "ErrAlreadyClaimed"
# Error message: "already claimed"
# Exit code: 11
#
# Error: The node claiming process is still in progress.
# HTTP Status code: 102
# Error key: "ErrProcessingClaim"
# Error message: "processing claiming"
# Exit code: 12
#
# Error: Internal server error. Any other unexpected error (DB problems, etc.)
# HTTP Status code: 500
# Error key: "ErrInternalServerError"
# Error message: "Internal Server Error"
# Exit code: 13
#
# Error: There was a timout processing the claim.
# HTTP Status code: 504
# Error key: "ErrGatewayTimeout"
# Error message: "Gateway Timeout"
# Exit code: 14
#
# Error: The service cannot handle the claiming request at this time.
# HTTP Status code: 503
# Error key: "ErrServiceUnavailable"
# Error message: "Service Unavailable"
# Exit code: 15
if command -v curl >/dev/null 2>&1 ; then
URLTOOL="curl"
elif command -v wget >/dev/null 2>&1 ; then
URLTOOL="wget"
else
echo >&2 "I need curl or wget to proceed, but neither is available on this system."
exit 3
fi
if ! command -v openssl >/dev/null 2>&1 ; then
echo >&2 "I need openssl to proceed, but it is not available on this system."
exit 3
fi
# -----------------------------------------------------------------------------
# defaults to allow running this script by hand
[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
MACHINE_GUID_FILE="@registrydir_POST@/netdata.public.unique.id"
CLAIMING_DIR="${NETDATA_USER_CONFIG_DIR}/claim.d"
TOKEN="unknown"
URL_BASE="https://app.netdata.cloud"
ID="unknown"
ROOMS=""
HOSTNAME=$(hostname)
CLOUD_CERTIFICATE_FILE="${CLAIMING_DIR}/cloud_fullchain.pem"
VERBOSE=0
INSECURE=0
RELOAD=1
NETDATA_USER=netdata
[ -z "$EUID" ] && EUID="$(id -u)"
CONF_USER=$(grep '^[^#]*run as user[ \t]*=' "${NETDATA_USER_CONFIG_DIR}/netdata.conf" 2>/dev/null)
if [ -n "$CONF_USER" ]; then
NETDATA_USER=$(echo "$CONF_USER" | sed 's/^[^=]*=[ \t]*//' | sed 's/[ \t]*$//')
fi
# get the MACHINE_GUID by default
if [ -r "${MACHINE_GUID_FILE}" ]; then
ID="$(cat "${MACHINE_GUID_FILE}")"
fi
# get token from file
if [ -r "${CLAIMING_DIR}/token" ]; then
TOKEN="$(cat "${CLAIMING_DIR}/token")"
fi
# get rooms from file
if [ -r "${CLAIMING_DIR}/rooms" ]; then
ROOMS="$(cat "${CLAIMING_DIR}/rooms")"
fi
for arg in "$@"
do
case $arg in
-token=*) TOKEN=${arg:7} ;;
-url=*) URL_BASE=${arg:5} ;;
-id=*) ID=${arg:4} ;;
-rooms=*) ROOMS=${arg:7} ;;
-hostname=*) HOSTNAME=${arg:10} ;;
-verbose) VERBOSE=1 ;;
-insecure) INSECURE=1 ;;
-proxy=*) PROXY=${arg:7} ;;
-noproxy) NOPROXY=yes ;;
-noreload) RELOAD=0 ;;
-user=*) NETDATA_USER=${arg:6} ;;
*) echo >&2 "Unknown argument ${arg}"
exit 1 ;;
esac
shift 1
done
if [ "$EUID" != "0" ] && [ "$(whoami)" != "$NETDATA_USER" ]; then
echo >&2 "This script must be run by the $NETDATA_USER user account"
exit 7
fi
# if curl not installed give warning SOCKS can't be used
if [[ "${URLTOOL}" != "curl" && "${PROXY:0:5}" = socks ]] ; then
echo >&2 "wget doesn't support SOCKS. Please install curl or disable SOCKS proxy."
exit 1
fi
echo >&2 "Token: ****************"
echo >&2 "Base URL: $URL_BASE"
echo >&2 "Id: $ID"
echo >&2 "Rooms: $ROOMS"
echo >&2 "Hostname: $HOSTNAME"
echo >&2 "Proxy: $PROXY"
echo >&2 "Netdata user: $NETDATA_USER"
# create the claiming directory for this user
if [ ! -d "${CLAIMING_DIR}" ] ; then
mkdir -p "${CLAIMING_DIR}" && chmod 0770 "${CLAIMING_DIR}"
# shellcheck disable=SC2181
if [ $? -ne 0 ] ; then
echo >&2 "Failed to create claiming working directory ${CLAIMING_DIR}"
exit 2
fi
fi
if [ ! -w "${CLAIMING_DIR}" ] ; then
echo >&2 "No write permission in claiming working directory ${CLAIMING_DIR}"
exit 2
fi
if [ ! -f "${CLAIMING_DIR}/private.pem" ] ; then
echo >&2 "Generating private/public key for the first time."
if ! openssl genrsa -out "${CLAIMING_DIR}/private.pem" 2048 ; then
echo >&2 "Failed to generate private/public key pair."
exit 2
fi
fi
if [ ! -f "${CLAIMING_DIR}/public.pem" ] ; then
echo >&2 "Extracting public key from private key."
if ! openssl rsa -in "${CLAIMING_DIR}/private.pem" -outform PEM -pubout -out "${CLAIMING_DIR}/public.pem" ; then
echo >&2 "Failed to extract public key."
exit 2
fi
fi
TARGET_URL="${URL_BASE%/}/api/v1/spaces/nodes/${ID}"
# shellcheck disable=SC2002
KEY=$(cat "${CLAIMING_DIR}/public.pem" | tr '\n' '!' | sed -e 's/!/\\n/g')
# shellcheck disable=SC2001
[ -n "$ROOMS" ] && ROOMS=\"$(echo "$ROOMS" | sed s'/,/", "/g')\"
cat > "${CLAIMING_DIR}/tmpin.txt" <<EMBED_JSON
{
"node": {
"id": "$ID",
"hostname": "$HOSTNAME"
},
"token": "$TOKEN",
"rooms" : [ $ROOMS ],
"publicKey" : "$KEY"
}
EMBED_JSON
if [ "${VERBOSE}" == 1 ] ; then
echo "Request to server:"
cat "${CLAIMING_DIR}/tmpin.txt"
fi
if [ "${URLTOOL}" = "curl" ] ; then
URLCOMMAND="curl --connect-timeout 5 --retry 0 -s -i -X PUT -d \"@${CLAIMING_DIR}/tmpin.txt\""
if [ "${NOPROXY}" = "yes" ] ; then
URLCOMMAND="${URLCOMMAND} -x \"\""
elif [ -n "${PROXY}" ] ; then
URLCOMMAND="${URLCOMMAND} -x \"${PROXY}\""
fi
else
URLCOMMAND="wget -T 15 -O - -q --save-headers --content-on-error=on --method=PUT \
--body-file=\"${CLAIMING_DIR}/tmpin.txt\""
if [ "${NOPROXY}" = "yes" ] ; then
URLCOMMAND="${URLCOMMAND} --no-proxy"
elif [ "${PROXY:0:4}" = http ] ; then
URLCOMMAND="export http_proxy=${PROXY}; ${URLCOMMAND}"
fi
fi
if [ "${INSECURE}" == 1 ] ; then
if [ "${URLTOOL}" = "curl" ] ; then
URLCOMMAND="${URLCOMMAND} --insecure"
else
URLCOMMAND="${URLCOMMAND} --no-check-certificate"
fi
fi
if [ -r "${CLOUD_CERTIFICATE_FILE}" ] ; then
if [ "${URLTOOL}" = "curl" ] ; then
URLCOMMAND="${URLCOMMAND} --cacert \"${CLOUD_CERTIFICATE_FILE}\""
else
URLCOMMAND="${URLCOMMAND} --ca-certificate \"${CLOUD_CERTIFICATE_FILE}\""
fi
fi
if [ "${VERBOSE}" == 1 ]; then
echo "${URLCOMMAND} \"${TARGET_URL}\""
fi
eval "${URLCOMMAND} \"${TARGET_URL}\"" >"${CLAIMING_DIR}/tmpout.txt"
URLCOMMAND_EXIT_CODE=$?
if [ "${URLTOOL}" = "wget" ] && [ "${URLCOMMAND_EXIT_CODE}" -eq 8 ] ; then
# We consider the server issuing an error response a successful attempt at communicating
URLCOMMAND_EXIT_CODE=0
fi
rm -f "${CLAIMING_DIR}/tmpin.txt"
# Check if URLCOMMAND connected and received reply
if [ "${URLCOMMAND_EXIT_CODE}" -ne 0 ] ; then
echo >&2 "Failed to connect to ${URL_BASE}, return code ${URLCOMMAND_EXIT_CODE}"
rm -f "${CLAIMING_DIR}/tmpout.txt"
exit 4
fi
if [ "${VERBOSE}" == 1 ] ; then
echo "Response from server:"
cat "${CLAIMING_DIR}/tmpout.txt"
fi
HTTP_STATUS_CODE=$(grep "HTTP" "${CLAIMING_DIR}/tmpout.txt" | awk -F " " '{print $2}')
if [ "${HTTP_STATUS_CODE}" = "204" ] ; then
rm -f "${CLAIMING_DIR}/tmpout.txt"
echo -n "${ID}" >"${CLAIMING_DIR}/claimed_id" || (echo >&2 "Claiming failed"; set -e; exit 2)
rm -f "${CLAIMING_DIR}/token" || (echo >&2 "Claiming failed"; set -e; exit 2)
if [ "$EUID" == "0" ]; then
chown -R "${NETDATA_USER}:${NETDATA_USER}" ${CLAIMING_DIR} || (echo >&2 "Claiming failed"; set -e; exit 2)
fi
if [ "${RELOAD}" == "0" ] ; then
exit 0
fi
netdatacli reload-claiming-state && echo >&2 "Node was successfully claimed." && exit 0
echo "The claim was successful but the agent could not be notified ($?)- it requires a restart to connect to the cloud"
exit 6
fi
ERROR_MESSAGE=$(grep "\"errorMsgKey\":" "${CLAIMING_DIR}/tmpout.txt" | awk -F "errorMsgKey\":\"" '{print $2}' | awk -F "\"" '{print $1}')
case ${ERROR_MESSAGE} in
"ErrInvalidNodeID") EXIT_CODE=6 ;;
"ErrInvalidNodeName") EXIT_CODE=7 ;;
"ErrInvalidRoomID") EXIT_CODE=8 ;;
"ErrInvalidPublicKey") EXIT_CODE=9 ;;
"ErrForbidden") EXIT_CODE=10 ;;
"ErrAlreadyClaimed") EXIT_CODE=11 ;;
"ErrProcessingClaim") EXIT_CODE=12 ;;
"ErrInternalServerError") EXIT_CODE=13 ;;
"ErrGatewayTimeout") EXIT_CODE=14 ;;
"ErrServiceUnavailable") EXIT_CODE=15 ;;
*) EXIT_CODE=5 ;;
esac
echo >&2 "Failed to claim node."
rm -f "${CLAIMING_DIR}/tmpout.txt"
exit $EXIT_CODE