Claim on Windows (#18410)
thiagoftsm committed
Aug 29, 2024 at 21:12 UTC
f4531bc522338ff921984c746d6349a45c962b5e
8 files changed
+499
-29
CMakeLists.txt
+25
@@ -118,6 +118,10 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN" OR "${CMAKE_SYSTEM_NAME}" STREQU
118
endif()
119
120
set(BINDIR usr/bin)
121
+ set(CMAKE_RC_COMPILER_INIT windres)
122
+ ENABLE_LANGUAGE(RC)
123
+
124
+ SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
125
add_definitions(-D_GNU_SOURCE)
126
127
if($ENV{CLION_IDE})
@@ -1296,6 +1300,13 @@ set(CLAIM_PLUGIN_FILES
1300
src/claim/cloud-status.h
1301
)
1302
1303
+set(CLAIM_WINDOWS_FILES
1304
+ src/claim/netdata_claim.c
1305
+ src/claim/netdata_claim.h
1306
+ src/claim/netdata_claim_window.c
1307
+ src/claim/netdata_claim_window.h
1308
+)
1309
+
1310
set(ACLK_ALWAYS_BUILD
1311
src/aclk/aclk_rrdhost_state.h
1312
src/aclk/aclk_proxy.c
@@ -2238,6 +2249,13 @@ add_executable(netdata
2249
"$<$<BOOL:${ENABLE_EXPORTER_PROMETHEUS_REMOTE_WRITE}>:${PROMETHEUS_REMOTE_WRITE_EXPORTING_FILES}>"
2250
)
2251
2252
+if(OS_WINDOWS)
2253
+ set(NETDATA_CLAIM_RES_FILES "packaging/windows/resources/netdata_claim.rc")
2254
+
2255
+ add_executable(netdata_claim ${CLAIM_WINDOWS_FILES} ${NETDATA_CLAIM_RES_FILES})
2256
+ target_link_libraries(netdata_claim shell32;gdi32;msftedit)
2257
+endif()
2258
+
2259
target_compile_definitions(netdata PRIVATE
2260
"$<$<BOOL:${ENABLE_ML}>:DLIB_NO_GUI_SUPPORT>"
2261
)
@@ -2426,6 +2444,13 @@ install(PROGRAMS
2444
COMPONENT netdata
2445
DESTINATION "${BINDIR}")
2446
2447
+if(OS_WINDOWS)
2448
+ install(PROGRAMS
2449
+ ${CMAKE_BINARY_DIR}/netdata_claim.exe
2450
+ COMPONENT netdata
2451
+ DESTINATION "${BINDIR}")
2452
+endif()
2453
+
2454
#
2455
# We don't check ENABLE_PLUGIN_CGROUP_NETWORK because rpm builds assume
2456
# the files exists unconditionally.
packaging/windows/installer.nsi
+66
-29
@@ -34,8 +34,14 @@ var startMsys
34
35
var hCloudToken
36
var cloudToken
37
-var hCloudRoom
38
-var cloudRoom
37
+var hCloudRooms
38
+var cloudRooms
39
+var hProxy
40
+var proxy
41
+var hInsecure
42
+var insecure
43
+
44
+var avoidClaim
45
46
Function .onInit
47
nsExec::ExecToLog '$SYSDIR\sc.exe stop Netdata'
@@ -46,6 +52,8 @@ Function .onInit
52
${EndIf}
53
54
StrCpy $startMsys ${BST_UNCHECKED}
55
+ StrCpy $insecure ${BST_UNCHECKED}
56
+ StrCpy $avoidClaim ${BST_UNCHECKED}
57
FunctionEnd
58
59
Function NetdataConfigPage
@@ -57,40 +65,76 @@ Function NetdataConfigPage
65
Abort
66
${EndIf}
67
60
- ${NSD_CreateLabel} 0 0 100% 12u "Enter your Token and Cloud Room."
68
+ IfFileExists "$INSTDIR\etc\netdata\claim.conf" NotNeeded
69
+
70
+ ${NSD_CreateLabel} 0 0 100% 12u "Enter your Token and Cloud Room(s)."
71
${NSD_CreateLabel} 0 15% 100% 12u "Optionally, you can open a terminal to execute additional commands."
72
63
- ${NSD_CreateLabel} 0 35% 20% 10% "Token"
73
+ ${NSD_CreateLabel} 0 30% 20% 10% "Token"
74
Pop $0
65
- ${NSD_CreateText} 21% 35% 79% 10% ""
75
+ ${NSD_CreateText} 21% 30% 79% 10% ""
76
Pop $hCloudToken
77
68
- ${NSD_CreateLabel} 0 55% 20% 10% "Room"
78
+ ${NSD_CreateLabel} 0 45% 20% 10% "Room(s)"
79
Pop $0
70
- ${NSD_CreateText} 21% 55% 79% 10% ""
71
- Pop $hCloudRoom
80
+ ${NSD_CreateText} 21% 45% 79% 10% ""
81
+ Pop $hCloudRooms
82
+
83
+ ${NSD_CreateLabel} 0 60% 20% 10% "Proxy"
84
+ Pop $0
85
+ ${NSD_CreateText} 21% 60% 79% 10% ""
86
+ Pop $hProxy
87
+
88
+ ${NSD_CreateCheckbox} 0 75% 100% 10u "Insecure connection"
89
+ Pop $hInsecure
90
73
- ${NSD_CreateCheckbox} 0 70% 100% 10u "Open terminal"
91
+ ${NSD_CreateCheckbox} 0 90% 100% 10u "Open terminal"
92
Pop $hStartMsys
93
+ Goto EndDialogDraw
94
+
95
+ NotNeeded:
96
+ StrCpy $avoidClaim ${BST_CHECKED}
97
+ ${NSD_CreateLabel} 0 0 100% 12u "Your host has already been claimed. You can proceed with the update."
98
+
99
+ EndDialogDraw:
100
nsDialogs::Show
101
FunctionEnd
102
103
Function NetdataConfigLeave
79
- ${NSD_GetText} $hCloudToken $cloudToken
80
- ${NSD_GetText} $hCloudRoom $cloudRoom
81
- ${NSD_GetState} $hStartMsys $startMsys
82
-
83
- StrLen $0 $cloudToken
84
- StrLen $1 $cloudRoom
85
- ${If} $0 == 125
86
- ${AndIf} $0 == 36
87
- # We should start our new claiming software here
88
- MessageBox MB_OK "$cloudToken | $cloudRoom | $startMsys"
104
+ ${If} $avoidClaim == ${BST_UNCHECKED}
105
+ ${NSD_GetText} $hCloudToken $cloudToken
106
+ ${NSD_GetText} $hCloudRooms $cloudRooms
107
+ ${NSD_GetText} $hProxy $proxy
108
+ ${NSD_GetState} $hStartMsys $startMsys
109
+ ${NSD_GetState} $hInsecure $insecure
110
+
111
+ StrLen $0 $cloudToken
112
+ StrLen $1 $cloudRooms
113
+ ${If} $0 == 0
114
+ ${OrIf} $1 == 0
115
+ Goto runMsys
116
+ ${EndIf}
117
+
118
+ ${If} $0 == 135
119
+ ${AndIf} $1 >= 36
120
+ nsExec::ExecToLog '$INSTDIR\usr\bin\netdata_claim.exe /T $cloudToken /R $cloudRooms /P $proxy /I $insecure'
121
+ pop $0
122
+ ${Else}
123
+ MessageBox MB_OK "The Cloud information does not have the expected length."
124
+ ${EndIf}
125
+
126
+ runMsys:
127
+ ${If} $startMsys == ${BST_CHECKED}
128
+ nsExec::ExecToLog '$INSTDIR\msys2.exe'
129
+ pop $0
130
+ ${EndIf}
131
${EndIf}
132
91
- ${If} $startMsys == 1
92
- nsExec::ExecToLog '$INSTDIR\msys2.exe'
93
- pop $0
133
+ ClearErrors
134
+ nsExec::ExecToLog '$SYSDIR\sc.exe start Netdata'
135
+ pop $0
136
+ ${If} $0 != 0
137
+ MessageBox MB_OK "Warning: Failed to start Netdata service."
138
${EndIf}
139
FunctionEnd
140
@@ -152,13 +196,6 @@ Section "Install Netdata"
196
DetailPrint "Warning: Failed to add Netdata service description."
197
${EndIf}
198
155
- ClearErrors
156
- nsExec::ExecToLog '$SYSDIR\sc.exe start Netdata'
157
- pop $0
158
- ${If} $0 != 0
159
- DetailPrint "Warning: Failed to start Netdata service."
160
- ${EndIf}
161
-
199
WriteUninstaller "$INSTDIR\Uninstall.exe"
200
201
Call NetdataUninstallRegistry
packaging/windows/resources/netdata_claim.manifest
new
+16
@@ -0,0 +1,16 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3
+ <assemblyIdentity version="1.99.0.0"
4
+ processorArchitecture="*"
5
+ name="netdata_claim"
6
+ type="win32"/>
7
+ <description>Netdata Claim!</description>
8
+ <!-- Identify the application security requirements. -->
9
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
10
+ <security>
11
+ <requestedPrivileges>
12
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
13
+ </requestedPrivileges>
14
+ </security>
15
+ </trustInfo>
16
+</assembly>
packaging/windows/resources/netdata_claim.rc
new
+3
@@ -0,0 +1,3 @@
1
+#include "winuser.h"
2
+1 RT_MANIFEST "netdata_claim.manifest"
3
+11 ICON "../NetdataWhite.ico"
src/claim/netdata_claim.c
new
+250
@@ -0,0 +1,250 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#define UNICODE
4
+#define _UNICODE
5
+#include <windows.h>
6
+#include <shellapi.h>
7
+#include <stdlib.h>
8
+#include <stdio.h>
9
+#include <string.h>
10
+#include <signal.h>
11
+
12
+#include "netdata_claim.h"
13
+
14
+LPWSTR token = NULL;
15
+LPWSTR room = NULL;
16
+LPWSTR proxy = NULL;
17
+LPWSTR *argv = NULL;
18
+
19
+char *aToken = NULL;
20
+char *aRoom = NULL;
21
+char *aProxy = NULL;
22
+int insecure = 0;
23
+
24
+LPWSTR netdata_claim_get_formatted_message(LPWSTR pMessage, ...)
25
+{
26
+ LPWSTR pBuffer = NULL;
27
+
28
+ va_list args = NULL;
29
+ va_start(args, pMessage);
30
+
31
+ FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, pMessage, 0, 0, (LPWSTR)&pBuffer,
32
+ 0, &args);
33
+ va_end(args);
34
+
35
+ return pBuffer;
36
+}
37
+
38
+// Common Functions
39
+void netdata_claim_error_exit(wchar_t *function)
40
+{
41
+ DWORD error = GetLastError();
42
+ LPWSTR pMessage = L"The function %1 failed with error %2.";
43
+ LPWSTR pBuffer = netdata_claim_get_formatted_message(pMessage, function, error);
44
+
45
+ if (pBuffer) {
46
+ MessageBoxW(NULL, pBuffer, L"Error", MB_OK|MB_ICONERROR);
47
+ LocalFree(pBuffer);
48
+ }
49
+
50
+ ExitProcess(error);
51
+}
52
+
53
+/**
54
+ * Parse Args
55
+ *
56
+ * Parse arguments identifying necessity to make a window
57
+ *
58
+ * @param argc number of arguments
59
+ * @param argv A pointer for all arguments given
60
+ *
61
+ * @return it return the number of arguments parsed.
62
+ */
63
+int nd_claim_parse_args(int argc, LPWSTR *argv)
64
+{
65
+ int i;
66
+ for (i = 1 ; i < argc; i++) {
67
+ // We are working with Microsoft, thus it does not make sense wait for only smallcase
68
+ if(wcscasecmp(L"/T", argv[i]) == 0) {
69
+ if (argc <= i + 1)
70
+ continue;
71
+ i++;
72
+ token = argv[i];
73
+ }
74
+
75
+ if(wcscasecmp(L"/R", argv[i]) == 0) {
76
+ if (argc <= i + 1)
77
+ continue;
78
+ i++;
79
+ room = argv[i];
80
+ }
81
+
82
+ if(wcscasecmp(L"/P", argv[i]) == 0) {
83
+ if (argc <= i + 1)
84
+ continue;
85
+ i++;
86
+ // Minimum IPV4
87
+ if(wcslen(argv[i]) >= 8) {
88
+ proxy = argv[i];
89
+ }
90
+ }
91
+
92
+ if(wcscasecmp(L"/I", argv[i]) == 0) {
93
+ if (argc <= i + 1)
94
+ continue;
95
+
96
+ i++;
97
+ size_t length = wcslen(argv[i]);
98
+ char *tmp = calloc(sizeof(char), length);
99
+ if (!tmp)
100
+ ExitProcess(1);
101
+
102
+ netdata_claim_convert_str(tmp, argv[i], length - 1);
103
+ if (i < argc)
104
+ insecure = atoi(tmp);
105
+ else
106
+ insecure = 1;
107
+
108
+ free(tmp);
109
+ }
110
+ }
111
+
112
+ if (!token || !room)
113
+ return 0;
114
+
115
+ return argc;
116
+}
117
+
118
+static int netdata_claim_prepare_strings()
119
+{
120
+ if (!token || !room)
121
+ return -1;
122
+
123
+ size_t length = wcslen(token) + 1;
124
+ aToken = calloc(sizeof(char), length);
125
+ if (!aToken)
126
+ return -1;
127
+
128
+ netdata_claim_convert_str(aToken, token, length - 1);
129
+
130
+ length = wcslen(room) + 1;
131
+ aRoom = calloc(sizeof(char), length - 1);
132
+ if (!aRoom)
133
+ return -1;
134
+
135
+ netdata_claim_convert_str(aRoom, room, length - 1);
136
+
137
+ if (proxy) {
138
+ length = wcslen(proxy) + 1;
139
+ aProxy = calloc(sizeof(char), length - 1);
140
+ if (!aProxy)
141
+ return -1;
142
+
143
+ netdata_claim_convert_str(aProxy, proxy, length - 1);
144
+ }
145
+ return 0;
146
+}
147
+
148
+static void netdata_claim_exit_callback(int signal)
149
+{
150
+ (void)signal;
151
+ if (aToken)
152
+ free(aToken);
153
+
154
+ if (aRoom)
155
+ free(aRoom);
156
+
157
+ if (aProxy)
158
+ free(aProxy);
159
+
160
+ if (argv)
161
+ LocalFree(argv);
162
+}
163
+
164
+static inline int netdata_claim_prepare_data(char *out, size_t length)
165
+{
166
+ char *proxyLabel = (aProxy) ? "proxy = " : "# proxy = ";
167
+ char *proxyValue = (aProxy) ? aProxy : "";
168
+ return snprintf(out,
169
+ length,
170
+ "[global]\n url = https://app.netdata.cloud\n token = %s\n rooms = %s\n %s%s\n insecure = %s",
171
+ aToken,
172
+ aRoom,
173
+ proxyLabel,
174
+ proxyValue,
175
+ (insecure) ? "YES" : "NO"
176
+ );
177
+}
178
+
179
+static int netdata_claim_get_path(char *path)
180
+{
181
+ char *usrPath = { "\\usr\\bin" };
182
+ DWORD length = GetCurrentDirectoryA(WINDOWS_MAX_PATH, path);
183
+ if (!length) {
184
+ return -1;
185
+ }
186
+
187
+ if (strstr(path, usrPath)) {
188
+ length -= 7;
189
+ path[length] = '\0';
190
+ }
191
+
192
+ return 0;
193
+}
194
+
195
+static void netdata_claim_write_config(char *path)
196
+{
197
+ char configPath[WINDOWS_MAX_PATH + 1];
198
+ char data[WINDOWS_MAX_PATH + 1];
199
+ snprintf(configPath, WINDOWS_MAX_PATH - 1, "%s\\etc\\netdata\\claim.conf", path);
200
+
201
+ HANDLE hf = CreateFileA(configPath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
202
+ if (hf == INVALID_HANDLE_VALUE)
203
+ netdata_claim_error_exit(L"CreateFileA");
204
+
205
+ DWORD length = netdata_claim_prepare_data(data, WINDOWS_MAX_PATH);
206
+ DWORD written = 0;
207
+
208
+ BOOL ret = WriteFile(hf, data, length, &written, NULL);
209
+ if (!ret) {
210
+ CloseHandle(hf);
211
+ netdata_claim_error_exit(L"WriteFileA");
212
+ }
213
+
214
+ if (length != written)
215
+ MessageBoxW(NULL, L"Cannot write claim.conf.", L"Error", MB_OK|MB_ICONERROR);
216
+
217
+ CloseHandle(hf);
218
+}
219
+
220
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
221
+{
222
+ signal(SIGABRT, netdata_claim_exit_callback);
223
+ signal(SIGINT, netdata_claim_exit_callback);
224
+ signal(SIGTERM, netdata_claim_exit_callback);
225
+
226
+ int argc;
227
+ LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
228
+ if (argc)
229
+ argc = nd_claim_parse_args(argc, argv);
230
+
231
+ // When no data is given, user must to use graphic mode
232
+ int ret = 0;
233
+ if (!argc) {
234
+ ret = netdata_claim_window_loop(hInstance, nCmdShow);
235
+ } else {
236
+ if (netdata_claim_prepare_strings()) {
237
+ goto exit_claim;
238
+ }
239
+
240
+ char basePath[WINDOWS_MAX_PATH];
241
+ if (!netdata_claim_get_path(basePath)) {
242
+ netdata_claim_write_config(basePath);
243
+ }
244
+ }
245
+
246
+exit_claim:
247
+ netdata_claim_exit_callback(0);
248
+
249
+ return ret;
250
+}
src/claim/netdata_claim.h
new
+19
@@ -0,0 +1,19 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_CLAIM_H_
4
+# define NETDATA_CLAIM_H_ 1
5
+
6
+#include <wchar.h>
7
+#include "netdata_claim_window.h"
8
+
9
+extern LPWSTR token;
10
+extern LPWSTR room;
11
+extern LPWSTR proxy;
12
+
13
+void netdata_claim_error_exit(wchar_t *function);
14
+static inline void netdata_claim_convert_str(char *dst, wchar_t *src, size_t len) {
15
+ size_t copied = wcstombs(dst, src, len);
16
+ dst[copied] = '\0';
17
+}
18
+
19
+#endif //NETDATA_CLAIM_H_
src/claim/netdata_claim_window.c
new
+108
@@ -0,0 +1,108 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#define UNICODE
4
+#define _UNICODE
5
+#include <windows.h>
6
+#include "richedit.h"
7
+#include "tchar.h"
8
+#include "netdata_claim.h"
9
+
10
+static LPCTSTR szWindowClass = _T("DesktopApp");
11
+
12
+static HINSTANCE hInst;
13
+static HWND hToken;
14
+static HWND hRoom;
15
+
16
+LRESULT CALLBACK WndProc(HWND hNetdatawnd, UINT message, WPARAM wParam, LPARAM lParam)
17
+{
18
+ PAINTSTRUCT ps;
19
+ HDC hdc;
20
+ LPCTSTR topMsg[] = { L" Help",
21
+ L" ",
22
+ L"In this initial version of the software, there are no fields for data",
23
+ L" entry. To claim your agent, you must use the following options:",
24
+ L" ",
25
+ L"/T TOKEN: The cloud token;",
26
+ L"/R ROOMS: A list of rooms to claim;",
27
+ L"/P PROXY: The proxy information;",
28
+ L"/I : Use insecure connection;"
29
+ };
30
+
31
+ switch (message)
32
+ {
33
+ case WM_PAINT: {
34
+ hdc = BeginPaint(hNetdatawnd, &ps);
35
+
36
+ int i;
37
+ for (i = 0; i < sizeof(topMsg) / sizeof(LPCTSTR); i++) {
38
+ TextOut(hdc, 5, 5 + 15*i, topMsg[i], wcslen(topMsg[i]));
39
+ }
40
+ EndPaint(hNetdatawnd, &ps);
41
+ break;
42
+ }
43
+ case WM_COMMAND:
44
+ case WM_DESTROY: {
45
+ PostQuitMessage(0);
46
+ break;
47
+ }
48
+ default: {
49
+ return DefWindowProc(hNetdatawnd, message, wParam, lParam);
50
+ break;
51
+ }
52
+ }
53
+
54
+ return 0;
55
+}
56
+
57
+int netdata_claim_window_loop(HINSTANCE hInstance, int nCmdShow)
58
+{
59
+ WNDCLASSEX wcex;
60
+
61
+ wcex.cbSize = sizeof(WNDCLASSEX);
62
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
63
+ wcex.lpfnWndProc = WndProc;
64
+ wcex.cbClsExtra = 0;
65
+ wcex.cbWndExtra = 0;
66
+ wcex.hInstance = hInstance;
67
+ wcex.hIcon = LoadIcon(wcex.hInstance, MAKEINTRESOURCEW(11));
68
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
69
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
70
+ wcex.lpszMenuName = NULL;
71
+ wcex.lpszClassName = szWindowClass;
72
+ wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
73
+
74
+ if (!RegisterClassEx(&wcex)) {
75
+ MessageBoxW(NULL, L"Call to RegisterClassEx failed!", L"Error", 0);
76
+ return 1;
77
+ }
78
+
79
+ hInst = hInstance;
80
+
81
+ HWND hNetdatawnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
82
+ szWindowClass,
83
+ L"Netdata Claim",
84
+ WS_OVERLAPPEDWINDOW,
85
+ CW_USEDEFAULT, CW_USEDEFAULT,
86
+ 460, 220,
87
+ NULL,
88
+ NULL,
89
+ hInstance,
90
+ NULL
91
+ );
92
+
93
+ if (!hNetdatawnd) {
94
+ MessageBoxW(NULL, L"Call to CreateWindow failed!", L"Error", 0);
95
+ return 1;
96
+ }
97
+
98
+ ShowWindow(hNetdatawnd, nCmdShow);
99
+ UpdateWindow(hNetdatawnd);
100
+
101
+ MSG msg;
102
+ while (GetMessage(&msg, NULL, 0, 0)) {
103
+ TranslateMessage(&msg);
104
+ DispatchMessage(&msg);
105
+ }
106
+
107
+ return (int) msg.wParam;
108
+}
src/claim/netdata_claim_window.h
new
+12
@@ -0,0 +1,12 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_CLAIM_WINDOW_H_
4
+# define NETDATA_CLAIM_WINDOW_H_ 1
5
+
6
+// https://learn.microsoft.com/en-us/troubleshoot/windows-client/shell-experience/command-line-string-limitation
7
+// https://sourceforge.net/p/mingw/mailman/mingw-users/thread/4C8FD4EB.4050503@xs4all.nl/
8
+#define WINDOWS_MAX_PATH 8191
9
+
10
+int netdata_claim_window_loop(HINSTANCE hInstance, int nCmdShow);
11
+
12
+#endif //NETDATA_CLAIM_WINDOW_H_