@cryptotaxi247 / netdata-1 / commits / f4531bc52

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_