├── module_ubuntu
├── README.txt
└── zabbix_module_lxd.so
├── Makefile
├── README.md
├── Zabbix-template-LXD.xml
└── zabbix_module_lxd.c
/module_ubuntu/README.txt:
--------------------------------------------------------------------------------
1 | Module tested in Ubuntu 14.04 and Ubuntu 16.04.
2 |
--------------------------------------------------------------------------------
/module_ubuntu/zabbix_module_lxd.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scanterog/zabbix-lxd/HEAD/module_ubuntu/zabbix_module_lxd.so
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | zabbix_module_lxd: zabbix_module_lxd.c
2 | gcc -fPIC -shared -o zabbix_module_lxd.so zabbix_module_lxd.c -I../../../include -I../../../src/libs/zbxsysinfo
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # zabbix-lxd
2 |
3 | A loadable module for Zabbix Agent in order to monitor LXD containers.
4 |
5 | ## Get the source
6 |
7 | When you have Zabbix installed from the official repository:
8 | ```
9 | # debian / ubuntu / proxmox
10 | apt install dpkg-dev
11 | apt-get source zabbix-agent
12 | cd zabbix-3.2.x
13 |
14 | # redhat / centos
15 | # TODO
16 | ```
17 |
18 | or directly from svn:
19 |
20 | ```
21 | mkdir zabbix3.2
22 | cd zabbix3.2
23 | svn co svn://svn.zabbix.com/branches/3.2 .
24 | ./bootstrap.sh
25 | ```
26 |
27 | ## Compiling the module
28 |
29 | ```
30 | ./configure --enable-agent
31 | mkdir src/modules/zabbix_module_lxd
32 | cd src/modules/zabbix_module_lxd
33 | wget https://raw.githubusercontent.com/scanterog/zabbix-lxd/master/zabbix_module_lxd.c \
34 | https://raw.githubusercontent.com/scanterog/zabbix-lxd/master/Makefile
35 | make
36 | ```
37 | The output should be a dynamically linked shared object library named `zabbix_module_lxd.so`.
38 |
39 | ## Install and configure the module
40 |
41 | To install the module:
42 |
43 | ```
44 | mkdir -p /usr/lib/zabbix/modules
45 | cp zabbix_module_lxd.so /usr/lib/zabbix/modules
46 | ```
47 |
48 | To enable the module, add in `/etc/zabbix/zabbix_agentd.conf`:
49 | ```
50 | LoadModule=zabbix_module_lxd.so
51 | ```
52 |
53 | Finally, restart the zabbix-agent and upload `Zabbix-template-LXD.xml` to your Zabbix server.
54 |
--------------------------------------------------------------------------------
/Zabbix-template-LXD.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.2
4 | 2016-09-28T02:48:51Z
5 |
6 |
7 | Templates
8 |
9 |
10 |
11 |
12 | Template LXD
13 | Template LXD
14 |
15 |
16 |
17 | Templates
18 |
19 |
20 |
21 |
22 | LXD
23 |
24 |
25 |
26 |
27 |
28 | Running containers
29 | 0
30 |
31 |
32 | lxd.discovery
33 | 60
34 | 0
35 |
36 |
37 |
38 | 0
39 | 0
40 |
41 | 0
42 |
43 |
44 |
45 |
46 | 0
47 |
48 |
49 |
50 |
51 |
52 |
53 | 0
54 |
55 |
56 |
57 | 10
58 |
59 |
60 |
61 | CPU system time {#HCONTAINERID}
62 | 0
63 |
64 | 1
65 |
66 | lxd.cpu[/{#HCONTAINERID},system]
67 | 30
68 | 90
69 | 365
70 | 0
71 | 0
72 |
73 | %
74 | 1
75 |
76 |
77 | 0
78 | 0
79 |
80 | 0
81 |
82 | 100
83 |
84 |
85 |
86 | 0
87 | 0
88 |
89 |
90 |
91 |
92 |
93 |
94 | 0
95 |
96 |
97 | LXD
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | CPU user time {#HCONTAINERID}
106 | 0
107 |
108 | 1
109 |
110 | lxd.cpu[/{#HCONTAINERID},user]
111 | 30
112 | 90
113 | 365
114 | 0
115 | 0
116 |
117 | %
118 | 1
119 |
120 |
121 | 0
122 | 0
123 |
124 | 0
125 |
126 | 100
127 |
128 |
129 |
130 | 0
131 | 0
132 |
133 |
134 |
135 |
136 |
137 |
138 | 0
139 |
140 |
141 | LXD
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | Used cache memory {#HCONTAINERID}
150 | 0
151 |
152 | 0
153 |
154 | lxd.mem[/{#HCONTAINERID},total_cache]
155 | 30
156 | 90
157 | 365
158 | 0
159 | 3
160 |
161 | B
162 | 0
163 |
164 |
165 | 0
166 | 0
167 |
168 | 0
169 |
170 | 1
171 |
172 |
173 |
174 | 0
175 | 0
176 |
177 |
178 |
179 |
180 |
181 |
182 | 0
183 |
184 |
185 | LXD
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | Used RSS memory {#HCONTAINERID}
194 | 0
195 |
196 | 0
197 |
198 | lxd.mem[/{#HCONTAINERID},total_rss]
199 | 30
200 | 90
201 | 365
202 | 0
203 | 3
204 |
205 | B
206 | 0
207 |
208 |
209 | 0
210 | 0
211 |
212 | 0
213 |
214 | 1
215 |
216 |
217 |
218 | 0
219 | 0
220 |
221 |
222 |
223 |
224 |
225 |
226 | 0
227 |
228 |
229 | LXD
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | Used swap {#HCONTAINERID}
238 | 0
239 |
240 | 0
241 |
242 | lxd.mem[/{#HCONTAINERID},total_swap]
243 | 30
244 | 90
245 | 365
246 | 0
247 | 3
248 |
249 | B
250 | 0
251 |
252 |
253 | 0
254 | 0
255 |
256 | 0
257 |
258 | 1
259 |
260 |
261 |
262 | 0
263 | 0
264 |
265 |
266 |
267 |
268 |
269 |
270 | 0
271 |
272 |
273 | LXD
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 | Container {#HCONTAINERID} is running
282 | 0
283 |
284 | 0
285 |
286 | lxd.up[/{#HCONTAINERID}]
287 | 30
288 | 90
289 | 365
290 | 0
291 | 3
292 |
293 |
294 | 0
295 |
296 |
297 | 0
298 | 0
299 |
300 | 0
301 |
302 | 1
303 |
304 |
305 |
306 | 3
307 | 0
308 |
309 |
310 |
311 |
312 |
313 | Check if container is running:
314 | 1-is running
315 | 0-is not running
316 | 0
317 |
318 |
319 | LXD
320 |
321 |
322 |
323 | Service state
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | CPU utilization of {#HCONTAINERID} container
333 | 900
334 | 200
335 | 0.0000
336 | 100.0000
337 | 1
338 | 1
339 | 1
340 | 1
341 | 0
342 | 0.0000
343 | 0.0000
344 | 1
345 | 0
346 | 0
347 | 0
348 |
349 |
350 | 0
351 | 0
352 | 990000
353 | 0
354 | 2
355 | 0
356 | -
357 | Template LXD
358 | lxd.cpu[/{#HCONTAINERID},system]
359 |
360 |
361 |
362 | 1
363 | 0
364 | 000099
365 | 0
366 | 2
367 | 0
368 | -
369 | Template LXD
370 | lxd.cpu[/{#HCONTAINERID},user]
371 |
372 |
373 |
374 |
375 |
376 | Memory usage of {#HCONTAINERID} container
377 | 900
378 | 200
379 | 0.0000
380 | 100.0000
381 | 1
382 | 1
383 | 1
384 | 1
385 | 0
386 | 0.0000
387 | 0.0000
388 | 1
389 | 0
390 | 0
391 | 0
392 |
393 |
394 | 0
395 | 0
396 | 00C800
397 | 0
398 | 2
399 | 0
400 | -
401 | Template LXD
402 | lxd.mem[/{#HCONTAINERID},total_cache]
403 |
404 |
405 |
406 | 1
407 | 0
408 | 0000C8
409 | 0
410 | 2
411 | 0
412 | -
413 | Template LXD
414 | lxd.mem[/{#HCONTAINERID},total_rss]
415 |
416 |
417 |
418 | 2
419 | 0
420 | EE0000
421 | 0
422 | 2
423 | 0
424 | -
425 | Template LXD
426 | lxd.mem[/{#HCONTAINERID},total_swap]
427 |
428 |
429 |
430 |
431 |
432 | State of {#HCONTAINERID} container
433 | 900
434 | 200
435 | 0.0000
436 | 100.0000
437 | 1
438 | 1
439 | 0
440 | 1
441 | 0
442 | 0.0000
443 | 0.0000
444 | 1
445 | 0
446 | 0
447 | 0
448 |
449 |
450 | 0
451 | 0
452 | 000088
453 | 0
454 | 2
455 | 0
456 | -
457 | Template LXD
458 | lxd.up[/{#HCONTAINERID}]
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 | Service state
476 |
477 |
478 | 0
479 | Down
480 |
481 |
482 | 1
483 | Up
484 |
485 |
486 |
487 |
488 |
489 |
--------------------------------------------------------------------------------
/zabbix_module_lxd.c:
--------------------------------------------------------------------------------
1 | /*
2 | ** Zabbix module for LXD container monitoring
3 | ** Script based on Jan Garaj from www.monitoringartist.com
4 | ** Author: Samuel Cantero
5 | **
6 | ** This program is free software; you can redistribute it and/or modify
7 | ** it under the terms of the GNU General Public License as published by
8 | ** the Free Software Foundation; either version 2 of the License, or
9 | ** (at your option) any later version.
10 | **
11 | ** This program is distributed in the hope that it will be useful,
12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ** GNU General Public License for more details.
15 | **
16 | ** You should have received a copy of the GNU General Public License
17 | ** along with this program; if not, write to the Free Software
18 | ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 | **/
20 |
21 | #include "common.h"
22 | #include "log.h"
23 | #include "comms.h"
24 | #include "module.h"
25 | #include "sysinc.h"
26 | #include "zbxjson.h"
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | // request parameters
37 | #include "common/common.h"
38 | #include "sysinfo.c"
39 |
40 | #ifndef ZBX_MODULE_API_VERSION
41 | # define ZBX_MODULE_API_VERSION ZBX_MODULE_API_VERSION_ONE
42 | #endif
43 |
44 | struct inspect_result
45 | {
46 | char *value;
47 | int return_code;
48 | };
49 |
50 | char *m_version = "v0.1";
51 | char *stat_dir = NULL, *driver, *cpu_cgroup = NULL, *hostname = 0;
52 | static int item_timeout = 1, buffer_size = 1024, cid_length = 66, socket_api;
53 | int zbx_module_lxd_discovery(AGENT_REQUEST *request, AGENT_RESULT *result);
54 | int zbx_module_lxd_up(AGENT_REQUEST *request, AGENT_RESULT *result);
55 | int zbx_module_lxd_mem(AGENT_REQUEST *request, AGENT_RESULT *result);
56 | int zbx_module_lxd_cpu(AGENT_REQUEST *request, AGENT_RESULT *result);
57 | int zbx_module_lxd_dev(AGENT_REQUEST *request, AGENT_RESULT *result);
58 |
59 |
60 | static ZBX_METRIC keys[] =
61 | /* KEY FLAG FUNCTION TEST PARAMETERS */
62 | {
63 | {"lxd.discovery", CF_HAVEPARAMS, zbx_module_lxd_discovery, ", , "},
64 | {"lxd.up", CF_HAVEPARAMS, zbx_module_lxd_up, "container name"},
65 | {"lxd.mem", CF_HAVEPARAMS, zbx_module_lxd_mem, "container name, memory metric name"},
66 | {"lxd.cpu", CF_HAVEPARAMS, zbx_module_lxd_cpu, "container name, cpu metric name"},
67 | {"lxd.dev", CF_HAVEPARAMS, zbx_module_lxd_dev, "container name, blkio file, blkio metric name"},
68 | {NULL}
69 | };
70 |
71 | /******************************************************************************
72 | * *
73 | * Function: zbx_module_api_version *
74 | * *
75 | * Purpose: returns version number of the module interface *
76 | * *
77 | * Return value: ZBX_MODULE_API_VERSION_ONE - the only version supported by *
78 | * Zabbix currently *
79 | * *
80 | ******************************************************************************/
81 | int zbx_module_api_version()
82 | {
83 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_api_version()");
84 | return ZBX_MODULE_API_VERSION_ONE;
85 | }
86 |
87 | /******************************************************************************
88 | * *
89 | * Function: zbx_module_item_timeout *
90 | * *
91 | * Purpose: set timeout value for processing of items *
92 | * *
93 | * Parameters: timeout - timeout in seconds, 0 - no timeout set *
94 | * *
95 | ******************************************************************************/
96 | void zbx_module_item_timeout(int timeout)
97 | {
98 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_item_timeout()");
99 | item_timeout = timeout;
100 | }
101 |
102 | /******************************************************************************
103 | * *
104 | * Function: zbx_module_item_list *
105 | * *
106 | * Purpose: returns list of item keys supported by the module *
107 | * *
108 | * Return value: list of item keys *
109 | * *
110 | ******************************************************************************/
111 | ZBX_METRIC *zbx_module_item_list()
112 | {
113 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_item_list()");
114 | return keys;
115 | }
116 |
117 | /******************************************************************************
118 | * *
119 | * Function: zbx_lxd_dir_detect *
120 | * *
121 | * Purpose: it should find metric folder - it depends on exec environment *
122 | * *
123 | * Return value: SYSINFO_RET_FAIL - stat folder was not found *
124 | * SYSINFO_RET_OK - stat folder was found *
125 | * *
126 | ******************************************************************************/
127 | int zbx_lxd_dir_detect()
128 | {
129 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_lxd_dir_detect()");
130 |
131 | char *drivers[] = {
132 | "lxc/", // LXC
133 | ""
134 | }, **tdriver;
135 | char path[512];
136 | char *temp1, *temp2;
137 | FILE *fp;
138 | DIR *dir;
139 |
140 | if ((fp = fopen("/proc/mounts", "r")) == NULL)
141 | {
142 | zabbix_log(LOG_LEVEL_WARNING, "Cannot open /proc/mounts: %s", zbx_strerror(errno));
143 | return SYSINFO_RET_FAIL;
144 | }
145 |
146 | while (fgets(path, 512, fp) != NULL)
147 | {
148 | if ((strstr(path, "cpuset cgroup")) != NULL)
149 | {
150 | temp1 = string_replace(path, "cgroup ", "");
151 | temp2 = string_replace(temp1, strstr(temp1, " "), "");
152 | free(temp1);
153 | if (stat_dir != NULL) free(stat_dir);
154 | stat_dir = string_replace(temp2, "cpuset", "");
155 | free(temp2);
156 | zabbix_log(LOG_LEVEL_DEBUG, "Detected LXD stat directory: %s", stat_dir);
157 |
158 |
159 | pclose(fp);
160 |
161 | char *cgroup = "cpuset/";
162 | tdriver = drivers;
163 | size_t ddir_size;
164 | char *ddir;
165 | while (*tdriver != "")
166 | {
167 | ddir_size = strlen(cgroup) + strlen(stat_dir) + strlen(*tdriver) + 1;
168 | ddir = malloc(ddir_size);
169 | zbx_strlcpy(ddir, stat_dir, ddir_size);
170 | zbx_strlcat(ddir, cgroup, ddir_size);
171 | zbx_strlcat(ddir, *tdriver, ddir_size);
172 | zabbix_log(LOG_LEVEL_DEBUG, "ddir to test: %s", ddir);
173 |
174 | if (NULL != (dir = opendir(ddir)))
175 | {
176 | closedir(dir);
177 | free(ddir);
178 | driver = *tdriver;
179 | zabbix_log(LOG_LEVEL_DEBUG, "Detected used LXD driver dir: %s", driver);
180 |
181 | // detect cpu_cgroup - JoinController cpu,cpuacct
182 | cgroup = "cpu,cpuacct/";
183 | ddir_size = strlen(cgroup) + strlen(stat_dir) + 1;
184 | ddir = malloc(ddir_size);
185 | zbx_strlcpy(ddir, stat_dir, ddir_size);
186 | zbx_strlcat(ddir, cgroup, ddir_size);
187 | if (NULL != (dir = opendir(ddir)))
188 | {
189 | closedir(dir);
190 | cpu_cgroup = "cpu,cpuacct/";
191 | zabbix_log(LOG_LEVEL_DEBUG, "Detected JoinController cpu,cpuacct");
192 | } else {
193 | cpu_cgroup = "cpuacct/";
194 | }
195 | free(ddir);
196 | return SYSINFO_RET_OK;
197 | }
198 | *tdriver++;
199 | free(ddir);
200 | }
201 | driver = "";
202 | zabbix_log(LOG_LEVEL_DEBUG, "Cannot detect used LXD driver");
203 | return SYSINFO_RET_FAIL;
204 | }
205 | }
206 | pclose(fp);
207 | zabbix_log(LOG_LEVEL_DEBUG, "Cannot detect LXD stat directory");
208 | return SYSINFO_RET_FAIL;
209 | }
210 |
211 | /******************************************************************************
212 | * *
213 | * Function: zbx_module_lxd_up *
214 | * *
215 | * Purpose: check if container is running *
216 | * *
217 | * Return value: 1 - is running, 0 - is not running *
218 | * *
219 | ******************************************************************************/
220 | int zbx_module_lxd_up(AGENT_REQUEST *request, AGENT_RESULT *result)
221 | {
222 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_lxd_up()");
223 | char *container;
224 |
225 | if (1 != request->nparam)
226 | {
227 | zabbix_log(LOG_LEVEL_ERR, "Invalid number of parameters: %d", request->nparam);
228 | SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
229 | return SYSINFO_RET_FAIL;
230 | }
231 |
232 | if (stat_dir == NULL || driver == NULL)
233 | {
234 | zabbix_log(LOG_LEVEL_DEBUG, "up check is not available at the moment - no stat directory");
235 | SET_MSG_RESULT(result, zbx_strdup(NULL, "up check is not available at the moment - no stat directory"));
236 | return SYSINFO_RET_FAIL;
237 | }
238 |
239 | if(cpu_cgroup == NULL)
240 | {
241 | if (zbx_lxd_dir_detect() == SYSINFO_RET_FAIL)
242 | {
243 | zabbix_log(LOG_LEVEL_DEBUG, "up check is not available at the moment - no cpu_cgroup directory");
244 | SET_MSG_RESULT(result, zbx_strdup(NULL, "up check is not available at the moment - no cpu_cgroup directory"));
245 | return SYSINFO_RET_FAIL;
246 | }
247 | }
248 |
249 | container = zbx_strdup(NULL, get_rparam(request, 0));
250 | char *stat_file = "/cpuacct.stat";
251 | char *cgroup = cpu_cgroup;
252 | size_t filename_size = strlen(cgroup) + strlen(container) + strlen(stat_dir) + strlen(driver) + strlen(stat_file) + 2;
253 | char *filename = malloc(filename_size);
254 | zbx_strlcpy(filename, stat_dir, filename_size);
255 | zbx_strlcat(filename, cgroup, filename_size);
256 | zbx_strlcat(filename, driver, filename_size);
257 | zbx_strlcat(filename, container, filename_size);
258 | free(container);
259 | zbx_strlcat(filename, stat_file, filename_size);
260 | zabbix_log(LOG_LEVEL_DEBUG, "Metric source file: %s", filename);
261 |
262 | FILE *file;
263 | if (NULL == (file = fopen(filename, "r")))
264 | {
265 | zabbix_log(LOG_LEVEL_DEBUG, "Cannot open metric file: '%s', container doesn't run", filename);
266 | free(filename);
267 | SET_UI64_RESULT(result, 0);
268 | return SYSINFO_RET_OK;
269 | }
270 | zbx_fclose(file);
271 | zabbix_log(LOG_LEVEL_DEBUG, "Can open metric file: '%s', container is running", filename);
272 | free(filename);
273 | SET_UI64_RESULT(result, 1);
274 | return SYSINFO_RET_OK;
275 | }
276 |
277 | /******************************************************************************
278 | * *
279 | * Function: zbx_module_lxd_mem *
280 | * *
281 | * Purpose: container memory metrics *
282 | * *
283 | * Return value: SYSINFO_RET_FAIL - function failed, item will be marked *
284 | * as not supported by zabbix *
285 | * SYSINFO_RET_OK - success *
286 | * *
287 | * Notes: https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt *
288 | ******************************************************************************/
289 | int zbx_module_lxd_mem(AGENT_REQUEST *request, AGENT_RESULT *result)
290 | {
291 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_lxd_mem()");
292 | char *container, *metric;
293 | int ret = SYSINFO_RET_FAIL;
294 |
295 | if (2 != request->nparam)
296 | {
297 | zabbix_log(LOG_LEVEL_ERR, "Invalid number of parameters: %d", request->nparam);
298 | SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
299 | return SYSINFO_RET_FAIL;
300 | }
301 |
302 | if (stat_dir == NULL || driver == NULL)
303 | {
304 | zabbix_log(LOG_LEVEL_DEBUG, "mem metrics are not available at the moment - no stat directory");
305 | SET_MSG_RESULT(result, zbx_strdup(NULL, "mem metrics are not available at the moment - no stat directory"));
306 | return SYSINFO_RET_FAIL;
307 | }
308 |
309 | container = zbx_strdup(NULL, get_rparam(request, 0));
310 | metric = get_rparam(request, 1);
311 | char *stat_file = "/memory.stat";
312 | char *cgroup = "memory/";
313 | size_t filename_size = strlen(cgroup) + strlen(container) + strlen(stat_dir) + strlen(driver) + strlen(stat_file) + 2;
314 | char *filename = malloc(filename_size);
315 | zbx_strlcpy(filename, stat_dir, filename_size);
316 | zbx_strlcat(filename, cgroup, filename_size);
317 | zbx_strlcat(filename, driver, filename_size);
318 | zbx_strlcat(filename, container, filename_size);
319 | zbx_strlcat(filename, stat_file, filename_size);
320 | zabbix_log(LOG_LEVEL_DEBUG, "Metric source file: %s", filename);
321 |
322 | FILE *file;
323 | if (NULL == (file = fopen(filename, "r")))
324 | {
325 | zabbix_log(LOG_LEVEL_ERR, "Cannot open metric file: '%s'", filename);
326 | free(container);
327 | free(filename);
328 | SET_MSG_RESULT(result, strdup("Cannot open memory.stat file"));
329 | return SYSINFO_RET_FAIL;
330 | }
331 |
332 | char line[MAX_STRING_LEN];
333 | char *metric2 = malloc(strlen(metric)+3);
334 | memcpy(metric2, metric, strlen(metric));
335 | memcpy(metric2 + strlen(metric), " ", 2);
336 | zbx_uint64_t value = 0;
337 | zabbix_log(LOG_LEVEL_DEBUG, "Looking metric %s in memory.stat file", metric);
338 | while (NULL != fgets(line, sizeof(line), file))
339 | {
340 | if (0 != strncmp(line, metric2, strlen(metric2)))
341 | continue;
342 | if (1 != sscanf(line, "%*s " ZBX_FS_UI64, &value))
343 | {
344 | zabbix_log(LOG_LEVEL_ERR, "sscanf failed for matched metric line");
345 | continue;
346 | }
347 | zabbix_log(LOG_LEVEL_DEBUG, "Id: %s; metric: %s; value: %d", container, metric, value);
348 | SET_UI64_RESULT(result, value);
349 | ret = SYSINFO_RET_OK;
350 | break;
351 | }
352 | zbx_fclose(file);
353 |
354 | free(container);
355 | free(filename);
356 | free(metric2);
357 |
358 | if (SYSINFO_RET_FAIL == ret)
359 | SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find a line with requested metric in memory.stat file"));
360 |
361 | return ret;
362 | }
363 |
364 | /******************************************************************************
365 | * *
366 | * Function: zbx_module_lxd_cpu *
367 | * *
368 | * Purpose: container CPU metrics *
369 | * *
370 | * Return value: SYSINFO_RET_FAIL - function failed, item will be marked *
371 | * as not supported by zabbix *
372 | * SYSINFO_RET_OK - success *
373 | * *
374 | * Notes: https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt *
375 | ******************************************************************************/
376 | int zbx_module_lxd_cpu(AGENT_REQUEST *request, AGENT_RESULT *result)
377 | {
378 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_lxd_cpu()");
379 |
380 | char *container, *metric;
381 | int ret = SYSINFO_RET_FAIL;
382 |
383 | if (2 != request->nparam)
384 | {
385 | zabbix_log(LOG_LEVEL_ERR, "Invalid number of parameters: %d", request->nparam);
386 | SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
387 | return SYSINFO_RET_FAIL;
388 | }
389 |
390 | if (stat_dir == NULL || driver == NULL)
391 | {
392 | zabbix_log(LOG_LEVEL_DEBUG, "cpu metrics are not available at the moment - no stat directory");
393 | SET_MSG_RESULT(result, zbx_strdup(NULL, "cpu metrics are not available at the moment - no stat directory"));
394 | return SYSINFO_RET_FAIL;
395 | }
396 |
397 | if(cpu_cgroup == NULL)
398 | {
399 | if (zbx_lxd_dir_detect() == SYSINFO_RET_FAIL)
400 | {
401 | zabbix_log(LOG_LEVEL_DEBUG, "cpu check is not available at the moment - no cpu_cgroup directory");
402 | SET_MSG_RESULT(result, zbx_strdup(NULL, "cpu check is not available at the moment - no cpu_cgroup directory"));
403 | return SYSINFO_RET_FAIL;
404 | }
405 | }
406 |
407 | container = zbx_strdup(NULL, get_rparam(request, 0));
408 | metric = get_rparam(request, 1);
409 | char *cgroup = NULL, *stat_file = NULL;
410 | if(strcmp(metric, "user") == 0 || strcmp(metric, "system") == 0) {
411 | stat_file = "/cpuacct.stat";
412 | cgroup = cpu_cgroup;
413 | } else {
414 | stat_file = "/cpu.stat";
415 | if (strchr(cpu_cgroup, ',') != NULL) {
416 | cgroup = cpu_cgroup;
417 | } else {
418 | cgroup = "cpu/";
419 | }
420 | }
421 |
422 | zabbix_log(LOG_LEVEL_DEBUG, "cpu_cgroup: %s, cgroup: %s, stat_file: %s, metric: %s, container: %s", cpu_cgroup, cgroup, stat_file, metric, container);
423 | size_t filename_size = strlen(cgroup) + strlen(container) + strlen(stat_dir) + strlen(driver) + strlen(stat_file) + 2;
424 | char *filename = malloc(filename_size);
425 |
426 | zbx_strlcpy(filename, stat_dir, filename_size);
427 | zbx_strlcat(filename, cgroup, filename_size);
428 | zbx_strlcat(filename, driver, filename_size);
429 | zbx_strlcat(filename, container, filename_size);
430 | zbx_strlcat(filename, stat_file, filename_size);
431 | zabbix_log(LOG_LEVEL_DEBUG, "Metric source file: %s", filename);
432 |
433 | FILE *file;
434 | if (NULL == (file = fopen(filename, "r")))
435 | {
436 | zabbix_log(LOG_LEVEL_ERR, "Cannot open metric file: '%s'", filename);
437 | free(filename);
438 | free(container);
439 | SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open %s file", ++stat_file));
440 | return SYSINFO_RET_FAIL;
441 | }
442 |
443 | char line[MAX_STRING_LEN];
444 | char *metric2 = malloc(strlen(metric)+3);
445 | zbx_uint64_t cpu_num;
446 | memcpy(metric2, metric, strlen(metric));
447 | memcpy(metric2 + strlen(metric), " ", 2);
448 | zbx_uint64_t value = 0;
449 | zabbix_log(LOG_LEVEL_DEBUG, "Looking metric %s in cpuacct.stat file", metric);
450 | while (NULL != fgets(line, sizeof(line), file))
451 | {
452 |
453 | if (0 != strncmp(line, metric2, strlen(metric2)))
454 | continue;
455 | if (1 != sscanf(line, "%*s " ZBX_FS_UI64, &value))
456 | {
457 | zabbix_log(LOG_LEVEL_ERR, "sscanf failed for matched metric line");
458 | continue;
459 | }
460 | // normalize CPU usage by using number of online CPUs
461 | if (1 < (cpu_num = sysconf(_SC_NPROCESSORS_ONLN)))
462 | {
463 | value /= cpu_num;
464 | }
465 | zabbix_log(LOG_LEVEL_DEBUG, "Id: %s; metric: %s; value: %d", container, metric, value);
466 | SET_UI64_RESULT(result, value);
467 | ret = SYSINFO_RET_OK;
468 | break;
469 | }
470 | zbx_fclose(file);
471 |
472 | free(container);
473 | free(filename);
474 | free(metric2);
475 |
476 | if (SYSINFO_RET_FAIL == ret)
477 | SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find a line with requested metric in cpuacct.stat file"));
478 |
479 | return ret;
480 | }
481 |
482 | /******************************************************************************
483 | * *
484 | * Function: zbx_module_lxd_dev *
485 | * *
486 | * Purpose: container device blkio metrics *
487 | * *
488 | * Return value: SYSINFO_RET_FAIL - function failed, item will be marked *
489 | * as not supported by zabbix *
490 | * SYSINFO_RET_OK - success *
491 | * *
492 | * Notes: https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt
493 | ******************************************************************************/
494 | int zbx_module_lxd_dev(AGENT_REQUEST *request, AGENT_RESULT *result)
495 | {
496 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_lxd_dev()");
497 | char *container, *metric;
498 | int ret = SYSINFO_RET_FAIL;
499 |
500 | if (3 != request->nparam)
501 | {
502 | zabbix_log(LOG_LEVEL_ERR, "Invalid number of parameters: %d", request->nparam);
503 | SET_MSG_RESULT(result, strdup("Invalid number of parameters"));
504 | return SYSINFO_RET_FAIL;
505 | }
506 |
507 | if (stat_dir == NULL || driver == NULL)
508 | {
509 | zabbix_log(LOG_LEVEL_DEBUG, "dev metrics are not available at the moment - no stat directory");
510 | SET_MSG_RESULT(result, zbx_strdup(NULL, "dev metrics are not available at the moment - no stat directory"));
511 | return SYSINFO_RET_FAIL;
512 | }
513 |
514 | container = zbx_strdup(NULL, get_rparam(request, 0));
515 | char *stat_file = malloc(strlen(get_rparam(request, 1)) + 2);
516 | zbx_strlcpy(stat_file, "/", strlen(get_rparam(request, 1)) + 2);
517 | zbx_strlcat(stat_file, get_rparam(request, 1), strlen(get_rparam(request, 1)) + 2);
518 | metric = get_rparam(request, 2);
519 |
520 | char *cgroup = "blkio/";
521 | size_t filename_size = strlen(cgroup) + strlen(container) + strlen(stat_dir) + strlen(driver) + strlen(stat_file) + 2;
522 | char *filename = malloc(filename_size);
523 | zbx_strlcpy(filename, stat_dir, filename_size);
524 | zbx_strlcat(filename, cgroup, filename_size);
525 | zbx_strlcat(filename, driver, filename_size);
526 | zbx_strlcat(filename, container, filename_size);
527 | zbx_strlcat(filename, stat_file, filename_size);
528 | zabbix_log(LOG_LEVEL_DEBUG, "Metric source file: %s", filename);
529 |
530 | FILE *file;
531 | if (NULL == (file = fopen(filename, "r")))
532 | {
533 | zabbix_log(LOG_LEVEL_ERR, "Cannot open metric file: '%s'", filename);
534 | free(container);
535 | free(stat_file);
536 | free(filename);
537 | SET_MSG_RESULT(result, strdup("Cannot open stat file, maybe CONFIG_DEBUG_BLK_CGROUP is not enabled"));
538 | zabbix_log(LOG_LEVEL_ERR, "Cannot open stat file, maybe CONFIG_DEBUG_BLK_CGROUP is not enabled");
539 | return SYSINFO_RET_FAIL;
540 | }
541 |
542 | char line[MAX_STRING_LEN];
543 | char *metric2 = malloc(strlen(metric)+3);
544 | memcpy(metric2, metric, strlen(metric));
545 | memcpy(metric2 + strlen(metric), " ", 2);
546 | zbx_uint64_t value = 0;
547 | zabbix_log(LOG_LEVEL_DEBUG, "Looking metric %s in blkio file", metric);
548 | while (NULL != fgets(line, sizeof(line), file))
549 | {
550 | if (0 != strncmp(line, metric2, strlen(metric2)))
551 | continue;
552 | if (1 != sscanf(line, "%*s " ZBX_FS_UI64, &value))
553 | {
554 | // maybe per blk device metric, e.g. '8:0 Read'
555 | if (1 != sscanf(line, "%*s %*s " ZBX_FS_UI64, &value))
556 | {
557 | zabbix_log(LOG_LEVEL_ERR, "sscanf failed for matched metric line");
558 | break;
559 | }
560 | }
561 | zabbix_log(LOG_LEVEL_DEBUG, "Id: %s; stat file: %s, metric: %s; value: %d", container, stat_file, metric, value);
562 | SET_UI64_RESULT(result, value);
563 | ret = SYSINFO_RET_OK;
564 | break;
565 | }
566 | zbx_fclose(file);
567 |
568 | free(container);
569 | free(stat_file);
570 | free(filename);
571 | free(metric2);
572 |
573 | if (SYSINFO_RET_FAIL == ret){
574 | SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find a line with requested metric in blkio file"));
575 | zabbix_log(LOG_LEVEL_ERR, "Cannot find a line with requested metric in blkio file");
576 | }
577 |
578 | return ret;
579 | }
580 |
581 |
582 | /******************************************************************************
583 | * *
584 | * Function: zbx_module_uninit *
585 | * *
586 | * Purpose: the function is called on agent shutdown *
587 | * It should be used to cleanup used resources if there are any *
588 | * *
589 | * Return value: ZBX_MODULE_OK - success *
590 | * ZBX_MODULE_FAIL - function failed *
591 | * *
592 | ******************************************************************************/
593 | int zbx_module_uninit()
594 | {
595 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_uninit()");
596 |
597 | const char* znetns_prefix = "zabbix_module_lxd_";
598 | DIR *dir;
599 | struct dirent *d;
600 |
601 | if (NULL == (dir = opendir("/var/run/netns")))
602 | {
603 | zabbix_log(LOG_LEVEL_DEBUG, "/var/run/netns: %s", zbx_strerror(errno));
604 | return ZBX_MODULE_OK;
605 | }
606 | char *file = NULL;
607 | while (NULL != (d = readdir(dir)))
608 | {
609 | if(0 == strcmp(d->d_name, ".") || 0 == strcmp(d->d_name, ".."))
610 | continue;
611 |
612 | // delete zabbix netns
613 | if ((strstr(d->d_name, znetns_prefix)) != NULL)
614 | {
615 | file = NULL;
616 | file = zbx_dsprintf(file, "/var/run/netns/%s", d->d_name);
617 | if(unlink(file) != 0)
618 | {
619 | zabbix_log(LOG_LEVEL_WARNING, "%s: %s", d->d_name, zbx_strerror(errno));
620 | }
621 | }
622 | }
623 | if(0 != closedir(dir))
624 | {
625 | zabbix_log(LOG_LEVEL_WARNING, "/var/run/netns/: %s", zbx_strerror(errno));
626 | }
627 |
628 | free(stat_dir);
629 |
630 | return ZBX_MODULE_OK;
631 | }
632 |
633 | /******************************************************************************
634 | * *
635 | * Function: zbx_module_init *
636 | * *
637 | * Purpose: the function is called on agent startup *
638 | * It should be used to call any initialization routines *
639 | * *
640 | * Return value: ZBX_MODULE_OK - success *
641 | * ZBX_MODULE_FAIL - module initialization failed *
642 | * *
643 | * Comment: the module won't be loaded in case of ZBX_MODULE_FAIL *
644 | * *
645 | ******************************************************************************/
646 | int zbx_module_init()
647 | {
648 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_init()");
649 | zabbix_log(LOG_LEVEL_DEBUG, "zabbix_module_lxd %s, compilation time: %s %s", m_version, __DATE__, __TIME__);
650 | zbx_lxd_dir_detect();
651 | return ZBX_MODULE_OK;
652 | }
653 |
654 |
655 | /******************************************************************************
656 | * *
657 | * Function: zbx_module_lxd_discovery *
658 | * *
659 | * Purpose: container discovery *
660 | * *
661 | * Return value: SYSINFO_RET_FAIL - function failed, item will be marked *
662 | * as not supported by zabbix *
663 | * SYSINFO_RET_OK - success *
664 | * *
665 | ******************************************************************************/
666 | int zbx_module_lxd_discovery(AGENT_REQUEST *request, AGENT_RESULT *result)
667 | {
668 | zabbix_log(LOG_LEVEL_DEBUG, "In zbx_module_lxd_discovery()");
669 |
670 | struct zbx_json j;
671 | if(stat_dir == NULL && zbx_lxd_dir_detect() == SYSINFO_RET_FAIL)
672 | {
673 | zabbix_log(LOG_LEVEL_DEBUG, "lxd.discovery is not available at the moment - no stat directory - empty discovery");
674 | zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
675 | zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
676 | zbx_json_close(&j);
677 | SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
678 | zbx_json_free(&j);
679 | return SYSINFO_RET_FAIL;
680 | }
681 |
682 | DIR *dir;
683 | zbx_stat_t sb;
684 | char *file = NULL, *containerid;
685 | struct dirent *d;
686 | char *cgroup = "cpuset/";
687 | size_t ddir_size = strlen(cgroup) + strlen(stat_dir) + strlen(driver) + 2;
688 | char *ddir = malloc(ddir_size);
689 | zbx_strlcpy(ddir, stat_dir, ddir_size);
690 | zbx_strlcat(ddir, cgroup, ddir_size);
691 | zbx_strlcat(ddir, driver, ddir_size);
692 | zabbix_log(LOG_LEVEL_DEBUG, "lxd.discovery-> ddir: %s", ddir);
693 |
694 | if (NULL == (dir = opendir(ddir)))
695 | {
696 | zabbix_log(LOG_LEVEL_WARNING, "%s: %s", ddir, zbx_strerror(errno));
697 | free(ddir);
698 | return SYSINFO_RET_FAIL;
699 | }
700 |
701 | zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
702 | zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
703 |
704 | size_t hostname_len = 128;
705 | while (1) {
706 | char* realloc_hostname = realloc(hostname, hostname_len);
707 | if (realloc_hostname == 0) {
708 | free(hostname);
709 | }
710 | hostname = realloc_hostname;
711 | hostname[hostname_len-1] = 0;
712 | if (gethostname(hostname, hostname_len-1) == 0) {
713 | size_t count = strlen(hostname);
714 | if (count < hostname_len-2) {
715 | break;
716 | }
717 | }
718 | hostname_len *= 2;
719 | }
720 | zabbix_log(LOG_LEVEL_WARNING, "hostname: %s, dir: %s", hostname, ddir);
721 | while (NULL != (d = readdir(dir)))
722 | {
723 | if(0 == strcmp(d->d_name, ".") || 0 == strcmp(d->d_name, ".."))
724 | continue;
725 |
726 | file = zbx_dsprintf(file, "%s/%s", ddir, d->d_name);
727 |
728 | if (0 != zbx_stat(file, &sb) || 0 == S_ISDIR(sb.st_mode))
729 | continue;
730 |
731 | containerid = d->d_name;
732 |
733 | zbx_json_addobject(&j, NULL);
734 | zbx_json_addstring(&j, "{#HCONTAINERID}", containerid, ZBX_JSON_TYPE_STRING);
735 | zbx_json_addstring(&j, "{#SYSTEM.HOSTNAME}", hostname, ZBX_JSON_TYPE_STRING);
736 | zbx_json_close(&j);
737 |
738 | }
739 |
740 | if(0 != closedir(dir))
741 | {
742 | zabbix_log(LOG_LEVEL_WARNING, "%s: %s\n", ddir, zbx_strerror(errno));
743 | }
744 |
745 | zbx_json_close(&j);
746 |
747 | SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
748 |
749 | zbx_json_free(&j);
750 |
751 | free(ddir);
752 |
753 | return SYSINFO_RET_OK;
754 | }
755 |
756 |
--------------------------------------------------------------------------------