mirror of
https://github.com/netdata/netdata.git
synced 2025-04-15 10:04:15 +00:00

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.
315 lines
10 KiB
Bash
Executable file
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
|