Agent claiming (#7525)
Initial infrastructure support for agent claiming. This feature is not currently enabled as we are still finalizing the details of the cloud infrastructure w.r.t. agent claiming. The feature will be enabled when we are ready to release it.
Markos Fountoulakis committed
Dec 19, 2019 at 11:01 UTC
ce9f70d7b3696a54f099628f3337f5c4d5bd1407
18 files changed
+499
-2
.gitignore
+1
@@ -116,6 +116,7 @@ daemon/anonymous-statistics.sh
116
daemon/get-kubernetes-labels.sh
117
118
health/notifications/alarm-notify.sh
119
+claim/netdata-claim.sh
120
collectors/cgroups.plugin/cgroup-name.sh
121
collectors/tc.plugin/tc-qos-helper.sh
122
collectors/charts.d.plugin/charts.d.plugin
BUILD.md
-1
@@ -1,4 +1,3 @@
1
-
1
# The build system
2
3
We are currently migrating from `autotools` to `CMake` as a build-system. This document
CMakeLists.txt
+6
@@ -601,6 +601,11 @@ set(BACKENDS_PLUGIN_FILES
601
backends/prometheus/backend_prometheus.h
602
)
603
604
+set(CLAIM_PLUGIN_FILES
605
+ claim/claim.c
606
+ claim/claim.h
607
+ )
608
+
609
set(EXPORTING_ENGINE_FILES
610
exporting/exporting_engine.c
611
exporting/exporting_engine.h
@@ -667,6 +672,7 @@ set(NETDATA_FILES
672
${STATSD_PLUGIN_FILES}
673
${STREAMING_PLUGIN_FILES}
674
${WEB_PLUGIN_FILES}
675
+ ${CLAIM_PLUGIN_FILES}
676
)
677
678
set(NETDATACLI_FILES
Makefile.am
+7
@@ -99,6 +99,7 @@ SUBDIRS += \
99
registry \
100
streaming \
101
web \
102
+ claim \
103
$(NULL)
104
105
@@ -454,6 +455,11 @@ BACKENDS_PLUGIN_FILES = \
455
backends/prometheus/backend_prometheus.h \
456
$(NULL)
457
458
+CLAIM_PLUGIN_FILES = \
459
+ claim/claim.c \
460
+ claim/claim.h \
461
+ $(NULL)
462
+
463
EXPORTING_ENGINE_FILES = \
464
exporting/exporting_engine.c \
465
exporting/exporting_engine.h \
@@ -521,6 +527,7 @@ NETDATA_FILES = \
527
$(STREAMING_PLUGIN_FILES) \
528
$(STATSD_PLUGIN_FILES) \
529
$(WEB_PLUGIN_FILES) \
530
+ $(CLAIM_PLUGIN_FILES) \
531
$(NULL)
532
533
if FREEBSD
claim/Makefile.am
new
+21
@@ -0,0 +1,21 @@
1
+# SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+AUTOMAKE_OPTIONS = subdir-objects
4
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5
+
6
+CLEANFILES = \
7
+ netdata-claim.sh \
8
+ $(NULL)
9
+
10
+include $(top_srcdir)/build/subst.inc
11
+SUFFIXES = .in
12
+
13
+sbin_SCRIPTS = \
14
+ netdata-claim.sh \
15
+ $(NULL)
16
+
17
+dist_noinst_DATA = \
18
+ netdata-claim.sh.in \
19
+ README.md \
20
+ $(NULL)
21
+
claim/README.md
new
+72
@@ -0,0 +1,72 @@
1
+# Agent claiming
2
+
3
+Agent claiming is part of the onboarding process when creating a workspace in Netdata Cloud. Each workspace gets its own
4
+common invitation mechanism, which begins with the administrators of the workspace creating a **claiming-token**. They,
5
+or other users is their organization, can then use the claiming-token to add an agent to their workspace.
6
+
7
+To claim a Netdata agent, you first send a claiming request to Netdata Cloud (from the agent node). Once the
8
+Netdata Cloud validates the claiming request of the agent (based on the claiming token), and returns a successful
9
+result, the node is considered claimed.
10
+
11
+## Claiming script
12
+
13
+The user can claim an agent by directly calling the `netdata-claim.sh` script **as the netdata user** and passing the
14
+following arguments:
15
+
16
+```sh
17
+-token=TOKEN
18
+ where TOKEN is the workspace claiming-token.
19
+-rooms=ROOM1,ROOM2,...
20
+ where ROOMX is the workspace war-room to join. This list is optional.
21
+-url=URL_BASE
22
+ where URL_BASE is the Netdata Cloud endpoint base URL. By default, this is https://netdata.cloud.
23
+-id=AGENT_ID
24
+ where AGENT_ID is the unique identifier of the agent. This is the agent's MACHINE_GUID by default.
25
+-hostname=HOSTNAME
26
+ where HOSTNAME is the result of the hostname command by default.
27
+```
28
+
29
+For example, the following command claims an agent and adds it to rooms `room1` and `room2`:
30
+
31
+```sh
32
+netdata-claim.sh -token=MYTOKEN1234567 -rooms=room1,room2
33
+```
34
+
35
+You should then update the `netdata` service about the result with `netdatacli`:
36
+
37
+```sh
38
+netdatacli reload-claiming-state
39
+```
40
+
41
+This reloads the agent claiming state from disk.
42
+
43
+## Netdata agent command line
44
+
45
+The user can trigger agent claiming by calling the `netdata` service binary with the additional command line parameters:
46
+
47
+```sh
48
+-W "claim -token=TOKEN -rooms=ROOM1,ROOM2"
49
+```
50
+
51
+For example:
52
+
53
+```sh
54
+/usr/sbin/netdata -D -W "claim -token=MYTOKEN1234567 -rooms=room1,room2"
55
+```
56
+
57
+If need be, the user can override the agent's defaults by providing additional arguments like those described
58
+[here](#claiming-script).
59
+
60
+## Claiming directory
61
+
62
+Netdata stores the agent claiming-related state in the user configuration directory under `claim.d`, e.g. in
63
+`/etc/netdata/claim.d`. The user can put files in this directory to provide defaults to the `-token` and `-rooms`
64
+arguments. These files should be owned **by the `netdata` user**.
65
+
66
+The `claim.d/token` file should contain the claiming-token and the `claim.d/rooms` file should contain the list of
67
+war-rooms.
68
+
69
+The user can also put the Cloud endpoint's full certificate chain in `claim.d/cloud_fullchain.pem` so that the agent
70
+can trust the endpoint if necessary.
71
+
72
+[](<>)
claim/claim.c
new
+103
@@ -0,0 +1,103 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "claim.h"
4
+#include "../registry/registry_internals.h"
5
+
6
+char *claiming_pending_arguments = NULL;
7
+
8
+static char *claiming_errors[] = {
9
+ "Agent claimed successfully", // 0
10
+ "Unknown argument", // 1
11
+ "Problems with claiming working directory", // 2
12
+ "Missing dependencies", // 3
13
+ "Failure to connect to endpoint", // 4
14
+ "Unknown HTTP error message", // 5
15
+ "invalid agent id", // 6
16
+ "invalid public key", // 7
17
+ "token has expired", // 8
18
+ "invalid token", // 9
19
+ "duplicate agent id", // 10
20
+ "claimed in another workspace", // 11
21
+ "internal server error" // 12
22
+};
23
+
24
+#define AGENT_UNCLAIMED 0
25
+#define AGENT_CLAIMED 1
26
+static uint8_t claiming_status = AGENT_UNCLAIMED;
27
+
28
+uint8_t is_agent_claimed(void)
29
+{
30
+ return (AGENT_CLAIMED == claiming_status);
31
+}
32
+
33
+#define CLAIMING_COMMAND_LENGTH 16384
34
+
35
+extern struct registry registry;
36
+
37
+/* rrd_init() must have been called before this function */
38
+void claim_agent(char *claiming_arguments)
39
+{
40
+ info("The claiming feature is under development and still subject to change before the next release");
41
+ return;
42
+
43
+ int exit_code;
44
+ pid_t command_pid;
45
+ char command_buffer[CLAIMING_COMMAND_LENGTH + 1];
46
+ FILE *fp;
47
+
48
+ snprintfz(command_buffer,
49
+ CLAIMING_COMMAND_LENGTH,
50
+ "exec netdata-claim.sh -hostname=%s -id=%s -url=%s %s",
51
+ netdata_configured_hostname,
52
+ localhost->machine_guid,
53
+ registry.cloud_base_url,
54
+ claiming_arguments);
55
+
56
+ info("Executing agent claiming command 'netdata-claim.sh'");
57
+ fp = mypopen(command_buffer, &command_pid);
58
+ if(!fp) {
59
+ error("Cannot popen(\"%s\").", command_buffer);
60
+ return;
61
+ }
62
+ info("Waiting for claiming command to finish.");
63
+ while (fgets(command_buffer, CLAIMING_COMMAND_LENGTH, fp) != NULL) {;}
64
+ exit_code = mypclose(fp, command_pid);
65
+ info("Agent claiming command returned with code %d", exit_code);
66
+ if (0 == exit_code) {
67
+ claiming_status = AGENT_CLAIMED;
68
+ info("Agent successfully claimed.");
69
+ return;
70
+ }
71
+ if (exit_code < 0) {
72
+ error("Agent claiming command failed to complete its run.");
73
+ return;
74
+ }
75
+ errno = 0;
76
+ unsigned maximum_known_exit_code = sizeof(claiming_errors) / sizeof(claiming_errors[0]);
77
+
78
+ if ((unsigned)exit_code > maximum_known_exit_code) {
79
+ error("Agent failed to be claimed with an unknown error.");
80
+ return;
81
+ }
82
+ error("Agent failed to be claimed with the following error message:");
83
+ error("\"%s\"", claiming_errors[exit_code]);
84
+}
85
+
86
+void load_claiming_state(void)
87
+{
88
+ info("The claiming feature is under development and still subject to change before the next release");
89
+ return;
90
+
91
+ char filename[FILENAME_MAX + 1];
92
+ struct stat statbuf;
93
+
94
+ snprintfz(filename, FILENAME_MAX, "%s/claim.d/is_claimed", netdata_configured_user_config_dir);
95
+ // check if the file exists
96
+ if (lstat(filename, &statbuf) != 0) {
97
+ info("File '%s' was not found. Setting state to AGENT_UNCLAIMED.", filename);
98
+ claiming_status = AGENT_UNCLAIMED;
99
+ } else {
100
+ info("File '%s' was found. Setting state to AGENT_CLAIMED.", filename);
101
+ claiming_status = AGENT_CLAIMED;
102
+ }
103
+}
claim/claim.h
new
+14
@@ -0,0 +1,14 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_CLAIM_H
4
+#define NETDATA_CLAIM_H 1
5
+
6
+#include "../daemon/common.h"
7
+
8
+extern char *claiming_pending_arguments;
9
+
10
+void claim_agent(char *claiming_arguments);
11
+uint8_t is_agent_claimed(void);
12
+void load_claiming_state(void);
13
+
14
+#endif //NETDATA_CLAIM_H
claim/netdata-claim.sh.in
new
+216
@@ -0,0 +1,216 @@
1
+#!/usr/bin/env bash
2
+# netdata
3
+# real-time performance and health monitoring, done right!
4
+# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
5
+# SPDX-License-Identifier: GPL-3.0-or-later
6
+
7
+# Exit code: 0 - Success
8
+# Exit code: 1 - Unknown argument
9
+# Exit code: 2 - Problems with claiming working directory
10
+# Exit code: 3 - Missing dependencies
11
+# Exit code: 4 - Failure to connect to endpoint
12
+# Exit code: 5 - Unknown HTTP error message
13
+#
14
+# OK: Agent claimed successfully
15
+# HTTP Status code: 200
16
+# Exit code: 0
17
+#
18
+# Error: The agent id is invalid; it does not fulfill the constraints
19
+# HTTP Status code: 422
20
+# Error message: "invalid agent id"
21
+# Exit code: 6
22
+#
23
+# Error: Invalid public key; the public key is empty or not present
24
+# HTTP Status code: 422
25
+# Error message: "invalid public key"
26
+# Exit code: 7
27
+#
28
+# Error: Expired token
29
+# HTTP Status code: 403
30
+# Error message: "token has expired"
31
+# Exit code: 8
32
+#
33
+# Error: Invalid claiming token; missing, undecryptable, invalid payload...
34
+# HTTP Status code: 422
35
+# Error message: "invalid token"
36
+# Exit code: 9
37
+#
38
+# Error: Duplicate agent id; an agent with the same id but a different public key is already registered in the cloud
39
+# HTTP Status code: 409
40
+# Error message: "duplicate agent id"
41
+# Exit code: 10
42
+#
43
+# Error: Already claimed in another workspace;
44
+# this agent (same id, same public key) already belongs to another workspace
45
+# HTTP Status code: 403
46
+# Error message: "claimed in another workspace"
47
+# Exit code: 11
48
+#
49
+# Error: Internal server error. Any other unexpected error (DB problems, etc.)
50
+# HTTP Status code: 500
51
+# Error message: "internal server error"
52
+# Exit code: 12
53
+
54
+if command -v curl >/dev/null 2>&1 ; then
55
+ URLTOOL="curl"
56
+elif command -v wget >/dev/null 2>&1 ; then
57
+ URLTOOL="wget"
58
+else
59
+ echo >&2 "I need curl or wget to proceed, but neither is available on this system."
60
+ exit 3
61
+fi
62
+if ! command -v openssl >/dev/null 2>&1 ; then
63
+ echo >&2 "I need openssl to proceed, but neither is available on this system."
64
+ exit 3
65
+fi
66
+
67
+
68
+# -----------------------------------------------------------------------------
69
+# defaults to allow running this script by hand
70
+
71
+[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
72
+MACHINE_GUID_FILE="@registrydir_POST@/netdata.public.unique.id"
73
+CLAIMING_DIR="${NETDATA_USER_CONFIG_DIR}/claim.d"
74
+TOKEN="unknown"
75
+URL_BASE="https://netdata.cloud"
76
+ID="unknown"
77
+ROOMS=""
78
+HOSTNAME=$(hostname)
79
+CLOUD_CERTIFICATE_FILE="${CLAIMING_DIR}/cloud_fullchain.pem"
80
+
81
+# get the MACHINE_GUID by default
82
+if [ -r "${MACHINE_GUID_FILE}" ]; then
83
+ ID="$(cat "${MACHINE_GUID_FILE}")"
84
+fi
85
+
86
+# get token from file
87
+if [ -r "${CLAIMING_DIR}/token" ]; then
88
+ TOKEN="$(cat "${CLAIMING_DIR}/token")"
89
+fi
90
+
91
+# get rooms from file
92
+if [ -r "${CLAIMING_DIR}/rooms" ]; then
93
+ ROOMS="$(cat "${CLAIMING_DIR}/rooms")"
94
+fi
95
+
96
+for arg in "$@"
97
+do
98
+ case $arg in
99
+ -token=*) TOKEN=${arg:7} ;;
100
+ -url=*) URL_BASE=${arg:5} ;;
101
+ -id=*) ID=${arg:4} ;;
102
+ -rooms=*) ROOMS=${arg:7} ;;
103
+ -hostname=*) HOSTNAME=${arg:10} ;;
104
+ *) echo >&2 "Unknown argument ${arg}"
105
+ exit 1 ;;
106
+ esac
107
+ shift 1
108
+done
109
+
110
+echo >&2 "Token: ****************"
111
+echo >&2 "Base URL: $URL_BASE"
112
+echo >&2 "Id: $ID"
113
+echo >&2 "Rooms: $ROOMS"
114
+echo >&2 "Hostname: $HOSTNAME"
115
+
116
+# create the claiming directory for this user
117
+if [ ! -d "${CLAIMING_DIR}" ] ; then
118
+ mkdir -p "${CLAIMING_DIR}" && chmod 0770 "${CLAIMING_DIR}"
119
+# shellcheck disable=SC2181
120
+ if [ $? -ne 0 ] ; then
121
+ echo >&2 "Failed to create claiming working directory ${CLAIMING_DIR}"
122
+ exit 2
123
+ fi
124
+fi
125
+if [ ! -w "${CLAIMING_DIR}" ] ; then
126
+ echo >&2 "No write permission in claiming working directory ${CLAIMING_DIR}"
127
+ exit 2
128
+fi
129
+
130
+if [ ! -f "${CLAIMING_DIR}/private.pem" ] ; then
131
+ echo >&2 "Generating private/public key for the first time."
132
+ if ! openssl genrsa -out "${CLAIMING_DIR}/private.pem" 2048 ; then
133
+ echo >&2 "Failed to generate private/public key pair."
134
+ exit 2
135
+ fi
136
+fi
137
+if [ ! -f "${CLAIMING_DIR}/public.pem" ] ; then
138
+ echo >&2 "Extracting public key from private key."
139
+ if ! openssl rsa -in "${CLAIMING_DIR}/private.pem" -outform PEM -pubout -out "${CLAIMING_DIR}/public.pem" ; then
140
+ echo >&2 "Failed to extract public key."
141
+ exit 2
142
+ fi
143
+fi
144
+
145
+TARGET_URL="${URL_BASE}/api/v1/workspaces/agents/${ID}"
146
+# shellcheck disable=SC2002
147
+KEY=$(cat "${CLAIMING_DIR}/public.pem" | tr '\n' '!' | sed -e 's/!/\\n/g')
148
+# shellcheck disable=SC2001
149
+[ -n "$ROOMS" ] && ROOMS=\"$(echo "$ROOMS" | sed s'/,/", "/g')\"
150
+
151
+cat > "${CLAIMING_DIR}/tmpin.txt" <<EMBED_JSON
152
+{
153
+ "agent": {
154
+ "id": "$ID",
155
+ "hostname": "$HOSTNAME"
156
+ },
157
+ "token": "$TOKEN",
158
+ "rooms" : [ $ROOMS ],
159
+ "publicKey" : "$KEY"
160
+}
161
+EMBED_JSON
162
+
163
+
164
+if [ "${URLTOOL}" = "curl" ] ; then
165
+ URLCOMMAND="curl --connect-timeout 5 --retry 3 -s -i -X PUT -d \"@${CLAIMING_DIR}/tmpin.txt\""
166
+else
167
+ URLCOMMAND="wget -T 15 -O - -q --save-headers --content-on-error=on --method=PUT \
168
+ --body-file=\"${CLAIMING_DIR}/tmpin.txt\""
169
+fi
170
+
171
+if [ -r "${CLOUD_CERTIFICATE_FILE}" ] ; then
172
+ if [ "${URLTOOL}" = "curl" ] ; then
173
+ URLCOMMAND="${URLCOMMAND} --cacert \"${CLOUD_CERTIFICATE_FILE}\""
174
+ else
175
+ URLCOMMAND="${URLCOMMAND} --ca-certificate \"${CLOUD_CERTIFICATE_FILE}\""
176
+ fi
177
+fi
178
+
179
+eval "${URLCOMMAND} \"${TARGET_URL}\"" | tee "${CLAIMING_DIR}/tmpout.txt"
180
+URLCOMMAND_EXIT_CODE=$?
181
+if [ "${URLTOOL}" = "wget" ] && [ "${URLCOMMAND_EXIT_CODE}" -eq 8 ] ; then
182
+# We consider the server issuing an error response a successful attempt at communicating
183
+ URLCOMMAND_EXIT_CODE=0
184
+fi
185
+
186
+rm -f "${CLAIMING_DIR}/tmpin.txt"
187
+
188
+# Check if URLCOMMAND connected and received reply
189
+if [ "${URLCOMMAND_EXIT_CODE}" -ne 0 ] ; then
190
+ echo >&2 "Failed to connect to ${URL_BASE}"
191
+ rm -f "${CLAIMING_DIR}/tmpout.txt"
192
+ exit 4
193
+fi
194
+
195
+HTTP_STATUS_CODE=$(grep "HTTP" "${CLAIMING_DIR}/tmpout.txt" | awk -F " " '{print $2}')
196
+if [ "${HTTP_STATUS_CODE}" -ne 200 ] ; then
197
+ ERROR_MESSAGE=$(grep "\"error\":" "${CLAIMING_DIR}/tmpout.txt" | awk -F "error\":\"" '{print $2}' | sed s'/"}//g')
198
+ case ${ERROR_MESSAGE} in
199
+ "invalid agent id") EXIT_CODE=6 ;;
200
+ "invalid public key") EXIT_CODE=7 ;;
201
+ "token has expired") EXIT_CODE=8 ;;
202
+ "invalid token") EXIT_CODE=9 ;;
203
+ "duplicate agent id") EXIT_CODE=10 ;;
204
+ "claimed in another workspace") EXIT_CODE=11 ;;
205
+ "internal server error") EXIT_CODE=12 ;;
206
+ *) EXIT_CODE=5 ;;
207
+ esac
208
+ echo >&2 "Failed to claim agent."
209
+ rm -f "${CLAIMING_DIR}/tmpout.txt"
210
+ exit $EXIT_CODE
211
+fi
212
+
213
+rm -f "${CLAIMING_DIR}/tmpout.txt"
214
+touch "${CLAIMING_DIR}/is_claimed"
215
+rm -f "${CLAIMING_DIR}/token"
216
+echo >&2 "Agent was successfully claimed."
\ No newline at end of file
cli/README.md
+2
@@ -19,6 +19,8 @@ shutdown-agent
19
Cleanup and exit the netdata agent.
20
fatal-agent
21
Log the state and halt the netdata agent.
22
+reload-claiming-state
23
+ Reload agent claiming state from disk.
24
```
25
26
Those commands are the same that can be sent to netdata via [signals](../daemon#command-line-options).
configure.ac
+1
@@ -1282,6 +1282,7 @@ AC_CONFIG_FILES([
1282
web/gui/Makefile
1283
web/server/Makefile
1284
web/server/static/Makefile
1285
+ claim/Makefile
1286
])
1287
AC_OUTPUT
1288
daemon/commands.c
+20
-1
@@ -40,6 +40,7 @@ static cmd_status_t cmd_save_database_execute(char *args, char **message);
40
static cmd_status_t cmd_reopen_logs_execute(char *args, char **message);
41
static cmd_status_t cmd_exit_execute(char *args, char **message);
42
static cmd_status_t cmd_fatal_execute(char *args, char **message);
43
+static cmd_status_t cmd_reload_claiming_state_execute(char *args, char **message);
44
static cmd_status_t cmd_reload_labels_execute(char *args, char **message);
45
46
static command_info_t command_info_array[] = {
@@ -49,6 +50,7 @@ static command_info_t command_info_array[] = {
50
{"reopen-logs", cmd_reopen_logs_execute, CMD_TYPE_ORTHOGONAL}, // Close and reopen log files
51
{"shutdown-agent", cmd_exit_execute, CMD_TYPE_EXCLUSIVE}, // exit cleanly
52
{"fatal-agent", cmd_fatal_execute, CMD_TYPE_HIGH_PRIORITY}, // exit with fatal error
53
+ {"reload-claiming-state", cmd_reload_claiming_state_execute, CMD_TYPE_ORTHOGONAL}, // reload claiming state
54
{"reload-labels", cmd_reload_labels_execute, CMD_TYPE_ORTHOGONAL}, // reload the labels
55
};
56
@@ -108,7 +110,9 @@ static cmd_status_t cmd_help_execute(char *args, char **message)
110
"shutdown-agent\n"
111
" Cleanup and exit the netdata agent.\n"
112
"fatal-agent\n"
111
- " Log the state and halt the netdata agent.\n",
113
+ " Log the state and halt the netdata agent.\n"
114
+ "reload-claiming-state\n"
115
+ " Reload agent claiming state from disk.\n",
116
MAX_COMMAND_LENGTH - 1);
117
return CMD_STATUS_SUCCESS;
118
}
@@ -176,6 +180,21 @@ static cmd_status_t cmd_fatal_execute(char *args, char **message)
180
return CMD_STATUS_SUCCESS;
181
}
182
183
+static cmd_status_t cmd_reload_claiming_state_execute(char *args, char **message)
184
+{
185
+ (void)args;
186
+ (void)message;
187
+
188
+ info("The claiming feature is still in development and subject to change before the next release");
189
+ return CMD_STATUS_FAILURE;
190
+
191
+ error_log_limit_unlimited();
192
+ info("COMMAND: Reloading Agent Claiming configuration.");
193
+ load_claiming_state();
194
+ error_log_limit_reset();
195
+ return CMD_STATUS_SUCCESS;
196
+}
197
+
198
static cmd_status_t cmd_reload_labels_execute(char *args, char **message)
199
{
200
(void)args;
daemon/commands.h
+1
@@ -19,6 +19,7 @@ typedef enum cmd {
19
CMD_REOPEN_LOGS,
20
CMD_EXIT,
21
CMD_FATAL,
22
+ CMD_RELOAD_CLAIMING_STATE,
23
CMD_RELOAD_LABELS,
24
CMD_TOTAL_COMMANDS
25
} cmd_t;
daemon/common.h
+3
@@ -60,6 +60,9 @@
60
// netdata unit tests
61
#include "unit_test.h"
62
63
+// netdata agent claiming
64
+#include "claim/claim.h"
65
+
66
// the netdata deamon
67
#include "daemon.h"
68
#include "main.h"
daemon/daemon.c
+6
@@ -4,6 +4,7 @@
4
#include <sched.h>
5
6
char pidfile[FILENAME_MAX + 1] = "";
7
+char claimingdirectory[FILENAME_MAX + 1];
8
9
static void chown_open_file(int fd, uid_t uid, gid_t gid) {
10
if(fd == -1) return;
@@ -50,6 +51,7 @@ int become_user(const char *username, int pid_fd) {
51
52
create_needed_dir(netdata_configured_cache_dir, uid, gid);
53
create_needed_dir(netdata_configured_varlib_dir, uid, gid);
54
+ create_needed_dir(claimingdirectory, uid, gid);
55
56
if(pidfile[0]) {
57
if(chown(pidfile, uid, gid) == -1)
@@ -434,6 +436,9 @@ int become_daemon(int dont_fork, const char *user)
436
// never become a problem
437
sched_setscheduler_set();
438
439
+ // Set claiming directory based on user config directory with correct ownership
440
+ snprintfz(claimingdirectory, FILENAME_MAX, "%s/claim.d", netdata_configured_user_config_dir);
441
+
442
if(user && *user) {
443
if(become_user(user, pidfd) != 0) {
444
error("Cannot become user '%s'. Continuing as we are.", user);
@@ -443,6 +448,7 @@ int become_daemon(int dont_fork, const char *user)
448
else {
449
create_needed_dir(netdata_configured_cache_dir, getuid(), getgid());
450
create_needed_dir(netdata_configured_varlib_dir, getuid(), getgid());
451
+ create_needed_dir(claimingdirectory, getuid(), getgid());
452
}
453
454
if(pidfd != -1)
daemon/main.c
+15
@@ -351,6 +351,8 @@ int help(int exitcode) {
351
" set netdata.conf option from the command line.\n\n"
352
" -W simple-pattern pattern string\n"
353
" Check if string matches pattern and exit.\n\n"
354
+ " -W \"claim -token=TOKEN -rooms=ROOM1,ROOM2\"\n"
355
+ " Claim the agent to the workspace rooms pointed to by TOKEN and ROOM*.\n\n"
356
);
357
358
fprintf(stream, "\n Signals netdata handles:\n\n"
@@ -926,6 +928,7 @@ int main(int argc, char **argv) {
928
{
929
char* stacksize_string = "stacksize=";
930
char* debug_flags_string = "debug_flags=";
931
+ char* claim_string = "claim";
932
#ifdef ENABLE_DBENGINE
933
char* createdataset_string = "createdataset=";
934
char* stresstest_string = "stresstest=";
@@ -1086,6 +1089,10 @@ int main(int argc, char **argv) {
1089
printf("%s\n", value);
1090
return 0;
1091
}
1092
+ else if(strncmp(optarg, claim_string, strlen(claim_string)) == 0) {
1093
+ /* will trigger a claiming attempt when the agent is initialized */
1094
+ claiming_pending_arguments = optarg + strlen(claim_string);
1095
+ }
1096
else {
1097
fprintf(stderr, "Unknown -W parameter '%s'\n", optarg);
1098
return help(1);
@@ -1271,6 +1278,14 @@ int main(int argc, char **argv) {
1278
get_system_info(system_info);
1279
1280
rrd_init(netdata_configured_hostname, system_info);
1281
+
1282
+ // ------------------------------------------------------------------------
1283
+ // Claim netdata agent to a cloud endpoint
1284
+
1285
+ if (claiming_pending_arguments)
1286
+ claim_agent(claiming_pending_arguments);
1287
+ load_claiming_state();
1288
+
1289
// ------------------------------------------------------------------------
1290
// enable log flood protection
1291
netdata-installer.sh
+10
@@ -617,6 +617,7 @@ NETDATA_LOG_DIR="$(config_option "global" "log directory" "${NETDATA_PREFIX}/var
617
NETDATA_USER_CONFIG_DIR="$(config_option "global" "config directory" "${NETDATA_PREFIX}/etc/netdata")"
618
NETDATA_STOCK_CONFIG_DIR="$(config_option "global" "stock config directory" "${NETDATA_PREFIX}/usr/lib/netdata/conf.d")"
619
NETDATA_RUN_DIR="${NETDATA_PREFIX}/var/run"
620
+NETDATA_CLAIMING_DIR="${NETDATA_USER_CONFIG_DIR}/claim.d"
621
622
cat <<OPTIONSEOF
623
@@ -690,6 +691,15 @@ done
691
692
run chmod 755 "${NETDATA_LOG_DIR}"
693
694
+# --- claiming dir ----
695
+
696
+if [ ! -d "${NETDATA_CLAIMING_DIR}" ]; then
697
+ echo >&2 "Creating directory '${NETDATA_CLAIMING_DIR}'"
698
+ run mkdir -p "${NETDATA_CLAIMING_DIR}" || exit 1
699
+fi
700
+run chown -R "${NETDATA_USER}:${NETDATA_GROUP}" "${NETDATA_CLAIMING_DIR}"
701
+run chmod 770 "${NETDATA_CLAIMING_DIR}"
702
+
703
# --- plugins ----
704
705
if [ "${UID}" -eq 0 ]; then
packaging/installer/netdata-uninstaller.sh
+1
@@ -313,6 +313,7 @@ if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}" ]; then
313
else
314
rm_file "/usr/sbin/netdata"
315
rm_file "/usr/sbin/netdatacli"
316
+ rm_file "/usr/sbin/netdata-claim.sh"
317
rm_dir "/usr/share/netdata"
318
rm_dir "/usr/libexec/netdata"
319
rm_dir "/var/lib/netdata"