summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--BUILD.md1
-rw-r--r--CMakeLists.txt6
-rw-r--r--Makefile.am7
-rw-r--r--claim/Makefile.am21
-rw-r--r--claim/README.md72
-rw-r--r--claim/claim.c103
-rw-r--r--claim/claim.h14
-rwxr-xr-xclaim/netdata-claim.sh.in216
-rw-r--r--cli/README.md2
-rw-r--r--configure.ac1
-rw-r--r--daemon/commands.c21
-rw-r--r--daemon/commands.h1
-rw-r--r--daemon/common.h3
-rw-r--r--daemon/daemon.c6
-rw-r--r--daemon/main.c15
-rwxr-xr-xnetdata-installer.sh10
-rwxr-xr-xpackaging/installer/netdata-uninstaller.sh1
18 files changed, 499 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 284fcda506..f94c5603a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,6 +116,7 @@ daemon/anonymous-statistics.sh
daemon/get-kubernetes-labels.sh
health/notifications/alarm-notify.sh
+claim/netdata-claim.sh
collectors/cgroups.plugin/cgroup-name.sh
collectors/tc.plugin/tc-qos-helper.sh
collectors/charts.d.plugin/charts.d.plugin
diff --git a/BUILD.md b/BUILD.md
index e22e6a2fff..5ad4bdbaef 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,4 +1,3 @@
-
# The build system
We are currently migrating from `autotools` to `CMake` as a build-system. This document
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ff64b1c38..fe221b9b0a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -601,6 +601,11 @@ set(BACKENDS_PLUGIN_FILES
backends/prometheus/backend_prometheus.h
)
+set(CLAIM_PLUGIN_FILES
+ claim/claim.c
+ claim/claim.h
+ )
+
set(EXPORTING_ENGINE_FILES
exporting/exporting_engine.c
exporting/exporting_engine.h
@@ -667,6 +672,7 @@ set(NETDATA_FILES
${STATSD_PLUGIN_FILES}
${STREAMING_PLUGIN_FILES}
${WEB_PLUGIN_FILES}
+ ${CLAIM_PLUGIN_FILES}
)
set(NETDATACLI_FILES
diff --git a/Makefile.am b/Makefile.am
index 1158cf073d..0a8c3e8800 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ SUBDIRS += \
registry \
streaming \
web \
+ claim \
$(NULL)
@@ -454,6 +455,11 @@ BACKENDS_PLUGIN_FILES = \
backends/prometheus/backend_prometheus.h \
$(NULL)
+CLAIM_PLUGIN_FILES = \
+ claim/claim.c \
+ claim/claim.h \
+ $(NULL)
+
EXPORTING_ENGINE_FILES = \
exporting/exporting_engine.c \
exporting/exporting_engine.h \
@@ -521,6 +527,7 @@ NETDATA_FILES = \
$(STREAMING_PLUGIN_FILES) \
$(STATSD_PLUGIN_FILES) \
$(WEB_PLUGIN_FILES) \
+ $(CLAIM_PLUGIN_FILES) \
$(NULL)
if FREEBSD
diff --git a/claim/Makefile.am b/claim/Makefile.am
new file mode 100644
index 0000000000..c838db9b66
--- /dev/null
+++ b/claim/Makefile.am
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = \
+ netdata-claim.sh \
+ $(NULL)
+
+include $(top_srcdir)/build/subst.inc
+SUFFIXES = .in
+
+sbin_SCRIPTS = \
+ netdata-claim.sh \
+ $(NULL)
+
+dist_noinst_DATA = \
+ netdata-claim.sh.in \
+ README.md \
+ $(NULL)
+
diff --git a/claim/README.md b/claim/README.md
new file mode 100644
index 0000000000..05de636155
--- /dev/null
+++ b/claim/README.md
@@ -0,0 +1,72 @@
+# Agent claiming
+
+Agent claiming is part of the onboarding process when creating a workspace in Netdata Cloud. Each workspace gets its own
+common invitation mechanism, which begins with the administrators of the workspace creating a **claiming-token**. They,
+or other users is their organization, can then use the claiming-token to add an agent to their workspace.
+
+To claim a Netdata agent, you first send a claiming request to Netdata Cloud (from the agent node). Once the
+Netdata Cloud validates the claiming request of the agent (based on the claiming token), and returns a successful
+result, the node is considered claimed.
+
+## Claiming script
+
+The user can claim an agent by directly calling the `netdata-claim.sh` script **as the netdata user** and passing the
+following arguments:
+
+```sh
+-token=TOKEN
+ where TOKEN is the workspace claiming-token.
+-rooms=ROOM1,ROOM2,...
+ where ROOMX is the workspace war-room to join. This list is optional.
+-url=URL_BASE
+ where URL_BASE is the Netdata Cloud endpoint base URL. By default, this is https://netdata.cloud.
+-id=AGENT_ID
+ where AGENT_ID is the unique identifier of the agent. This is the agent's MACHINE_GUID by default.
+-hostname=HOSTNAME
+ where HOSTNAME is the result of the hostname command by default.
+```
+
+For example, the following command claims an agent and adds it to rooms `room1` and `room2`:
+
+```sh
+netdata-claim.sh -token=MYTOKEN1234567 -rooms=room1,room2
+```
+
+You should then update the `netdata` service about the result with `netdatacli`:
+
+```sh
+netdatacli reload-claiming-state
+```
+
+This reloads the agent claiming state from disk.
+
+## Netdata agent command line
+
+The user can trigger agent claiming by calling the `netdata` service binary with the additional command line parameters:
+
+```sh
+-W "claim -token=TOKEN -rooms=ROOM1,ROOM2"
+```
+
+For example:
+
+```sh
+/usr/sbin/netdata -D -W "claim -token=MYTOKEN1234567 -rooms=room1,room2"
+```
+
+If need be, the user can override the agent's defaults by providing additional arguments like those described
+[here](#claiming-script).
+
+## Claiming directory
+
+Netdata stores the agent claiming-related state in the user configuration directory under `claim.d`, e.g. in
+`/etc/netdata/claim.d`. The user can put files in this directory to provide defaults to the `-token` and `-rooms`
+arguments. These files should be owned **by the `netdata` user**.
+
+The `claim.d/token` file should contain the claiming-token and the `claim.d/rooms` file should contain the list of
+war-rooms.
+
+The user can also put the Cloud endpoint's full certificate chain in `claim.d/cloud_fullchain.pem` so that the agent
+can trust the endpoint if necessary.
+
+[![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fclaim%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>)
diff --git a/claim/claim.c b/claim/claim.c
new file mode 100644
index 0000000000..75f0a437d6
--- /dev/null
+++ b/claim/claim.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "claim.h"
+#include "../registry/registry_internals.h"
+
+char *claiming_pending_arguments = NULL;
+
+static char *claiming_errors[] = {
+ "Agent claimed successfully", // 0
+ "Unknown argument", // 1
+ "Problems with claiming working directory", // 2
+ "Missing dependencies", // 3
+ "Failure to connect to endpoint", // 4
+ "Unknown HTTP error message", // 5
+ "invalid agent id", // 6
+ "invalid public key", // 7
+ "token has expired", // 8
+ "invalid token", // 9
+ "duplicate agent id", // 10
+ "claimed in another workspace", // 11
+ "internal server error" // 12
+};
+
+#define AGENT_UNCLAIMED 0
+#define AGENT_CLAIMED 1
+static uint8_t claiming_status = AGENT_UNCLAIMED;
+
+uint8_t is_agent_claimed(void)
+{
+ return (AGENT_CLAIMED == claiming_status);
+}
+
+#define CLAIMING_COMMAND_LENGTH 16384
+
+extern struct registry registry;
+
+/* rrd_init() must have been called before this function */
+void claim_agent(char *claiming_arguments)
+{
+ info("The claiming feature is under development and still subject to change before the next release");
+ return;
+
+ int exit_code;
+ pid_t command_pid;
+ char command_buffer[CLAIMING_COMMAND_LENGTH + 1];
+ FILE *fp;
+
+ snprintfz(command_buffer,
+ CLAIMING_COMMAND_LENGTH,
+ "exec netdata-claim.sh -hostname=%s -id=%s -url=%s %s",
+ netdata_configured_hostname,
+ localhost->machine_guid,
+ registry.cloud_base_url,
+ claiming_arguments);
+
+ info("Executing agent claiming command 'netdata-claim.sh'");
+ fp = mypopen(command_buffer, &command_pid);
+ if(!fp) {
+ error("Cannot popen(\"%s\").", command_buffer);
+ return;
+ }
+ info("Waiting for claiming command to finish.");
+ while (fgets(command_buffer, CLAIMING_COMMAND_LENGTH, fp) != NULL) {;}
+ exit_code = mypclose(fp, command_pid);
+ info("Agent claiming command returned with code %d", exit_code);
+ if (0 == exit_code) {
+ claiming_status = AGENT_CLAIMED;
+ info("Agent successfully claimed.");
+ return;
+ }
+ if (exit_code < 0) {
+ error("Agent claiming command failed to complete its run.");
+ return;
+ }
+ errno = 0;
+ unsigned maximum_known_exit_code = sizeof(claiming_errors) / sizeof(claiming_errors[0]);
+
+ if ((unsigned)exit_code > maximum_known_exit_code) {
+ error("Agent failed to be claimed with an unknown error.");
+ return;
+ }
+ error("Agent failed to be claimed with the following error message:");
+ error("\"%s\"", claiming_errors[exit_code]);
+}
+
+void load_claiming_state(void)
+{
+ info("The claiming feature is under development and still subject to change before the next release");
+ return;
+
+ char filename[FILENAME_MAX + 1];
+ struct stat statbuf;
+
+ snprintfz(filename, FILENAME_MAX, "%s/claim.d/is_claimed", netdata_configured_user_config_dir);
+ // check if the file exists
+ if (lstat(filename, &statbuf) != 0) {
+ info("File '%s' was not found. Setting state to AGENT_UNCLAIMED.", filename);
+ claiming_status = AGENT_UNCLAIMED;
+ } else {
+ info("File '%s' was found. Setting state to AGENT_CLAIMED.", filename);
+ claiming_status = AGENT_CLAIMED;
+ }
+}
diff --git a/claim/claim.h b/claim/claim.h
new file mode 100644
index 0000000000..3b2b867434
--- /dev/null
+++ b/claim/claim.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_CLAIM_H
+#define NETDATA_CLAIM_H 1
+
+#include "../daemon/common.h"
+
+extern char *claiming_pending_arguments;
+
+void claim_agent(char *claiming_arguments);
+uint8_t is_agent_claimed(void);
+void load_claiming_state(void);
+
+#endif //NETDATA_CLAIM_H
diff --git a/claim/netdata-claim.sh.in b/claim/netdata-claim.sh.in
new file mode 100755
index 0000000000..e565e3de28
--- /dev/null
+++ b/claim/netdata-claim.sh.in
@@ -0,0 +1,216 @@
+#!/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
+#
+# OK: Agent claimed successfully
+# HTTP Status code: 200
+# Exit code: 0
+#
+# Error: The agent id is invalid; it does not fulfill the constraints
+# HTTP Status code: 422
+# Error message: "invalid agent id"
+# Exit code: 6
+#
+# Error: Invalid public key; the public key is empty or not present
+# HTTP Status code: 422
+# Error message: "invalid public key"
+# Exit code: 7
+#
+# Error: Expired token
+# HTTP Status code: 403
+# Error message: "token has expired"
+# Exit code: 8
+#
+# Error: Invalid claiming token; missing, undecryptable, invalid payload...
+# HTTP Status code: 422
+# Error message: "invalid token"
+# Exit code: 9
+#
+# Error: Duplicate agent id; an agent with the same id but a different public key is already registered in the cloud
+# HTTP Status code: 409
+# Error message: "duplicate agent id"
+# Exit code: 10
+#
+# Error: Already claimed in another workspace;
+# this agent (same id, same public key) already belongs to another workspace
+# HTTP Status code: 403
+# Error message: "claimed in another workspace"
+# Exit code: 11
+#
+# Error: Internal server error. Any other unexpected error (DB problems, etc.)
+# HTTP Status code: 500
+# Error message: "internal server error"
+# Exit code: 12
+
+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 neither is 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://netdata.cloud"
+ID="unknown"
+ROOMS=""
+HOSTNAME=$(hostname)
+CLOUD_CERTIFICATE_FILE="${CLAIMING_DIR}/cloud_fullchain.pem"
+
+# 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} ;;
+ *) echo >&2 "Unknown argument ${arg}"
+ exit 1 ;;
+ esac
+ shift 1
+done
+
+echo >&2 "Token: ****************"
+echo >&2 "Base URL: $URL_BASE"
+echo >&2 "Id: $ID"
+echo >&2 "Rooms: $ROOMS"
+echo >&2 "Hostname: $HOSTNAME"
+
+# 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/workspaces/agents/${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
+{
+ "agent": {
+ "id": "$ID",
+ "hostname": "$HOSTNAME"
+ },
+ "token": "$TOKEN",
+ "rooms" : [ $ROOMS ],
+ "publicKey" : "$KEY"
+}
+EMBED_JSON
+
+
+if [ "${URLTOOL}" = "curl" ] ; then
+ URLCOMMAND="curl --connect-timeout 5 --retry 3 -s -i -X PUT -d \"@${CLAIMING_DIR}/tmpin.txt\""
+else
+ URLCOMMAND="wget -T 15 -O - -q --save-headers --content-on-error=on --method=PUT \
+ --body-file=\"${CLAIMING_DIR}/tmpin.txt\""
+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
+
+eval "${URLCOMMAND} \"${TARGET_URL}\"" | tee "${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}"
+ rm -f "${CLAIMING_DIR}/tmpout.txt"
+ exit 4
+fi
+
+HTTP_STATUS_CODE=$(grep "HTTP" "${CLAIMING_DIR}/tmpout.txt" | awk -F " " '{print $2}')
+if [ "${HTTP_STATUS_CODE}" -ne 200 ] ; then
+ ERROR_MESSAGE=$(grep "\"error\":" "${CLAIMING_DIR}/tmpout.txt" | awk -F "error\":\"" '{print $2}' | sed s'/"}//g')
+ case ${ERROR_MESSAGE} in
+ "invalid agent id") EXIT_CODE=6 ;;
+ "invalid public key") EXIT_CODE=7 ;;
+ "token has expired") EXIT_CODE=8 ;;
+ "invalid token") EXIT_CODE=9 ;;
+ "duplicate agent id") EXIT_CODE=10 ;;
+ "claimed in another workspace") EXIT_CODE=11 ;;
+ "internal server error") EXIT_CODE=12 ;;
+ *) EXIT_CODE=5 ;;
+ esac
+ echo >&2 "Failed to claim agent."
+ rm -f "${CLAIMING_DIR}/tmpout.txt"
+ exit $EXIT_CODE
+fi
+
+rm -f "${CLAIMING_DIR}/tmpout.txt"
+touch "${CLAIMING_DIR}/is_claimed"
+rm -f "${CLAIMING_DIR}/token"
+echo >&2 "Agent was successfully claimed." \ No newline at end of file
diff --git a/cli/README.md b/cli/README.md
index 3872dac1c1..d39198f26d 100644
--- a/cli/README.md
+++ b/cli/README.md
@@ -19,6 +19,8 @@ shutdown-agent
Cleanup and exit the netdata agent.
fatal-agent
Log the state and halt the netdata agent.
+reload-claiming-state
+ Reload agent claiming state from disk.
```
Those commands are the same that can be sent to netdata via [signals](../daemon#command-line-options).
diff --git a/configure.ac b/configure.ac
index 6fcb3baeba..ad35aa61cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1282,6 +1282,7 @@ AC_CONFIG_FILES([
web/gui/Makefile
web/server/Makefile
web/server/static/Makefile
+ claim/Makefile
])
AC_OUTPUT
diff --git a/daemon/commands.c b/daemon/commands.c
index 5eb22a6693..b12c19216b 100644
--- a/daemon/commands.c
+++ b/daemon/commands.c
@@ -40,6 +40,7 @@ static cmd_status_t cmd_save_database_execute(char *args, char **message);
static cmd_status_t cmd_reopen_logs_execute(char *args, char **message);
static cmd_status_t cmd_exit_execute(char *args, char **message);
static cmd_status_t cmd_fatal_execute(char *args, char **message);
+static cmd_status_t cmd_reload_claiming_state_execute(char *args, char **message);
static cmd_status_t cmd_reload_labels_execute(char *args, char **message);
static command_info_t command_info_array[] = {
@@ -49,6 +50,7 @@ static command_info_t command_info_array[] = {
{"reopen-logs", cmd_reopen_logs_execute, CMD_TYPE_ORTHOGONAL}, // Close and reopen log files
{"shutdown-agent", cmd_exit_execute, CMD_TYPE_EXCLUSIVE}, // exit cleanly
{"fatal-agent", cmd_fatal_execute, CMD_TYPE_HIGH_PRIORITY}, // exit with fatal error
+ {"reload-claiming-state", cmd_reload_claiming_state_execute, CMD_TYPE_ORTHOGONAL}, // reload claiming state
{"reload-labels", cmd_reload_labels_execute, CMD_TYPE_ORTHOGONAL}, // reload the labels
};
@@ -108,7 +110,9 @@ static cmd_status_t cmd_help_execute(char *args, char **message)
"shutdown-agent\n"
" Cleanup and exit the netdata agent.\n"
"fatal-agent\n"
- " Log the state and halt the netdata agent.\n",
+ " Log the state and halt the netdata agent.\n"
+ "reload-claiming-state\n"
+ " Reload agent claiming state from disk.\n",
MAX_COMMAND_LENGTH - 1);
return CMD_STATUS_SUCCESS;
}
@@ -176,6 +180,21 @@ static cmd_status_t cmd_fatal_execute(char *args, char **message)
return CMD_STATUS_SUCCESS;
}
+static cmd_status_t cmd_reload_claiming_state_execute(char *args, char **message)
+{
+ (void)args;
+ (void)message;
+
+ info("The claiming feature is still in development and subject to change before the next release");
+ return CMD_STATUS_FAILURE;
+
+ error_log_limit_unlimited();
+ info("COMMAND: Reloading Agent Claiming configuration.");
+ load_claiming_state();
+ error_log_limit_reset();
+ return CMD_STATUS_SUCCESS;
+}
+
static cmd_status_t cmd_reload_labels_execute(char *args, char **message)
{
(void)args;
diff --git a/daemon/commands.h b/daemon/commands.h
index 6de4084217..cb879c2a8c 100644
--- a/daemon/commands.h
+++ b/daemon/commands.h
@@ -19,6 +19,7 @@ typedef enum cmd {
CMD_REOPEN_LOGS,
CMD_EXIT,
CMD_FATAL,
+ CMD_RELOAD_CLAIMING_STATE,
CMD_RELOAD_LABELS,
CMD_TOTAL_COMMANDS
} cmd_t;
diff --git a/daemon/common.h b/daemon/common.h
index 5202a53082..6ac3cb3c87 100644
--- a/daemon/common.h
+++ b/daemon/common.h
@@ -60,6 +60,9 @@
// netdata unit tests
#include "unit_test.h"
+// netdata agent claiming
+#include "claim/claim.h"
+
// the netdata deamon
#include "daemon.h"
#include "main.h"
diff --git a/daemon/daemon.c b/daemon/daemon.c
index 4ad082b95e..77448c0e73 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.c
@@ -4,6 +4,7 @@
#include <sched.h>
char pidfile[FILENAME_MAX + 1] = "";
+char claimingdirectory[FILENAME_MAX + 1];
static void chown_open_file(int fd, uid_t uid, gid_t gid) {
if(fd == -1) return;
@@ -50,6 +51,7 @@ int become_user(const char *username, int pid_fd) {
create_needed_dir(netdata_configured_cache_dir, uid, gid);
create_needed_dir(netdata_configured_varlib_dir, uid, gid);
+ create_needed_dir(claimingdirectory, uid, gid);
if(pidfile[0]) {
if(chown(pidfile, uid, gid) == -1)
@@ -434,6 +436,9 @@ int become_daemon(int dont_fork, const char *user)
// never become a problem
sched_setscheduler_set();
+ // Set claiming directory based on user config directory with correct ownership
+ snprintfz(claimingdirectory, FILENAME_MAX, "%s/claim.d", netdata_configured_user_config_dir);
+
if(user && *user) {
if(become_user(user, pidfd) != 0) {
error("Cannot become user '%s'. Continuing as we are.", user);
@@ -443,6 +448,7 @@ int become_daemon(int dont_fork, const char *user)
else {
create_needed_dir(netdata_configured_cache_dir, getuid(), getgid());
create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid());
+ create_needed_dir(claimingdirectory, getuid(), getgid());
}
if(pidfd != -1)
diff --git a/daemon/main.c b/daemon/main.c
index b00de00628..1dcdb6edd2 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -351,6 +351,8 @@ int help(int exitcode) {
" set netdata.conf option from the command line.\n\n"
" -W simple-pattern pattern string\n"
" Check if string matches pattern and exit.\n\n"
+ " -W \"claim -token=TOKEN -rooms=ROOM1,ROOM2\"\n"
+ " Claim the agent to the workspace rooms pointed to by TOKEN and ROOM*.\n\n"
);
fprintf(stream, "\n Signals netdata handles:\n\n"
@@ -926,6 +928,7 @@ int main(int argc, char **argv) {
{
char* stacksize_string = "stacksize=";
char* debug_flags_string = "debug_flags=";
+ char* claim_string = "claim";
#ifdef ENABLE_DBENGINE
char* createdataset_string = "createdataset=";
char* stresstest_string = "stresstest=";
@@ -1086,6 +1089,10 @@ int main(int argc, char **argv) {
printf("%s\n", value);
return 0;
}
+ else if(strncmp(optarg, claim_string, strlen(claim_string)) == 0) {
+ /* will trigger a claiming attempt when the agent is initialized */
+ claiming_pending_arguments = optarg + strlen(claim_string);
+ }
else {
fprintf(stderr, "Unknown -W parameter '%s'\n", optarg);
return help(1);
@@ -1271,6 +1278,14 @@ int main(int argc, char **argv) {
get_system_info(system_info);
rrd_init(netdata_configured_hostname, system_info);
+
+ // ------------------------------------------------------------------------
+ // Claim netdata agent to a cloud endpoint
+
+ if (claiming_pending_arguments)
+ claim_agent(claiming_pending_arguments);
+ load_claiming_state();
+
// ------------------------------------------------------------------------
// enable log flood protection
diff --git a/netdata-installer.sh b/netdata-installer.sh
index 442b28e87e..e6affc36e5 100755
--- a/netdata-installer.sh
+++ b/netdata-installer.sh
@@ -617,6 +617,7 @@ NETDATA_LOG_DIR="$(config_option "global" "log directory" "${NETDATA_PREFIX}/var
NETDATA_USER_CONFIG_DIR="$(config_option "global" "config directory" "${NETDATA_PREFIX}/etc/netdata")"
NETDATA_STOCK_CONFIG_DIR="$(config_option "global" "stock config directory" "${NETDATA_PREFIX}/usr/lib/netdata/conf.d")"
NETDATA_RUN_DIR="${NETDATA_PREFIX}/var/run"
+NETDATA_CLAIMING_DIR="${NETDATA_USER_CONFIG_DIR}/claim.d"
cat <<OPTIONSEOF
@@ -690,6 +691,15 @@ done
run chmod 755 "${NETDATA_LOG_DIR}"
+# --- claiming dir ----
+
+if [ ! -d "${NETDATA_CLAIMING_DIR}" ]; then
+ echo >&2 "Creating directory '${NETDATA_CLAIMING_DIR}'"
+ run mkdir -p "${NETDATA_CLAIMING_DIR}" || exit 1
+fi
+run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${NETDATA_CLAIMING_DIR}"
+run chmod 770 "${NETDATA_CLAIMING_DIR}"
+
# --- plugins ----
if [ "${UID}" -eq 0 ]; then
diff --git a/packaging/installer/netdata-uninstaller.sh b/packaging/installer/netdata-uninstaller.sh
index 424367b595..dc3a0eabb0 100755
--- a/packaging/installer/netdata-uninstaller.sh
+++ b/packaging/installer/netdata-uninstaller.sh
@@ -313,6 +313,7 @@ if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}" ]; then
else
rm_file "/usr/sbin/netdata"
rm_file "/usr/sbin/netdatacli"
+ rm_file "/usr/sbin/netdata-claim.sh"
rm_dir "/usr/share/netdata"
rm_dir "/usr/libexec/netdata"
rm_dir "/var/lib/netdata"