1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 /* LIBXML2 is used */
23 #ifdef HAVE_LIBXML2
24 # include <libxml/parser.h>
25 # include <libxml/tree.h>
26 # include <libxml/xpath.h>
27 #endif
28
29 #include "ipc.h"
30 #include "memalloc.h"
31 #include "log.h"
32 #include "zbxalgo.h"
33 #include "daemon.h"
34 #include "zbxself.h"
35
36 #include "vmware.h"
37 #include "../../libs/zbxalgo/vectorimpl.h"
38
39 /*
40 * The VMware data (zbx_vmware_service_t structure) are stored in shared memory.
41 * This data can be accessed with zbx_vmware_get_service() function and is regularly
42 * updated by VMware collector processes.
43 *
44 * When a new service is requested by poller the zbx_vmware_get_service() function
45 * creates a new service object, marks it as new, but still returns NULL object.
46 *
47 * The collectors check the service object list for new services or services not updated
48 * during last CONFIG_VMWARE_FREQUENCY seconds. If such service is found it is marked
49 * as updating.
50 *
51 * The service object is updated by creating a new data object, initializing it
52 * with the latest data from VMware vCenter (or Hypervisor), destroying the old data
53 * object and replacing it with the new one.
54 *
55 * The collector must be locked only when accessing service object list and working with
56 * a service object. It is not locked for new data object creation during service update,
57 * which is the most time consuming task.
58 *
59 * As the data retrieved by VMware collector can be quite big (for example 1 Hypervisor
60 * with 500 Virtual Machines will result in approximately 20 MB of data), VMware collector
61 * updates performance data (which is only 10% of the structure data) separately
62 * with CONFIG_VMWARE_PERF_FREQUENCY period. The performance data is stored directly
63 * in VMware service object entities vector - so the structure data is not affected by
64 * performance data updates.
65 */
66
67 extern int CONFIG_VMWARE_FREQUENCY;
68 extern int CONFIG_VMWARE_PERF_FREQUENCY;
69 extern zbx_uint64_t CONFIG_VMWARE_CACHE_SIZE;
70 extern int CONFIG_VMWARE_TIMEOUT;
71
72 extern unsigned char process_type, program_type;
73 extern int server_num, process_num;
74 extern char *CONFIG_SOURCE_IP;
75
76 #define VMWARE_VECTOR_CREATE(ref, type) zbx_vector_##type##_create_ext(ref, __vm_mem_malloc_func, \
77 __vm_mem_realloc_func, __vm_mem_free_func)
78
79 #define ZBX_VMWARE_CACHE_UPDATE_PERIOD CONFIG_VMWARE_FREQUENCY
80 #define ZBX_VMWARE_PERF_UPDATE_PERIOD CONFIG_VMWARE_PERF_FREQUENCY
81 #define ZBX_VMWARE_SERVICE_TTL SEC_PER_HOUR
82 #define ZBX_XML_DATETIME 26
83 #define ZBX_INIT_UPD_XML_SIZE (100 * ZBX_KIBIBYTE)
84 #define zbx_xml_free_doc(xdoc) if (NULL != xdoc)\
85 xmlFreeDoc(xdoc)
86 #define ZBX_VMWARE_DS_REFRESH_VERSION 6
87
88 static zbx_mutex_t vmware_lock = ZBX_MUTEX_NULL;
89
90 static zbx_mem_info_t *vmware_mem = NULL;
91
92 ZBX_MEM_FUNC_IMPL(__vm, vmware_mem)
93
94 static zbx_vmware_t *vmware = NULL;
95
96 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
97
98 /* according to libxml2 changelog XML_PARSE_HUGE option was introduced in version 2.7.0 */
99 #if 20700 <= LIBXML_VERSION /* version 2.7.0 */
100 # define ZBX_XML_PARSE_OPTS XML_PARSE_HUGE
101 #else
102 # define ZBX_XML_PARSE_OPTS 0
103 #endif
104
105 #define ZBX_VMWARE_COUNTERS_INIT_SIZE 500
106
107 #define ZBX_VPXD_STATS_MAXQUERYMETRICS 64
108 #define ZBX_MAXQUERYMETRICS_UNLIMITED 1000
109 #define ZBX_VCENTER_LESS_THAN_6_5_0_STATS_MAXQUERYMETRICS 64
110 #define ZBX_VCENTER_6_5_0_AND_MORE_STATS_MAXQUERYMETRICS 256
111
112 ZBX_PTR_VECTOR_IMPL(str_uint64_pair, zbx_str_uint64_pair_t)
113 ZBX_PTR_VECTOR_IMPL(vmware_datastore, zbx_vmware_datastore_t *)
114 ZBX_PTR_VECTOR_IMPL(vmware_datacenter, zbx_vmware_datacenter_t *)
115
116 /* VMware service object name mapping for vcenter and vsphere installations */
117 typedef struct
118 {
119 const char *performance_manager;
120 const char *session_manager;
121 const char *event_manager;
122 const char *property_collector;
123 const char *root_folder;
124 }
125 zbx_vmware_service_objects_t;
126
127 static zbx_vmware_service_objects_t vmware_service_objects[3] =
128 {
129 {NULL, NULL, NULL, NULL, NULL},
130 {"ha-perfmgr", "ha-sessionmgr", "ha-eventmgr", "ha-property-collector", "ha-folder-root"},
131 {"PerfMgr", "SessionManager", "EventManager", "propertyCollector", "group-d1"}
132 };
133
134 /* mapping of performance counter group/key[rollup type] to its id (net/transmitted[average] -> <id>) */
135 typedef struct
136 {
137 char *path;
138 zbx_uint64_t id;
139 }
140 zbx_vmware_counter_t;
141
142 /* performance counter value for a specific instance */
143 typedef struct
144 {
145 zbx_uint64_t counterid;
146 char *instance;
147 zbx_uint64_t value;
148 }
149 zbx_vmware_perf_value_t;
150
151 /* performance data for a performance collector entity */
152 typedef struct
153 {
154 /* entity type: HostSystem, Datastore or VirtualMachine */
155 char *type;
156
157 /* entity id */
158 char *id;
159
160 /* the performance counter values (see zbx_vmware_perfvalue_t) */
161 zbx_vector_ptr_t values;
162
163 /* error information */
164 char *error;
165 }
166 zbx_vmware_perf_data_t;
167
168 typedef struct
169 {
170 zbx_uint64_t id;
171 xmlNode *xml_node;
172 }
173 zbx_id_xmlnode_t;
174
175 /* VMware events host information */
176 typedef struct
177 {
178 const char *node_name;
179 int flag;
180 char *name;
181 }
182 event_hostinfo_node_t;
183
184 #define ZBX_HOSTINFO_NODES_DATACENTER 0x01
185 #define ZBX_HOSTINFO_NODES_COMPRES 0x02
186 #define ZBX_HOSTINFO_NODES_HOST 0x04
187 #define ZBX_HOSTINFO_NODES_MASK_ALL \
188 (ZBX_HOSTINFO_NODES_DATACENTER | ZBX_HOSTINFO_NODES_COMPRES | ZBX_HOSTINFO_NODES_HOST)
189
190 ZBX_VECTOR_DECL(id_xmlnode, zbx_id_xmlnode_t)
191 ZBX_VECTOR_IMPL(id_xmlnode, zbx_id_xmlnode_t)
192
193 static zbx_hashset_t evt_msg_strpool;
194
195 static zbx_uint64_t evt_req_chunk_size;
196
197 /*
198 * SOAP support
199 */
200 #define ZBX_XML_HEADER1 "Soapaction:urn:vim25/4.1"
201 #define ZBX_XML_HEADER2 "Content-Type:text/xml; charset=utf-8"
202 /* cURL specific attribute to prevent the use of "Expect" directive */
203 /* according to RFC 7231/5.1.1 if xml request is larger than 1k */
204 #define ZBX_XML_HEADER3 "Expect:"
205
206 #define ZBX_POST_VSPHERE_HEADER \
207 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
208 "<SOAP-ENV:Envelope" \
209 " xmlns:ns0=\"urn:vim25\"" \
210 " xmlns:ns1=\"http://schemas.xmlsoap.org/soap/envelope/\"" \
211 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" \
212 " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" \
213 "<SOAP-ENV:Header/>" \
214 "<ns1:Body>"
215 #define ZBX_POST_VSPHERE_FOOTER \
216 "</ns1:Body>" \
217 "</SOAP-ENV:Envelope>"
218
219 #define ZBX_XPATH_FAULTSTRING() \
220 "/*/*/*[local-name()='Fault']/*[local-name()='faultstring']"
221
222 #define ZBX_XPATH_REFRESHRATE() \
223 "/*/*/*/*/*[local-name()='refreshRate' and ../*[local-name()='currentSupported']='true']"
224
225 #define ZBX_XPATH_ISAGGREGATE() \
226 "/*/*/*/*/*[local-name()='entity'][../*[local-name()='summarySupported']='true' and " \
227 "../*[local-name()='currentSupported']='false']"
228
229 #define ZBX_XPATH_COUNTERINFO() \
230 "/*/*/*/*/*/*[local-name()='propSet']/*[local-name()='val']/*[local-name()='PerfCounterInfo']"
231
232 #define ZBX_XPATH_DATASTORE_MOUNT() \
233 "/*/*/*/*/*/*[local-name()='propSet']/*/*[local-name()='DatastoreHostMount']" \
234 "/*[local-name()='mountInfo']/*[local-name()='path']"
235
236 #define ZBX_XPATH_HV_DATASTORES() \
237 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='datastore']]" \
238 "/*[local-name()='val']/*[@type='Datastore']"
239
240 #define ZBX_XPATH_HV_DATASTORE_MOUNTINFO() \
241 "/*/*/*/*/*[local-name()='objects'][*[local-name()='obj'][@type='Datastore'][text()='%s']]"
242
243 #define ZBX_XPATH_HV_VMS() \
244 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='vm']]" \
245 "/*[local-name()='val']/*[@type='VirtualMachine']"
246
247 #define ZBX_XPATH_DATASTORE_SUMMARY(property) \
248 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='summary']]" \
249 "/*[local-name()='val']/*[local-name()='" property "']"
250
251 #define ZBX_XPATH_MAXQUERYMETRICS() \
252 "/*/*/*/*[*[local-name()='key']='config.vpxd.stats.maxQueryMetrics']/*[local-name()='value']"
253
254 #define ZBX_XPATH_VM_HARDWARE(property) \
255 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='config.hardware']]" \
256 "/*[local-name()='val']/*[local-name()='" property "']"
257
258 #define ZBX_XPATH_VM_GUESTDISKS() \
259 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='guest.disk']]" \
260 "/*/*[local-name()='GuestDiskInfo']"
261
262 #define ZBX_XPATH_VM_UUID() \
263 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='config.uuid']]" \
264 "/*[local-name()='val']"
265
266 #define ZBX_XPATH_VM_INSTANCE_UUID() \
267 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name'][text()='config.instanceUuid']]" \
268 "/*[local-name()='val']"
269
270 #define ZBX_XPATH_HV_SENSOR_STATUS(sensor) \
271 "/*/*/*/*/*/*[local-name()='propSet'][*[local-name()='name']" \
272 "[text()='runtime.healthSystemRuntime.systemHealthInfo']]" \
273 "/*[local-name()='val']/*[local-name()='numericSensorInfo']" \
274 "[*[local-name()='name'][text()='" sensor "']]" \
275 "/*[local-name()='healthState']/*[local-name()='key']"
276
277 #define ZBX_XPATH_EVT_INFO(param) \
278 "*[local-name()='" param "']/*[local-name()='name']"
279
280 #define ZBX_XPATH_EVT_ARGUMENT(key) \
281 "*[local-name()='arguments'][*[local-name()='key'][text()='" key "']]/*[local-name()='value']"
282
283 #define ZBX_XPATH_VMWARE_ABOUT(property) \
284 "/*/*/*/*/*[local-name()='about']/*[local-name()='" property "']"
285
286 # define ZBX_XPATH_NN(NN) "*[local-name()='" NN "']"
287 # define ZBX_XPATH_LN(LN) "/" ZBX_XPATH_NN(LN)
288 # define ZBX_XPATH_LN1(LN1) "/" ZBX_XPATH_LN(LN1)
289 # define ZBX_XPATH_LN2(LN1, LN2) "/" ZBX_XPATH_LN(LN1) ZBX_XPATH_LN(LN2)
290 # define ZBX_XPATH_LN3(LN1, LN2, LN3) "/" ZBX_XPATH_LN(LN1) ZBX_XPATH_LN(LN2) ZBX_XPATH_LN(LN3)
291
292
293 #define ZBX_XPATH_PROP_NAME_NODE(property) \
294 "*[local-name()='propSet'][*[local-name()='name'][text()='" property "']]/*[local-name()='val']"
295
296 #define ZBX_XPATH_PROP_NAME(property) \
297 "/*/*/*/*/*/" ZBX_XPATH_PROP_NAME_NODE(property)
298
299 #define ZBX_XPATH_PROP_SUFFIX(property) \
300 "*[local-name()='propSet'][*[local-name()='name']" \
301 "[substring(text(),string-length(text())-string-length('" property "')+1)='" property "']]" \
302 "/*[local-name()='val']"
303
304 #define ZBX_VM_NONAME_XML "noname.xml"
305
306 #define ZBX_PROPMAP(property) {property, ZBX_XPATH_PROP_NAME(property)}
307
308 typedef struct
309 {
310 const char *name;
311 const char *xpath;
312 }
313 zbx_vmware_propmap_t;
314
315 static zbx_vmware_propmap_t hv_propmap[] = {
316 ZBX_PROPMAP("summary.quickStats.overallCpuUsage"), /* ZBX_VMWARE_HVPROP_OVERALL_CPU_USAGE */
317 ZBX_PROPMAP("summary.config.product.fullName"), /* ZBX_VMWARE_HVPROP_FULL_NAME */
318 ZBX_PROPMAP("summary.hardware.numCpuCores"), /* ZBX_VMWARE_HVPROP_HW_NUM_CPU_CORES */
319 ZBX_PROPMAP("summary.hardware.cpuMhz"), /* ZBX_VMWARE_HVPROP_HW_CPU_MHZ */
320 ZBX_PROPMAP("summary.hardware.cpuModel"), /* ZBX_VMWARE_HVPROP_HW_CPU_MODEL */
321 ZBX_PROPMAP("summary.hardware.numCpuThreads"), /* ZBX_VMWARE_HVPROP_HW_NUM_CPU_THREADS */
322 ZBX_PROPMAP("summary.hardware.memorySize"), /* ZBX_VMWARE_HVPROP_HW_MEMORY_SIZE */
323 ZBX_PROPMAP("summary.hardware.model"), /* ZBX_VMWARE_HVPROP_HW_MODEL */
324 ZBX_PROPMAP("summary.hardware.uuid"), /* ZBX_VMWARE_HVPROP_HW_UUID */
325 ZBX_PROPMAP("summary.hardware.vendor"), /* ZBX_VMWARE_HVPROP_HW_VENDOR */
326 ZBX_PROPMAP("summary.quickStats.overallMemoryUsage"), /* ZBX_VMWARE_HVPROP_MEMORY_USED */
327 {"runtime.healthSystemRuntime.systemHealthInfo", /* ZBX_VMWARE_HVPROP_HEALTH_STATE */
328 ZBX_XPATH_HV_SENSOR_STATUS("VMware Rollup Health State")},
329 ZBX_PROPMAP("summary.quickStats.uptime"), /* ZBX_VMWARE_HVPROP_UPTIME */
330 ZBX_PROPMAP("summary.config.product.version"), /* ZBX_VMWARE_HVPROP_VERSION */
331 ZBX_PROPMAP("summary.config.name"), /* ZBX_VMWARE_HVPROP_NAME */
332 ZBX_PROPMAP("overallStatus") /* ZBX_VMWARE_HVPROP_STATUS */
333 };
334
335 static zbx_vmware_propmap_t vm_propmap[] = {
336 ZBX_PROPMAP("summary.config.numCpu"), /* ZBX_VMWARE_VMPROP_CPU_NUM */
337 ZBX_PROPMAP("summary.quickStats.overallCpuUsage"), /* ZBX_VMWARE_VMPROP_CPU_USAGE */
338 ZBX_PROPMAP("summary.config.name"), /* ZBX_VMWARE_VMPROP_NAME */
339 ZBX_PROPMAP("summary.config.memorySizeMB"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE */
340 ZBX_PROPMAP("summary.quickStats.balloonedMemory"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_BALLOONED */
341 ZBX_PROPMAP("summary.quickStats.compressedMemory"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_COMPRESSED */
342 ZBX_PROPMAP("summary.quickStats.swappedMemory"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_SWAPPED */
343 ZBX_PROPMAP("summary.quickStats.guestMemoryUsage"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_USAGE_GUEST */
344 ZBX_PROPMAP("summary.quickStats.hostMemoryUsage"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_USAGE_HOST */
345 ZBX_PROPMAP("summary.quickStats.privateMemory"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_PRIVATE */
346 ZBX_PROPMAP("summary.quickStats.sharedMemory"), /* ZBX_VMWARE_VMPROP_MEMORY_SIZE_SHARED */
347 ZBX_PROPMAP("summary.runtime.powerState"), /* ZBX_VMWARE_VMPROP_POWER_STATE */
348 ZBX_PROPMAP("summary.storage.committed"), /* ZBX_VMWARE_VMPROP_STORAGE_COMMITED */
349 ZBX_PROPMAP("summary.storage.unshared"), /* ZBX_VMWARE_VMPROP_STORAGE_UNSHARED */
350 ZBX_PROPMAP("summary.storage.uncommitted"), /* ZBX_VMWARE_VMPROP_STORAGE_UNCOMMITTED */
351 ZBX_PROPMAP("summary.quickStats.uptimeSeconds") /* ZBX_VMWARE_VMPROP_UPTIME */
352 };
353
354 /* hypervisor hashset support */
vmware_hv_hash(const void * data)355 static zbx_hash_t vmware_hv_hash(const void *data)
356 {
357 zbx_vmware_hv_t *hv = (zbx_vmware_hv_t *)data;
358
359 return ZBX_DEFAULT_STRING_HASH_ALGO(hv->uuid, strlen(hv->uuid), ZBX_DEFAULT_HASH_SEED);
360 }
361
vmware_hv_compare(const void * d1,const void * d2)362 static int vmware_hv_compare(const void *d1, const void *d2)
363 {
364 zbx_vmware_hv_t *hv1 = (zbx_vmware_hv_t *)d1;
365 zbx_vmware_hv_t *hv2 = (zbx_vmware_hv_t *)d2;
366
367 return strcmp(hv1->uuid, hv2->uuid);
368 }
369
370 /* virtual machine index support */
vmware_vm_hash(const void * data)371 static zbx_hash_t vmware_vm_hash(const void *data)
372 {
373 zbx_vmware_vm_index_t *vmi = (zbx_vmware_vm_index_t *)data;
374
375 return ZBX_DEFAULT_STRING_HASH_ALGO(vmi->vm->uuid, strlen(vmi->vm->uuid), ZBX_DEFAULT_HASH_SEED);
376 }
377
vmware_vm_compare(const void * d1,const void * d2)378 static int vmware_vm_compare(const void *d1, const void *d2)
379 {
380 zbx_vmware_vm_index_t *vmi1 = (zbx_vmware_vm_index_t *)d1;
381 zbx_vmware_vm_index_t *vmi2 = (zbx_vmware_vm_index_t *)d2;
382
383 return strcmp(vmi1->vm->uuid, vmi2->vm->uuid);
384 }
385
386 /* string pool support */
387
388 #define REFCOUNT_FIELD_SIZE sizeof(zbx_uint32_t)
389
390 #define evt_msg_strpool_strdup(str, len) vmware_strpool_strdup(str, &evt_msg_strpool, len)
391
vmware_strpool_hash_func(const void * data)392 static zbx_hash_t vmware_strpool_hash_func(const void *data)
393 {
394 return ZBX_DEFAULT_STRING_HASH_FUNC((char *)data + REFCOUNT_FIELD_SIZE);
395 }
396
vmware_strpool_compare_func(const void * d1,const void * d2)397 static int vmware_strpool_compare_func(const void *d1, const void *d2)
398 {
399 return strcmp((char *)d1 + REFCOUNT_FIELD_SIZE, (char *)d2 + REFCOUNT_FIELD_SIZE);
400 }
401
vmware_shared_strsearch(const char * str)402 static int vmware_shared_strsearch(const char *str)
403 {
404 return NULL == zbx_hashset_search(&vmware->strpool, str - REFCOUNT_FIELD_SIZE) ? FAIL : SUCCEED;
405 }
406
vmware_strpool_strdup(const char * str,zbx_hashset_t * strpool,zbx_uint64_t * len)407 static char *vmware_strpool_strdup(const char *str, zbx_hashset_t *strpool, zbx_uint64_t *len)
408 {
409 void *ptr;
410
411 if (NULL != len)
412 *len = 0;
413
414 if (NULL == str)
415 return NULL;
416
417 ptr = zbx_hashset_search(strpool, str - REFCOUNT_FIELD_SIZE);
418
419 if (NULL == ptr)
420 {
421 zbx_uint64_t sz;
422
423 sz = REFCOUNT_FIELD_SIZE + strlen(str) + 1;
424 ptr = zbx_hashset_insert_ext(strpool, str - REFCOUNT_FIELD_SIZE, sz, REFCOUNT_FIELD_SIZE);
425
426 *(zbx_uint32_t *)ptr = 0;
427
428 if (NULL != len)
429 *len = sz + ZBX_HASHSET_ENTRY_OFFSET;
430 }
431
432 (*(zbx_uint32_t *)ptr)++;
433
434 return (char *)ptr + REFCOUNT_FIELD_SIZE;
435 }
436
vmware_shared_strdup(const char * str)437 static char *vmware_shared_strdup(const char *str)
438 {
439 char *strdup;
440 zbx_uint64_t len;
441
442 strdup = vmware_strpool_strdup(str, &vmware->strpool, &len);
443
444 if (0 < len)
445 vmware->strpool_sz += zbx_mem_required_chunk_size(len);
446
447 return strdup;
448 }
449
vmware_strpool_strfree(char * str,zbx_hashset_t * strpool,zbx_uint64_t * len)450 static void vmware_strpool_strfree(char *str, zbx_hashset_t *strpool, zbx_uint64_t *len)
451 {
452 if (NULL != len)
453 *len = 0;
454
455 if (NULL != str)
456 {
457 void *ptr = str - REFCOUNT_FIELD_SIZE;
458
459 if (0 == --(*(zbx_uint32_t *)ptr))
460 {
461 if (NULL != len)
462 *len = REFCOUNT_FIELD_SIZE + strlen(str) + 1 + ZBX_HASHSET_ENTRY_OFFSET;
463
464 zbx_hashset_remove_direct(strpool, ptr);
465 }
466 }
467 }
468
vmware_shared_strfree(char * str)469 static void vmware_shared_strfree(char *str)
470 {
471 zbx_uint64_t len;
472
473 vmware_strpool_strfree(str, &vmware->strpool, &len);
474
475 if (0 < len)
476 vmware->strpool_sz -= zbx_mem_required_chunk_size(len);
477 }
478
evt_msg_strpool_strfree(char * str)479 static void evt_msg_strpool_strfree(char *str)
480 {
481 vmware_strpool_strfree(str, &evt_msg_strpool, NULL);
482 }
483
484 #define ZBX_XPATH_OBJECTS_BY_TYPE(type) \
485 "/*/*/*/*/*[local-name()='objects'][*[local-name()='obj'][@type='" type "']]"
486
487 #define ZBX_XPATH_NAME_BY_TYPE(type) \
488 ZBX_XPATH_OBJECTS_BY_TYPE(type) "/*[local-name()='propSet'][*[local-name()='name']]" \
489 "/*[local-name()='val']"
490
491 #define ZBX_XPATH_HV_PARENTFOLDERNAME(parent_id) \
492 "/*/*/*/*/*[local-name()='objects'][" \
493 "*[local-name()='obj'][@type='Folder'] and " \
494 "*[local-name()='propSet'][*[local-name()='name'][text()='childEntity']]" \
495 "/*[local-name()='val']/*[local-name()='ManagedObjectReference']=" parent_id " and " \
496 "*[local-name()='propSet'][*[local-name()='name'][text()='parent']]" \
497 "/*[local-name()='val'][@type!='Datacenter']" \
498 "]/*[local-name()='propSet'][*[local-name()='name'][text()='name']]/*[local-name()='val']"
499
500 #define ZBX_XPATH_HV_PARENTID \
501 "/*/*/*/*/*[local-name()='objects'][*[local-name()='obj'][@type='HostSystem']]" \
502 "/*[local-name()='propSet'][*[local-name()='name'][text()='parent']]/*[local-name()='val']"
503
504 typedef struct
505 {
506 char *data;
507 size_t alloc;
508 size_t offset;
509 }
510 ZBX_HTTPPAGE;
511
512 static int zbx_xml_read_values(xmlDoc *xdoc, const char *xpath, zbx_vector_str_t *values);
513 static int zbx_xml_try_read_value(const char *data, size_t len, const char *xpath, xmlDoc **xdoc, char **value,
514 char **error);
515 static char *zbx_xml_read_node_value(xmlDoc *doc, xmlNode *node, const char *xpath);
516 static char *zbx_xml_read_doc_value(xmlDoc *xdoc, const char *xpath);
517
curl_write_cb(void * ptr,size_t size,size_t nmemb,void * userdata)518 static size_t curl_write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
519 {
520 size_t r_size = size * nmemb;
521 ZBX_HTTPPAGE *page_http = (ZBX_HTTPPAGE *)userdata;
522
523 zbx_strncpy_alloc(&page_http->data, &page_http->alloc, &page_http->offset, (const char *)ptr, r_size);
524
525 return r_size;
526 }
527
curl_header_cb(void * ptr,size_t size,size_t nmemb,void * userdata)528 static size_t curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
529 {
530 ZBX_UNUSED(ptr);
531 ZBX_UNUSED(userdata);
532
533 return size * nmemb;
534 }
535
536 /******************************************************************************
537 * *
538 * Function: zbx_str_uint64_pair_free *
539 * *
540 * Purpose: free memory of vector element *
541 * *
542 ******************************************************************************/
zbx_str_uint64_pair_free(zbx_str_uint64_pair_t data)543 static void zbx_str_uint64_pair_free(zbx_str_uint64_pair_t data)
544 {
545 zbx_free(data.name);
546 }
547
548 /******************************************************************************
549 * *
550 * Function: zbx_str_uint64_pair_name_compare *
551 * *
552 * Purpose: sorting function to sort zbx_str_uint64_pair_t vector by name *
553 * *
554 ******************************************************************************/
zbx_str_uint64_pair_name_compare(const void * p1,const void * p2)555 int zbx_str_uint64_pair_name_compare(const void *p1, const void *p2)
556 {
557 const zbx_str_uint64_pair_t *v1 = (const zbx_str_uint64_pair_t *)p1;
558 const zbx_str_uint64_pair_t *v2 = (const zbx_str_uint64_pair_t *)p2;
559
560 return strcmp(v1->name, v2->name);
561 }
562
563 /******************************************************************************
564 * *
565 * Function: zbx_http_post *
566 * *
567 * Purpose: abstracts the curl_easy_setopt/curl_easy_perform call pair *
568 * *
569 * Parameters: easyhandle - [IN] the CURL handle *
570 * request - [IN] the http request *
571 * response - [OUT] the http response *
572 * error - [OUT] the error message in the case of failure *
573 * *
574 * Return value: SUCCEED - the http request was completed successfully *
575 * FAIL - the http request has failed *
576 ******************************************************************************/
zbx_http_post(CURL * easyhandle,const char * request,ZBX_HTTPPAGE ** response,char ** error)577 static int zbx_http_post(CURL *easyhandle, const char *request, ZBX_HTTPPAGE **response, char **error)
578 {
579 CURLoption opt;
580 CURLcode err;
581 ZBX_HTTPPAGE *resp;
582
583 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POSTFIELDS, request)))
584 {
585 if (NULL != error)
586 *error = zbx_dsprintf(*error, "Cannot set cURL option %d: %s.", (int)opt, curl_easy_strerror(err));
587
588 return FAIL;
589 }
590
591 if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_PRIVATE, (char **)&resp)))
592 {
593 if (NULL != error)
594 *error = zbx_dsprintf(*error, "Cannot get response buffer: %s.", curl_easy_strerror(err));
595
596 return FAIL;
597 }
598
599 resp->offset = 0;
600
601 if (CURLE_OK != (err = curl_easy_perform(easyhandle)))
602 {
603 if (NULL != error)
604 *error = zbx_strdup(*error, curl_easy_strerror(err));
605
606 return FAIL;
607 }
608
609 *response = resp;
610
611 return SUCCEED;
612 }
613 /******************************************************************************
614 * *
615 * Function: zbx_soap_post *
616 * *
617 * Purpose: unification of vmware web service call with SOAP error validation *
618 * *
619 * Parameters: fn_parent - [IN] the parent function name for Log records *
620 * easyhandle - [IN] the CURL handle *
621 * request - [IN] the http request *
622 * xdoc - [OUT] the xml document response (optional) *
623 * error - [OUT] the error message in the case of failure *
624 * (optional) *
625 * *
626 * Return value: SUCCEED - the SOAP request was completed successfully *
627 * FAIL - the SOAP request has failed *
628 ******************************************************************************/
zbx_soap_post(const char * fn_parent,CURL * easyhandle,const char * request,xmlDoc ** xdoc,char ** error)629 static int zbx_soap_post(const char *fn_parent, CURL *easyhandle, const char *request, xmlDoc **xdoc, char **error)
630 {
631 xmlDoc *doc;
632 ZBX_HTTPPAGE *resp;
633 int ret = SUCCEED;
634
635 if (SUCCEED != zbx_http_post(easyhandle, request, &resp, error))
636 return FAIL;
637
638 if (NULL != fn_parent)
639 zabbix_log(LOG_LEVEL_TRACE, "%s() SOAP response: %s", fn_parent, resp->data);
640
641 if (SUCCEED != zbx_xml_try_read_value(resp->data, resp->offset, ZBX_XPATH_FAULTSTRING(), &doc, error, error)
642 || NULL != *error)
643 {
644 ret = FAIL;
645 }
646
647 if (NULL != xdoc)
648 {
649 *xdoc = doc;
650 }
651 else
652 {
653 zbx_xml_free_doc(doc);
654 }
655
656 return ret;
657 }
658
659 /******************************************************************************
660 * *
661 * performance counter hashset support functions *
662 * *
663 ******************************************************************************/
vmware_counter_hash_func(const void * data)664 static zbx_hash_t vmware_counter_hash_func(const void *data)
665 {
666 zbx_vmware_counter_t *counter = (zbx_vmware_counter_t *)data;
667
668 return ZBX_DEFAULT_STRING_HASH_ALGO(counter->path, strlen(counter->path), ZBX_DEFAULT_HASH_SEED);
669 }
670
vmware_counter_compare_func(const void * d1,const void * d2)671 static int vmware_counter_compare_func(const void *d1, const void *d2)
672 {
673 zbx_vmware_counter_t *c1 = (zbx_vmware_counter_t *)d1;
674 zbx_vmware_counter_t *c2 = (zbx_vmware_counter_t *)d2;
675
676 return strcmp(c1->path, c2->path);
677 }
678
679 /******************************************************************************
680 * *
681 * performance entities hashset support functions *
682 * *
683 ******************************************************************************/
vmware_perf_entity_hash_func(const void * data)684 static zbx_hash_t vmware_perf_entity_hash_func(const void *data)
685 {
686 zbx_hash_t seed;
687
688 zbx_vmware_perf_entity_t *entity = (zbx_vmware_perf_entity_t *)data;
689
690 seed = ZBX_DEFAULT_STRING_HASH_ALGO(entity->type, strlen(entity->type), ZBX_DEFAULT_HASH_SEED);
691
692 return ZBX_DEFAULT_STRING_HASH_ALGO(entity->id, strlen(entity->id), seed);
693 }
694
vmware_perf_entity_compare_func(const void * d1,const void * d2)695 static int vmware_perf_entity_compare_func(const void *d1, const void *d2)
696 {
697 int ret;
698
699 zbx_vmware_perf_entity_t *e1 = (zbx_vmware_perf_entity_t *)d1;
700 zbx_vmware_perf_entity_t *e2 = (zbx_vmware_perf_entity_t *)d2;
701
702 if (0 == (ret = strcmp(e1->type, e2->type)))
703 ret = strcmp(e1->id, e2->id);
704
705 return ret;
706 }
707
708 /******************************************************************************
709 * *
710 * Function: vmware_free_perfvalue *
711 * *
712 * Purpose: frees perfvalue data structure *
713 * *
714 ******************************************************************************/
vmware_free_perfvalue(zbx_vmware_perf_value_t * value)715 static void vmware_free_perfvalue(zbx_vmware_perf_value_t *value)
716 {
717 zbx_free(value->instance);
718 zbx_free(value);
719 }
720
721 /******************************************************************************
722 * *
723 * Function: vmware_free_perfdata *
724 * *
725 * Purpose: frees perfdata data structure *
726 * *
727 ******************************************************************************/
vmware_free_perfdata(zbx_vmware_perf_data_t * data)728 static void vmware_free_perfdata(zbx_vmware_perf_data_t *data)
729 {
730 zbx_free(data->id);
731 zbx_free(data->type);
732 zbx_free(data->error);
733 zbx_vector_ptr_clear_ext(&data->values, (zbx_mem_free_func_t)vmware_free_perfvalue);
734 zbx_vector_ptr_destroy(&data->values);
735
736 zbx_free(data);
737 }
738
739 /******************************************************************************
740 * *
741 * Function: xml_read_props *
742 * *
743 * Purpose: reads the vmware object properties by their xpaths from xml data *
744 * *
745 * Parameters: xdoc - [IN] the xml document *
746 * propmap - [IN] the xpaths of the properties to read *
747 * props_num - [IN] the number of properties to read *
748 * *
749 * Return value: an array of property values *
750 * *
751 * Comments: The array with property values must be freed by the caller. *
752 * *
753 ******************************************************************************/
xml_read_props(xmlDoc * xdoc,const zbx_vmware_propmap_t * propmap,int props_num)754 static char **xml_read_props(xmlDoc *xdoc, const zbx_vmware_propmap_t *propmap, int props_num)
755 {
756 xmlXPathContext *xpathCtx;
757 xmlXPathObject *xpathObj;
758 xmlNodeSetPtr nodeset;
759 xmlChar *val;
760 char **props;
761 int i;
762
763 props = (char **)zbx_malloc(NULL, sizeof(char *) * props_num);
764 memset(props, 0, sizeof(char *) * props_num);
765
766 for (i = 0; i < props_num; i++)
767 {
768 xpathCtx = xmlXPathNewContext(xdoc);
769
770 if (NULL != (xpathObj = xmlXPathEvalExpression((const xmlChar *)propmap[i].xpath, xpathCtx)))
771 {
772 if (0 == xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
773 {
774 nodeset = xpathObj->nodesetval;
775
776 if (NULL != (val = xmlNodeListGetString(xdoc, nodeset->nodeTab[0]->xmlChildrenNode, 1)))
777 {
778 props[i] = zbx_strdup(NULL, (const char *)val);
779 xmlFree(val);
780 }
781 }
782
783 xmlXPathFreeObject(xpathObj);
784 }
785
786 xmlXPathFreeContext(xpathCtx);
787 }
788
789 return props;
790 }
791
792 /******************************************************************************
793 * *
794 * Function: vmware_counters_shared_copy *
795 * *
796 * Purpose: copies performance counter vector into shared memory hashset *
797 * *
798 * Parameters: dst - [IN] the destination hashset *
799 * src - [IN] the source vector *
800 * *
801 ******************************************************************************/
vmware_counters_shared_copy(zbx_hashset_t * dst,const zbx_vector_ptr_t * src)802 static void vmware_counters_shared_copy(zbx_hashset_t *dst, const zbx_vector_ptr_t *src)
803 {
804 int i;
805 zbx_vmware_counter_t *csrc, *cdst;
806
807 if (SUCCEED != zbx_hashset_reserve(dst, src->values_num))
808 {
809 THIS_SHOULD_NEVER_HAPPEN;
810 exit(EXIT_FAILURE);
811 }
812
813 for (i = 0; i < src->values_num; i++)
814 {
815 csrc = (zbx_vmware_counter_t *)src->values[i];
816
817 cdst = (zbx_vmware_counter_t *)zbx_hashset_insert(dst, csrc, sizeof(zbx_vmware_counter_t));
818
819 /* check if the counter was inserted - copy path only for inserted counters */
820 if (cdst->path == csrc->path)
821 cdst->path = vmware_shared_strdup(csrc->path);
822 }
823 }
824
825 /******************************************************************************
826 * *
827 * Function: vmware_vector_str_uint64_pair_shared_clean *
828 * *
829 * Purpose: frees shared resources allocated to store instance performance *
830 * counter values *
831 * *
832 * Parameters: pairs - [IN] vector of performance counter pairs *
833 * *
834 ******************************************************************************/
vmware_vector_str_uint64_pair_shared_clean(zbx_vector_str_uint64_pair_t * pairs)835 static void vmware_vector_str_uint64_pair_shared_clean(zbx_vector_str_uint64_pair_t *pairs)
836 {
837 int i;
838
839 for (i = 0; i < pairs->values_num; i++)
840 {
841 zbx_str_uint64_pair_t *pair = &pairs->values[i];
842
843 if (NULL != pair->name)
844 vmware_shared_strfree(pair->name);
845 }
846
847 pairs->values_num = 0;
848 }
849
850 /******************************************************************************
851 * *
852 * Function: vmware_perf_counter_shared_free *
853 * *
854 * Purpose: frees shared resources allocated to store performance counter *
855 * data *
856 * *
857 * Parameters: counter - [IN] the performance counter data *
858 * *
859 ******************************************************************************/
vmware_perf_counter_shared_free(zbx_vmware_perf_counter_t * counter)860 static void vmware_perf_counter_shared_free(zbx_vmware_perf_counter_t *counter)
861 {
862 vmware_vector_str_uint64_pair_shared_clean(&counter->values);
863 zbx_vector_str_uint64_pair_destroy(&counter->values);
864 __vm_mem_free_func(counter);
865 }
866
867 /******************************************************************************
868 * *
869 * Function: vmware_entities_shared_clean_stats *
870 * *
871 * Purpose: removes statistics data from vmware entities *
872 * *
873 ******************************************************************************/
vmware_entities_shared_clean_stats(zbx_hashset_t * entities)874 static void vmware_entities_shared_clean_stats(zbx_hashset_t *entities)
875 {
876 int i;
877 zbx_vmware_perf_entity_t *entity;
878 zbx_vmware_perf_counter_t *counter;
879 zbx_hashset_iter_t iter;
880
881
882 zbx_hashset_iter_reset(entities, &iter);
883 while (NULL != (entity = (zbx_vmware_perf_entity_t *)zbx_hashset_iter_next(&iter)))
884 {
885 for (i = 0; i < entity->counters.values_num; i++)
886 {
887 counter = (zbx_vmware_perf_counter_t *)entity->counters.values[i];
888 vmware_vector_str_uint64_pair_shared_clean(&counter->values);
889
890 if (0 != (counter->state & ZBX_VMWARE_COUNTER_UPDATING))
891 counter->state = ZBX_VMWARE_COUNTER_READY;
892 }
893 vmware_shared_strfree(entity->error);
894 entity->error = NULL;
895 }
896 }
897
898 /******************************************************************************
899 * *
900 * Function: vmware_datastore_shared_free *
901 * *
902 * Purpose: frees shared resources allocated to store datastore data *
903 * *
904 * Parameters: datastore - [IN] the datastore *
905 * *
906 ******************************************************************************/
vmware_datastore_shared_free(zbx_vmware_datastore_t * datastore)907 static void vmware_datastore_shared_free(zbx_vmware_datastore_t *datastore)
908 {
909 vmware_shared_strfree(datastore->name);
910 vmware_shared_strfree(datastore->id);
911
912 if (NULL != datastore->uuid)
913 vmware_shared_strfree(datastore->uuid);
914
915 vmware_vector_str_uint64_pair_shared_clean(&datastore->hv_uuids_access);
916 zbx_vector_str_uint64_pair_destroy(&datastore->hv_uuids_access);
917
918 __vm_mem_free_func(datastore);
919 }
920
921 /******************************************************************************
922 * *
923 * Function: vmware_datacenter_shared_free *
924 * *
925 * Purpose: frees shared resources allocated to store datacenter data *
926 * *
927 * Parameters: datacenter - [IN] the datacenter *
928 * *
929 ******************************************************************************/
vmware_datacenter_shared_free(zbx_vmware_datacenter_t * datacenter)930 static void vmware_datacenter_shared_free(zbx_vmware_datacenter_t *datacenter)
931 {
932 vmware_shared_strfree(datacenter->name);
933 vmware_shared_strfree(datacenter->id);
934
935 __vm_mem_free_func(datacenter);
936 }
937
938 /******************************************************************************
939 * *
940 * Function: vmware_props_shared_free *
941 * *
942 * Purpose: frees shared resources allocated to store properties list *
943 * *
944 * Parameters: props - [IN] the properties list *
945 * props_num - [IN] the number of properties in the list *
946 * *
947 ******************************************************************************/
vmware_props_shared_free(char ** props,int props_num)948 static void vmware_props_shared_free(char **props, int props_num)
949 {
950 int i;
951
952 if (NULL == props)
953 return;
954
955 for (i = 0; i < props_num; i++)
956 {
957 if (NULL != props[i])
958 vmware_shared_strfree(props[i]);
959 }
960
961 __vm_mem_free_func(props);
962 }
963
964 /******************************************************************************
965 * *
966 * Function: vmware_dev_shared_free *
967 * *
968 * Purpose: frees shared resources allocated to store vm device data *
969 * *
970 * Parameters: dev - [IN] the vm device *
971 * *
972 ******************************************************************************/
vmware_dev_shared_free(zbx_vmware_dev_t * dev)973 static void vmware_dev_shared_free(zbx_vmware_dev_t *dev)
974 {
975 if (NULL != dev->instance)
976 vmware_shared_strfree(dev->instance);
977
978 if (NULL != dev->label)
979 vmware_shared_strfree(dev->label);
980
981 __vm_mem_free_func(dev);
982 }
983
984 /******************************************************************************
985 * *
986 * Function: vmware_fs_shared_free *
987 * *
988 * Purpose: frees shared resources allocated to store file system object *
989 * *
990 * Parameters: fs - [IN] the file system *
991 * *
992 ******************************************************************************/
vmware_fs_shared_free(zbx_vmware_fs_t * fs)993 static void vmware_fs_shared_free(zbx_vmware_fs_t *fs)
994 {
995 if (NULL != fs->path)
996 vmware_shared_strfree(fs->path);
997
998 __vm_mem_free_func(fs);
999 }
1000
1001 /******************************************************************************
1002 * *
1003 * Function: vmware_vm_shared_free *
1004 * *
1005 * Purpose: frees shared resources allocated to store virtual machine *
1006 * *
1007 * Parameters: vm - [IN] the virtual machine *
1008 * *
1009 ******************************************************************************/
vmware_vm_shared_free(zbx_vmware_vm_t * vm)1010 static void vmware_vm_shared_free(zbx_vmware_vm_t *vm)
1011 {
1012 zbx_vector_ptr_clear_ext(&vm->devs, (zbx_clean_func_t)vmware_dev_shared_free);
1013 zbx_vector_ptr_destroy(&vm->devs);
1014
1015 zbx_vector_ptr_clear_ext(&vm->file_systems, (zbx_mem_free_func_t)vmware_fs_shared_free);
1016 zbx_vector_ptr_destroy(&vm->file_systems);
1017
1018 if (NULL != vm->uuid)
1019 vmware_shared_strfree(vm->uuid);
1020
1021 if (NULL != vm->id)
1022 vmware_shared_strfree(vm->id);
1023
1024 vmware_props_shared_free(vm->props, ZBX_VMWARE_VMPROPS_NUM);
1025
1026 __vm_mem_free_func(vm);
1027 }
1028
1029 /******************************************************************************
1030 * *
1031 * Function: vmware_hv_shared_clean *
1032 * *
1033 * Purpose: frees shared resources allocated to store vmware hypervisor *
1034 * *
1035 * Parameters: hv - [IN] the vmware hypervisor *
1036 * *
1037 ******************************************************************************/
vmware_hv_shared_clean(zbx_vmware_hv_t * hv)1038 static void vmware_hv_shared_clean(zbx_vmware_hv_t *hv)
1039 {
1040 zbx_vector_str_clear_ext(&hv->ds_names, vmware_shared_strfree);
1041 zbx_vector_str_destroy(&hv->ds_names);
1042
1043 zbx_vector_ptr_clear_ext(&hv->vms, (zbx_clean_func_t)vmware_vm_shared_free);
1044 zbx_vector_ptr_destroy(&hv->vms);
1045
1046 if (NULL != hv->uuid)
1047 vmware_shared_strfree(hv->uuid);
1048
1049 if (NULL != hv->id)
1050 vmware_shared_strfree(hv->id);
1051
1052 if (NULL != hv->clusterid)
1053 vmware_shared_strfree(hv->clusterid);
1054
1055 if (NULL != hv->datacenter_name)
1056 vmware_shared_strfree(hv->datacenter_name);
1057
1058 if (NULL != hv->parent_name)
1059 vmware_shared_strfree(hv->parent_name);
1060
1061 if (NULL != hv->parent_type)
1062 vmware_shared_strfree(hv->parent_type);
1063
1064 vmware_props_shared_free(hv->props, ZBX_VMWARE_HVPROPS_NUM);
1065 }
1066
1067 /******************************************************************************
1068 * *
1069 * Function: vmware_cluster_shared_free *
1070 * *
1071 * Purpose: frees shared resources allocated to store vmware cluster *
1072 * *
1073 * Parameters: cluster - [IN] the vmware cluster *
1074 * *
1075 ******************************************************************************/
vmware_cluster_shared_free(zbx_vmware_cluster_t * cluster)1076 static void vmware_cluster_shared_free(zbx_vmware_cluster_t *cluster)
1077 {
1078 if (NULL != cluster->name)
1079 vmware_shared_strfree(cluster->name);
1080
1081 if (NULL != cluster->id)
1082 vmware_shared_strfree(cluster->id);
1083
1084 if (NULL != cluster->status)
1085 vmware_shared_strfree(cluster->status);
1086
1087 __vm_mem_free_func(cluster);
1088 }
1089
1090 /******************************************************************************
1091 * *
1092 * Function: vmware_event_shared_free *
1093 * *
1094 * Purpose: frees shared resources allocated to store vmware event *
1095 * *
1096 * Parameters: event - [IN] the vmware event *
1097 * *
1098 ******************************************************************************/
vmware_event_shared_free(zbx_vmware_event_t * event)1099 static void vmware_event_shared_free(zbx_vmware_event_t *event)
1100 {
1101 if (NULL != event->message)
1102 vmware_shared_strfree(event->message);
1103
1104 __vm_mem_free_func(event);
1105 }
1106
1107 /******************************************************************************
1108 * *
1109 * Function: vmware_data_shared_free *
1110 * *
1111 * Purpose: frees shared resources allocated to store vmware service data *
1112 * *
1113 * Parameters: data - [IN] the vmware service data *
1114 * *
1115 ******************************************************************************/
vmware_data_shared_free(zbx_vmware_data_t * data)1116 static void vmware_data_shared_free(zbx_vmware_data_t *data)
1117 {
1118 if (NULL != data)
1119 {
1120 zbx_hashset_iter_t iter;
1121 zbx_vmware_hv_t *hv;
1122
1123 zbx_hashset_iter_reset(&data->hvs, &iter);
1124 while (NULL != (hv = (zbx_vmware_hv_t *)zbx_hashset_iter_next(&iter)))
1125 vmware_hv_shared_clean(hv);
1126
1127 zbx_hashset_destroy(&data->hvs);
1128 zbx_hashset_destroy(&data->vms_index);
1129
1130 zbx_vector_ptr_clear_ext(&data->clusters, (zbx_clean_func_t)vmware_cluster_shared_free);
1131 zbx_vector_ptr_destroy(&data->clusters);
1132
1133 zbx_vector_ptr_clear_ext(&data->events, (zbx_clean_func_t)vmware_event_shared_free);
1134 zbx_vector_ptr_destroy(&data->events);
1135
1136 zbx_vector_vmware_datastore_clear_ext(&data->datastores, vmware_datastore_shared_free);
1137 zbx_vector_vmware_datastore_destroy(&data->datastores);
1138
1139 zbx_vector_vmware_datacenter_clear_ext(&data->datacenters, vmware_datacenter_shared_free);
1140 zbx_vector_vmware_datacenter_destroy(&data->datacenters);
1141
1142 if (NULL != data->error)
1143 vmware_shared_strfree(data->error);
1144
1145 __vm_mem_free_func(data);
1146 }
1147 }
1148
1149 /******************************************************************************
1150 * *
1151 * Function: vmware_shared_perf_entity_clean *
1152 * *
1153 * Purpose: cleans resources allocated by vmware performance entity in vmware *
1154 * cache *
1155 * *
1156 * Parameters: entity - [IN] the entity to free *
1157 * *
1158 ******************************************************************************/
vmware_shared_perf_entity_clean(zbx_vmware_perf_entity_t * entity)1159 static void vmware_shared_perf_entity_clean(zbx_vmware_perf_entity_t *entity)
1160 {
1161 zbx_vector_ptr_clear_ext(&entity->counters, (zbx_mem_free_func_t)vmware_perf_counter_shared_free);
1162 zbx_vector_ptr_destroy(&entity->counters);
1163
1164 vmware_shared_strfree(entity->query_instance);
1165 vmware_shared_strfree(entity->type);
1166 vmware_shared_strfree(entity->id);
1167 vmware_shared_strfree(entity->error);
1168 }
1169
1170 /******************************************************************************
1171 * *
1172 * Function: vmware_counter_shared_clean *
1173 * *
1174 * Purpose: frees resources allocated by vmware performance counter *
1175 * *
1176 * Parameters: counter - [IN] the performance counter to free *
1177 * *
1178 ******************************************************************************/
vmware_counter_shared_clean(zbx_vmware_counter_t * counter)1179 static void vmware_counter_shared_clean(zbx_vmware_counter_t *counter)
1180 {
1181 vmware_shared_strfree(counter->path);
1182 }
1183
1184 /******************************************************************************
1185 * *
1186 * Function: vmware_service_shared_free *
1187 * *
1188 * Purpose: frees shared resources allocated to store vmware service *
1189 * *
1190 * Parameters: data - [IN] the vmware service data *
1191 * *
1192 ******************************************************************************/
vmware_service_shared_free(zbx_vmware_service_t * service)1193 static void vmware_service_shared_free(zbx_vmware_service_t *service)
1194 {
1195 zbx_hashset_iter_t iter;
1196 zbx_vmware_counter_t *counter;
1197 zbx_vmware_perf_entity_t *entity;
1198
1199 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, service->username, service->url);
1200
1201 vmware_shared_strfree(service->url);
1202 vmware_shared_strfree(service->username);
1203 vmware_shared_strfree(service->password);
1204
1205 if (NULL != service->version)
1206 vmware_shared_strfree(service->version);
1207
1208 if (NULL != service->fullname)
1209 vmware_shared_strfree(service->fullname);
1210
1211 vmware_data_shared_free(service->data);
1212
1213 zbx_hashset_iter_reset(&service->entities, &iter);
1214 while (NULL != (entity = (zbx_vmware_perf_entity_t *)zbx_hashset_iter_next(&iter)))
1215 vmware_shared_perf_entity_clean(entity);
1216
1217 zbx_hashset_destroy(&service->entities);
1218
1219 zbx_hashset_iter_reset(&service->counters, &iter);
1220 while (NULL != (counter = (zbx_vmware_counter_t *)zbx_hashset_iter_next(&iter)))
1221 vmware_counter_shared_clean(counter);
1222
1223 zbx_hashset_destroy(&service->counters);
1224
1225 __vm_mem_free_func(service);
1226
1227 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
1228 }
1229
1230 /******************************************************************************
1231 * *
1232 * Function: vmware_cluster_shared_dup *
1233 * *
1234 * Purpose: copies vmware cluster object into shared memory *
1235 * *
1236 * Parameters: src - [IN] the vmware cluster object *
1237 * *
1238 * Return value: a copied vmware cluster object *
1239 * *
1240 ******************************************************************************/
vmware_cluster_shared_dup(const zbx_vmware_cluster_t * src)1241 static zbx_vmware_cluster_t *vmware_cluster_shared_dup(const zbx_vmware_cluster_t *src)
1242 {
1243 zbx_vmware_cluster_t *cluster;
1244
1245 cluster = (zbx_vmware_cluster_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_cluster_t));
1246 cluster->id = vmware_shared_strdup(src->id);
1247 cluster->name = vmware_shared_strdup(src->name);
1248 cluster->status = vmware_shared_strdup(src->status);
1249
1250 return cluster;
1251 }
1252
1253 /******************************************************************************
1254 * *
1255 * Function: vmware_event_shared_dup *
1256 * *
1257 * Purpose: copies vmware event object into shared memory *
1258 * *
1259 * Parameters: src - [IN] the vmware event object *
1260 * *
1261 * Return value: a copied vmware event object *
1262 * *
1263 ******************************************************************************/
vmware_event_shared_dup(const zbx_vmware_event_t * src)1264 static zbx_vmware_event_t *vmware_event_shared_dup(const zbx_vmware_event_t *src)
1265 {
1266 zbx_vmware_event_t *event;
1267
1268 event = (zbx_vmware_event_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_event_t));
1269 event->key = src->key;
1270 event->message = vmware_shared_strdup(src->message);
1271 event->timestamp = src->timestamp;
1272
1273 return event;
1274 }
1275
1276 /******************************************************************************
1277 * *
1278 * Function: vmware_datastore_shared_dup *
1279 * *
1280 * Purpose: copies vmware hypervisor datastore object into shared memory *
1281 * *
1282 * Parameters: src - [IN] the vmware datastore object *
1283 * *
1284 * Return value: a duplicated vmware datastore object *
1285 * *
1286 ******************************************************************************/
vmware_datastore_shared_dup(const zbx_vmware_datastore_t * src)1287 static zbx_vmware_datastore_t *vmware_datastore_shared_dup(const zbx_vmware_datastore_t *src)
1288 {
1289 int i;
1290 zbx_vmware_datastore_t *datastore;
1291
1292 datastore = (zbx_vmware_datastore_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_datastore_t));
1293 datastore->uuid = vmware_shared_strdup(src->uuid);
1294 datastore->name = vmware_shared_strdup(src->name);
1295 datastore->id = vmware_shared_strdup(src->id);
1296 VMWARE_VECTOR_CREATE(&datastore->hv_uuids_access, str_uint64_pair);
1297 zbx_vector_str_uint64_pair_reserve(&datastore->hv_uuids_access, src->hv_uuids_access.values_num);
1298
1299 datastore->capacity = src->capacity;
1300 datastore->free_space = src->free_space;
1301 datastore->uncommitted = src->uncommitted;
1302
1303 for (i = 0; i < src->hv_uuids_access.values_num; i++)
1304 {
1305 zbx_str_uint64_pair_t val;
1306
1307 val.name = vmware_shared_strdup(src->hv_uuids_access.values[i].name);
1308 val.value = src->hv_uuids_access.values[i].value;
1309 zbx_vector_str_uint64_pair_append_ptr(&datastore->hv_uuids_access, &val);
1310 }
1311
1312 return datastore;
1313 }
1314
1315 /******************************************************************************
1316 * *
1317 * Function: vmware_datacenter_shared_dup *
1318 * *
1319 * Purpose: copies vmware datacenter object into shared memory *
1320 * *
1321 * Parameters: src - [IN] the vmware datacenter object *
1322 * *
1323 * Return value: a duplicated vmware datacenter object *
1324 * *
1325 ******************************************************************************/
vmware_datacenter_shared_dup(const zbx_vmware_datacenter_t * src)1326 static zbx_vmware_datacenter_t *vmware_datacenter_shared_dup(const zbx_vmware_datacenter_t *src)
1327 {
1328 zbx_vmware_datacenter_t *datacenter;
1329
1330 datacenter = (zbx_vmware_datacenter_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_datacenter_t));
1331 datacenter->name = vmware_shared_strdup(src->name);
1332 datacenter->id = vmware_shared_strdup(src->id);
1333
1334 return datacenter;
1335 }
1336
1337 /******************************************************************************
1338 * *
1339 * Function: vmware_dev_shared_dup *
1340 * *
1341 * Purpose: copies vmware virtual machine device object into shared memory *
1342 * *
1343 * Parameters: src - [IN] the vmware device object *
1344 * *
1345 * Return value: a duplicated vmware device object *
1346 * *
1347 ******************************************************************************/
vmware_dev_shared_dup(const zbx_vmware_dev_t * src)1348 static zbx_vmware_dev_t *vmware_dev_shared_dup(const zbx_vmware_dev_t *src)
1349 {
1350 zbx_vmware_dev_t *dev;
1351
1352 dev = (zbx_vmware_dev_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_dev_t));
1353 dev->type = src->type;
1354 dev->instance = vmware_shared_strdup(src->instance);
1355 dev->label = vmware_shared_strdup(src->label);
1356
1357 return dev;
1358 }
1359
1360 /******************************************************************************
1361 * *
1362 * Function: vmware_fs_shared_dup *
1363 * *
1364 * Purpose: copies vmware virtual machine file system object into shared *
1365 * memory *
1366 * *
1367 * Parameters: src - [IN] the vmware device object *
1368 * *
1369 * Return value: a duplicated vmware device object *
1370 * *
1371 ******************************************************************************/
vmware_fs_shared_dup(const zbx_vmware_fs_t * src)1372 static zbx_vmware_fs_t *vmware_fs_shared_dup(const zbx_vmware_fs_t *src)
1373 {
1374 zbx_vmware_fs_t *fs;
1375
1376 fs = (zbx_vmware_fs_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_fs_t));
1377 fs->path = vmware_shared_strdup(src->path);
1378 fs->capacity = src->capacity;
1379 fs->free_space = src->free_space;
1380
1381 return fs;
1382 }
1383
1384 /******************************************************************************
1385 * *
1386 * Function: vmware_props_shared_dup *
1387 * *
1388 * Purpose: copies object properties list into shared memory *
1389 * *
1390 * Parameters: src - [IN] the properties list *
1391 * props_num - [IN] the number of properties in the list *
1392 * *
1393 * Return value: a duplicated object properties list *
1394 * *
1395 ******************************************************************************/
vmware_props_shared_dup(char ** const src,int props_num)1396 static char **vmware_props_shared_dup(char ** const src, int props_num)
1397 {
1398 char **props;
1399 int i;
1400
1401 props = (char **)__vm_mem_malloc_func(NULL, sizeof(char *) * props_num);
1402
1403 for (i = 0; i < props_num; i++)
1404 props[i] = vmware_shared_strdup(src[i]);
1405
1406 return props;
1407 }
1408
1409 /******************************************************************************
1410 * *
1411 * Function: vmware_vm_shared_dup *
1412 * *
1413 * Purpose: copies vmware virtual machine object into shared memory *
1414 * *
1415 * Parameters: src - [IN] the vmware virtual machine object *
1416 * *
1417 * Return value: a duplicated vmware virtual machine object *
1418 * *
1419 ******************************************************************************/
vmware_vm_shared_dup(const zbx_vmware_vm_t * src)1420 static zbx_vmware_vm_t *vmware_vm_shared_dup(const zbx_vmware_vm_t *src)
1421 {
1422 zbx_vmware_vm_t *vm;
1423 int i;
1424
1425 vm = (zbx_vmware_vm_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_vm_t));
1426
1427 VMWARE_VECTOR_CREATE(&vm->devs, ptr);
1428 VMWARE_VECTOR_CREATE(&vm->file_systems, ptr);
1429 zbx_vector_ptr_reserve(&vm->devs, src->devs.values_num);
1430 zbx_vector_ptr_reserve(&vm->file_systems, src->file_systems.values_num);
1431
1432 vm->uuid = vmware_shared_strdup(src->uuid);
1433 vm->id = vmware_shared_strdup(src->id);
1434 vm->props = vmware_props_shared_dup(src->props, ZBX_VMWARE_VMPROPS_NUM);
1435
1436 for (i = 0; i < src->devs.values_num; i++)
1437 zbx_vector_ptr_append(&vm->devs, vmware_dev_shared_dup((zbx_vmware_dev_t *)src->devs.values[i]));
1438
1439 for (i = 0; i < src->file_systems.values_num; i++)
1440 zbx_vector_ptr_append(&vm->file_systems, vmware_fs_shared_dup((zbx_vmware_fs_t *)src->file_systems.values[i]));
1441
1442 return vm;
1443 }
1444
1445 /******************************************************************************
1446 * *
1447 * Function: vmware_hv_shared_copy *
1448 * *
1449 * Purpose: copies vmware hypervisor object into shared memory *
1450 * *
1451 * Parameters: src - [IN] the vmware hypervisor object *
1452 * *
1453 * Return value: a duplicated vmware hypervisor object *
1454 * *
1455 ******************************************************************************/
vmware_hv_shared_copy(zbx_vmware_hv_t * dst,const zbx_vmware_hv_t * src)1456 static void vmware_hv_shared_copy(zbx_vmware_hv_t *dst, const zbx_vmware_hv_t *src)
1457 {
1458 int i;
1459
1460 VMWARE_VECTOR_CREATE(&dst->ds_names, str);
1461 VMWARE_VECTOR_CREATE(&dst->vms, ptr);
1462 zbx_vector_str_reserve(&dst->ds_names, src->ds_names.values_num);
1463 zbx_vector_ptr_reserve(&dst->vms, src->vms.values_num);
1464
1465 dst->uuid = vmware_shared_strdup(src->uuid);
1466 dst->id = vmware_shared_strdup(src->id);
1467 dst->clusterid = vmware_shared_strdup(src->clusterid);
1468
1469 dst->props = vmware_props_shared_dup(src->props, ZBX_VMWARE_HVPROPS_NUM);
1470 dst->datacenter_name = vmware_shared_strdup(src->datacenter_name);
1471 dst->parent_name = vmware_shared_strdup(src->parent_name);
1472 dst->parent_type= vmware_shared_strdup(src->parent_type);
1473
1474 for (i = 0; i < src->ds_names.values_num; i++)
1475 zbx_vector_str_append(&dst->ds_names, vmware_shared_strdup(src->ds_names.values[i]));
1476
1477 for (i = 0; i < src->vms.values_num; i++)
1478 zbx_vector_ptr_append(&dst->vms, vmware_vm_shared_dup((zbx_vmware_vm_t *)src->vms.values[i]));
1479 }
1480
1481 /******************************************************************************
1482 * *
1483 * Function: vmware_data_shared_dup *
1484 * *
1485 * Purpose: copies vmware data object into shared memory *
1486 * *
1487 * Parameters: src - [IN] the vmware data object *
1488 * *
1489 * Return value: a duplicated vmware data object *
1490 * *
1491 ******************************************************************************/
vmware_data_shared_dup(zbx_vmware_data_t * src)1492 static zbx_vmware_data_t *vmware_data_shared_dup(zbx_vmware_data_t *src)
1493 {
1494 zbx_vmware_data_t *data;
1495 int i;
1496 zbx_hashset_iter_t iter;
1497 zbx_vmware_hv_t *hv, hv_local;
1498
1499 data = (zbx_vmware_data_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_data_t));
1500 zbx_hashset_create_ext(&data->hvs, 1, vmware_hv_hash, vmware_hv_compare, NULL, __vm_mem_malloc_func,
1501 __vm_mem_realloc_func, __vm_mem_free_func);
1502 VMWARE_VECTOR_CREATE(&data->clusters, ptr);
1503 VMWARE_VECTOR_CREATE(&data->events, ptr);
1504 VMWARE_VECTOR_CREATE(&data->datastores, vmware_datastore);
1505 VMWARE_VECTOR_CREATE(&data->datacenters, vmware_datacenter);
1506 zbx_vector_ptr_reserve(&data->clusters, src->clusters.values_num);
1507 zbx_vector_ptr_reserve(&data->events, src->events.values_alloc);
1508 zbx_vector_vmware_datastore_reserve(&data->datastores, src->datastores.values_num);
1509 zbx_vector_vmware_datacenter_reserve(&data->datacenters, src->datacenters.values_num);
1510
1511 zbx_hashset_create_ext(&data->vms_index, 100, vmware_vm_hash, vmware_vm_compare, NULL, __vm_mem_malloc_func,
1512 __vm_mem_realloc_func, __vm_mem_free_func);
1513
1514 data->error = vmware_shared_strdup(src->error);
1515
1516 for (i = 0; i < src->clusters.values_num; i++)
1517 zbx_vector_ptr_append(&data->clusters, vmware_cluster_shared_dup((zbx_vmware_cluster_t *)src->clusters.values[i]));
1518
1519 for (i = 0; i < src->events.values_num; i++)
1520 zbx_vector_ptr_append(&data->events, vmware_event_shared_dup((zbx_vmware_event_t *)src->events.values[i]));
1521
1522 for (i = 0; i < src->datastores.values_num; i++)
1523 zbx_vector_vmware_datastore_append(&data->datastores, vmware_datastore_shared_dup(src->datastores.values[i]));
1524
1525 for (i = 0; i < src->datacenters.values_num; i++)
1526 {
1527 zbx_vector_vmware_datacenter_append(&data->datacenters,
1528 vmware_datacenter_shared_dup(src->datacenters.values[i]));
1529 }
1530
1531 zbx_hashset_iter_reset(&src->hvs, &iter);
1532 while (NULL != (hv = (zbx_vmware_hv_t *)zbx_hashset_iter_next(&iter)))
1533 {
1534
1535 vmware_hv_shared_copy(&hv_local, hv);
1536 hv = (zbx_vmware_hv_t *)zbx_hashset_insert(&data->hvs, &hv_local, sizeof(hv_local));
1537
1538 if (SUCCEED != zbx_hashset_reserve(&data->vms_index, hv->vms.values_num))
1539 {
1540 THIS_SHOULD_NEVER_HAPPEN;
1541 exit(EXIT_FAILURE);
1542 }
1543
1544 for (i = 0; i < hv->vms.values_num; i++)
1545 {
1546 zbx_vmware_vm_index_t vmi_local = {(zbx_vmware_vm_t *)hv->vms.values[i], hv};
1547
1548 zbx_hashset_insert(&data->vms_index, &vmi_local, sizeof(vmi_local));
1549 }
1550 }
1551
1552 data->max_query_metrics = src->max_query_metrics;
1553
1554 return data;
1555 }
1556
1557 /******************************************************************************
1558 * *
1559 * Function: vmware_datastore_free *
1560 * *
1561 * Purpose: frees resources allocated to store datastore data *
1562 * *
1563 * Parameters: datastore - [IN] the datastore *
1564 * *
1565 ******************************************************************************/
vmware_datastore_free(zbx_vmware_datastore_t * datastore)1566 static void vmware_datastore_free(zbx_vmware_datastore_t *datastore)
1567 {
1568 zbx_vector_str_uint64_pair_clear_ext(&datastore->hv_uuids_access, zbx_str_uint64_pair_free);
1569 zbx_vector_str_uint64_pair_destroy(&datastore->hv_uuids_access);
1570
1571 zbx_free(datastore->name);
1572 zbx_free(datastore->uuid);
1573 zbx_free(datastore->id);
1574 zbx_free(datastore);
1575 }
1576
1577 /******************************************************************************
1578 * *
1579 * Function: vmware_datacenter_free *
1580 * *
1581 * Purpose: frees resources allocated to store datacenter data *
1582 * *
1583 * Parameters: datacenter - [IN] the datacenter *
1584 * *
1585 ******************************************************************************/
vmware_datacenter_free(zbx_vmware_datacenter_t * datacenter)1586 static void vmware_datacenter_free(zbx_vmware_datacenter_t *datacenter)
1587 {
1588 zbx_free(datacenter->name);
1589 zbx_free(datacenter->id);
1590 zbx_free(datacenter);
1591 }
1592
1593 /******************************************************************************
1594 * *
1595 * Function: vmware_props_free *
1596 * *
1597 * Purpose: frees shared resources allocated to store properties list *
1598 * *
1599 * Parameters: props - [IN] the properties list *
1600 * props_num - [IN] the number of properties in the list *
1601 * *
1602 ******************************************************************************/
vmware_props_free(char ** props,int props_num)1603 static void vmware_props_free(char **props, int props_num)
1604 {
1605 int i;
1606
1607 if (NULL == props)
1608 return;
1609
1610 for (i = 0; i < props_num; i++)
1611 zbx_free(props[i]);
1612
1613 zbx_free(props);
1614 }
1615
1616 /******************************************************************************
1617 * *
1618 * Function: vmware_dev_free *
1619 * *
1620 * Purpose: frees resources allocated to store vm device object *
1621 * *
1622 * Parameters: dev - [IN] the vm device *
1623 * *
1624 ******************************************************************************/
vmware_dev_free(zbx_vmware_dev_t * dev)1625 static void vmware_dev_free(zbx_vmware_dev_t *dev)
1626 {
1627 zbx_free(dev->instance);
1628 zbx_free(dev->label);
1629 zbx_free(dev);
1630 }
1631
1632 /******************************************************************************
1633 * *
1634 * Function: vmware_fs_free *
1635 * *
1636 * Purpose: frees resources allocated to store vm file system object *
1637 * *
1638 * Parameters: fs - [IN] the file system *
1639 * *
1640 ******************************************************************************/
vmware_fs_free(zbx_vmware_fs_t * fs)1641 static void vmware_fs_free(zbx_vmware_fs_t *fs)
1642 {
1643 zbx_free(fs->path);
1644 zbx_free(fs);
1645 }
1646
1647 /******************************************************************************
1648 * *
1649 * Function: vmware_vm_free *
1650 * *
1651 * Purpose: frees resources allocated to store virtual machine *
1652 * *
1653 * Parameters: vm - [IN] the virtual machine *
1654 * *
1655 ******************************************************************************/
vmware_vm_free(zbx_vmware_vm_t * vm)1656 static void vmware_vm_free(zbx_vmware_vm_t *vm)
1657 {
1658 zbx_vector_ptr_clear_ext(&vm->devs, (zbx_clean_func_t)vmware_dev_free);
1659 zbx_vector_ptr_destroy(&vm->devs);
1660
1661 zbx_vector_ptr_clear_ext(&vm->file_systems, (zbx_mem_free_func_t)vmware_fs_free);
1662 zbx_vector_ptr_destroy(&vm->file_systems);
1663
1664 zbx_free(vm->uuid);
1665 zbx_free(vm->id);
1666 vmware_props_free(vm->props, ZBX_VMWARE_VMPROPS_NUM);
1667 zbx_free(vm);
1668 }
1669
1670 /******************************************************************************
1671 * *
1672 * Function: vmware_hv_clean *
1673 * *
1674 * Purpose: frees resources allocated to store vmware hypervisor *
1675 * *
1676 * Parameters: hv - [IN] the vmware hypervisor *
1677 * *
1678 ******************************************************************************/
vmware_hv_clean(zbx_vmware_hv_t * hv)1679 static void vmware_hv_clean(zbx_vmware_hv_t *hv)
1680 {
1681 zbx_vector_str_clear_ext(&hv->ds_names, zbx_str_free);
1682 zbx_vector_str_destroy(&hv->ds_names);
1683
1684 zbx_vector_ptr_clear_ext(&hv->vms, (zbx_clean_func_t)vmware_vm_free);
1685 zbx_vector_ptr_destroy(&hv->vms);
1686
1687 zbx_free(hv->uuid);
1688 zbx_free(hv->id);
1689 zbx_free(hv->clusterid);
1690 zbx_free(hv->datacenter_name);
1691 zbx_free(hv->parent_name);
1692 zbx_free(hv->parent_type);
1693 vmware_props_free(hv->props, ZBX_VMWARE_HVPROPS_NUM);
1694 }
1695
1696 /******************************************************************************
1697 * *
1698 * Function: vmware_cluster_free *
1699 * *
1700 * Purpose: frees resources allocated to store vmware cluster *
1701 * *
1702 * Parameters: cluster - [IN] the vmware cluster *
1703 * *
1704 ******************************************************************************/
vmware_cluster_free(zbx_vmware_cluster_t * cluster)1705 static void vmware_cluster_free(zbx_vmware_cluster_t *cluster)
1706 {
1707 zbx_free(cluster->name);
1708 zbx_free(cluster->id);
1709 zbx_free(cluster->status);
1710 zbx_free(cluster);
1711 }
1712
1713 /******************************************************************************
1714 * *
1715 * Function: vmware_event_free *
1716 * *
1717 * Purpose: frees resources allocated to store vmware event *
1718 * *
1719 * Parameters: event - [IN] the vmware event *
1720 * *
1721 ******************************************************************************/
vmware_event_free(zbx_vmware_event_t * event)1722 static void vmware_event_free(zbx_vmware_event_t *event)
1723 {
1724 evt_msg_strpool_strfree(event->message);
1725 zbx_free(event);
1726 }
1727
1728 /******************************************************************************
1729 * *
1730 * Function: vmware_data_free *
1731 * *
1732 * Purpose: frees resources allocated to store vmware service data *
1733 * *
1734 * Parameters: data - [IN] the vmware service data *
1735 * *
1736 ******************************************************************************/
vmware_data_free(zbx_vmware_data_t * data)1737 static void vmware_data_free(zbx_vmware_data_t *data)
1738 {
1739 zbx_hashset_iter_t iter;
1740 zbx_vmware_hv_t *hv;
1741
1742 zbx_hashset_iter_reset(&data->hvs, &iter);
1743 while (NULL != (hv = (zbx_vmware_hv_t *)zbx_hashset_iter_next(&iter)))
1744 vmware_hv_clean(hv);
1745
1746 zbx_hashset_destroy(&data->hvs);
1747
1748 zbx_vector_ptr_clear_ext(&data->clusters, (zbx_clean_func_t)vmware_cluster_free);
1749 zbx_vector_ptr_destroy(&data->clusters);
1750
1751 zbx_vector_ptr_clear_ext(&data->events, (zbx_clean_func_t)vmware_event_free);
1752 zbx_vector_ptr_destroy(&data->events);
1753
1754 zbx_vector_vmware_datastore_clear_ext(&data->datastores, vmware_datastore_free);
1755 zbx_vector_vmware_datastore_destroy(&data->datastores);
1756
1757 zbx_vector_vmware_datacenter_clear_ext(&data->datacenters, vmware_datacenter_free);
1758 zbx_vector_vmware_datacenter_destroy(&data->datacenters);
1759
1760 zbx_free(data->error);
1761 zbx_free(data);
1762 }
1763
1764 /******************************************************************************
1765 * *
1766 * Function: vmware_counter_free *
1767 * *
1768 * Purpose: frees vmware performance counter and the resources allocated by *
1769 * it *
1770 * *
1771 * Parameters: counter - [IN] the performance counter to free *
1772 * *
1773 ******************************************************************************/
vmware_counter_free(zbx_vmware_counter_t * counter)1774 static void vmware_counter_free(zbx_vmware_counter_t *counter)
1775 {
1776 zbx_free(counter->path);
1777 zbx_free(counter);
1778 }
1779
1780 /******************************************************************************
1781 * *
1782 * Function: vmware_service_authenticate *
1783 * *
1784 * Purpose: authenticates vmware service *
1785 * *
1786 * Parameters: service - [IN] the vmware service *
1787 * easyhandle - [IN] the CURL handle *
1788 * page - [IN] the CURL output buffer *
1789 * error - [OUT] the error message in the case of failure *
1790 * *
1791 * Return value: SUCCEED - the authentication was completed successfully *
1792 * FAIL - the authentication process has failed *
1793 * *
1794 * Comments: If service type is unknown this function will attempt to *
1795 * determine the right service type by trying to login with vCenter *
1796 * and vSphere session managers. *
1797 * *
1798 ******************************************************************************/
vmware_service_authenticate(zbx_vmware_service_t * service,CURL * easyhandle,ZBX_HTTPPAGE * page,char ** error)1799 static int vmware_service_authenticate(zbx_vmware_service_t *service, CURL *easyhandle, ZBX_HTTPPAGE *page,
1800 char **error)
1801 {
1802 # define ZBX_POST_VMWARE_AUTH \
1803 ZBX_POST_VSPHERE_HEADER \
1804 "<ns0:Login xsi:type=\"ns0:LoginRequestType\">" \
1805 "<ns0:_this type=\"SessionManager\">%s</ns0:_this>" \
1806 "<ns0:userName>%s</ns0:userName>" \
1807 "<ns0:password>%s</ns0:password>" \
1808 "</ns0:Login>" \
1809 ZBX_POST_VSPHERE_FOOTER
1810
1811 char xml[MAX_STRING_LEN], *error_object = NULL, *username_esc = NULL, *password_esc = NULL;
1812 CURLoption opt;
1813 CURLcode err;
1814 xmlDoc *doc = NULL;
1815 int ret = FAIL;
1816
1817 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, service->username, service->url);
1818
1819 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_COOKIEFILE, "")) ||
1820 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_FOLLOWLOCATION, 1L)) ||
1821 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_WRITEFUNCTION, curl_write_cb)) ||
1822 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_WRITEDATA, page)) ||
1823 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_PRIVATE, page)) ||
1824 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HEADERFUNCTION, curl_header_cb)) ||
1825 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYPEER, 0L)) ||
1826 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST, 1L)) ||
1827 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, service->url)) ||
1828 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_TIMEOUT,
1829 (long)CONFIG_VMWARE_TIMEOUT)) ||
1830 CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYHOST, 0L)))
1831 {
1832 *error = zbx_dsprintf(*error, "Cannot set cURL option %d: %s.", (int)opt, curl_easy_strerror(err));
1833 goto out;
1834 }
1835
1836 if (NULL != CONFIG_SOURCE_IP)
1837 {
1838 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_INTERFACE, CONFIG_SOURCE_IP)))
1839 {
1840 *error = zbx_dsprintf(*error, "Cannot set cURL option %d: %s.", (int)opt,
1841 curl_easy_strerror(err));
1842 goto out;
1843 }
1844 }
1845
1846 username_esc = xml_escape_dyn(service->username);
1847 password_esc = xml_escape_dyn(service->password);
1848
1849 if (ZBX_VMWARE_TYPE_UNKNOWN == service->type)
1850 {
1851 /* try to detect the service type first using vCenter service manager object */
1852 zbx_snprintf(xml, sizeof(xml), ZBX_POST_VMWARE_AUTH,
1853 vmware_service_objects[ZBX_VMWARE_TYPE_VCENTER].session_manager,
1854 username_esc, password_esc);
1855
1856 if (SUCCEED != zbx_soap_post(__func__, easyhandle, xml, &doc, error) && NULL == doc)
1857 goto out;
1858
1859 if (NULL == *error)
1860 {
1861 /* Successfully authenticated with vcenter service manager. */
1862 /* Set the service type and return with success. */
1863 service->type = ZBX_VMWARE_TYPE_VCENTER;
1864 ret = SUCCEED;
1865 goto out;
1866 }
1867
1868 /* If the wrong service manager was used, set the service type as vsphere and */
1869 /* try again with vsphere service manager. Otherwise return with failure. */
1870 if (NULL == (error_object = zbx_xml_read_doc_value(doc,
1871 ZBX_XPATH_LN3("detail", "NotAuthenticatedFault", "object"))))
1872 {
1873 goto out;
1874 }
1875
1876 if (0 != strcmp(error_object, vmware_service_objects[ZBX_VMWARE_TYPE_VCENTER].session_manager))
1877 goto out;
1878
1879 service->type = ZBX_VMWARE_TYPE_VSPHERE;
1880 zbx_free(*error);
1881 }
1882
1883 zbx_snprintf(xml, sizeof(xml), ZBX_POST_VMWARE_AUTH, vmware_service_objects[service->type].session_manager,
1884 username_esc, password_esc);
1885
1886 if (SUCCEED != zbx_soap_post(__func__, easyhandle, xml, NULL, error))
1887 goto out;
1888
1889 ret = SUCCEED;
1890 out:
1891 zbx_free(error_object);
1892 zbx_free(username_esc);
1893 zbx_free(password_esc);
1894 zbx_xml_free_doc(doc);
1895
1896 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1897
1898 return ret;
1899 }
1900
1901 /******************************************************************************
1902 * *
1903 * Function: vmware_service_logout *
1904 * *
1905 * Purpose: Close unused connection with vCenter *
1906 * *
1907 * Parameters: service - [IN] the vmware service *
1908 * easyhandle - [IN] the CURL handle *
1909 * error - [OUT] the error message in the case of failure *
1910 * *
1911 ******************************************************************************/
vmware_service_logout(zbx_vmware_service_t * service,CURL * easyhandle,char ** error)1912 static int vmware_service_logout(zbx_vmware_service_t *service, CURL *easyhandle, char **error)
1913 {
1914 # define ZBX_POST_VMWARE_LOGOUT \
1915 ZBX_POST_VSPHERE_HEADER \
1916 "<ns0:Logout>" \
1917 "<ns0:_this type=\"SessionManager\">%s</ns0:_this>" \
1918 "</ns0:Logout>" \
1919 ZBX_POST_VSPHERE_FOOTER
1920
1921 char tmp[MAX_STRING_LEN];
1922
1923 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_LOGOUT, vmware_service_objects[service->type].session_manager);
1924 return zbx_soap_post(__func__, easyhandle, tmp, NULL, error);
1925 }
1926
1927 typedef struct
1928 {
1929 const char *property_collector;
1930 CURL *easyhandle;
1931 char *token;
1932 }
1933 zbx_property_collection_iter;
1934
zbx_property_collection_init(CURL * easyhandle,const char * property_collection_query,const char * property_collector,zbx_property_collection_iter ** iter,xmlDoc ** xdoc,char ** error)1935 static int zbx_property_collection_init(CURL *easyhandle, const char *property_collection_query,
1936 const char *property_collector, zbx_property_collection_iter **iter, xmlDoc **xdoc, char **error)
1937 {
1938 # define ZBX_XPATH_RETRIEVE_PROPERTIES_TOKEN \
1939 "/*[local-name()='Envelope']/*[local-name()='Body']" \
1940 "/*[local-name()='RetrievePropertiesExResponse']" \
1941 "/*[local-name()='returnval']/*[local-name()='token']"
1942
1943 *iter = (zbx_property_collection_iter *)zbx_malloc(*iter, sizeof(zbx_property_collection_iter));
1944 (*iter)->property_collector = property_collector;
1945 (*iter)->easyhandle = easyhandle;
1946 (*iter)->token = NULL;
1947
1948 if (SUCCEED != zbx_soap_post("zbx_property_collection_init", (*iter)->easyhandle, property_collection_query, xdoc, error))
1949 return FAIL;
1950
1951 (*iter)->token = zbx_xml_read_doc_value(*xdoc, ZBX_XPATH_RETRIEVE_PROPERTIES_TOKEN);
1952
1953 return SUCCEED;
1954 }
1955
zbx_property_collection_next(zbx_property_collection_iter * iter,xmlDoc ** xdoc,char ** error)1956 static int zbx_property_collection_next(zbx_property_collection_iter *iter, xmlDoc **xdoc, char **error)
1957 {
1958 # define ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES \
1959 ZBX_POST_VSPHERE_HEADER \
1960 "<ns0:ContinueRetrievePropertiesEx xsi:type=\"ns0:ContinueRetrievePropertiesExRequestType\">" \
1961 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
1962 "<ns0:token>%s</ns0:token>" \
1963 "</ns0:ContinueRetrievePropertiesEx>" \
1964 ZBX_POST_VSPHERE_FOOTER
1965
1966 # define ZBX_XPATH_CONTINUE_RETRIEVE_PROPERTIES_TOKEN \
1967 "/*[local-name()='Envelope']/*[local-name()='Body']" \
1968 "/*[local-name()='ContinueRetrievePropertiesExResponse']" \
1969 "/*[local-name()='returnval']/*[local-name()='token']"
1970
1971 char *token_esc, post[MAX_STRING_LEN];
1972
1973 zabbix_log(LOG_LEVEL_DEBUG, "%s() continue retrieving properties with token: '%s'", __func__,
1974 iter->token);
1975
1976 token_esc = xml_escape_dyn(iter->token);
1977 zbx_snprintf(post, sizeof(post), ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES, iter->property_collector, token_esc);
1978 zbx_free(token_esc);
1979
1980 if (SUCCEED != zbx_soap_post(__func__, iter->easyhandle, post, xdoc, error))
1981 return FAIL;
1982
1983 zbx_free(iter->token);
1984 iter->token = zbx_xml_read_doc_value(*xdoc, ZBX_XPATH_CONTINUE_RETRIEVE_PROPERTIES_TOKEN);
1985
1986 return SUCCEED;
1987 }
1988
zbx_property_collection_free(zbx_property_collection_iter * iter)1989 static void zbx_property_collection_free(zbx_property_collection_iter *iter)
1990 {
1991 if (NULL != iter)
1992 {
1993 zbx_free(iter->token);
1994 zbx_free(iter);
1995 }
1996 }
1997
1998 /******************************************************************************
1999 * *
2000 * Function: vmware_service_get_contents *
2001 * *
2002 * Purpose: retrieves vmware service instance contents *
2003 * *
2004 * Parameters: easyhandle - [IN] the CURL handle *
2005 * version - [OUT] the version of the instance *
2006 * fullname - [OUT] the fullname of the instance *
2007 * error - [OUT] the error message in the case of failure *
2008 * *
2009 * Return value: SUCCEED - the contents were retrieved successfully *
2010 * FAIL - the content retrieval failed *
2011 * *
2012 ******************************************************************************/
vmware_service_get_contents(CURL * easyhandle,char ** version,char ** fullname,char ** error)2013 static int vmware_service_get_contents(CURL *easyhandle, char **version, char **fullname, char **error)
2014 {
2015 # define ZBX_POST_VMWARE_CONTENTS \
2016 ZBX_POST_VSPHERE_HEADER \
2017 "<ns0:RetrieveServiceContent>" \
2018 "<ns0:_this type=\"ServiceInstance\">ServiceInstance</ns0:_this>" \
2019 "</ns0:RetrieveServiceContent>" \
2020 ZBX_POST_VSPHERE_FOOTER
2021
2022 xmlDoc *doc = NULL;
2023
2024 if (SUCCEED != zbx_soap_post(__func__, easyhandle, ZBX_POST_VMWARE_CONTENTS, &doc, error))
2025 {
2026 zbx_xml_free_doc(doc);
2027 return FAIL;
2028 }
2029
2030 *version = zbx_xml_read_doc_value(doc, ZBX_XPATH_VMWARE_ABOUT("version"));
2031 *fullname = zbx_xml_read_doc_value(doc, ZBX_XPATH_VMWARE_ABOUT("fullName"));
2032 zbx_xml_free_doc(doc);
2033
2034 return SUCCEED;
2035
2036 # undef ZBX_POST_VMWARE_CONTENTS
2037 }
2038
2039 /******************************************************************************
2040 * *
2041 * Function: vmware_service_get_perf_counter_refreshrate *
2042 * *
2043 * Purpose: get the performance counter refreshrate for the specified entity *
2044 * *
2045 * Parameters: service - [IN] the vmware service *
2046 * easyhandle - [IN] the CURL handle *
2047 * type - [IN] the entity type (HostSystem, Datastore or *
2048 * VirtualMachine) *
2049 * id - [IN] the entity id *
2050 * refresh_rate - [OUT] a pointer to variable to store the *
2051 * regresh rate *
2052 * error - [OUT] the error message in the case of failure *
2053 * *
2054 * Return value: SUCCEED - the authentication was completed successfully *
2055 * FAIL - the authentication process has failed *
2056 * *
2057 ******************************************************************************/
vmware_service_get_perf_counter_refreshrate(zbx_vmware_service_t * service,CURL * easyhandle,const char * type,const char * id,int * refresh_rate,char ** error)2058 static int vmware_service_get_perf_counter_refreshrate(zbx_vmware_service_t *service, CURL *easyhandle,
2059 const char *type, const char *id, int *refresh_rate, char **error)
2060 {
2061 # define ZBX_POST_VCENTER_PERF_COUNTERS_REFRESH_RATE \
2062 ZBX_POST_VSPHERE_HEADER \
2063 "<ns0:QueryPerfProviderSummary>" \
2064 "<ns0:_this type=\"PerformanceManager\">%s</ns0:_this>" \
2065 "<ns0:entity type=\"%s\">%s</ns0:entity>" \
2066 "</ns0:QueryPerfProviderSummary>" \
2067 ZBX_POST_VSPHERE_FOOTER
2068
2069 char tmp[MAX_STRING_LEN], *value = NULL, *id_esc;
2070 int ret = FAIL;
2071 xmlDoc *doc = NULL;
2072
2073
2074 zabbix_log(LOG_LEVEL_DEBUG, "In %s() type: %s id: %s", __func__, type, id);
2075
2076 id_esc = xml_escape_dyn(id);
2077 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VCENTER_PERF_COUNTERS_REFRESH_RATE,
2078 vmware_service_objects[service->type].performance_manager, type, id_esc);
2079 zbx_free(id_esc);
2080
2081 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
2082 goto out;
2083
2084 if (NULL != (value = zbx_xml_read_doc_value(doc, ZBX_XPATH_ISAGGREGATE())))
2085 {
2086 zbx_free(value);
2087 *refresh_rate = ZBX_VMWARE_PERF_INTERVAL_NONE;
2088 ret = SUCCEED;
2089
2090 zabbix_log(LOG_LEVEL_DEBUG, "%s() refresh_rate: unused", __func__);
2091 goto out;
2092 }
2093 else if (NULL == (value = zbx_xml_read_doc_value(doc, ZBX_XPATH_REFRESHRATE())))
2094 {
2095 *error = zbx_strdup(*error, "Cannot find refreshRate.");
2096 goto out;
2097 }
2098
2099 zabbix_log(LOG_LEVEL_DEBUG, "%s() refresh_rate:%s", __func__, value);
2100
2101 if (SUCCEED != (ret = is_uint31(value, refresh_rate)))
2102 *error = zbx_dsprintf(*error, "Cannot convert refreshRate from %s.", value);
2103
2104 zbx_free(value);
2105 out:
2106 zbx_xml_free_doc(doc);
2107 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2108
2109 return ret;
2110 }
2111
2112 /******************************************************************************
2113 * *
2114 * Function: vmware_service_get_perf_counters *
2115 * *
2116 * Purpose: get the performance counter ids *
2117 * *
2118 * Parameters: service - [IN] the vmware service *
2119 * easyhandle - [IN] the CURL handle *
2120 * counters - [IN/OUT] the vector the created performance *
2121 * counter object should be added to *
2122 * error - [OUT] the error message in the case of failure *
2123 * *
2124 * Return value: SUCCEED - the operation has completed successfully *
2125 * FAIL - the operation has failed *
2126 * *
2127 ******************************************************************************/
vmware_service_get_perf_counters(zbx_vmware_service_t * service,CURL * easyhandle,zbx_vector_ptr_t * counters,char ** error)2128 static int vmware_service_get_perf_counters(zbx_vmware_service_t *service, CURL *easyhandle,
2129 zbx_vector_ptr_t *counters, char **error)
2130 {
2131 # define ZBX_POST_VMWARE_GET_PERFCOUNTER \
2132 ZBX_POST_VSPHERE_HEADER \
2133 "<ns0:RetrievePropertiesEx>" \
2134 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
2135 "<ns0:specSet>" \
2136 "<ns0:propSet>" \
2137 "<ns0:type>PerformanceManager</ns0:type>" \
2138 "<ns0:pathSet>perfCounter</ns0:pathSet>" \
2139 "</ns0:propSet>" \
2140 "<ns0:objectSet>" \
2141 "<ns0:obj type=\"PerformanceManager\">%s</ns0:obj>" \
2142 "</ns0:objectSet>" \
2143 "</ns0:specSet>" \
2144 "<ns0:options/>" \
2145 "</ns0:RetrievePropertiesEx>" \
2146 ZBX_POST_VSPHERE_FOOTER
2147
2148 char tmp[MAX_STRING_LEN], *group = NULL, *key = NULL, *rollup = NULL, *stats = NULL,
2149 *counterid = NULL;
2150 xmlDoc *doc = NULL;
2151 xmlXPathContext *xpathCtx;
2152 xmlXPathObject *xpathObj;
2153 xmlNodeSetPtr nodeset;
2154 int i, ret = FAIL;
2155
2156 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2157
2158 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_GET_PERFCOUNTER,
2159 vmware_service_objects[service->type].property_collector,
2160 vmware_service_objects[service->type].performance_manager);
2161
2162 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
2163 goto out;
2164
2165 xpathCtx = xmlXPathNewContext(doc);
2166
2167 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)ZBX_XPATH_COUNTERINFO(), xpathCtx)))
2168 {
2169 *error = zbx_strdup(*error, "Cannot make performance counter list parsing query.");
2170 goto clean;
2171 }
2172
2173 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
2174 {
2175 *error = zbx_strdup(*error, "Cannot find items in performance counter list.");
2176 goto clean;
2177 }
2178
2179 nodeset = xpathObj->nodesetval;
2180 zbx_vector_ptr_reserve(counters, 2 * nodeset->nodeNr + counters->values_alloc);
2181
2182 for (i = 0; i < nodeset->nodeNr; i++)
2183 {
2184 zbx_vmware_counter_t *counter;
2185
2186 group = zbx_xml_read_node_value(doc, nodeset->nodeTab[i],
2187 "*[local-name()='groupInfo']/*[local-name()='key']");
2188
2189 key = zbx_xml_read_node_value(doc, nodeset->nodeTab[i],
2190 "*[local-name()='nameInfo']/*[local-name()='key']");
2191
2192 rollup = zbx_xml_read_node_value(doc, nodeset->nodeTab[i], "*[local-name()='rollupType']");
2193 stats = zbx_xml_read_node_value(doc, nodeset->nodeTab[i], "*[local-name()='statsType']");
2194 counterid = zbx_xml_read_node_value(doc, nodeset->nodeTab[i], "*[local-name()='key']");
2195
2196 if (NULL != group && NULL != key && NULL != rollup && NULL != counterid)
2197 {
2198 counter = (zbx_vmware_counter_t *)zbx_malloc(NULL, sizeof(zbx_vmware_counter_t));
2199 counter->path = zbx_dsprintf(NULL, "%s/%s[%s]", group, key, rollup);
2200 ZBX_STR2UINT64(counter->id, counterid);
2201
2202 zbx_vector_ptr_append(counters, counter);
2203
2204 zabbix_log(LOG_LEVEL_DEBUG, "adding performance counter %s:" ZBX_FS_UI64, counter->path,
2205 counter->id);
2206 }
2207
2208 if (NULL != group && NULL != key && NULL != rollup && NULL != counterid && NULL != stats)
2209 {
2210 counter = (zbx_vmware_counter_t *)zbx_malloc(NULL, sizeof(zbx_vmware_counter_t));
2211 counter->path = zbx_dsprintf(NULL, "%s/%s[%s,%s]", group, key, rollup, stats);
2212 ZBX_STR2UINT64(counter->id, counterid);
2213
2214 zbx_vector_ptr_append(counters, counter);
2215
2216 zabbix_log(LOG_LEVEL_DEBUG, "adding performance counter %s:" ZBX_FS_UI64, counter->path,
2217 counter->id);
2218 }
2219
2220 zbx_free(counterid);
2221 zbx_free(stats);
2222 zbx_free(rollup);
2223 zbx_free(key);
2224 zbx_free(group);
2225 }
2226
2227 ret = SUCCEED;
2228 clean:
2229 if (NULL != xpathObj)
2230 xmlXPathFreeObject(xpathObj);
2231
2232 xmlXPathFreeContext(xpathCtx);
2233 out:
2234 zbx_xml_free_doc(doc);
2235 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2236
2237 return ret;
2238 }
2239
2240 /******************************************************************************
2241 * *
2242 * Function: vmware_vm_get_nic_devices *
2243 * *
2244 * Purpose: gets virtual machine network interface devices *
2245 * *
2246 * Parameters: vm - [OUT] the virtual machine *
2247 * details - [IN] a xml document containing virtual machine data *
2248 * *
2249 * Comments: The network interface devices are taken from vm device list *
2250 * filtered by macAddress key. *
2251 * *
2252 ******************************************************************************/
vmware_vm_get_nic_devices(zbx_vmware_vm_t * vm,xmlDoc * details)2253 static void vmware_vm_get_nic_devices(zbx_vmware_vm_t *vm, xmlDoc *details)
2254 {
2255 xmlXPathContext *xpathCtx;
2256 xmlXPathObject *xpathObj;
2257 xmlNodeSetPtr nodeset;
2258 int i, nics = 0;
2259
2260 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2261
2262 xpathCtx = xmlXPathNewContext(details);
2263
2264 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)ZBX_XPATH_VM_HARDWARE("device")
2265 "[*[local-name()='macAddress']]", xpathCtx)))
2266 {
2267 goto clean;
2268 }
2269
2270 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
2271 goto clean;
2272
2273 nodeset = xpathObj->nodesetval;
2274 zbx_vector_ptr_reserve(&vm->devs, nodeset->nodeNr + vm->devs.values_alloc);
2275
2276 for (i = 0; i < nodeset->nodeNr; i++)
2277 {
2278 char *key;
2279 zbx_vmware_dev_t *dev;
2280
2281 if (NULL == (key = zbx_xml_read_node_value(details, nodeset->nodeTab[i], "*[local-name()='key']")))
2282 continue;
2283
2284 dev = (zbx_vmware_dev_t *)zbx_malloc(NULL, sizeof(zbx_vmware_dev_t));
2285 dev->type = ZBX_VMWARE_DEV_TYPE_NIC;
2286 dev->instance = key;
2287 dev->label = zbx_xml_read_node_value(details, nodeset->nodeTab[i],
2288 "*[local-name()='deviceInfo']/*[local-name()='label']");
2289
2290 zbx_vector_ptr_append(&vm->devs, dev);
2291 nics++;
2292 }
2293 clean:
2294 if (NULL != xpathObj)
2295 xmlXPathFreeObject(xpathObj);
2296
2297 xmlXPathFreeContext(xpathCtx);
2298 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() found:%d", __func__, nics);
2299 }
2300
2301 /******************************************************************************
2302 * *
2303 * Function: vmware_vm_get_disk_devices *
2304 * *
2305 * Purpose: gets virtual machine virtual disk devices *
2306 * *
2307 * Parameters: vm - [OUT] the virtual machine *
2308 * details - [IN] a xml document containing virtual machine data *
2309 * *
2310 ******************************************************************************/
vmware_vm_get_disk_devices(zbx_vmware_vm_t * vm,xmlDoc * details)2311 static void vmware_vm_get_disk_devices(zbx_vmware_vm_t *vm, xmlDoc *details)
2312 {
2313 xmlXPathContext *xpathCtx;
2314 xmlXPathObject *xpathObj;
2315 xmlNodeSetPtr nodeset;
2316 int i, disks = 0;
2317 char *xpath = NULL;
2318
2319 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2320
2321 xpathCtx = xmlXPathNewContext(details);
2322
2323 /* select all hardware devices of VirtualDisk type */
2324 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)ZBX_XPATH_VM_HARDWARE("device")
2325 "[string(@*[local-name()='type'])='VirtualDisk']", xpathCtx)))
2326 {
2327 goto clean;
2328 }
2329
2330 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
2331 goto clean;
2332
2333 nodeset = xpathObj->nodesetval;
2334 zbx_vector_ptr_reserve(&vm->devs, nodeset->nodeNr + vm->devs.values_alloc);
2335
2336 for (i = 0; i < nodeset->nodeNr; i++)
2337 {
2338 zbx_vmware_dev_t *dev;
2339 char *unitNumber = NULL, *controllerKey = NULL, *busNumber = NULL,
2340 *controllerLabel = NULL, *controllerType = NULL,
2341 *scsiCtlrUnitNumber = NULL;
2342 xmlXPathObject *xpathObjController = NULL;
2343
2344 do
2345 {
2346 if (NULL == (unitNumber = zbx_xml_read_node_value(details, nodeset->nodeTab[i],
2347 "*[local-name()='unitNumber']")))
2348 {
2349 break;
2350 }
2351
2352 if (NULL == (controllerKey = zbx_xml_read_node_value(details, nodeset->nodeTab[i],
2353 "*[local-name()='controllerKey']")))
2354 {
2355 break;
2356 }
2357
2358 /* find the controller (parent) device */
2359 xpath = zbx_dsprintf(xpath, ZBX_XPATH_VM_HARDWARE("device")
2360 "[*[local-name()='key']/text()='%s']", controllerKey);
2361
2362 if (NULL == (xpathObjController = xmlXPathEvalExpression((xmlChar *)xpath, xpathCtx)))
2363 break;
2364
2365 if (0 != xmlXPathNodeSetIsEmpty(xpathObjController->nodesetval))
2366 break;
2367
2368 if (NULL == (busNumber = zbx_xml_read_node_value(details,
2369 xpathObjController->nodesetval->nodeTab[0], "*[local-name()='busNumber']")))
2370 {
2371 break;
2372 }
2373
2374 /* scsiCtlrUnitNumber property is simply used to determine controller type. */
2375 /* For IDE controllers it is not set. */
2376 scsiCtlrUnitNumber = zbx_xml_read_node_value(details, xpathObjController->nodesetval->nodeTab[0],
2377 "*[local-name()='scsiCtlrUnitNumber']");
2378
2379 dev = (zbx_vmware_dev_t *)zbx_malloc(NULL, sizeof(zbx_vmware_dev_t));
2380 dev->type = ZBX_VMWARE_DEV_TYPE_DISK;
2381
2382 /* the virtual disk instance has format <controller type><busNumber>:<unitNumber> */
2383 /* where controller type is either ide, sata or scsi depending on the controller type */
2384
2385 dev->label = zbx_xml_read_node_value(details, nodeset->nodeTab[i],
2386 "*[local-name()='deviceInfo']/*[local-name()='label']");
2387
2388 controllerLabel = zbx_xml_read_node_value(details, xpathObjController->nodesetval->nodeTab[0],
2389 "*[local-name()='deviceInfo']/*[local-name()='label']");
2390
2391 if (NULL != scsiCtlrUnitNumber ||
2392 (NULL != controllerLabel && NULL != strstr(controllerLabel, "SCSI")))
2393 {
2394 controllerType = "scsi";
2395 }
2396 else if (NULL != controllerLabel && NULL != strstr(controllerLabel, "SATA"))
2397 {
2398 controllerType = "sata";
2399 }
2400 else
2401 {
2402 controllerType = "ide";
2403 }
2404
2405 dev->instance = zbx_dsprintf(NULL, "%s%s:%s", controllerType, busNumber, unitNumber);
2406 zbx_vector_ptr_append(&vm->devs, dev);
2407
2408 disks++;
2409
2410 }
2411 while (0);
2412
2413 if (NULL != xpathObjController)
2414 xmlXPathFreeObject(xpathObjController);
2415
2416 zbx_free(controllerLabel);
2417 zbx_free(scsiCtlrUnitNumber);
2418 zbx_free(busNumber);
2419 zbx_free(unitNumber);
2420 zbx_free(controllerKey);
2421
2422 }
2423 clean:
2424 zbx_free(xpath);
2425
2426 if (NULL != xpathObj)
2427 xmlXPathFreeObject(xpathObj);
2428
2429 xmlXPathFreeContext(xpathCtx);
2430 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() found:%d", __func__, disks);
2431 }
2432
2433 /******************************************************************************
2434 * *
2435 * Function: vmware_vm_get_file_systems *
2436 * *
2437 * Purpose: gets the parameters of virtual machine disks *
2438 * *
2439 * Parameters: vm - [OUT] the virtual machine *
2440 * details - [IN] a xml document containing virtual machine data *
2441 * *
2442 ******************************************************************************/
vmware_vm_get_file_systems(zbx_vmware_vm_t * vm,xmlDoc * details)2443 static void vmware_vm_get_file_systems(zbx_vmware_vm_t *vm, xmlDoc *details)
2444 {
2445 xmlXPathContext *xpathCtx;
2446 xmlXPathObject *xpathObj;
2447 xmlNodeSetPtr nodeset;
2448 int i;
2449
2450 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2451
2452 xpathCtx = xmlXPathNewContext(details);
2453
2454 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)ZBX_XPATH_VM_GUESTDISKS(), xpathCtx)))
2455 goto clean;
2456
2457 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
2458 goto clean;
2459
2460 nodeset = xpathObj->nodesetval;
2461 zbx_vector_ptr_reserve(&vm->file_systems, nodeset->nodeNr + vm->file_systems.values_alloc);
2462
2463 for (i = 0; i < nodeset->nodeNr; i++)
2464 {
2465 zbx_vmware_fs_t *fs;
2466 char *value;
2467
2468 if (NULL == (value = zbx_xml_read_node_value(details, nodeset->nodeTab[i], "*[local-name()='diskPath']")))
2469 continue;
2470
2471 fs = (zbx_vmware_fs_t *)zbx_malloc(NULL, sizeof(zbx_vmware_fs_t));
2472 memset(fs, 0, sizeof(zbx_vmware_fs_t));
2473
2474 fs->path = value;
2475
2476 if (NULL != (value = zbx_xml_read_node_value(details, nodeset->nodeTab[i], "*[local-name()='capacity']")))
2477 {
2478 ZBX_STR2UINT64(fs->capacity, value);
2479 zbx_free(value);
2480 }
2481
2482 if (NULL != (value = zbx_xml_read_node_value(details, nodeset->nodeTab[i], "*[local-name()='freeSpace']")))
2483 {
2484 ZBX_STR2UINT64(fs->free_space, value);
2485 zbx_free(value);
2486 }
2487
2488 zbx_vector_ptr_append(&vm->file_systems, fs);
2489 }
2490 clean:
2491 if (NULL != xpathObj)
2492 xmlXPathFreeObject(xpathObj);
2493
2494 xmlXPathFreeContext(xpathCtx);
2495 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() found:%d", __func__, vm->file_systems.values_num);
2496 }
2497
2498 /******************************************************************************
2499 * *
2500 * Function: vmware_service_get_vm_data *
2501 * *
2502 * Purpose: gets the virtual machine data *
2503 * *
2504 * Parameters: service - [IN] the vmware service *
2505 * easyhandle - [IN] the CURL handle *
2506 * vmid - [IN] the virtual machine id *
2507 * propmap - [IN] the xpaths of the properties to read *
2508 * props_num - [IN] the number of properties to read *
2509 * xdoc - [OUT] a reference to output xml document *
2510 * error - [OUT] the error message in the case of failure *
2511 * *
2512 * Return value: SUCCEED - the operation has completed successfully *
2513 * FAIL - the operation has failed *
2514 * *
2515 ******************************************************************************/
vmware_service_get_vm_data(zbx_vmware_service_t * service,CURL * easyhandle,const char * vmid,const zbx_vmware_propmap_t * propmap,int props_num,xmlDoc ** xdoc,char ** error)2516 static int vmware_service_get_vm_data(zbx_vmware_service_t *service, CURL *easyhandle, const char *vmid,
2517 const zbx_vmware_propmap_t *propmap, int props_num, xmlDoc **xdoc, char **error)
2518 {
2519 # define ZBX_POST_VMWARE_VM_STATUS_EX \
2520 ZBX_POST_VSPHERE_HEADER \
2521 "<ns0:RetrievePropertiesEx>" \
2522 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
2523 "<ns0:specSet>" \
2524 "<ns0:propSet>" \
2525 "<ns0:type>VirtualMachine</ns0:type>" \
2526 "<ns0:pathSet>config.hardware</ns0:pathSet>" \
2527 "<ns0:pathSet>config.uuid</ns0:pathSet>" \
2528 "<ns0:pathSet>config.instanceUuid</ns0:pathSet>"\
2529 "<ns0:pathSet>guest.disk</ns0:pathSet>" \
2530 "%s" \
2531 "</ns0:propSet>" \
2532 "<ns0:objectSet>" \
2533 "<ns0:obj type=\"VirtualMachine\">%s</ns0:obj>" \
2534 "</ns0:objectSet>" \
2535 "</ns0:specSet>" \
2536 "<ns0:options/>" \
2537 "</ns0:RetrievePropertiesEx>" \
2538 ZBX_POST_VSPHERE_FOOTER
2539
2540 char tmp[MAX_STRING_LEN], props[MAX_STRING_LEN], *vmid_esc;
2541 int i, ret = FAIL;
2542
2543 zabbix_log(LOG_LEVEL_DEBUG, "In %s() vmid:'%s'", __func__, vmid);
2544 props[0] = '\0';
2545
2546 for (i = 0; i < props_num; i++)
2547 {
2548 zbx_strlcat(props, "<ns0:pathSet>", sizeof(props));
2549 zbx_strlcat(props, propmap[i].name, sizeof(props));
2550 zbx_strlcat(props, "</ns0:pathSet>", sizeof(props));
2551 }
2552
2553 vmid_esc = xml_escape_dyn(vmid);
2554
2555 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_VM_STATUS_EX,
2556 vmware_service_objects[service->type].property_collector, props, vmid_esc);
2557
2558 zbx_free(vmid_esc);
2559
2560 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, xdoc, error))
2561 goto out;
2562
2563 ret = SUCCEED;
2564 out:
2565 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2566
2567 return ret;
2568 }
2569
2570 /******************************************************************************
2571 * *
2572 * Function: vmware_service_create_vm *
2573 * *
2574 * Purpose: create virtual machine object *
2575 * *
2576 * Parameters: service - [IN] the vmware service *
2577 * easyhandle - [IN] the CURL handle *
2578 * id - [IN] the virtual machine id *
2579 * error - [OUT] the error message in the case of failure *
2580 * *
2581 * Return value: The created virtual machine object or NULL if an error was *
2582 * detected. *
2583 * *
2584 ******************************************************************************/
vmware_service_create_vm(zbx_vmware_service_t * service,CURL * easyhandle,const char * id,char ** error)2585 static zbx_vmware_vm_t *vmware_service_create_vm(zbx_vmware_service_t *service, CURL *easyhandle,
2586 const char *id, char **error)
2587 {
2588 zbx_vmware_vm_t *vm;
2589 char *value;
2590 xmlDoc *details = NULL;
2591 const char *uuid_xpath[3] = {NULL, ZBX_XPATH_VM_UUID(), ZBX_XPATH_VM_INSTANCE_UUID()};
2592 int ret = FAIL;
2593
2594 zabbix_log(LOG_LEVEL_DEBUG, "In %s() vmid:'%s'", __func__, id);
2595
2596 vm = (zbx_vmware_vm_t *)zbx_malloc(NULL, sizeof(zbx_vmware_vm_t));
2597 memset(vm, 0, sizeof(zbx_vmware_vm_t));
2598
2599 zbx_vector_ptr_create(&vm->devs);
2600 zbx_vector_ptr_create(&vm->file_systems);
2601
2602 if (SUCCEED != vmware_service_get_vm_data(service, easyhandle, id, vm_propmap,
2603 ZBX_VMWARE_VMPROPS_NUM, &details, error))
2604 {
2605 goto out;
2606 }
2607
2608 if (NULL == (value = zbx_xml_read_doc_value(details, uuid_xpath[service->type])))
2609 goto out;
2610
2611 vm->uuid = value;
2612 vm->id = zbx_strdup(NULL, id);
2613
2614 if (NULL == (vm->props = xml_read_props(details, vm_propmap, ZBX_VMWARE_VMPROPS_NUM)))
2615 goto out;
2616
2617 vmware_vm_get_nic_devices(vm, details);
2618 vmware_vm_get_disk_devices(vm, details);
2619 vmware_vm_get_file_systems(vm, details);
2620
2621 ret = SUCCEED;
2622 out:
2623 zbx_xml_free_doc(details);
2624
2625 if (SUCCEED != ret)
2626 {
2627 vmware_vm_free(vm);
2628 vm = NULL;
2629 }
2630
2631 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2632
2633 return vm;
2634 }
2635
2636 /******************************************************************************
2637 * *
2638 * Function: vmware_service_refresh_datastore_info *
2639 * *
2640 * Purpose: Refreshes all storage related information including free-space, *
2641 * capacity, and detailed usage of virtual machines. *
2642 * *
2643 * Parameters: easyhandle - [IN] the CURL handle *
2644 * id - [IN] the datastore id *
2645 * error - [OUT] the error message in the case of failure *
2646 * *
2647 * Comments: This is required for ESX/ESXi hosts version < 6.0 only *
2648 * *
2649 ******************************************************************************/
vmware_service_refresh_datastore_info(CURL * easyhandle,const char * id,char ** error)2650 static int vmware_service_refresh_datastore_info(CURL *easyhandle, const char *id, char **error)
2651 {
2652 # define ZBX_POST_REFRESH_DATASTORE \
2653 ZBX_POST_VSPHERE_HEADER \
2654 "<ns0:RefreshDatastoreStorageInfo>" \
2655 "<ns0:_this type=\"Datastore\">%s</ns0:_this>" \
2656 "</ns0:RefreshDatastoreStorageInfo>" \
2657 ZBX_POST_VSPHERE_FOOTER
2658
2659 char tmp[MAX_STRING_LEN];
2660 int ret = FAIL;
2661
2662 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_REFRESH_DATASTORE, id);
2663 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, NULL, error))
2664 goto out;
2665
2666 ret = SUCCEED;
2667 out:
2668 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2669
2670 return ret;
2671 }
2672
2673 /******************************************************************************
2674 * *
2675 * Function: vmware_service_create_datastore *
2676 * *
2677 * Purpose: create vmware hypervisor datastore object *
2678 * *
2679 * Parameters: service - [IN] the vmware service *
2680 * easyhandle - [IN] the CURL handle *
2681 * id - [IN] the datastore id *
2682 * *
2683 * Return value: The created datastore object or NULL if an error was *
2684 * detected *
2685 * *
2686 ******************************************************************************/
vmware_service_create_datastore(const zbx_vmware_service_t * service,CURL * easyhandle,const char * id)2687 static zbx_vmware_datastore_t *vmware_service_create_datastore(const zbx_vmware_service_t *service, CURL *easyhandle,
2688 const char *id)
2689 {
2690 # define ZBX_POST_DATASTORE_GET \
2691 ZBX_POST_VSPHERE_HEADER \
2692 "<ns0:RetrievePropertiesEx>" \
2693 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
2694 "<ns0:specSet>" \
2695 "<ns0:propSet>" \
2696 "<ns0:type>Datastore</ns0:type>" \
2697 "<ns0:pathSet>summary</ns0:pathSet>" \
2698 "<ns0:pathSet>host</ns0:pathSet>" \
2699 "</ns0:propSet>" \
2700 "<ns0:objectSet>" \
2701 "<ns0:obj type=\"Datastore\">%s</ns0:obj>" \
2702 "</ns0:objectSet>" \
2703 "</ns0:specSet>" \
2704 "<ns0:options/>" \
2705 "</ns0:RetrievePropertiesEx>" \
2706 ZBX_POST_VSPHERE_FOOTER
2707
2708 char tmp[MAX_STRING_LEN], *uuid = NULL, *name = NULL, *path, *id_esc, *value, *error = NULL;
2709 zbx_vmware_datastore_t *datastore = NULL;
2710 zbx_uint64_t capacity = ZBX_MAX_UINT64, free_space = ZBX_MAX_UINT64, uncommitted = ZBX_MAX_UINT64;
2711 xmlDoc *doc = NULL;
2712
2713 zabbix_log(LOG_LEVEL_DEBUG, "In %s() datastore:'%s'", __func__, id);
2714
2715 id_esc = xml_escape_dyn(id);
2716
2717 if (ZBX_VMWARE_TYPE_VSPHERE == service->type && NULL != service->version &&
2718 ZBX_VMWARE_DS_REFRESH_VERSION > service->major_version && SUCCEED !=
2719 vmware_service_refresh_datastore_info(easyhandle, id_esc, &error))
2720 {
2721 zbx_free(id_esc);
2722 goto out;
2723 }
2724
2725 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_DATASTORE_GET,
2726 vmware_service_objects[service->type].property_collector, id_esc);
2727
2728 zbx_free(id_esc);
2729
2730 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, &error))
2731 goto out;
2732
2733 name = zbx_xml_read_doc_value(doc, ZBX_XPATH_DATASTORE_SUMMARY("name"));
2734
2735 if (NULL != (path = zbx_xml_read_doc_value(doc, ZBX_XPATH_DATASTORE_MOUNT())))
2736 {
2737 if ('\0' != *path)
2738 {
2739 size_t len;
2740 char *ptr;
2741
2742 len = strlen(path);
2743
2744 if ('/' == path[len - 1])
2745 path[len - 1] = '\0';
2746
2747 for (ptr = path + len - 2; ptr > path && *ptr != '/'; ptr--)
2748 ;
2749
2750 uuid = zbx_strdup(NULL, ptr + 1);
2751 }
2752 zbx_free(path);
2753 }
2754
2755 if (ZBX_VMWARE_TYPE_VSPHERE == service->type)
2756 {
2757 if (NULL != (value = zbx_xml_read_doc_value(doc, ZBX_XPATH_DATASTORE_SUMMARY("capacity"))))
2758 {
2759 is_uint64(value, &capacity);
2760 zbx_free(value);
2761 }
2762
2763 if (NULL != (value = zbx_xml_read_doc_value(doc, ZBX_XPATH_DATASTORE_SUMMARY("freeSpace"))))
2764 {
2765 is_uint64(value, &free_space);
2766 zbx_free(value);
2767 }
2768
2769 if (NULL != (value = zbx_xml_read_doc_value(doc, ZBX_XPATH_DATASTORE_SUMMARY("uncommitted"))))
2770 {
2771 is_uint64(value, &uncommitted);
2772 zbx_free(value);
2773 }
2774 }
2775
2776 datastore = (zbx_vmware_datastore_t *)zbx_malloc(NULL, sizeof(zbx_vmware_datastore_t));
2777 datastore->name = (NULL != name) ? name : zbx_strdup(NULL, id);
2778 datastore->uuid = uuid;
2779 datastore->id = zbx_strdup(NULL, id);
2780 datastore->capacity = capacity;
2781 datastore->free_space = free_space;
2782 datastore->uncommitted = uncommitted;
2783 zbx_vector_str_uint64_pair_create(&datastore->hv_uuids_access);
2784 out:
2785 zbx_xml_free_doc(doc);
2786
2787 if (NULL != error)
2788 {
2789 zabbix_log(LOG_LEVEL_WARNING, "Cannot get Datastore info: %s.", error);
2790 zbx_free(error);
2791 }
2792
2793 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
2794
2795 return datastore;
2796 }
2797
2798 /******************************************************************************
2799 * *
2800 * Function: vmware_service_get_hv_data *
2801 * *
2802 * Purpose: gets the vmware hypervisor data *
2803 * *
2804 * Parameters: service - [IN] the vmware service *
2805 * easyhandle - [IN] the CURL handle *
2806 * hvid - [IN] the vmware hypervisor id *
2807 * propmap - [IN] the xpaths of the properties to read *
2808 * props_num - [IN] the number of properties to read *
2809 * xdoc - [OUT] a reference to output xml document *
2810 * error - [OUT] the error message in the case of failure *
2811 * *
2812 * Return value: SUCCEED - the operation has completed successfully *
2813 * FAIL - the operation has failed *
2814 * *
2815 ******************************************************************************/
vmware_service_get_hv_data(const zbx_vmware_service_t * service,CURL * easyhandle,const char * hvid,const zbx_vmware_propmap_t * propmap,int props_num,xmlDoc ** xdoc,char ** error)2816 static int vmware_service_get_hv_data(const zbx_vmware_service_t *service, CURL *easyhandle, const char *hvid,
2817 const zbx_vmware_propmap_t *propmap, int props_num, xmlDoc **xdoc, char **error)
2818 {
2819 # define ZBX_POST_HV_DETAILS \
2820 ZBX_POST_VSPHERE_HEADER \
2821 "<ns0:RetrievePropertiesEx>" \
2822 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
2823 "<ns0:specSet>" \
2824 "<ns0:propSet>" \
2825 "<ns0:type>HostSystem</ns0:type>" \
2826 "<ns0:pathSet>vm</ns0:pathSet>" \
2827 "<ns0:pathSet>parent</ns0:pathSet>" \
2828 "<ns0:pathSet>datastore</ns0:pathSet>" \
2829 "%s" \
2830 "</ns0:propSet>" \
2831 "<ns0:propSet>" \
2832 "<ns0:type>Datastore</ns0:type>" \
2833 "<ns0:pathSet>host[\"%s\"].mountInfo.mounted</ns0:pathSet>" \
2834 "<ns0:pathSet>host[\"%s\"].mountInfo.accessible</ns0:pathSet>" \
2835 "<ns0:pathSet>host[\"%s\"].mountInfo.accessMode</ns0:pathSet>" \
2836 "</ns0:propSet>" \
2837 "<ns0:objectSet>" \
2838 "<ns0:obj type=\"HostSystem\">%s</ns0:obj>" \
2839 "<ns0:skip>false</ns0:skip>" \
2840 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
2841 "<ns0:name>DSObject</ns0:name>" \
2842 "<ns0:type>HostSystem</ns0:type>" \
2843 "<ns0:path>datastore</ns0:path>" \
2844 "<ns0:skip>false</ns0:skip>" \
2845 "</ns0:selectSet>" \
2846 "</ns0:objectSet>" \
2847 "</ns0:specSet>" \
2848 "<ns0:options/>" \
2849 "</ns0:RetrievePropertiesEx>" \
2850 ZBX_POST_VSPHERE_FOOTER
2851
2852 char tmp[MAX_STRING_LEN], props[MAX_STRING_LEN], *hvid_esc;
2853 int i, ret = FAIL;
2854
2855 zabbix_log(LOG_LEVEL_DEBUG, "In %s() guesthvid:'%s'", __func__, hvid);
2856 props[0] = '\0';
2857
2858 for (i = 0; i < props_num; i++)
2859 {
2860 zbx_strlcat(props, "<ns0:pathSet>", sizeof(props));
2861 zbx_strlcat(props, propmap[i].name, sizeof(props));
2862 zbx_strlcat(props, "</ns0:pathSet>", sizeof(props));
2863 }
2864
2865 hvid_esc = xml_escape_dyn(hvid);
2866
2867 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_HV_DETAILS, vmware_service_objects[service->type].property_collector,
2868 props, hvid_esc, hvid_esc, hvid_esc, hvid_esc);
2869
2870 zbx_free(hvid_esc);
2871
2872 zabbix_log(LOG_LEVEL_TRACE, "%s() SOAP request: %s", __func__, tmp);
2873
2874 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, xdoc, error))
2875 goto out;
2876
2877 ret = SUCCEED;
2878 out:
2879 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2880
2881 return ret;
2882 }
2883
2884 /******************************************************************************
2885 * *
2886 * Function: vmware_hv_get_parent_data *
2887 * *
2888 * Purpose: gets the vmware hypervisor datacenter, parent folder or cluster *
2889 * name *
2890 * *
2891 * Parameters: service - [IN] the vmware service *
2892 * easyhandle - [IN] the CURL handle *
2893 * hv - [IN/OUT] the vmware hypervisor *
2894 * error - [OUT] the error message in the case of failure *
2895 * *
2896 * Return value: SUCCEED - the operation has completed successfully *
2897 * FAIL - the operation has failed *
2898 * *
2899 ******************************************************************************/
vmware_hv_get_parent_data(const zbx_vmware_service_t * service,CURL * easyhandle,zbx_vmware_hv_t * hv,char ** error)2900 static int vmware_hv_get_parent_data(const zbx_vmware_service_t *service, CURL *easyhandle,
2901 zbx_vmware_hv_t *hv, char **error)
2902 {
2903 # define ZBX_POST_HV_DATACENTER_NAME \
2904 ZBX_POST_VSPHERE_HEADER \
2905 "<ns0:RetrievePropertiesEx>" \
2906 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
2907 "<ns0:specSet>" \
2908 "<ns0:propSet>" \
2909 "<ns0:type>Datacenter</ns0:type>" \
2910 "<ns0:pathSet>name</ns0:pathSet>" \
2911 "</ns0:propSet>" \
2912 "%s" \
2913 "<ns0:objectSet>" \
2914 "<ns0:obj type=\"HostSystem\">%s</ns0:obj>" \
2915 "<ns0:skip>false</ns0:skip>" \
2916 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
2917 "<ns0:name>parentObject</ns0:name>" \
2918 "<ns0:type>HostSystem</ns0:type>" \
2919 "<ns0:path>parent</ns0:path>" \
2920 "<ns0:skip>false</ns0:skip>" \
2921 "<ns0:selectSet>" \
2922 "<ns0:name>parentComputeResource</ns0:name>" \
2923 "</ns0:selectSet>" \
2924 "<ns0:selectSet>" \
2925 "<ns0:name>parentFolder</ns0:name>" \
2926 "</ns0:selectSet>" \
2927 "</ns0:selectSet>" \
2928 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
2929 "<ns0:name>parentComputeResource</ns0:name>" \
2930 "<ns0:type>ComputeResource</ns0:type>" \
2931 "<ns0:path>parent</ns0:path>" \
2932 "<ns0:skip>false</ns0:skip>" \
2933 "<ns0:selectSet>" \
2934 "<ns0:name>parentFolder</ns0:name>" \
2935 "</ns0:selectSet>" \
2936 "</ns0:selectSet>" \
2937 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
2938 "<ns0:name>parentFolder</ns0:name>" \
2939 "<ns0:type>Folder</ns0:type>" \
2940 "<ns0:path>parent</ns0:path>" \
2941 "<ns0:skip>false</ns0:skip>" \
2942 "<ns0:selectSet>" \
2943 "<ns0:name>parentFolder</ns0:name>" \
2944 "</ns0:selectSet>" \
2945 "<ns0:selectSet>" \
2946 "<ns0:name>parentComputeResource</ns0:name>" \
2947 "</ns0:selectSet>" \
2948 "</ns0:selectSet>" \
2949 "</ns0:objectSet>" \
2950 "</ns0:specSet>" \
2951 "<ns0:options/>" \
2952 "</ns0:RetrievePropertiesEx>" \
2953 ZBX_POST_VSPHERE_FOOTER
2954
2955 # define ZBX_POST_SOAP_FOLDER \
2956 "<ns0:propSet>" \
2957 "<ns0:type>Folder</ns0:type>" \
2958 "<ns0:pathSet>name</ns0:pathSet>" \
2959 "<ns0:pathSet>parent</ns0:pathSet>" \
2960 "<ns0:pathSet>childEntity</ns0:pathSet>" \
2961 "</ns0:propSet>" \
2962 "<ns0:propSet>" \
2963 "<ns0:type>HostSystem</ns0:type>" \
2964 "<ns0:pathSet>parent</ns0:pathSet>" \
2965 "</ns0:propSet>"
2966
2967 # define ZBX_POST_SOAP_CUSTER \
2968 "<ns0:propSet>" \
2969 "<ns0:type>ClusterComputeResource</ns0:type>" \
2970 "<ns0:pathSet>name</ns0:pathSet>" \
2971 "</ns0:propSet>"
2972
2973 char tmp[MAX_STRING_LEN];
2974 int ret = FAIL;
2975 xmlDoc *doc = NULL;
2976
2977 zabbix_log(LOG_LEVEL_DEBUG, "In %s() id:'%s'", __func__, hv->id);
2978
2979 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_HV_DATACENTER_NAME,
2980 vmware_service_objects[service->type].property_collector,
2981 NULL != hv->clusterid ? ZBX_POST_SOAP_CUSTER : ZBX_POST_SOAP_FOLDER, hv->id);
2982
2983 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
2984 goto out;
2985
2986 if (NULL == (hv->datacenter_name = zbx_xml_read_doc_value(doc,
2987 ZBX_XPATH_NAME_BY_TYPE(ZBX_VMWARE_SOAP_DATACENTER))))
2988 {
2989 hv->datacenter_name = zbx_strdup(NULL, "");
2990 }
2991
2992 if (NULL != hv->clusterid && (NULL != (hv->parent_name = zbx_xml_read_doc_value(doc,
2993 ZBX_XPATH_NAME_BY_TYPE(ZBX_VMWARE_SOAP_CLUSTER)))))
2994 {
2995 hv->parent_type = zbx_strdup(NULL, ZBX_VMWARE_SOAP_CLUSTER);
2996 }
2997 else if (NULL != (hv->parent_name = zbx_xml_read_doc_value(doc,
2998 ZBX_XPATH_HV_PARENTFOLDERNAME(ZBX_XPATH_HV_PARENTID))))
2999 {
3000 hv->parent_type = zbx_strdup(NULL, ZBX_VMWARE_SOAP_FOLDER);
3001 }
3002 else if ('\0' != *hv->datacenter_name)
3003 {
3004 hv->parent_name = zbx_strdup(NULL, hv->datacenter_name);
3005 hv->parent_type = zbx_strdup(NULL, ZBX_VMWARE_SOAP_DATACENTER);
3006 }
3007 else
3008 {
3009 hv->parent_name = zbx_strdup(NULL, ZBX_VMWARE_TYPE_VCENTER == service->type ? "Vcenter" : "ESXi");
3010 hv->parent_type = zbx_strdup(NULL, ZBX_VMWARE_SOAP_DEFAULT);
3011 }
3012
3013 ret = SUCCEED;
3014 out:
3015 zbx_xml_free_doc(doc);
3016 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3017
3018 return ret;
3019 }
3020
3021 /******************************************************************************
3022 * *
3023 * Function: vmware_ds_name_compare *
3024 * *
3025 * Purpose: sorting function to sort Datastore vector by name *
3026 * *
3027 ******************************************************************************/
vmware_ds_name_compare(const void * d1,const void * d2)3028 int vmware_ds_name_compare(const void *d1, const void *d2)
3029 {
3030 const zbx_vmware_datastore_t *ds1 = *(const zbx_vmware_datastore_t **)d1;
3031 const zbx_vmware_datastore_t *ds2 = *(const zbx_vmware_datastore_t **)d2;
3032
3033 return strcmp(ds1->name, ds2->name);
3034 }
3035
3036 /******************************************************************************
3037 * *
3038 * Function: vmware_ds_id_compare *
3039 * *
3040 * Purpose: sorting function to sort Datastore vector by id *
3041 * *
3042 ******************************************************************************/
vmware_ds_id_compare(const void * d1,const void * d2)3043 static int vmware_ds_id_compare(const void *d1, const void *d2)
3044 {
3045 const zbx_vmware_datastore_t *ds1 = *(const zbx_vmware_datastore_t **)d1;
3046 const zbx_vmware_datastore_t *ds2 = *(const zbx_vmware_datastore_t **)d2;
3047
3048 return strcmp(ds1->id, ds2->id);
3049 }
3050
3051 /******************************************************************************
3052 * *
3053 * Function: vmware_dc_id_compare *
3054 * *
3055 * Purpose: sorting function to sort Datacenter vector by id *
3056 * *
3057 ******************************************************************************/
vmware_dc_id_compare(const void * d1,const void * d2)3058 static int vmware_dc_id_compare(const void *d1, const void *d2)
3059 {
3060 const zbx_vmware_datacenter_t *dc1 = *(const zbx_vmware_datacenter_t **)d1;
3061 const zbx_vmware_datacenter_t *dc2 = *(const zbx_vmware_datacenter_t **)d2;
3062
3063 return strcmp(dc1->id, dc2->id);
3064 }
3065
3066 /******************************************************************************
3067 * Function: vmware_hv_get_ds_access *
3068 * *
3069 * Purpose: populate array of values from a xml data *
3070 * *
3071 * Parameters: xdoc - [IN] XML document *
3072 * ds_id - [IN] datastore id *
3073 * *
3074 * Return: Upon successful completion the function return SUCCEED. *
3075 * Otherwise, FAIL is returned. *
3076 * *
3077 ******************************************************************************/
vmware_hv_get_ds_access(xmlDoc * xdoc,const char * ds_id)3078 static zbx_uint64_t vmware_hv_get_ds_access(xmlDoc *xdoc, const char *ds_id)
3079 {
3080
3081 zbx_uint64_t mi_access = ZBX_VMWARE_DS_NONE;
3082 char tmp[MAX_STRING_LEN];
3083 xmlXPathContext *xpathCtx;
3084 xmlXPathObject *xpathObj;
3085 xmlNode *xml_node;
3086 char *value;
3087
3088
3089 zabbix_log(LOG_LEVEL_DEBUG, "In %s() for DS:%s", __func__, ds_id);
3090
3091 zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_HV_DATASTORE_MOUNTINFO(), ds_id);
3092 xpathCtx = xmlXPathNewContext(xdoc);
3093
3094 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)tmp, xpathCtx)))
3095 {
3096 zabbix_log(LOG_LEVEL_DEBUG, "Cannot make montinfo parsing query for DS:%s", ds_id);
3097 goto clean;
3098 }
3099
3100 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
3101 {
3102 zabbix_log(LOG_LEVEL_DEBUG, "Cannot find items in mountinfo for DS:%s", ds_id);
3103 goto clean;
3104 }
3105
3106 xml_node = xpathObj->nodesetval->nodeTab[0];
3107
3108 if (NULL != (value = zbx_xml_read_node_value(xdoc, xml_node, ZBX_XPATH_PROP_SUFFIX("mounted"))))
3109 {
3110 if (0 == strcmp(value, "true"))
3111 mi_access |= ZBX_VMWARE_DS_MOUNTED;
3112
3113 zbx_free(value);
3114 }
3115 else
3116 zabbix_log(LOG_LEVEL_DEBUG, "Cannot find item 'mounted' in mountinfo for DS:%s", ds_id);
3117
3118 if (NULL != (value = zbx_xml_read_node_value(xdoc, xml_node, ZBX_XPATH_PROP_SUFFIX("accessible"))))
3119 {
3120 if (0 == strcmp(value, "true"))
3121 mi_access |= ZBX_VMWARE_DS_ACCESSIBLE;
3122
3123 zbx_free(value);
3124 }
3125 else
3126 zabbix_log(LOG_LEVEL_DEBUG, "Cannot find item 'accessible' in accessible for DS:%s", ds_id);
3127
3128 if (NULL != (value = zbx_xml_read_node_value(xdoc, xml_node, ZBX_XPATH_PROP_SUFFIX("accessMode"))))
3129 {
3130 if (0 == strcmp(value, "readWrite"))
3131 mi_access |= ZBX_VMWARE_DS_READWRITE;
3132 else
3133 mi_access |= ZBX_VMWARE_DS_READ;
3134
3135 zbx_free(value);
3136 }
3137 else
3138 zabbix_log(LOG_LEVEL_DEBUG, "Cannot find item 'accessMode' in mountinfo for DS:%s", ds_id);
3139
3140 clean:
3141 if (NULL != xpathObj)
3142 xmlXPathFreeObject(xpathObj);
3143
3144 xmlXPathFreeContext(xpathCtx);
3145 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() mountinfo:" ZBX_FS_UI64, __func__, mi_access);
3146
3147 return mi_access;
3148 }
3149
3150 /******************************************************************************
3151 * *
3152 * Function: vmware_service_init_hv *
3153 * *
3154 * Purpose: initialize vmware hypervisor object *
3155 * *
3156 * Parameters: service - [IN] the vmware service *
3157 * easyhandle - [IN] the CURL handle *
3158 * id - [IN] the vmware hypervisor id *
3159 * dss - [IN/OUT] the vector with all Datastores *
3160 * hv - [OUT] the hypervisor object (must be allocated) *
3161 * error - [OUT] the error message in the case of failure *
3162 * *
3163 * Return value: SUCCEED - the hypervisor object was initialized successfully *
3164 * FAIL - otherwise *
3165 * *
3166 ******************************************************************************/
vmware_service_init_hv(zbx_vmware_service_t * service,CURL * easyhandle,const char * id,zbx_vector_vmware_datastore_t * dss,zbx_vmware_hv_t * hv,char ** error)3167 static int vmware_service_init_hv(zbx_vmware_service_t *service, CURL *easyhandle, const char *id,
3168 zbx_vector_vmware_datastore_t *dss, zbx_vmware_hv_t *hv, char **error)
3169 {
3170 char *value;
3171 xmlDoc *details = NULL;
3172 zbx_vector_str_t datastores, vms;
3173 int i, j, ret = FAIL;
3174
3175 zabbix_log(LOG_LEVEL_DEBUG, "In %s() hvid:'%s'", __func__, id);
3176
3177 memset(hv, 0, sizeof(zbx_vmware_hv_t));
3178
3179 zbx_vector_str_create(&hv->ds_names);
3180 zbx_vector_ptr_create(&hv->vms);
3181
3182 zbx_vector_str_create(&datastores);
3183 zbx_vector_str_create(&vms);
3184
3185 if (SUCCEED != vmware_service_get_hv_data(service, easyhandle, id, hv_propmap,
3186 ZBX_VMWARE_HVPROPS_NUM, &details, error))
3187 {
3188 goto out;
3189 }
3190
3191 if (NULL == (hv->props = xml_read_props(details, hv_propmap, ZBX_VMWARE_HVPROPS_NUM)))
3192 goto out;
3193
3194 if (NULL == hv->props[ZBX_VMWARE_HVPROP_HW_UUID])
3195 goto out;
3196
3197 hv->uuid = zbx_strdup(NULL, hv->props[ZBX_VMWARE_HVPROP_HW_UUID]);
3198 hv->id = zbx_strdup(NULL, id);
3199
3200 if (NULL != (value = zbx_xml_read_doc_value(details, "//*[@type='" ZBX_VMWARE_SOAP_CLUSTER "']")))
3201 hv->clusterid = value;
3202
3203 if (SUCCEED != vmware_hv_get_parent_data(service, easyhandle, hv, error))
3204 goto out;
3205
3206 zbx_xml_read_values(details, ZBX_XPATH_HV_DATASTORES(), &datastores);
3207 zbx_vector_str_reserve(&hv->ds_names, datastores.values_num);
3208
3209 for (i = 0; i < datastores.values_num; i++)
3210 {
3211 zbx_vmware_datastore_t *ds, ds_cmp;
3212 zbx_str_uint64_pair_t hv_ds_access;
3213
3214 ds_cmp.id = datastores.values[i];
3215
3216 if (FAIL == (j = zbx_vector_vmware_datastore_bsearch(dss, &ds_cmp, vmware_ds_id_compare)))
3217 {
3218 zabbix_log(LOG_LEVEL_DEBUG, "%s(): Datastore \"%s\" not found on hypervisor \"%s\".", __func__,
3219 datastores.values[i], hv->id);
3220 continue;
3221 }
3222
3223 ds = dss->values[j];
3224 hv_ds_access.name = zbx_strdup(NULL, hv->uuid);
3225 hv_ds_access.value = vmware_hv_get_ds_access(details, ds->id);
3226 zbx_vector_str_uint64_pair_append_ptr(&ds->hv_uuids_access, &hv_ds_access);
3227 zbx_vector_str_append(&hv->ds_names, zbx_strdup(NULL, ds->name));
3228 }
3229
3230 zbx_vector_str_sort(&hv->ds_names, ZBX_DEFAULT_STR_COMPARE_FUNC);
3231 zbx_xml_read_values(details, ZBX_XPATH_HV_VMS(), &vms);
3232 zbx_vector_ptr_reserve(&hv->vms, vms.values_num + hv->vms.values_alloc);
3233
3234 for (i = 0; i < vms.values_num; i++)
3235 {
3236 zbx_vmware_vm_t *vm;
3237
3238 if (NULL != (vm = vmware_service_create_vm(service, easyhandle, vms.values[i], error)))
3239 zbx_vector_ptr_append(&hv->vms, vm);
3240 }
3241
3242 ret = SUCCEED;
3243 out:
3244 zbx_xml_free_doc(details);
3245
3246 zbx_vector_str_clear_ext(&vms, zbx_str_free);
3247 zbx_vector_str_destroy(&vms);
3248
3249 zbx_vector_str_clear_ext(&datastores, zbx_str_free);
3250 zbx_vector_str_destroy(&datastores);
3251
3252 if (SUCCEED != ret)
3253 vmware_hv_clean(hv);
3254
3255 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3256
3257 return ret;
3258 }
3259
3260 /******************************************************************************
3261 * *
3262 * Function: vmware_service_get_datacenters_list *
3263 * *
3264 * Purpose: retrieves a list of vmware service datacenters *
3265 * *
3266 * Parameters: doc - [IN] XML document *
3267 * datacenters - [OUT] list of vmware datacenters *
3268 * *
3269 * Return value: SUCCEED - the operation has completed successfully *
3270 * FAIL - the operation has failed *
3271 * *
3272 ******************************************************************************/
vmware_service_get_datacenters_list(xmlDoc * doc,zbx_vector_vmware_datacenter_t * datacenters)3273 static int vmware_service_get_datacenters_list(xmlDoc *doc, zbx_vector_vmware_datacenter_t *datacenters)
3274 {
3275 xmlXPathContext *xpathCtx;
3276 xmlXPathObject *xpathObj;
3277 xmlNodeSetPtr nodeset;
3278 char *id, *name;
3279 zbx_vmware_datacenter_t *datacenter;
3280 int i, ret = FAIL;
3281
3282 if (NULL == doc)
3283 return ret;
3284
3285 xpathCtx = xmlXPathNewContext(doc);
3286
3287 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *) ZBX_XPATH_OBJECTS_BY_TYPE("Datacenter"), xpathCtx)))
3288 goto out;
3289
3290 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
3291 {
3292 xmlXPathFreeObject(xpathObj);
3293 goto out;
3294 }
3295
3296 nodeset = xpathObj->nodesetval;
3297 zbx_vector_vmware_datacenter_reserve(datacenters, nodeset->nodeNr);
3298
3299 for (i = 0; i < nodeset->nodeNr; i++)
3300 {
3301 if (NULL == (id = zbx_xml_read_node_value(doc, nodeset->nodeTab[i], ZBX_XPATH_NN("obj"))))
3302 {
3303 zabbix_log(LOG_LEVEL_DEBUG, "%s(): Cannot get datacenter id.", __func__);
3304 continue;
3305 }
3306
3307 if (NULL == (name = zbx_xml_read_node_value(doc, nodeset->nodeTab[i], ZBX_XPATH_PROP_NAME_NODE("name"))))
3308 {
3309 zabbix_log(LOG_LEVEL_DEBUG, "%s(): Cannot get datacenter name for id: %s.", __func__, id);
3310 zbx_free(id);
3311 continue;
3312 }
3313
3314 datacenter = (zbx_vmware_datacenter_t *)zbx_malloc(NULL, sizeof(zbx_vmware_datacenter_t));
3315 datacenter->id = id;
3316 datacenter->name = name;
3317 zbx_vector_vmware_datacenter_append(datacenters, datacenter);
3318 }
3319
3320 zbx_vector_vmware_datacenter_sort(datacenters, vmware_dc_id_compare);
3321
3322 ret = SUCCEED;
3323 xmlXPathFreeObject(xpathObj);
3324 out:
3325 xmlXPathFreeContext(xpathCtx);
3326
3327 return ret;
3328 }
3329
3330 /******************************************************************************
3331 * *
3332 * Function: vmware_service_get_hv_ds_dc_list *
3333 * *
3334 * Purpose: retrieves a list of all vmware service hypervisor ids *
3335 * *
3336 * Parameters: service - [IN] the vmware service *
3337 * easyhandle - [IN] the CURL handle *
3338 * hvs - [OUT] list of vmware hypervisor ids *
3339 * dss - [OUT] list of vmware datastore ids *
3340 * datacenters - [OUT] list of vmware datacenters *
3341 * error - [OUT] the error message in the case of failure *
3342 * *
3343 * Return value: SUCCEED - the operation has completed successfully *
3344 * FAIL - the operation has failed *
3345 * *
3346 ******************************************************************************/
vmware_service_get_hv_ds_dc_list(const zbx_vmware_service_t * service,CURL * easyhandle,zbx_vector_str_t * hvs,zbx_vector_str_t * dss,zbx_vector_vmware_datacenter_t * datacenters,char ** error)3347 static int vmware_service_get_hv_ds_dc_list(const zbx_vmware_service_t *service, CURL *easyhandle,
3348 zbx_vector_str_t *hvs, zbx_vector_str_t *dss, zbx_vector_vmware_datacenter_t *datacenters, char **error)
3349 {
3350 # define ZBX_POST_VCENTER_HV_DS_LIST \
3351 ZBX_POST_VSPHERE_HEADER \
3352 "<ns0:RetrievePropertiesEx xsi:type=\"ns0:RetrievePropertiesExRequestType\">" \
3353 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
3354 "<ns0:specSet>" \
3355 "<ns0:propSet>" \
3356 "<ns0:type>HostSystem</ns0:type>" \
3357 "</ns0:propSet>" \
3358 "<ns0:propSet>" \
3359 "<ns0:type>Datastore</ns0:type>" \
3360 "</ns0:propSet>" \
3361 "<ns0:propSet>" \
3362 "<ns0:type>Datacenter</ns0:type>" \
3363 "<ns0:pathSet>name</ns0:pathSet>" \
3364 "</ns0:propSet>" \
3365 "<ns0:objectSet>" \
3366 "<ns0:obj type=\"Folder\">%s</ns0:obj>" \
3367 "<ns0:skip>false</ns0:skip>" \
3368 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3369 "<ns0:name>visitFolders</ns0:name>" \
3370 "<ns0:type>Folder</ns0:type>" \
3371 "<ns0:path>childEntity</ns0:path>" \
3372 "<ns0:skip>false</ns0:skip>" \
3373 "<ns0:selectSet>" \
3374 "<ns0:name>visitFolders</ns0:name>" \
3375 "</ns0:selectSet>" \
3376 "<ns0:selectSet>" \
3377 "<ns0:name>dcToHf</ns0:name>" \
3378 "</ns0:selectSet>" \
3379 "<ns0:selectSet>" \
3380 "<ns0:name>dcToVmf</ns0:name>" \
3381 "</ns0:selectSet>" \
3382 "<ns0:selectSet>" \
3383 "<ns0:name>crToH</ns0:name>" \
3384 "</ns0:selectSet>" \
3385 "<ns0:selectSet>" \
3386 "<ns0:name>crToRp</ns0:name>" \
3387 "</ns0:selectSet>" \
3388 "<ns0:selectSet>" \
3389 "<ns0:name>dcToDs</ns0:name>" \
3390 "</ns0:selectSet>" \
3391 "<ns0:selectSet>" \
3392 "<ns0:name>hToVm</ns0:name>" \
3393 "</ns0:selectSet>" \
3394 "<ns0:selectSet>" \
3395 "<ns0:name>rpToVm</ns0:name>" \
3396 "</ns0:selectSet>" \
3397 "</ns0:selectSet>" \
3398 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3399 "<ns0:name>dcToVmf</ns0:name>" \
3400 "<ns0:type>Datacenter</ns0:type>" \
3401 "<ns0:path>vmFolder</ns0:path>" \
3402 "<ns0:skip>false</ns0:skip>" \
3403 "<ns0:selectSet>" \
3404 "<ns0:name>visitFolders</ns0:name>" \
3405 "</ns0:selectSet>" \
3406 "</ns0:selectSet>" \
3407 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3408 "<ns0:name>dcToDs</ns0:name>" \
3409 "<ns0:type>Datacenter</ns0:type>" \
3410 "<ns0:path>datastore</ns0:path>" \
3411 "<ns0:skip>false</ns0:skip>" \
3412 "<ns0:selectSet>" \
3413 "<ns0:name>visitFolders</ns0:name>" \
3414 "</ns0:selectSet>" \
3415 "</ns0:selectSet>" \
3416 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3417 "<ns0:name>dcToHf</ns0:name>" \
3418 "<ns0:type>Datacenter</ns0:type>" \
3419 "<ns0:path>hostFolder</ns0:path>" \
3420 "<ns0:skip>false</ns0:skip>" \
3421 "<ns0:selectSet>" \
3422 "<ns0:name>visitFolders</ns0:name>" \
3423 "</ns0:selectSet>" \
3424 "</ns0:selectSet>" \
3425 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3426 "<ns0:name>crToH</ns0:name>" \
3427 "<ns0:type>ComputeResource</ns0:type>" \
3428 "<ns0:path>host</ns0:path>" \
3429 "<ns0:skip>false</ns0:skip>" \
3430 "</ns0:selectSet>" \
3431 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3432 "<ns0:name>crToRp</ns0:name>" \
3433 "<ns0:type>ComputeResource</ns0:type>" \
3434 "<ns0:path>resourcePool</ns0:path>" \
3435 "<ns0:skip>false</ns0:skip>" \
3436 "<ns0:selectSet>" \
3437 "<ns0:name>rpToRp</ns0:name>" \
3438 "</ns0:selectSet>" \
3439 "<ns0:selectSet>" \
3440 "<ns0:name>rpToVm</ns0:name>" \
3441 "</ns0:selectSet>" \
3442 "</ns0:selectSet>" \
3443 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3444 "<ns0:name>rpToRp</ns0:name>" \
3445 "<ns0:type>ResourcePool</ns0:type>" \
3446 "<ns0:path>resourcePool</ns0:path>" \
3447 "<ns0:skip>false</ns0:skip>" \
3448 "<ns0:selectSet>" \
3449 "<ns0:name>rpToRp</ns0:name>" \
3450 "</ns0:selectSet>" \
3451 "<ns0:selectSet>" \
3452 "<ns0:name>rpToVm</ns0:name>" \
3453 "</ns0:selectSet>" \
3454 "</ns0:selectSet>" \
3455 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3456 "<ns0:name>hToVm</ns0:name>" \
3457 "<ns0:type>HostSystem</ns0:type>" \
3458 "<ns0:path>vm</ns0:path>" \
3459 "<ns0:skip>false</ns0:skip>" \
3460 "<ns0:selectSet>" \
3461 "<ns0:name>visitFolders</ns0:name>" \
3462 "</ns0:selectSet>" \
3463 "</ns0:selectSet>" \
3464 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
3465 "<ns0:name>rpToVm</ns0:name>" \
3466 "<ns0:type>ResourcePool</ns0:type>" \
3467 "<ns0:path>vm</ns0:path>" \
3468 "<ns0:skip>false</ns0:skip>" \
3469 "</ns0:selectSet>" \
3470 "</ns0:objectSet>" \
3471 "</ns0:specSet>" \
3472 "<ns0:options/>" \
3473 "</ns0:RetrievePropertiesEx>" \
3474 ZBX_POST_VSPHERE_FOOTER
3475
3476 char tmp[MAX_STRING_LEN * 2];
3477 int ret = FAIL;
3478 xmlDoc *doc = NULL;
3479 zbx_property_collection_iter *iter = NULL;
3480
3481 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3482
3483 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VCENTER_HV_DS_LIST,
3484 vmware_service_objects[service->type].property_collector,
3485 vmware_service_objects[service->type].root_folder);
3486
3487 if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, "propertyCollector", &iter, &doc, error))
3488 {
3489 goto out;
3490 }
3491
3492 if (ZBX_VMWARE_TYPE_VCENTER == service->type)
3493 zbx_xml_read_values(doc, "//*[@type='HostSystem']", hvs);
3494 else
3495 zbx_vector_str_append(hvs, zbx_strdup(NULL, "ha-host"));
3496
3497 zbx_xml_read_values(doc, "//*[@type='Datastore']", dss);
3498 vmware_service_get_datacenters_list(doc, datacenters);
3499
3500 while (NULL != iter->token)
3501 {
3502 zbx_xml_free_doc(doc);
3503 doc = NULL;
3504
3505 if (SUCCEED != zbx_property_collection_next(iter, &doc, error))
3506 goto out;
3507
3508 if (ZBX_VMWARE_TYPE_VCENTER == service->type)
3509 zbx_xml_read_values(doc, "//*[@type='HostSystem']", hvs);
3510
3511 zbx_xml_read_values(doc, "//*[@type='Datastore']", dss);
3512 vmware_service_get_datacenters_list(doc, datacenters);
3513 }
3514
3515 ret = SUCCEED;
3516 out:
3517 zbx_property_collection_free(iter);
3518 zbx_xml_free_doc(doc);
3519 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s found hv:%d ds:%d dc:%d", __func__, zbx_result_string(ret),
3520 hvs->values_num, dss->values_num, datacenters->values_num);
3521
3522 return ret;
3523 }
3524
3525 /******************************************************************************
3526 * *
3527 * Function: vmware_service_get_event_session *
3528 * *
3529 * Purpose: retrieves event session name *
3530 * *
3531 * Parameters: service - [IN] the vmware service *
3532 * easyhandle - [IN] the CURL handle *
3533 * event_session - [OUT] a pointer to the output variable *
3534 * error - [OUT] the error message in the case of failure*
3535 * *
3536 * Return value: SUCCEED - the operation has completed successfully *
3537 * FAIL - the operation has failed *
3538 * *
3539 ******************************************************************************/
vmware_service_get_event_session(const zbx_vmware_service_t * service,CURL * easyhandle,char ** event_session,char ** error)3540 static int vmware_service_get_event_session(const zbx_vmware_service_t *service, CURL *easyhandle,
3541 char **event_session, char **error)
3542 {
3543 # define ZBX_POST_VMWARE_CREATE_EVENT_COLLECTOR \
3544 ZBX_POST_VSPHERE_HEADER \
3545 "<ns0:CreateCollectorForEvents>" \
3546 "<ns0:_this type=\"EventManager\">%s</ns0:_this>" \
3547 "<ns0:filter/>" \
3548 "</ns0:CreateCollectorForEvents>" \
3549 ZBX_POST_VSPHERE_FOOTER
3550
3551 char tmp[MAX_STRING_LEN];
3552 int ret = FAIL;
3553 xmlDoc *doc = NULL;
3554
3555 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3556
3557 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_CREATE_EVENT_COLLECTOR,
3558 vmware_service_objects[service->type].event_manager);
3559
3560 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
3561 goto out;
3562
3563 if (NULL == (*event_session = zbx_xml_read_doc_value(doc, "/*/*/*/*[@type='EventHistoryCollector']")))
3564 {
3565 *error = zbx_strdup(*error, "Cannot get EventHistoryCollector session.");
3566 goto out;
3567 }
3568
3569 ret = SUCCEED;
3570 out:
3571 zbx_xml_free_doc(doc);
3572 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s event_session:'%s'", __func__, zbx_result_string(ret),
3573 ZBX_NULL2EMPTY_STR(*event_session));
3574
3575 return ret;
3576 }
3577
3578 /******************************************************************************
3579 * *
3580 * Function: vmware_service_reset_event_history_collector *
3581 * *
3582 * Purpose: resets "scrollable view" to the latest events *
3583 * *
3584 * Parameters: easyhandle - [IN] the CURL handle *
3585 * event_session - [IN] event session (EventHistoryCollector) *
3586 * identifier *
3587 * error - [OUT] the error message in the case of failure*
3588 * *
3589 * Return value: SUCCEED - the operation has completed successfully *
3590 * FAIL - the operation has failed *
3591 * *
3592 ******************************************************************************/
vmware_service_reset_event_history_collector(CURL * easyhandle,const char * event_session,char ** error)3593 static int vmware_service_reset_event_history_collector(CURL *easyhandle, const char *event_session, char **error)
3594 {
3595 # define ZBX_POST_VMWARE_RESET_EVENT_COLLECTOR \
3596 ZBX_POST_VSPHERE_HEADER \
3597 "<ns0:ResetCollector>" \
3598 "<ns0:_this type=\"EventHistoryCollector\">%s</ns0:_this>" \
3599 "</ns0:ResetCollector>" \
3600 ZBX_POST_VSPHERE_FOOTER
3601
3602 int ret = FAIL;
3603 char tmp[MAX_STRING_LEN], *event_session_esc;
3604
3605 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3606
3607 event_session_esc = xml_escape_dyn(event_session);
3608
3609 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_RESET_EVENT_COLLECTOR, event_session_esc);
3610
3611 zbx_free(event_session_esc);
3612
3613 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, NULL, error))
3614 goto out;
3615
3616 ret = SUCCEED;
3617 out:
3618 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3619
3620 return ret;
3621
3622 # undef ZBX_POST_VMWARE_DESTROY_EVENT_COLLECTOR
3623 }
3624
3625 /******************************************************************************
3626 * *
3627 * Function: vmware_service_read_previous_events *
3628 * *
3629 * Purpose: reads events from "scrollable view" and moves it back in time *
3630 * *
3631 * Parameters: easyhandle - [IN] the CURL handle *
3632 * event_session - [IN] event session (EventHistoryCollector) *
3633 * identifier *
3634 * soap_count - [IN] max count of events in response *
3635 * xdoc - [OUT] the result as xml document *
3636 * error - [OUT] the error message in the case of failure*
3637 * *
3638 * Return value: SUCCEED - the operation has completed successfully *
3639 * FAIL - the operation has failed *
3640 * *
3641 ******************************************************************************/
vmware_service_read_previous_events(CURL * easyhandle,const char * event_session,int soap_count,xmlDoc ** xdoc,char ** error)3642 static int vmware_service_read_previous_events(CURL *easyhandle, const char *event_session, int soap_count,
3643 xmlDoc **xdoc, char **error)
3644 {
3645 # define ZBX_POST_VMWARE_READ_PREVIOUS_EVENTS \
3646 ZBX_POST_VSPHERE_HEADER \
3647 "<ns0:ReadPreviousEvents>" \
3648 "<ns0:_this type=\"EventHistoryCollector\">%s</ns0:_this>" \
3649 "<ns0:maxCount>%d</ns0:maxCount>" \
3650 "</ns0:ReadPreviousEvents>" \
3651 ZBX_POST_VSPHERE_FOOTER
3652
3653 int ret = FAIL;
3654 char tmp[MAX_STRING_LEN], *event_session_esc;
3655
3656 zabbix_log(LOG_LEVEL_DEBUG, "In %s() soap_count: %d", __func__, soap_count);
3657
3658 event_session_esc = xml_escape_dyn(event_session);
3659
3660 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_READ_PREVIOUS_EVENTS, event_session_esc, soap_count);
3661
3662 zbx_free(event_session_esc);
3663
3664 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, xdoc, error))
3665 goto out;
3666
3667 ret = SUCCEED;
3668 out:
3669 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3670
3671 return ret;
3672 }
3673
3674 /******************************************************************************
3675 * *
3676 * Function: vmware_service_destroy_event_session *
3677 * *
3678 * Purpose: destroys event session *
3679 * *
3680 * Parameters: easyhandle - [IN] the CURL handle *
3681 * event_session - [IN] event session (EventHistoryCollector) *
3682 * identifier *
3683 * error - [OUT] the error message in the case of failure*
3684 * *
3685 * Return value: SUCCEED - the operation has completed successfully *
3686 * FAIL - the operation has failed *
3687 * *
3688 ******************************************************************************/
vmware_service_destroy_event_session(CURL * easyhandle,const char * event_session,char ** error)3689 static int vmware_service_destroy_event_session(CURL *easyhandle, const char *event_session, char **error)
3690 {
3691 # define ZBX_POST_VMWARE_DESTROY_EVENT_COLLECTOR \
3692 ZBX_POST_VSPHERE_HEADER \
3693 "<ns0:DestroyCollector>" \
3694 "<ns0:_this type=\"EventHistoryCollector\">%s</ns0:_this>" \
3695 "</ns0:DestroyCollector>" \
3696 ZBX_POST_VSPHERE_FOOTER
3697
3698 int ret = FAIL;
3699 char tmp[MAX_STRING_LEN], *event_session_esc;
3700
3701 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3702
3703 event_session_esc = xml_escape_dyn(event_session);
3704
3705 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_DESTROY_EVENT_COLLECTOR, event_session_esc);
3706
3707 zbx_free(event_session_esc);
3708
3709 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, NULL, error))
3710 goto out;
3711
3712 ret = SUCCEED;
3713 out:
3714 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3715
3716 return ret;
3717 }
3718
3719 /******************************************************************************
3720 * *
3721 * Function: vmware_service_put_event_data *
3722 * *
3723 * Purpose: read event data by id from xml and put to array of events *
3724 * *
3725 * Parameters: events - [IN/OUT] the array of parsed events *
3726 * xml_event - [IN] the xml node and id of parsed event *
3727 * xdoc - [IN] xml document with eventlog records *
3728 * alloc_sz - [OUT] allocated memory size for events *
3729 * *
3730 * Return value: SUCCEED - the operation has completed successfully *
3731 * FAIL - the operation has failed *
3732 ******************************************************************************/
vmware_service_put_event_data(zbx_vector_ptr_t * events,zbx_id_xmlnode_t xml_event,xmlDoc * xdoc,zbx_uint64_t * alloc_sz)3733 static int vmware_service_put_event_data(zbx_vector_ptr_t *events, zbx_id_xmlnode_t xml_event, xmlDoc *xdoc,
3734 zbx_uint64_t *alloc_sz)
3735 {
3736 zbx_vmware_event_t *event = NULL;
3737 char *message, *time_str, *ip;
3738 int timestamp = 0, nodes_det = 0;
3739 unsigned int i;
3740 zbx_uint64_t sz;
3741 static event_hostinfo_node_t host_nodes[] =
3742 {
3743 { ZBX_XPATH_EVT_INFO("datacenter"), ZBX_HOSTINFO_NODES_DATACENTER, NULL },
3744 { ZBX_XPATH_EVT_INFO("computeResource"), ZBX_HOSTINFO_NODES_COMPRES, NULL },
3745 { ZBX_XPATH_EVT_INFO("host"), ZBX_HOSTINFO_NODES_HOST, NULL },
3746 { ZBX_XPATH_EVT_ARGUMENT("_sourcehost_"), ZBX_HOSTINFO_NODES_HOST, NULL },
3747 { ZBX_XPATH_EVT_ARGUMENT("entityName"), ZBX_HOSTINFO_NODES_HOST, NULL }
3748 };
3749
3750 if (NULL == (message = zbx_xml_read_node_value(xdoc, xml_event.xml_node, ZBX_XPATH_NN("fullFormattedMessage"))))
3751 {
3752 zabbix_log(LOG_LEVEL_TRACE, "skipping event key '" ZBX_FS_UI64 "', fullFormattedMessage"
3753 " is missing", xml_event.id);
3754 return FAIL;
3755 }
3756
3757 for (i = 0; i < ARRSIZE(host_nodes); i++)
3758 {
3759 if (0 == (nodes_det & host_nodes[i].flag) && NULL != (host_nodes[i].name =
3760 zbx_xml_read_node_value(xdoc, xml_event.xml_node, host_nodes[i].node_name)))
3761 {
3762 nodes_det |= host_nodes[i].flag;
3763
3764 if (ZBX_HOSTINFO_NODES_MASK_ALL == (nodes_det & ZBX_HOSTINFO_NODES_MASK_ALL))
3765 break;
3766 }
3767 }
3768
3769 if (0 != (nodes_det & ZBX_HOSTINFO_NODES_HOST))
3770 {
3771 message = zbx_strdcat(message, "\n\nsource: ");
3772
3773 for (i = 0; i < ARRSIZE(host_nodes); i++)
3774 {
3775 if (NULL == host_nodes[i].name)
3776 continue;
3777
3778 message = zbx_dsprintf(message, "%s%s%s", message, host_nodes[i].name,
3779 0 != (host_nodes[i].flag & ZBX_HOSTINFO_NODES_HOST) ? "" : "/");
3780 zbx_free(host_nodes[i].name);
3781 }
3782 }
3783 else
3784 {
3785 if (0 != (nodes_det & ZBX_HOSTINFO_NODES_MASK_ALL))
3786 {
3787 for (i = 0; i < ARRSIZE(host_nodes); i++)
3788 zbx_free(host_nodes[i].name);
3789 }
3790
3791 if (NULL != (ip = zbx_xml_read_node_value(xdoc, xml_event.xml_node, ZBX_XPATH_NN("ipAddress"))))
3792 {
3793 message = zbx_dsprintf(message, "%s\n\nsource: %s", message, ip);
3794 zbx_free(ip);
3795 }
3796 }
3797
3798 zbx_replace_invalid_utf8(message);
3799
3800 if (NULL == (time_str = zbx_xml_read_node_value(xdoc, xml_event.xml_node, ZBX_XPATH_NN("createdTime"))))
3801 {
3802 zabbix_log(LOG_LEVEL_TRACE, "createdTime is missing for event key '" ZBX_FS_UI64 "'", xml_event.id);
3803 }
3804 else
3805 {
3806 int year, mon, mday, hour, min, sec, t;
3807
3808 /* 2013-06-04T14:19:23.406298Z */
3809 if (6 != sscanf(time_str, "%d-%d-%dT%d:%d:%d.%*s", &year, &mon, &mday, &hour, &min, &sec))
3810 {
3811 zabbix_log(LOG_LEVEL_TRACE, "unexpected format of createdTime '%s' for event"
3812 " key '" ZBX_FS_UI64 "'", time_str, xml_event.id);
3813 }
3814 else if (SUCCEED != zbx_utc_time(year, mon, mday, hour, min, sec, &t))
3815 {
3816 zabbix_log(LOG_LEVEL_TRACE, "cannot convert createdTime '%s' for event key '"
3817 ZBX_FS_UI64 "'", time_str, xml_event.id);
3818 }
3819 else
3820 timestamp = t;
3821
3822 zbx_free(time_str);
3823 }
3824
3825 event = (zbx_vmware_event_t *)zbx_malloc(event, sizeof(zbx_vmware_event_t));
3826 event->key = xml_event.id;
3827 event->timestamp = timestamp;
3828 event->message = evt_msg_strpool_strdup(message, &sz);
3829 zbx_free(message);
3830 zbx_vector_ptr_append(events, event);
3831
3832 if (0 < sz)
3833 *alloc_sz += zbx_mem_required_chunk_size(sz);
3834
3835 return SUCCEED;
3836 }
3837
3838 /******************************************************************************
3839 * *
3840 * Function: vmware_service_parse_event_data *
3841 * *
3842 * Purpose: parse multiple events data *
3843 * *
3844 * Parameters: events - [IN/OUT] the array of parsed events *
3845 * last_key - [IN] the key of last parsed event *
3846 * xdoc - [IN] xml document with eventlog records *
3847 * alloc_sz - [OUT] allocated memory size for events *
3848 * *
3849 * Return value: The count of events successfully parsed *
3850 * *
3851 ******************************************************************************/
vmware_service_parse_event_data(zbx_vector_ptr_t * events,zbx_uint64_t last_key,xmlDoc * xdoc,zbx_uint64_t * alloc_sz)3852 static int vmware_service_parse_event_data(zbx_vector_ptr_t *events, zbx_uint64_t last_key, xmlDoc *xdoc,
3853 zbx_uint64_t *alloc_sz)
3854 {
3855 zbx_vector_id_xmlnode_t ids;
3856 int i, parsed_num = 0;
3857 char *value;
3858 xmlXPathContext *xpathCtx;
3859 xmlXPathObject *xpathObj;
3860 xmlNodeSetPtr nodeset;
3861
3862 zabbix_log(LOG_LEVEL_DEBUG, "In %s() last_key:" ZBX_FS_UI64, __func__, last_key);
3863
3864 xpathCtx = xmlXPathNewContext(xdoc);
3865
3866 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)"/*/*/*"ZBX_XPATH_LN("returnval"), xpathCtx)))
3867 {
3868 zabbix_log(LOG_LEVEL_DEBUG, "Cannot make evenlog list parsing query.");
3869 goto clean;
3870 }
3871
3872 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
3873 {
3874 zabbix_log(LOG_LEVEL_DEBUG, "Cannot find items in evenlog list.");
3875 goto clean;
3876 }
3877
3878 nodeset = xpathObj->nodesetval;
3879 zbx_vector_id_xmlnode_create(&ids);
3880 zbx_vector_id_xmlnode_reserve(&ids, nodeset->nodeNr);
3881
3882 for (i = 0; i < nodeset->nodeNr; i++)
3883 {
3884 zbx_id_xmlnode_t xml_event;
3885 zbx_uint64_t key;
3886
3887 if (NULL == (value = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], ZBX_XPATH_NN("key"))))
3888 {
3889 zabbix_log(LOG_LEVEL_TRACE, "skipping eventlog record without key, xml number '%d'", i);
3890 continue;
3891 }
3892
3893 key = (unsigned int) atoi(value);
3894
3895 if (0 == key && 0 == isdigit(value[('-' == *value || '+' == *value) ? 1 : 0 ]))
3896 {
3897 zabbix_log(LOG_LEVEL_TRACE, "skipping eventlog key '%s', not a number", value);
3898 zbx_free(value);
3899 continue;
3900 }
3901
3902 zbx_free(value);
3903
3904 if (key <= last_key)
3905 {
3906 zabbix_log(LOG_LEVEL_TRACE, "skipping event key '" ZBX_FS_UI64 "', has been processed", key);
3907 continue;
3908 }
3909
3910 xml_event.id = key;
3911 xml_event.xml_node = nodeset->nodeTab[i];
3912 zbx_vector_id_xmlnode_append(&ids, xml_event);
3913 }
3914
3915 if (0 != ids.values_num)
3916 {
3917 zbx_vector_id_xmlnode_sort(&ids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
3918 zbx_vector_ptr_reserve(events, ids.values_num + events->values_alloc);
3919
3920 /* we are reading "scrollable views" in reverse chronological order, */
3921 /* so inside a "scrollable view" latest events should come first too */
3922 for (i = ids.values_num - 1; i >= 0; i--)
3923 {
3924 if (SUCCEED == vmware_service_put_event_data(events, ids.values[i], xdoc, alloc_sz))
3925 parsed_num++;
3926 }
3927 }
3928
3929 zbx_vector_id_xmlnode_destroy(&ids);
3930 clean:
3931 if (NULL != xpathObj)
3932 xmlXPathFreeObject(xpathObj);
3933
3934 xmlXPathFreeContext(xpathCtx);
3935
3936 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() parsed:%d", __func__, parsed_num);
3937
3938 return parsed_num;
3939 }
3940
3941 /******************************************************************************
3942 * *
3943 * Function: vmware_service_get_event_data *
3944 * *
3945 * Purpose: retrieves event data *
3946 * *
3947 * Parameters: service - [IN] the vmware service *
3948 * easyhandle - [IN] the CURL handle *
3949 * events - [OUT] a pointer to the output variable *
3950 * alloc_sz - [OUT] allocated memory size for events *
3951 * error - [OUT] the error message in the case of failure *
3952 * *
3953 * Return value: SUCCEED - the operation has completed successfully *
3954 * FAIL - the operation has failed *
3955 * *
3956 ******************************************************************************/
vmware_service_get_event_data(const zbx_vmware_service_t * service,CURL * easyhandle,zbx_vector_ptr_t * events,zbx_uint64_t * alloc_sz,char ** error)3957 static int vmware_service_get_event_data(const zbx_vmware_service_t *service, CURL *easyhandle,
3958 zbx_vector_ptr_t *events, zbx_uint64_t *alloc_sz, char **error)
3959 {
3960 char *event_session = NULL;
3961 int ret = FAIL, soap_count = 5; /* 10 - initial value of eventlog records number in one response */
3962 xmlDoc *doc = NULL;
3963 zbx_uint64_t eventlog_last_key;
3964
3965 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3966
3967 if (SUCCEED != vmware_service_get_event_session(service, easyhandle, &event_session, error))
3968 goto out;
3969
3970 if (SUCCEED != vmware_service_reset_event_history_collector(easyhandle, event_session, error))
3971 goto end_session;
3972
3973 if (NULL != service->data && 0 != service->data->events.values_num &&
3974 ((const zbx_vmware_event_t *)service->data->events.values[0])->key > service->eventlog.last_key)
3975 {
3976 eventlog_last_key = ((const zbx_vmware_event_t *)service->data->events.values[0])->key;
3977 }
3978 else
3979 eventlog_last_key = service->eventlog.last_key;
3980
3981 do
3982 {
3983 zbx_xml_free_doc(doc);
3984 doc = NULL;
3985
3986 if ((ZBX_MAXQUERYMETRICS_UNLIMITED / 2) >= soap_count)
3987 soap_count = soap_count * 2;
3988 else if (ZBX_MAXQUERYMETRICS_UNLIMITED != soap_count)
3989 soap_count = ZBX_MAXQUERYMETRICS_UNLIMITED;
3990
3991 if (0 != events->values_num &&
3992 (((const zbx_vmware_event_t *)events->values[events->values_num - 1])->key -
3993 eventlog_last_key -1) < (unsigned int)soap_count)
3994 {
3995 soap_count = ((const zbx_vmware_event_t *)events->values[events->values_num - 1])->key -
3996 eventlog_last_key - 1;
3997 }
3998
3999 if (!ZBX_IS_RUNNING() || (0 < soap_count && SUCCEED != vmware_service_read_previous_events(easyhandle,
4000 event_session, soap_count, &doc, error)))
4001 {
4002 goto end_session;
4003 }
4004 }
4005 while (0 < vmware_service_parse_event_data(events, eventlog_last_key, doc, alloc_sz));
4006
4007 ret = SUCCEED;
4008 end_session:
4009 if (SUCCEED != vmware_service_destroy_event_session(easyhandle, event_session, error))
4010 ret = FAIL;
4011 out:
4012 zbx_free(event_session);
4013 zbx_xml_free_doc(doc);
4014
4015 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
4016
4017 return ret;
4018 }
4019
4020 /******************************************************************************
4021 * *
4022 * Function: vmware_service_get_last_event_data *
4023 * *
4024 * Purpose: retrieves data only last event *
4025 * *
4026 * Parameters: service - [IN] the vmware service *
4027 * easyhandle - [IN] the CURL handle *
4028 * events - [OUT] a pointer to the output variable *
4029 * alloc_sz - [OUT] allocated memory size for events *
4030 * error - [OUT] the error message in the case of failure *
4031 * *
4032 * Return value: SUCCEED - the operation has completed successfully *
4033 * FAIL - the operation has failed *
4034 * *
4035 ******************************************************************************/
vmware_service_get_last_event_data(const zbx_vmware_service_t * service,CURL * easyhandle,zbx_vector_ptr_t * events,zbx_uint64_t * alloc_sz,char ** error)4036 static int vmware_service_get_last_event_data(const zbx_vmware_service_t *service, CURL *easyhandle,
4037 zbx_vector_ptr_t *events, zbx_uint64_t *alloc_sz, char **error)
4038 {
4039 # define ZBX_POST_VMWARE_LASTEVENT \
4040 ZBX_POST_VSPHERE_HEADER \
4041 "<ns0:RetrievePropertiesEx>" \
4042 "<ns0:_this type=\"PropertyCollector\">%s</ns0:_this>" \
4043 "<ns0:specSet>" \
4044 "<ns0:propSet>" \
4045 "<ns0:type>EventManager</ns0:type>" \
4046 "<ns0:all>false</ns0:all>" \
4047 "<ns0:pathSet>latestEvent</ns0:pathSet>" \
4048 "</ns0:propSet>" \
4049 "<ns0:objectSet>" \
4050 "<ns0:obj type=\"EventManager\">%s</ns0:obj>" \
4051 "</ns0:objectSet>" \
4052 "</ns0:specSet>" \
4053 "<ns0:options/>" \
4054 "</ns0:RetrievePropertiesEx>" \
4055 ZBX_POST_VSPHERE_FOOTER
4056
4057 char tmp[MAX_STRING_LEN], *value;
4058 int ret = FAIL;
4059 xmlDoc *doc = NULL;
4060 zbx_id_xmlnode_t xml_event;
4061 xmlXPathContext *xpathCtx;
4062 xmlXPathObject *xpathObj;
4063
4064 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4065
4066 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_LASTEVENT,
4067 vmware_service_objects[service->type].property_collector,
4068 vmware_service_objects[service->type].event_manager);
4069
4070 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
4071 goto out;
4072
4073 xpathCtx = xmlXPathNewContext(doc);
4074
4075 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)ZBX_XPATH_PROP_NAME("latestEvent"), xpathCtx)))
4076 {
4077 *error = zbx_strdup(*error, "Cannot make lastevenlog list parsing query.");
4078 goto clean;
4079 }
4080
4081 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
4082 {
4083 *error = zbx_strdup(*error, "Cannot find items in lastevenlog list.");
4084 goto clean;
4085 }
4086
4087 xml_event.xml_node = xpathObj->nodesetval->nodeTab[0];
4088
4089 if (NULL == (value = zbx_xml_read_node_value(doc, xml_event.xml_node, ZBX_XPATH_NN("key"))))
4090 {
4091 *error = zbx_strdup(*error, "Cannot find last event key");
4092 goto clean;
4093 }
4094
4095 xml_event.id = (unsigned int) atoi(value);
4096
4097 if (0 == xml_event.id && 0 == isdigit(value[('-' == *value || '+' == *value) ? 1 : 0 ]))
4098 {
4099 *error = zbx_dsprintf(*error, "Cannot convert eventlog key from %s", value);
4100 zbx_free(value);
4101 goto clean;
4102 }
4103
4104 zbx_free(value);
4105
4106 if (SUCCEED != vmware_service_put_event_data(events, xml_event, doc, alloc_sz))
4107 {
4108 *error = zbx_dsprintf(*error, "Cannot retrieve last eventlog data for key "ZBX_FS_UI64, xml_event.id);
4109 goto clean;
4110 }
4111
4112 ret = SUCCEED;
4113 clean:
4114 if (NULL != xpathObj)
4115 xmlXPathFreeObject(xpathObj);
4116
4117 xmlXPathFreeContext(xpathCtx);
4118 out:
4119 zbx_xml_free_doc(doc);
4120 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
4121
4122 return ret;
4123
4124 # undef ZBX_POST_VMWARE_LASTEVENT
4125 }
4126
4127 /******************************************************************************
4128 * *
4129 * Function: vmware_service_get_clusters *
4130 * *
4131 * Purpose: retrieves a list of vmware service clusters *
4132 * *
4133 * Parameters: easyhandle - [IN] the CURL handle *
4134 * clusters - [OUT] a pointer to the output variable *
4135 * error - [OUT] the error message in the case of failure *
4136 * *
4137 * Return value: SUCCEED - the operation has completed successfully *
4138 * FAIL - the operation has failed *
4139 * *
4140 ******************************************************************************/
vmware_service_get_clusters(CURL * easyhandle,xmlDoc ** clusters,char ** error)4141 static int vmware_service_get_clusters(CURL *easyhandle, xmlDoc **clusters, char **error)
4142 {
4143 # define ZBX_POST_VCENTER_CLUSTER \
4144 ZBX_POST_VSPHERE_HEADER \
4145 "<ns0:RetrievePropertiesEx xsi:type=\"ns0:RetrievePropertiesExRequestType\">" \
4146 "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
4147 "<ns0:specSet>" \
4148 "<ns0:propSet>" \
4149 "<ns0:type>ClusterComputeResource</ns0:type>" \
4150 "<ns0:pathSet>name</ns0:pathSet>" \
4151 "</ns0:propSet>" \
4152 "<ns0:objectSet>" \
4153 "<ns0:obj type=\"Folder\">group-d1</ns0:obj>" \
4154 "<ns0:skip>false</ns0:skip>" \
4155 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4156 "<ns0:name>visitFolders</ns0:name>" \
4157 "<ns0:type>Folder</ns0:type>" \
4158 "<ns0:path>childEntity</ns0:path>" \
4159 "<ns0:skip>false</ns0:skip>" \
4160 "<ns0:selectSet>" \
4161 "<ns0:name>visitFolders</ns0:name>" \
4162 "</ns0:selectSet>" \
4163 "<ns0:selectSet>" \
4164 "<ns0:name>dcToHf</ns0:name>" \
4165 "</ns0:selectSet>" \
4166 "<ns0:selectSet>" \
4167 "<ns0:name>dcToVmf</ns0:name>" \
4168 "</ns0:selectSet>" \
4169 "<ns0:selectSet>" \
4170 "<ns0:name>crToH</ns0:name>" \
4171 "</ns0:selectSet>" \
4172 "<ns0:selectSet>" \
4173 "<ns0:name>crToRp</ns0:name>" \
4174 "</ns0:selectSet>" \
4175 "<ns0:selectSet>" \
4176 "<ns0:name>dcToDs</ns0:name>" \
4177 "</ns0:selectSet>" \
4178 "<ns0:selectSet>" \
4179 "<ns0:name>hToVm</ns0:name>" \
4180 "</ns0:selectSet>" \
4181 "<ns0:selectSet>" \
4182 "<ns0:name>rpToVm</ns0:name>" \
4183 "</ns0:selectSet>" \
4184 "</ns0:selectSet>" \
4185 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4186 "<ns0:name>dcToVmf</ns0:name>" \
4187 "<ns0:type>Datacenter</ns0:type>" \
4188 "<ns0:path>vmFolder</ns0:path>" \
4189 "<ns0:skip>false</ns0:skip>" \
4190 "<ns0:selectSet>" \
4191 "<ns0:name>visitFolders</ns0:name>" \
4192 "</ns0:selectSet>" \
4193 "</ns0:selectSet>" \
4194 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4195 "<ns0:name>dcToDs</ns0:name>" \
4196 "<ns0:type>Datacenter</ns0:type>" \
4197 "<ns0:path>datastore</ns0:path>" \
4198 "<ns0:skip>false</ns0:skip>" \
4199 "<ns0:selectSet>" \
4200 "<ns0:name>visitFolders</ns0:name>" \
4201 "</ns0:selectSet>" \
4202 "</ns0:selectSet>" \
4203 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4204 "<ns0:name>dcToHf</ns0:name>" \
4205 "<ns0:type>Datacenter</ns0:type>" \
4206 "<ns0:path>hostFolder</ns0:path>" \
4207 "<ns0:skip>false</ns0:skip>" \
4208 "<ns0:selectSet>" \
4209 "<ns0:name>visitFolders</ns0:name>" \
4210 "</ns0:selectSet>" \
4211 "</ns0:selectSet>" \
4212 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4213 "<ns0:name>crToH</ns0:name>" \
4214 "<ns0:type>ComputeResource</ns0:type>" \
4215 "<ns0:path>host</ns0:path>" \
4216 "<ns0:skip>false</ns0:skip>" \
4217 "</ns0:selectSet>" \
4218 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4219 "<ns0:name>crToRp</ns0:name>" \
4220 "<ns0:type>ComputeResource</ns0:type>" \
4221 "<ns0:path>resourcePool</ns0:path>" \
4222 "<ns0:skip>false</ns0:skip>" \
4223 "<ns0:selectSet>" \
4224 "<ns0:name>rpToRp</ns0:name>" \
4225 "</ns0:selectSet>" \
4226 "<ns0:selectSet>" \
4227 "<ns0:name>rpToVm</ns0:name>" \
4228 "</ns0:selectSet>" \
4229 "</ns0:selectSet>" \
4230 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4231 "<ns0:name>rpToRp</ns0:name>" \
4232 "<ns0:type>ResourcePool</ns0:type>" \
4233 "<ns0:path>resourcePool</ns0:path>" \
4234 "<ns0:skip>false</ns0:skip>" \
4235 "<ns0:selectSet>" \
4236 "<ns0:name>rpToRp</ns0:name>" \
4237 "</ns0:selectSet>" \
4238 "<ns0:selectSet>" \
4239 "<ns0:name>rpToVm</ns0:name>" \
4240 "</ns0:selectSet>" \
4241 "</ns0:selectSet>" \
4242 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4243 "<ns0:name>hToVm</ns0:name>" \
4244 "<ns0:type>HostSystem</ns0:type>" \
4245 "<ns0:path>vm</ns0:path>" \
4246 "<ns0:skip>false</ns0:skip>" \
4247 "<ns0:selectSet>" \
4248 "<ns0:name>visitFolders</ns0:name>" \
4249 "</ns0:selectSet>" \
4250 "</ns0:selectSet>" \
4251 "<ns0:selectSet xsi:type=\"ns0:TraversalSpec\">" \
4252 "<ns0:name>rpToVm</ns0:name>" \
4253 "<ns0:type>ResourcePool</ns0:type>" \
4254 "<ns0:path>vm</ns0:path>" \
4255 "<ns0:skip>false</ns0:skip>" \
4256 "</ns0:selectSet>" \
4257 "</ns0:objectSet>" \
4258 "</ns0:specSet>" \
4259 "<ns0:options/>" \
4260 "</ns0:RetrievePropertiesEx>" \
4261 ZBX_POST_VSPHERE_FOOTER
4262
4263 int ret = FAIL;
4264
4265 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4266
4267 if (SUCCEED != zbx_soap_post(__func__, easyhandle, ZBX_POST_VCENTER_CLUSTER, clusters, error))
4268 goto out;
4269
4270 ret = SUCCEED;
4271 out:
4272 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
4273
4274 return ret;
4275
4276 # undef ZBX_POST_VCENTER_CLUSTER
4277 }
4278
4279 /******************************************************************************
4280 * *
4281 * Function: vmware_service_get_cluster_status *
4282 * *
4283 * Purpose: retrieves status of the specified vmware cluster *
4284 * *
4285 * Parameters: easyhandle - [IN] the CURL handle *
4286 * clusterid - [IN] the cluster id *
4287 * status - [OUT] a pointer to the output variable *
4288 * error - [OUT] the error message in the case of failure *
4289 * *
4290 * Return value: SUCCEED - the operation has completed successfully *
4291 * FAIL - the operation has failed *
4292 * *
4293 ******************************************************************************/
vmware_service_get_cluster_status(CURL * easyhandle,const char * clusterid,char ** status,char ** error)4294 static int vmware_service_get_cluster_status(CURL *easyhandle, const char *clusterid, char **status, char **error)
4295 {
4296 # define ZBX_POST_VMWARE_CLUSTER_STATUS \
4297 ZBX_POST_VSPHERE_HEADER \
4298 "<ns0:RetrievePropertiesEx>" \
4299 "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
4300 "<ns0:specSet>" \
4301 "<ns0:propSet>" \
4302 "<ns0:type>ClusterComputeResource</ns0:type>" \
4303 "<ns0:all>false</ns0:all>" \
4304 "<ns0:pathSet>summary.overallStatus</ns0:pathSet>" \
4305 "</ns0:propSet>" \
4306 "<ns0:objectSet>" \
4307 "<ns0:obj type=\"ClusterComputeResource\">%s</ns0:obj>" \
4308 "</ns0:objectSet>" \
4309 "</ns0:specSet>" \
4310 "<ns0:options></ns0:options>" \
4311 "</ns0:RetrievePropertiesEx>" \
4312 ZBX_POST_VSPHERE_FOOTER
4313
4314 char tmp[MAX_STRING_LEN], *clusterid_esc;
4315 int ret = FAIL;
4316 xmlDoc *doc = NULL;
4317
4318 zabbix_log(LOG_LEVEL_DEBUG, "In %s() clusterid:'%s'", __func__, clusterid);
4319
4320 clusterid_esc = xml_escape_dyn(clusterid);
4321
4322 zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VMWARE_CLUSTER_STATUS, clusterid_esc);
4323
4324 zbx_free(clusterid_esc);
4325
4326 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, error))
4327 goto out;
4328
4329 *status = zbx_xml_read_doc_value(doc, ZBX_XPATH_PROP_NAME("summary.overallStatus"));
4330
4331 ret = SUCCEED;
4332 out:
4333 zbx_xml_free_doc(doc);
4334 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
4335
4336 return ret;
4337
4338 # undef ZBX_POST_VMWARE_CLUSTER_STATUS
4339 }
4340
4341 /******************************************************************************
4342 * *
4343 * Function: vmware_service_get_cluster_list *
4344 * *
4345 * Purpose: creates list of vmware cluster objects *
4346 * *
4347 * Parameters: easyhandle - [IN] the CURL handle *
4348 * clusters - [OUT] a pointer to the resulting cluster vector *
4349 * error - [OUT] the error message in the case of failure *
4350 * *
4351 * Return value: SUCCEED - the operation has completed successfully *
4352 * FAIL - the operation has failed *
4353 * *
4354 ******************************************************************************/
vmware_service_get_cluster_list(CURL * easyhandle,zbx_vector_ptr_t * clusters,char ** error)4355 static int vmware_service_get_cluster_list(CURL *easyhandle, zbx_vector_ptr_t *clusters, char **error)
4356 {
4357 char xpath[MAX_STRING_LEN], *name;
4358 xmlDoc *cluster_data = NULL;
4359 zbx_vector_str_t ids;
4360 zbx_vmware_cluster_t *cluster;
4361 int i, ret = FAIL;
4362
4363 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4364
4365 zbx_vector_str_create(&ids);
4366
4367 if (SUCCEED != vmware_service_get_clusters(easyhandle, &cluster_data, error))
4368 goto out;
4369
4370 zbx_xml_read_values(cluster_data, "//*[@type='ClusterComputeResource']", &ids);
4371 zbx_vector_ptr_reserve(clusters, ids.values_num + clusters->values_alloc);
4372
4373 for (i = 0; i < ids.values_num; i++)
4374 {
4375 char *status;
4376
4377 zbx_snprintf(xpath, sizeof(xpath), "//*[@type='ClusterComputeResource'][.='%s']"
4378 "/.." ZBX_XPATH_LN2("propSet", "val"), ids.values[i]);
4379
4380 if (NULL == (name = zbx_xml_read_doc_value(cluster_data, xpath)))
4381 continue;
4382
4383 if (SUCCEED != vmware_service_get_cluster_status(easyhandle, ids.values[i], &status, error))
4384 {
4385 zbx_free(name);
4386 goto out;
4387 }
4388
4389 cluster = (zbx_vmware_cluster_t *)zbx_malloc(NULL, sizeof(zbx_vmware_cluster_t));
4390 cluster->id = zbx_strdup(NULL, ids.values[i]);
4391 cluster->name = name;
4392 cluster->status = status;
4393
4394 zbx_vector_ptr_append(clusters, cluster);
4395 }
4396
4397 ret = SUCCEED;
4398 out:
4399 zbx_xml_free_doc(cluster_data);
4400 zbx_vector_str_clear_ext(&ids, zbx_str_free);
4401 zbx_vector_str_destroy(&ids);
4402
4403 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s found:%d", __func__, zbx_result_string(ret),
4404 clusters->values_num);
4405
4406 return ret;
4407 }
4408
4409 /******************************************************************************
4410 * *
4411 * Function: get_default_maxquerymetrics_for_vcenter *
4412 * *
4413 * Purpose: get statically defined default value for maxquerymetrics for *
4414 * vcenter when it could not be retrieved from soap, depending on *
4415 * vcenter version (https://kb.vmware.com/s/article/2107096) *
4416 * Parameters: service - [IN] the vmware service *
4417 * *
4418 * Return value: maxquerymetrics *
4419 * *
4420 ******************************************************************************/
get_default_maxquerymetrics_for_vcenter(const zbx_vmware_service_t * service)4421 static unsigned int get_default_maxquerymetrics_for_vcenter(const zbx_vmware_service_t *service)
4422 {
4423 if ((6 == service->major_version && 5 <= service->minor_version) ||
4424 6 < service->major_version)
4425 {
4426 return ZBX_VCENTER_6_5_0_AND_MORE_STATS_MAXQUERYMETRICS;
4427 }
4428 else
4429 return ZBX_VCENTER_LESS_THAN_6_5_0_STATS_MAXQUERYMETRICS;
4430 }
4431
4432 /******************************************************************************
4433 * *
4434 * Function: vmware_service_get_maxquerymetrics *
4435 * *
4436 * Purpose: get vpxd.stats.maxquerymetrics parameter from vcenter only *
4437 * *
4438 * Parameters: easyhandle - [IN] the CURL handle *
4439 * service - [IN] the vmware service *
4440 * max_qm - [OUT] max count of Datastore metrics in one *
4441 * request *
4442 * error - [OUT] the error message in the case of failure *
4443 * *
4444 * Return value: SUCCEED - the operation has completed successfully *
4445 * FAIL - the operation has failed *
4446 * *
4447 ******************************************************************************/
vmware_service_get_maxquerymetrics(CURL * easyhandle,zbx_vmware_service_t * service,int * max_qm,char ** error)4448 static int vmware_service_get_maxquerymetrics(CURL *easyhandle, zbx_vmware_service_t *service, int *max_qm,
4449 char **error)
4450 {
4451 # define ZBX_POST_MAXQUERYMETRICS \
4452 ZBX_POST_VSPHERE_HEADER \
4453 "<ns0:QueryOptions>" \
4454 "<ns0:_this type=\"OptionManager\">VpxSettings</ns0:_this>" \
4455 "<ns0:name>config.vpxd.stats.maxQueryMetrics</ns0:name>" \
4456 "</ns0:QueryOptions>" \
4457 ZBX_POST_VSPHERE_FOOTER
4458
4459 int ret = FAIL;
4460 char *val;
4461 xmlDoc *doc = NULL;
4462
4463 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4464
4465 if (SUCCEED != zbx_soap_post(__func__, easyhandle, ZBX_POST_MAXQUERYMETRICS, &doc, error))
4466 {
4467 if (NULL == doc) /* if not SOAP error */
4468 goto out;
4469
4470 zabbix_log(LOG_LEVEL_DEBUG, "Error of query maxQueryMetrics: %s.", *error);
4471 zbx_free(*error);
4472 }
4473
4474 ret = SUCCEED;
4475
4476 if (NULL == (val = zbx_xml_read_doc_value(doc, ZBX_XPATH_MAXQUERYMETRICS())))
4477 {
4478 *max_qm = get_default_maxquerymetrics_for_vcenter(service);
4479 zabbix_log(LOG_LEVEL_DEBUG, "maxQueryMetrics defaults to %d", *max_qm);
4480 goto out;
4481 }
4482
4483 /* vmware article 2107096 */
4484 /* Edit the config.vpxd.stats.maxQueryMetrics key in the advanced settings of vCenter Server */
4485 /* To disable the limit, set a value to -1 */
4486 /* Edit the web.xml file. To disable the limit, set a value 0 */
4487 if (-1 == atoi(val))
4488 {
4489 *max_qm = ZBX_MAXQUERYMETRICS_UNLIMITED;
4490 }
4491 else if (SUCCEED != is_uint31(val, max_qm))
4492 {
4493 zabbix_log(LOG_LEVEL_DEBUG, "Cannot convert maxQueryMetrics from %s.", val);
4494 *max_qm = get_default_maxquerymetrics_for_vcenter(service);
4495 zabbix_log(LOG_LEVEL_DEBUG, "maxQueryMetrics defaults to %d", *max_qm);
4496 }
4497 else if (0 == *max_qm)
4498 {
4499 *max_qm = ZBX_MAXQUERYMETRICS_UNLIMITED;
4500 }
4501
4502 zbx_free(val);
4503 out:
4504 zbx_xml_free_doc(doc);
4505 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
4506
4507 return ret;
4508 }
4509 /******************************************************************************
4510 * *
4511 * Function: vmware_counters_add_new *
4512 * *
4513 * Purpose: creates a new performance counter object in shared memory and *
4514 * adds to the specified vector *
4515 * *
4516 * Parameters: counters - [IN/OUT] the vector the created performance *
4517 * counter object should be added to *
4518 * counterid - [IN] the performance counter id *
4519 * *
4520 ******************************************************************************/
vmware_counters_add_new(zbx_vector_ptr_t * counters,zbx_uint64_t counterid)4521 static void vmware_counters_add_new(zbx_vector_ptr_t *counters, zbx_uint64_t counterid)
4522 {
4523 zbx_vmware_perf_counter_t *counter;
4524
4525 counter = (zbx_vmware_perf_counter_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_perf_counter_t));
4526 counter->counterid = counterid;
4527 counter->state = ZBX_VMWARE_COUNTER_NEW;
4528
4529 zbx_vector_str_uint64_pair_create_ext(&counter->values, __vm_mem_malloc_func, __vm_mem_realloc_func,
4530 __vm_mem_free_func);
4531
4532 zbx_vector_ptr_append(counters, counter);
4533 }
4534
4535 /******************************************************************************
4536 * *
4537 * Function: vmware_service_initialize *
4538 * *
4539 * Purpose: initializes vmware service object *
4540 * *
4541 * Parameters: service - [IN] the vmware service *
4542 * easyhandle - [IN] the CURL handle *
4543 * error - [OUT] the error message in the case of failure *
4544 * *
4545 * Return value: SUCCEED - the operation has completed successfully *
4546 * FAIL - the operation has failed *
4547 * *
4548 * Comments: While the service object can't be accessed from other processes *
4549 * during initialization it's still processed outside vmware locks *
4550 * and therefore must not allocate/free shared memory. *
4551 * *
4552 ******************************************************************************/
vmware_service_initialize(zbx_vmware_service_t * service,CURL * easyhandle,char ** error)4553 static int vmware_service_initialize(zbx_vmware_service_t *service, CURL *easyhandle, char **error)
4554 {
4555 # define UNPARSED_SERVICE_MAJOR_VERSION_DELIM "."
4556
4557 char *version_without_major, *version = NULL, *fullname = NULL;
4558 zbx_vector_ptr_t counters;
4559 int ret = FAIL;
4560
4561 zbx_vector_ptr_create(&counters);
4562
4563 if (SUCCEED != vmware_service_get_perf_counters(service, easyhandle, &counters, error))
4564 goto out;
4565
4566 if (SUCCEED != vmware_service_get_contents(easyhandle, &version, &fullname, error))
4567 goto out;
4568
4569 zbx_vmware_lock();
4570
4571 service->fullname = vmware_shared_strdup(fullname);
4572 vmware_counters_shared_copy(&service->counters, &counters);
4573 service->version = vmware_shared_strdup(version);
4574 service->major_version = atoi(version);
4575
4576 /* version should have the "x.y.z" format, but there is also an "x.y Un" format in nature */
4577 /* according to https://www.vmware.com/support/policies/version.html */
4578 if (NULL == (version_without_major = strstr(version, UNPARSED_SERVICE_MAJOR_VERSION_DELIM)))
4579 {
4580 *error = zbx_dsprintf(*error, "Invalid version: %s.", version);
4581 goto unlock;
4582 }
4583
4584 service->minor_version = atoi(strlen(UNPARSED_SERVICE_MAJOR_VERSION_DELIM) + version_without_major);
4585
4586 ret = SUCCEED;
4587 unlock:
4588 zbx_vmware_unlock();
4589 out:
4590 zbx_free(version);
4591 zbx_free(fullname);
4592
4593 zbx_vector_ptr_clear_ext(&counters, (zbx_mem_free_func_t)vmware_counter_free);
4594 zbx_vector_ptr_destroy(&counters);
4595
4596 return ret;
4597 }
4598
4599 /******************************************************************************
4600 * *
4601 * Function: vmware_service_add_perf_entity *
4602 * *
4603 * Purpose: adds entity to vmware service performance entity list *
4604 * *
4605 * Parameters: service - [IN] the vmware service *
4606 * type - [IN] the performance entity type (HostSystem, *
4607 * (Datastore, VirtualMachine...) *
4608 * id - [IN] the performance entity id *
4609 * counters - [IN] NULL terminated list of performance counters *
4610 * to be monitored for this entity *
4611 * instance - [IN] the performance counter instance name *
4612 * now - [IN] the current timestamp *
4613 * *
4614 * Comments: The performance counters are specified by their path: *
4615 * <group>/<key>[<rollup type>] *
4616 * *
4617 ******************************************************************************/
vmware_service_add_perf_entity(zbx_vmware_service_t * service,const char * type,const char * id,const char ** counters,const char * instance,int now)4618 static void vmware_service_add_perf_entity(zbx_vmware_service_t *service, const char *type, const char *id,
4619 const char **counters, const char *instance, int now)
4620 {
4621 zbx_vmware_perf_entity_t entity, *pentity;
4622 zbx_uint64_t counterid;
4623 int i;
4624
4625 zabbix_log(LOG_LEVEL_DEBUG, "In %s() type:%s id:%s", __func__, type, id);
4626
4627 if (NULL == (pentity = zbx_vmware_service_get_perf_entity(service, type, id)))
4628 {
4629 entity.type = vmware_shared_strdup(type);
4630 entity.id = vmware_shared_strdup(id);
4631
4632 pentity = (zbx_vmware_perf_entity_t *)zbx_hashset_insert(&service->entities, &entity, sizeof(zbx_vmware_perf_entity_t));
4633
4634 zbx_vector_ptr_create_ext(&pentity->counters, __vm_mem_malloc_func, __vm_mem_realloc_func,
4635 __vm_mem_free_func);
4636
4637 for (i = 0; NULL != counters[i]; i++)
4638 {
4639 if (SUCCEED == zbx_vmware_service_get_counterid(service, counters[i], &counterid))
4640 vmware_counters_add_new(&pentity->counters, counterid);
4641 else
4642 zabbix_log(LOG_LEVEL_DEBUG, "cannot find performance counter %s", counters[i]);
4643 }
4644
4645 zbx_vector_ptr_sort(&pentity->counters, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
4646 pentity->refresh = ZBX_VMWARE_PERF_INTERVAL_UNKNOWN;
4647 pentity->query_instance = vmware_shared_strdup(instance);
4648 pentity->error = NULL;
4649 }
4650
4651 pentity->last_seen = now;
4652
4653 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() perfcounters:%d", __func__, pentity->counters.values_num);
4654 }
4655
4656 /******************************************************************************
4657 * *
4658 * Function: vmware_service_update_perf_entities *
4659 * *
4660 * Purpose: adds new or remove old entities (hypervisors, virtual machines) *
4661 * from service performance entity list *
4662 * *
4663 * Parameters: service - [IN] the vmware service *
4664 * *
4665 ******************************************************************************/
vmware_service_update_perf_entities(zbx_vmware_service_t * service)4666 static void vmware_service_update_perf_entities(zbx_vmware_service_t *service)
4667 {
4668 int i;
4669 zbx_vmware_hv_t *hv;
4670 zbx_vmware_vm_t *vm;
4671 zbx_hashset_iter_t iter;
4672
4673 const char *hv_perfcounters[] = {
4674 "net/packetsRx[summation]", "net/packetsTx[summation]",
4675 "net/received[average]", "net/transmitted[average]",
4676 "datastore/totalReadLatency[average]",
4677 "datastore/totalWriteLatency[average]", NULL
4678 };
4679 const char *vm_perfcounters[] = {
4680 "virtualDisk/read[average]", "virtualDisk/write[average]",
4681 "virtualDisk/numberReadAveraged[average]",
4682 "virtualDisk/numberWriteAveraged[average]",
4683 "net/packetsRx[summation]", "net/packetsTx[summation]",
4684 "net/received[average]", "net/transmitted[average]",
4685 "cpu/ready[summation]", NULL
4686 };
4687
4688 const char *ds_perfcounters[] = {
4689 "disk/used[latest]", "disk/provisioned[latest]",
4690 "disk/capacity[latest]", NULL
4691 };
4692
4693 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
4694
4695 /* update current performance entities */
4696 zbx_hashset_iter_reset(&service->data->hvs, &iter);
4697 while (NULL != (hv = (zbx_vmware_hv_t *)zbx_hashset_iter_next(&iter)))
4698 {
4699 vmware_service_add_perf_entity(service, "HostSystem", hv->id, hv_perfcounters, "*", service->lastcheck);
4700
4701 for (i = 0; i < hv->vms.values_num; i++)
4702 {
4703 vm = (zbx_vmware_vm_t *)hv->vms.values[i];
4704 vmware_service_add_perf_entity(service, "VirtualMachine", vm->id, vm_perfcounters, "*",
4705 service->lastcheck);
4706 zabbix_log(LOG_LEVEL_TRACE, "%s() for type: VirtualMachine hv id: %s hv uuid: %s linked vm id:"
4707 " %s vm uuid: %s", __func__, hv->id, hv->uuid, vm->id, vm->uuid);
4708 }
4709 }
4710
4711 if (ZBX_VMWARE_TYPE_VCENTER == service->type)
4712 {
4713 for (i = 0; i < service->data->datastores.values_num; i++)
4714 {
4715 zbx_vmware_datastore_t *ds = service->data->datastores.values[i];
4716 vmware_service_add_perf_entity(service, "Datastore", ds->id, ds_perfcounters, "",
4717 service->lastcheck);
4718 zabbix_log(LOG_LEVEL_TRACE, "%s() for type: Datastore id: %s name: %s uuid: %s", __func__,
4719 ds->id, ds->name, ds->uuid);
4720 }
4721 }
4722
4723 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() entities:%d", __func__, service->entities.num_data);
4724 }
4725
4726 /******************************************************************************
4727 * *
4728 * Function: vmware_service_update *
4729 * *
4730 * Purpose: updates object with a new data from vmware service *
4731 * *
4732 * Parameters: service - [IN] the vmware service *
4733 * *
4734 ******************************************************************************/
vmware_service_update(zbx_vmware_service_t * service)4735 static void vmware_service_update(zbx_vmware_service_t *service)
4736 {
4737 CURL *easyhandle = NULL;
4738 CURLoption opt;
4739 CURLcode err;
4740 struct curl_slist *headers = NULL;
4741 zbx_vmware_data_t *data;
4742 zbx_vector_str_t hvs, dss;
4743 zbx_vector_ptr_t events;
4744 int i, ret = FAIL;
4745 ZBX_HTTPPAGE page; /* 347K/87K */
4746 unsigned char skip_old = service->eventlog.skip_old;
4747 zbx_uint64_t events_sz = 0;
4748 char msg[MAX_STRING_LEN / 8];
4749
4750 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, service->username, service->url);
4751
4752 data = (zbx_vmware_data_t *)zbx_malloc(NULL, sizeof(zbx_vmware_data_t));
4753 memset(data, 0, sizeof(zbx_vmware_data_t));
4754 page.alloc = 0;
4755
4756 zbx_hashset_create(&data->hvs, 1, vmware_hv_hash, vmware_hv_compare);
4757 zbx_vector_ptr_create(&data->clusters);
4758 zbx_vector_ptr_create(&data->events);
4759 zbx_vector_vmware_datastore_create(&data->datastores);
4760 zbx_vector_vmware_datacenter_create(&data->datacenters);
4761
4762 zbx_vector_str_create(&hvs);
4763 zbx_vector_str_create(&dss);
4764
4765 if (NULL == (easyhandle = curl_easy_init()))
4766 {
4767 zabbix_log(LOG_LEVEL_WARNING, "Cannot initialize cURL library");
4768 goto out;
4769 }
4770
4771 page.alloc = ZBX_INIT_UPD_XML_SIZE;
4772 page.data = (char *)zbx_malloc(NULL, page.alloc);
4773 headers = curl_slist_append(headers, ZBX_XML_HEADER1);
4774 headers = curl_slist_append(headers, ZBX_XML_HEADER2);
4775 headers = curl_slist_append(headers, ZBX_XML_HEADER3);
4776
4777 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HTTPHEADER, headers)))
4778 {
4779 zabbix_log(LOG_LEVEL_WARNING, "Cannot set cURL option %d: %s.", (int)opt, curl_easy_strerror(err));
4780 goto clean;
4781 }
4782
4783 if (SUCCEED != vmware_service_authenticate(service, easyhandle, &page, &data->error))
4784 goto clean;
4785
4786 if (0 != (service->state & ZBX_VMWARE_STATE_NEW) &&
4787 SUCCEED != vmware_service_initialize(service, easyhandle, &data->error))
4788 {
4789 goto clean;
4790 }
4791
4792 if (SUCCEED != vmware_service_get_hv_ds_dc_list(service, easyhandle, &hvs, &dss, &data->datacenters,
4793 &data->error))
4794 {
4795 goto clean;
4796 }
4797
4798 zbx_vector_vmware_datastore_reserve(&data->datastores, dss.values_num + data->datastores.values_alloc);
4799
4800 for (i = 0; i < dss.values_num; i++)
4801 {
4802 zbx_vmware_datastore_t *datastore;
4803
4804 if (NULL != (datastore = vmware_service_create_datastore(service, easyhandle, dss.values[i])))
4805 zbx_vector_vmware_datastore_append(&data->datastores, datastore);
4806 }
4807
4808 zbx_vector_vmware_datastore_sort(&data->datastores, vmware_ds_id_compare);
4809
4810 if (SUCCEED != zbx_hashset_reserve(&data->hvs, hvs.values_num))
4811 {
4812 THIS_SHOULD_NEVER_HAPPEN;
4813 exit(EXIT_FAILURE);
4814 }
4815
4816 for (i = 0; i < hvs.values_num; i++)
4817 {
4818 zbx_vmware_hv_t hv_local;
4819
4820 if (SUCCEED == vmware_service_init_hv(service, easyhandle, hvs.values[i], &data->datastores, &hv_local,
4821 &data->error))
4822 {
4823 zbx_hashset_insert(&data->hvs, &hv_local, sizeof(hv_local));
4824 }
4825 }
4826
4827 for (i = 0; i < data->datastores.values_num; i++)
4828 {
4829 zbx_vector_str_uint64_pair_sort(&data->datastores.values[i]->hv_uuids_access,
4830 zbx_str_uint64_pair_name_compare);
4831 }
4832
4833 zbx_vector_vmware_datastore_sort(&data->datastores, vmware_ds_name_compare);
4834
4835 if (0 == service->eventlog.req_sz)
4836 {
4837 /* skip collection of event data if we don't know where */
4838 /* we stopped last time or item can't accept values */
4839 if (ZBX_VMWARE_EVENT_KEY_UNINITIALIZED != service->eventlog.last_key &&
4840 0 == service->eventlog.skip_old &&
4841 SUCCEED != vmware_service_get_event_data(service, easyhandle, &data->events,
4842 &events_sz, &data->error))
4843 {
4844 goto clean;
4845 }
4846
4847 if (0 != service->eventlog.skip_old)
4848 {
4849 char *error = NULL;
4850
4851 /* May not be present */
4852 if (SUCCEED != vmware_service_get_last_event_data(service, easyhandle, &data->events,
4853 &events_sz, &error))
4854 {
4855 zabbix_log(LOG_LEVEL_DEBUG, "Unable retrieve lastevent value: %s.", error);
4856 zbx_free(error);
4857 }
4858 else
4859 skip_old = 0;
4860 }
4861 }
4862
4863 if (ZBX_VMWARE_TYPE_VCENTER == service->type &&
4864 SUCCEED != vmware_service_get_cluster_list(easyhandle, &data->clusters, &data->error))
4865 {
4866 goto clean;
4867 }
4868
4869 if (ZBX_VMWARE_TYPE_VCENTER != service->type)
4870 data->max_query_metrics = ZBX_VPXD_STATS_MAXQUERYMETRICS;
4871 else if (SUCCEED != vmware_service_get_maxquerymetrics(easyhandle, service, &data->max_query_metrics,
4872 &data->error))
4873 {
4874 goto clean;
4875 }
4876
4877 if (SUCCEED != vmware_service_logout(service, easyhandle, &data->error))
4878 {
4879 zabbix_log(LOG_LEVEL_DEBUG, "Cannot close vmware connection: %s.", data->error);
4880 zbx_free(data->error);
4881 }
4882
4883 ret = SUCCEED;
4884 clean:
4885 curl_slist_free_all(headers);
4886 curl_easy_cleanup(easyhandle);
4887 zbx_free(page.data);
4888
4889 zbx_vector_str_clear_ext(&hvs, zbx_str_free);
4890 zbx_vector_str_destroy(&hvs);
4891 zbx_vector_str_clear_ext(&dss, zbx_str_free);
4892 zbx_vector_str_destroy(&dss);
4893 out:
4894 zbx_vector_ptr_create(&events);
4895 zbx_vmware_lock();
4896
4897 /* remove UPDATING flag and set READY or FAILED flag */
4898 service->state &= ~(ZBX_VMWARE_STATE_MASK | ZBX_VMWARE_STATE_UPDATING);
4899 service->state |= (SUCCEED == ret) ? ZBX_VMWARE_STATE_READY : ZBX_VMWARE_STATE_FAILED;
4900
4901 if (0 < data->events.values_num)
4902 {
4903 if (0 != service->eventlog.oom)
4904 service->eventlog.oom = 0;
4905
4906 events_sz += evt_req_chunk_size * data->events.values_num +
4907 zbx_mem_required_chunk_size(data->events.values_alloc * sizeof(zbx_vmware_event_t*));
4908
4909 if (0 == service->eventlog.last_key || vmware_mem->free_size < events_sz ||
4910 SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
4911 {
4912 for (i = 0; i < data->events.values_num; i++)
4913 {
4914 zbx_vmware_event_t *event = data->events.values[i];
4915
4916 if (SUCCEED == vmware_shared_strsearch(event->message))
4917 {
4918 events_sz -= zbx_mem_required_chunk_size(strlen(event->message) +
4919 REFCOUNT_FIELD_SIZE + 1 + ZBX_HASHSET_ENTRY_OFFSET);
4920 }
4921 }
4922
4923 if (vmware_mem->free_size < events_sz)
4924 {
4925 service->eventlog.req_sz = events_sz;
4926 service->eventlog.oom = 1;
4927 zbx_vector_ptr_clear_ext(&data->events, (zbx_clean_func_t)vmware_event_free);
4928
4929 zabbix_log(LOG_LEVEL_WARNING, "Postponed VMware events requires up to " ZBX_FS_UI64
4930 " bytes of free VMwareCache memory, while currently only " ZBX_FS_UI64
4931 " bytes are free. VMwareCache memory usage (free/strpool/total): "
4932 ZBX_FS_UI64 " / " ZBX_FS_UI64 " / " ZBX_FS_UI64, events_sz,
4933 vmware_mem->free_size, vmware_mem->free_size, vmware->strpool_sz,
4934 vmware_mem->total_size);
4935 }
4936 else
4937 {
4938 int level;
4939
4940 level = 0 == service->eventlog.last_key ? LOG_LEVEL_WARNING : LOG_LEVEL_DEBUG;
4941
4942 zabbix_log(level, "Processed VMware events requires up to " ZBX_FS_UI64
4943 " bytes of free VMwareCache memory. VMwareCache memory usage"
4944 " (free/strpool/total): " ZBX_FS_UI64 " / " ZBX_FS_UI64 " / "
4945 ZBX_FS_UI64, events_sz, vmware_mem->free_size, vmware->strpool_sz,
4946 vmware_mem->total_size);
4947 }
4948 }
4949 }
4950 else if (0 < service->eventlog.req_sz && service->eventlog.req_sz <= vmware_mem->free_size)
4951 {
4952 service->eventlog.req_sz = 0;
4953 }
4954
4955 if (NULL != service->data && 0 != service->data->events.values_num &&
4956 ((const zbx_vmware_event_t *)service->data->events.values[0])->key > service->eventlog.last_key)
4957 {
4958 zbx_vector_ptr_append_array(&events, service->data->events.values, service->data->events.values_num);
4959 zbx_vector_ptr_reserve(&data->events, data->events.values_num + service->data->events.values_num);
4960 zbx_vector_ptr_clear(&service->data->events);
4961 }
4962
4963 vmware_data_shared_free(service->data);
4964 service->data = vmware_data_shared_dup(data);
4965 service->eventlog.skip_old = skip_old;
4966
4967 if (0 != events.values_num)
4968 zbx_vector_ptr_append_array(&service->data->events, events.values, events.values_num);
4969
4970 service->lastcheck = time(NULL);
4971
4972 vmware_service_update_perf_entities(service);
4973
4974 zbx_snprintf(msg, sizeof(msg), "VMwareCache memory usage (free/strpool/total): " ZBX_FS_UI64 " / "
4975 ZBX_FS_UI64 " / " ZBX_FS_UI64, vmware_mem->free_size, vmware->strpool_sz,
4976 vmware_mem->total_size);
4977
4978 zbx_vmware_unlock();
4979
4980 vmware_data_free(data);
4981 zbx_vector_ptr_destroy(&events);
4982
4983 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s \tprocessed:" ZBX_FS_SIZE_T " bytes of data. %s", __func__,
4984 zbx_result_string(ret), (zbx_fs_size_t)page.alloc, msg);
4985 }
4986
4987 /******************************************************************************
4988 * *
4989 * Function: vmware_service_process_perf_entity_data *
4990 * *
4991 * Purpose: updates vmware performance statistics data *
4992 * *
4993 * Parameters: pervalues - [OUT] the performance counter values *
4994 * xdoc - [IN] the XML document containing performance *
4995 * counter values for all entities *
4996 * node - [IN] the XML node containing performance counter *
4997 * values for the specified entity *
4998 * *
4999 * Return value: SUCCEED - the performance entity data was parsed *
5000 * FAIL - the perofmance entity data did not contain valid *
5001 * values *
5002 * *
5003 ******************************************************************************/
vmware_service_process_perf_entity_data(zbx_vector_ptr_t * pervalues,xmlDoc * xdoc,xmlNode * node)5004 static int vmware_service_process_perf_entity_data(zbx_vector_ptr_t *pervalues, xmlDoc *xdoc, xmlNode *node)
5005 {
5006 xmlXPathContext *xpathCtx;
5007 xmlXPathObject *xpathObj;
5008 xmlNodeSetPtr nodeset;
5009 char *instance, *counter, *value;
5010 int i, values = 0, ret = FAIL;
5011 zbx_vmware_perf_value_t *perfvalue;
5012
5013 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5014
5015 xpathCtx = xmlXPathNewContext(xdoc);
5016 xpathCtx->node = node;
5017
5018 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)"*[local-name()='value']", xpathCtx)))
5019 goto out;
5020
5021 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
5022 goto out;
5023
5024 nodeset = xpathObj->nodesetval;
5025 zbx_vector_ptr_reserve(pervalues, nodeset->nodeNr + pervalues->values_alloc);
5026
5027 for (i = 0; i < nodeset->nodeNr; i++)
5028 {
5029 value = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], "*[local-name()='value'][last()]");
5030 instance = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], "*[local-name()='id']"
5031 "/*[local-name()='instance']");
5032 counter = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], "*[local-name()='id']"
5033 "/*[local-name()='counterId']");
5034
5035 if (NULL != value && NULL != counter)
5036 {
5037 perfvalue = (zbx_vmware_perf_value_t *)zbx_malloc(NULL, sizeof(zbx_vmware_perf_value_t));
5038
5039 ZBX_STR2UINT64(perfvalue->counterid, counter);
5040 perfvalue->instance = (NULL != instance ? instance : zbx_strdup(NULL, ""));
5041
5042 if (0 == strcmp(value, "-1") || SUCCEED != is_uint64(value, &perfvalue->value))
5043 perfvalue->value = UINT64_MAX;
5044 else if (FAIL == ret)
5045 ret = SUCCEED;
5046
5047 zbx_vector_ptr_append(pervalues, perfvalue);
5048
5049 instance = NULL;
5050 values++;
5051 }
5052
5053 zbx_free(counter);
5054 zbx_free(instance);
5055 zbx_free(value);
5056 }
5057
5058 out:
5059 if (NULL != xpathObj)
5060 xmlXPathFreeObject(xpathObj);
5061
5062 xmlXPathFreeContext(xpathCtx);
5063
5064 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() values:%d", __func__, values);
5065
5066 return ret;
5067 }
5068
5069 /******************************************************************************
5070 * *
5071 * Function: vmware_service_parse_perf_data *
5072 * *
5073 * Purpose: updates vmware performance statistics data *
5074 * *
5075 * Parameters: perfdata - [OUT] performance entity data *
5076 * xdoc - [IN] the performance data xml document *
5077 * *
5078 ******************************************************************************/
vmware_service_parse_perf_data(zbx_vector_ptr_t * perfdata,xmlDoc * xdoc)5079 static void vmware_service_parse_perf_data(zbx_vector_ptr_t *perfdata, xmlDoc *xdoc)
5080 {
5081 xmlXPathContext *xpathCtx;
5082 xmlXPathObject *xpathObj;
5083 xmlNodeSetPtr nodeset;
5084 int i;
5085
5086 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5087
5088 xpathCtx = xmlXPathNewContext(xdoc);
5089
5090 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)"/*/*/*/*", xpathCtx)))
5091 goto clean;
5092
5093 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
5094 goto clean;
5095
5096 nodeset = xpathObj->nodesetval;
5097 zbx_vector_ptr_reserve(perfdata, nodeset->nodeNr + perfdata->values_alloc);
5098
5099 for (i = 0; i < nodeset->nodeNr; i++)
5100 {
5101 zbx_vmware_perf_data_t *data;
5102 int ret = FAIL;
5103
5104 data = (zbx_vmware_perf_data_t *)zbx_malloc(NULL, sizeof(zbx_vmware_perf_data_t));
5105
5106 data->id = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], "*[local-name()='entity']");
5107 data->type = zbx_xml_read_node_value(xdoc, nodeset->nodeTab[i], "*[local-name()='entity']/@type");
5108 data->error = NULL;
5109 zbx_vector_ptr_create(&data->values);
5110
5111 if (NULL != data->type && NULL != data->id)
5112 ret = vmware_service_process_perf_entity_data(&data->values, xdoc, nodeset->nodeTab[i]);
5113
5114 if (SUCCEED == ret)
5115 zbx_vector_ptr_append(perfdata, data);
5116 else
5117 vmware_free_perfdata(data);
5118 }
5119 clean:
5120 if (NULL != xpathObj)
5121 xmlXPathFreeObject(xpathObj);
5122
5123 xmlXPathFreeContext(xpathCtx);
5124 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5125 }
5126
5127 /******************************************************************************
5128 * *
5129 * Function: vmware_perf_data_add_error *
5130 * *
5131 * Purpose: adds error for the specified perf entity *
5132 * *
5133 * Parameters: perfdata - [OUT] the collected performance counter data *
5134 * type - [IN] the performance entity type (HostSystem, *
5135 * (Datastore, VirtualMachine...) *
5136 * id - [IN] the performance entity id *
5137 * error - [IN] the error to add *
5138 * *
5139 * Comments: The performance counters are specified by their path: *
5140 * <group>/<key>[<rollup type>] *
5141 * *
5142 ******************************************************************************/
vmware_perf_data_add_error(zbx_vector_ptr_t * perfdata,const char * type,const char * id,const char * error)5143 static void vmware_perf_data_add_error(zbx_vector_ptr_t *perfdata, const char *type, const char *id,
5144 const char *error)
5145 {
5146 zbx_vmware_perf_data_t *data;
5147
5148 data = zbx_malloc(NULL, sizeof(zbx_vmware_perf_data_t));
5149
5150 data->type = zbx_strdup(NULL, type);
5151 data->id = zbx_strdup(NULL, id);
5152 data->error = zbx_strdup(NULL, error);
5153 zbx_vector_ptr_create(&data->values);
5154
5155 zbx_vector_ptr_append(perfdata, data);
5156 }
5157
5158 /******************************************************************************
5159 * *
5160 * Function: vmware_service_copy_perf_data *
5161 * *
5162 * Purpose: copies vmware performance statistics of specified service *
5163 * *
5164 * Parameters: service - [IN] the vmware service *
5165 * perfdata - [IN/OUT] the performance data *
5166 * *
5167 ******************************************************************************/
vmware_service_copy_perf_data(zbx_vmware_service_t * service,zbx_vector_ptr_t * perfdata)5168 static void vmware_service_copy_perf_data(zbx_vmware_service_t *service, zbx_vector_ptr_t *perfdata)
5169 {
5170 int i, j, index;
5171 zbx_vmware_perf_data_t *data;
5172 zbx_vmware_perf_value_t *value;
5173 zbx_vmware_perf_entity_t *entity;
5174 zbx_vmware_perf_counter_t *perfcounter;
5175 zbx_str_uint64_pair_t perfvalue;
5176
5177 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5178
5179 for (i = 0; i < perfdata->values_num; i++)
5180 {
5181 data = (zbx_vmware_perf_data_t *)perfdata->values[i];
5182
5183 if (NULL == (entity = zbx_vmware_service_get_perf_entity(service, data->type, data->id)))
5184 continue;
5185
5186 if (NULL != data->error)
5187 {
5188 entity->error = vmware_shared_strdup(data->error);
5189 continue;
5190 }
5191
5192 for (j = 0; j < data->values.values_num; j++)
5193 {
5194 value = (zbx_vmware_perf_value_t *)data->values.values[j];
5195
5196 if (FAIL == (index = zbx_vector_ptr_bsearch(&entity->counters, &value->counterid,
5197 ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
5198 {
5199 continue;
5200 }
5201
5202 perfcounter = (zbx_vmware_perf_counter_t *)entity->counters.values[index];
5203
5204 perfvalue.name = vmware_shared_strdup(value->instance);
5205 perfvalue.value = value->value;
5206
5207 zbx_vector_str_uint64_pair_append_ptr(&perfcounter->values, &perfvalue);
5208 }
5209 }
5210
5211 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5212 }
5213
5214 /******************************************************************************
5215 * *
5216 * Function: vmware_service_retrieve_perf_counters *
5217 * *
5218 * Purpose: retrieves performance counter values from vmware service *
5219 * *
5220 * Parameters: service - [IN] the vmware service *
5221 * easyhandle - [IN] prepared cURL connection handle *
5222 * entities - [IN] the performance collector entities to *
5223 * retrieve counters for *
5224 * counters_max - [IN] the maximum number of counters per query. *
5225 * perfdata - [OUT] the performance counter values *
5226 * *
5227 ******************************************************************************/
vmware_service_retrieve_perf_counters(zbx_vmware_service_t * service,CURL * easyhandle,zbx_vector_ptr_t * entities,int counters_max,zbx_vector_ptr_t * perfdata)5228 static void vmware_service_retrieve_perf_counters(zbx_vmware_service_t *service, CURL *easyhandle,
5229 zbx_vector_ptr_t *entities, int counters_max, zbx_vector_ptr_t *perfdata)
5230 {
5231 char *tmp = NULL, *error = NULL;
5232 size_t tmp_alloc = 0, tmp_offset;
5233 int i, j, start_counter = 0;
5234 zbx_vmware_perf_entity_t *entity;
5235 xmlDoc *doc = NULL;
5236
5237 zabbix_log(LOG_LEVEL_DEBUG, "In %s() counters_max:%d", __func__, counters_max);
5238
5239 while (0 != entities->values_num)
5240 {
5241 int counters_num = 0;
5242
5243 tmp_offset = 0;
5244 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ZBX_POST_VSPHERE_HEADER);
5245 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "<ns0:QueryPerf>"
5246 "<ns0:_this type=\"PerformanceManager\">%s</ns0:_this>",
5247 vmware_service_objects[service->type].performance_manager);
5248
5249 zbx_vmware_lock();
5250
5251 for (i = entities->values_num - 1; 0 <= i && counters_num < counters_max;)
5252 {
5253 char *id_esc;
5254
5255 entity = (zbx_vmware_perf_entity_t *)entities->values[i];
5256
5257 id_esc = xml_escape_dyn(entity->id);
5258
5259 /* add entity performance counter request */
5260 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "<ns0:querySpec>"
5261 "<ns0:entity type=\"%s\">%s</ns0:entity>", entity->type, id_esc);
5262
5263 zbx_free(id_esc);
5264
5265 if (ZBX_VMWARE_PERF_INTERVAL_NONE == entity->refresh)
5266 {
5267 time_t st_raw;
5268 struct tm st;
5269 char st_str[ZBX_XML_DATETIME];
5270
5271 /* add startTime for entity performance counter request for decrease XML data load */
5272 st_raw = zbx_time() - SEC_PER_HOUR;
5273 gmtime_r(&st_raw, &st);
5274 strftime(st_str, sizeof(st_str), "%Y-%m-%dT%TZ", &st);
5275 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "<ns0:startTime>%s</ns0:startTime>",
5276 st_str);
5277 }
5278
5279 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "<ns0:maxSample>1</ns0:maxSample>");
5280
5281 for (j = start_counter; j < entity->counters.values_num && counters_num < counters_max; j++)
5282 {
5283 zbx_vmware_perf_counter_t *counter;
5284
5285 counter = (zbx_vmware_perf_counter_t *)entity->counters.values[j];
5286
5287 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset,
5288 "<ns0:metricId><ns0:counterId>" ZBX_FS_UI64
5289 "</ns0:counterId><ns0:instance>%s</ns0:instance></ns0:metricId>",
5290 counter->counterid, entity->query_instance);
5291
5292 counter->state |= ZBX_VMWARE_COUNTER_UPDATING;
5293
5294 counters_num++;
5295 }
5296
5297 if (j == entity->counters.values_num)
5298 {
5299 start_counter = 0;
5300 i--;
5301 }
5302 else
5303 start_counter = j;
5304
5305
5306 if (ZBX_VMWARE_PERF_INTERVAL_NONE != entity->refresh)
5307 {
5308 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "<ns0:intervalId>%d</ns0:intervalId>",
5309 entity->refresh);
5310 }
5311
5312 zbx_snprintf_alloc(&tmp, &tmp_alloc, &tmp_offset, "</ns0:querySpec>");
5313 }
5314
5315 zbx_vmware_unlock();
5316 zbx_xml_free_doc(doc);
5317 doc = NULL;
5318
5319 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, "</ns0:QueryPerf>");
5320 zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ZBX_POST_VSPHERE_FOOTER);
5321
5322 zabbix_log(LOG_LEVEL_TRACE, "%s() SOAP request: %s", __func__, tmp);
5323
5324 if (SUCCEED != zbx_soap_post(__func__, easyhandle, tmp, &doc, &error))
5325 {
5326 for (j = i + 1; j < entities->values_num; j++)
5327 {
5328 entity = (zbx_vmware_perf_entity_t *)entities->values[j];
5329 vmware_perf_data_add_error(perfdata, entity->type, entity->id, error);
5330 }
5331
5332 zbx_free(error);
5333 break;
5334 }
5335
5336 /* parse performance data into local memory */
5337 vmware_service_parse_perf_data(perfdata, doc);
5338
5339 while (entities->values_num > i + 1)
5340 zbx_vector_ptr_remove_noorder(entities, entities->values_num - 1);
5341 }
5342
5343 zbx_free(tmp);
5344 zbx_xml_free_doc(doc);
5345
5346 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5347 }
5348
5349 /******************************************************************************
5350 * *
5351 * Function: vmware_service_update_perf *
5352 * *
5353 * Purpose: updates vmware statistics data *
5354 * *
5355 * Parameters: service - [IN] the vmware service *
5356 * *
5357 ******************************************************************************/
vmware_service_update_perf(zbx_vmware_service_t * service)5358 static void vmware_service_update_perf(zbx_vmware_service_t *service)
5359 {
5360 # define INIT_PERF_XML_SIZE 200 * ZBX_KIBIBYTE
5361
5362 CURL *easyhandle = NULL;
5363 CURLoption opt;
5364 CURLcode err;
5365 struct curl_slist *headers = NULL;
5366 int i, ret = FAIL;
5367 char *error = NULL;
5368 zbx_vector_ptr_t entities, hist_entities;
5369 zbx_vmware_perf_entity_t *entity;
5370 zbx_hashset_iter_t iter;
5371 zbx_vector_ptr_t perfdata;
5372 static ZBX_HTTPPAGE page; /* 173K */
5373
5374 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, service->username, service->url);
5375
5376 zbx_vector_ptr_create(&entities);
5377 zbx_vector_ptr_create(&hist_entities);
5378 zbx_vector_ptr_create(&perfdata);
5379 page.alloc = 0;
5380
5381 if (NULL == (easyhandle = curl_easy_init()))
5382 {
5383 error = zbx_strdup(error, "cannot initialize cURL library");
5384 goto out;
5385 }
5386
5387 page.alloc = INIT_PERF_XML_SIZE;
5388 page.data = (char *)zbx_malloc(NULL, page.alloc);
5389 headers = curl_slist_append(headers, ZBX_XML_HEADER1);
5390 headers = curl_slist_append(headers, ZBX_XML_HEADER2);
5391 headers = curl_slist_append(headers, ZBX_XML_HEADER3);
5392
5393 if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HTTPHEADER, headers)))
5394 {
5395 error = zbx_dsprintf(error, "Cannot set cURL option %d: %s.", (int)opt, curl_easy_strerror(err));
5396 goto clean;
5397 }
5398
5399 if (SUCCEED != vmware_service_authenticate(service, easyhandle, &page, &error))
5400 goto clean;
5401
5402 /* update performance counter refresh rate for entities */
5403
5404 zbx_vmware_lock();
5405
5406 zbx_hashset_iter_reset(&service->entities, &iter);
5407 while (NULL != (entity = (zbx_vmware_perf_entity_t *)zbx_hashset_iter_next(&iter)))
5408 {
5409 /* remove old entities */
5410 if (0 != entity->last_seen && entity->last_seen < service->lastcheck)
5411 {
5412 vmware_shared_perf_entity_clean(entity);
5413 zbx_hashset_iter_remove(&iter);
5414 continue;
5415 }
5416
5417 if (ZBX_VMWARE_PERF_INTERVAL_UNKNOWN != entity->refresh)
5418 continue;
5419
5420 /* Entities are removed only during performance counter update and no two */
5421 /* performance counter updates for one service can happen simultaneously. */
5422 /* This means for refresh update we can safely use reference to entity */
5423 /* outside vmware lock. */
5424 zbx_vector_ptr_append(&entities, entity);
5425 }
5426
5427 zbx_vmware_unlock();
5428
5429 /* get refresh rates */
5430 for (i = 0; i < entities.values_num; i++)
5431 {
5432 entity = entities.values[i];
5433
5434 if (SUCCEED != vmware_service_get_perf_counter_refreshrate(service, easyhandle, entity->type,
5435 entity->id, &entity->refresh, &error))
5436 {
5437 zabbix_log(LOG_LEVEL_WARNING, "cannot get refresh rate for %s \"%s\": %s", entity->type,
5438 entity->id, error);
5439 zbx_free(error);
5440 }
5441 }
5442
5443 zbx_vector_ptr_clear(&entities);
5444
5445 zbx_vmware_lock();
5446
5447 zbx_hashset_iter_reset(&service->entities, &iter);
5448 while (NULL != (entity = (zbx_vmware_perf_entity_t *)zbx_hashset_iter_next(&iter)))
5449 {
5450 if (ZBX_VMWARE_PERF_INTERVAL_UNKNOWN == entity->refresh)
5451 {
5452 zabbix_log(LOG_LEVEL_DEBUG, "skipping performance entity with zero refresh rate "
5453 "type:%s id:%s", entity->type, entity->id);
5454 continue;
5455 }
5456
5457 if (ZBX_VMWARE_PERF_INTERVAL_NONE == entity->refresh)
5458 zbx_vector_ptr_append(&hist_entities, entity);
5459 else
5460 zbx_vector_ptr_append(&entities, entity);
5461 }
5462
5463 zbx_vmware_unlock();
5464
5465 vmware_service_retrieve_perf_counters(service, easyhandle, &entities, ZBX_MAXQUERYMETRICS_UNLIMITED, &perfdata);
5466 vmware_service_retrieve_perf_counters(service, easyhandle, &hist_entities, service->data->max_query_metrics,
5467 &perfdata);
5468
5469 if (SUCCEED != vmware_service_logout(service, easyhandle, &error))
5470 {
5471 zabbix_log(LOG_LEVEL_DEBUG, "Cannot close vmware connection: %s.", error);
5472 zbx_free(error);
5473 }
5474
5475 ret = SUCCEED;
5476 clean:
5477 curl_slist_free_all(headers);
5478 curl_easy_cleanup(easyhandle);
5479 zbx_free(page.data);
5480 out:
5481 zbx_vmware_lock();
5482
5483 if (FAIL == ret)
5484 {
5485 zbx_hashset_iter_reset(&service->entities, &iter);
5486 while (NULL != (entity = zbx_hashset_iter_next(&iter)))
5487 entity->error = vmware_shared_strdup(error);
5488
5489 zbx_free(error);
5490 }
5491 else
5492 {
5493 /* clean old performance data and copy the new data into shared memory */
5494 vmware_entities_shared_clean_stats(&service->entities);
5495 vmware_service_copy_perf_data(service, &perfdata);
5496 }
5497
5498 service->state &= ~(ZBX_VMWARE_STATE_UPDATING_PERF);
5499 service->lastperfcheck = time(NULL);
5500
5501 zbx_vmware_unlock();
5502
5503 zbx_vector_ptr_clear_ext(&perfdata, (zbx_mem_free_func_t)vmware_free_perfdata);
5504 zbx_vector_ptr_destroy(&perfdata);
5505
5506 zbx_vector_ptr_destroy(&hist_entities);
5507 zbx_vector_ptr_destroy(&entities);
5508
5509 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s \tprocessed " ZBX_FS_SIZE_T " bytes of data", __func__,
5510 zbx_result_string(ret), (zbx_fs_size_t)page.alloc);
5511 }
5512
5513 /******************************************************************************
5514 * *
5515 * Function: vmware_service_remove *
5516 * *
5517 * Purpose: removes vmware service *
5518 * *
5519 * Parameters: service - [IN] the vmware service *
5520 * *
5521 ******************************************************************************/
vmware_service_remove(zbx_vmware_service_t * service)5522 static void vmware_service_remove(zbx_vmware_service_t *service)
5523 {
5524 int index;
5525
5526 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, service->username, service->url);
5527
5528 zbx_vmware_lock();
5529
5530 if (FAIL != (index = zbx_vector_ptr_search(&vmware->services, service, ZBX_DEFAULT_PTR_COMPARE_FUNC)))
5531 {
5532 zbx_vector_ptr_remove(&vmware->services, index);
5533 vmware_service_shared_free(service);
5534 }
5535
5536 zbx_vmware_unlock();
5537
5538 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5539 }
5540
5541 /*
5542 * Public API
5543 */
5544
5545 /******************************************************************************
5546 * *
5547 * Function: zbx_vmware_get_service *
5548 * *
5549 * Purpose: gets vmware service object *
5550 * *
5551 * Parameters: url - [IN] the vmware service URL *
5552 * username - [IN] the vmware service username *
5553 * password - [IN] the vmware service password *
5554 * *
5555 * Return value: the requested service object or NULL if the object is not *
5556 * yet ready. *
5557 * *
5558 * Comments: vmware lock must be locked with zbx_vmware_lock() function *
5559 * before calling this function. *
5560 * If the service list does not contain the requested service object*
5561 * then a new object is created, marked as new, added to the list *
5562 * and a NULL value is returned. *
5563 * If the object is in list, but is not yet updated also a NULL *
5564 * value is returned. *
5565 * *
5566 ******************************************************************************/
zbx_vmware_get_service(const char * url,const char * username,const char * password)5567 zbx_vmware_service_t *zbx_vmware_get_service(const char* url, const char* username, const char* password)
5568 {
5569 int i, now;
5570 zbx_vmware_service_t *service = NULL;
5571
5572 zabbix_log(LOG_LEVEL_DEBUG, "In %s() '%s'@'%s'", __func__, username, url);
5573
5574 if (NULL == vmware)
5575 goto out;
5576
5577 now = time(NULL);
5578
5579 for (i = 0; i < vmware->services.values_num; i++)
5580 {
5581 service = (zbx_vmware_service_t *)vmware->services.values[i];
5582
5583 if (0 == strcmp(service->url, url) && 0 == strcmp(service->username, username) &&
5584 0 == strcmp(service->password, password))
5585 {
5586 service->lastaccess = now;
5587
5588 /* return NULL if the service is not ready yet */
5589 if (0 == (service->state & (ZBX_VMWARE_STATE_READY | ZBX_VMWARE_STATE_FAILED)))
5590 service = NULL;
5591
5592 goto out;
5593 }
5594 }
5595
5596 service = (zbx_vmware_service_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_service_t));
5597 memset(service, 0, sizeof(zbx_vmware_service_t));
5598
5599 service->url = vmware_shared_strdup(url);
5600 service->username = vmware_shared_strdup(username);
5601 service->password = vmware_shared_strdup(password);
5602 service->type = ZBX_VMWARE_TYPE_UNKNOWN;
5603 service->state = ZBX_VMWARE_STATE_NEW;
5604 service->lastaccess = now;
5605 service->eventlog.last_key = ZBX_VMWARE_EVENT_KEY_UNINITIALIZED;
5606 service->eventlog.skip_old = 0;
5607 service->eventlog.req_sz = 0;
5608 service->eventlog.oom = 0;
5609
5610 zbx_hashset_create_ext(&service->entities, 100, vmware_perf_entity_hash_func, vmware_perf_entity_compare_func,
5611 NULL, __vm_mem_malloc_func, __vm_mem_realloc_func, __vm_mem_free_func);
5612
5613 zbx_hashset_create_ext(&service->counters, ZBX_VMWARE_COUNTERS_INIT_SIZE, vmware_counter_hash_func,
5614 vmware_counter_compare_func, NULL, __vm_mem_malloc_func, __vm_mem_realloc_func,
5615 __vm_mem_free_func);
5616
5617 zbx_vector_ptr_append(&vmware->services, service);
5618
5619 /* new service does not have any data - return NULL */
5620 service = NULL;
5621 out:
5622 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__,
5623 zbx_result_string(NULL != service ? SUCCEED : FAIL));
5624
5625 return service;
5626 }
5627
5628
5629 /******************************************************************************
5630 * *
5631 * Function: zbx_vmware_service_get_counterid *
5632 * *
5633 * Purpose: gets vmware performance counter id by the path *
5634 * *
5635 * Parameters: service - [IN] the vmware service *
5636 * path - [IN] the path of counter to retrieve in format *
5637 * <group>/<key>[<rollup type>] *
5638 * counterid - [OUT] the counter id *
5639 * *
5640 * Return value: SUCCEED if the counter was found, FAIL otherwise *
5641 * *
5642 ******************************************************************************/
zbx_vmware_service_get_counterid(zbx_vmware_service_t * service,const char * path,zbx_uint64_t * counterid)5643 int zbx_vmware_service_get_counterid(zbx_vmware_service_t *service, const char *path,
5644 zbx_uint64_t *counterid)
5645 {
5646 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
5647 zbx_vmware_counter_t *counter;
5648 int ret = FAIL;
5649
5650 zabbix_log(LOG_LEVEL_DEBUG, "In %s() path:%s", __func__, path);
5651
5652 if (NULL == (counter = (zbx_vmware_counter_t *)zbx_hashset_search(&service->counters, &path)))
5653 goto out;
5654
5655 *counterid = counter->id;
5656
5657 zabbix_log(LOG_LEVEL_DEBUG, "%s() counterid:" ZBX_FS_UI64, __func__, *counterid);
5658
5659 ret = SUCCEED;
5660 out:
5661 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
5662
5663 return ret;
5664 #else
5665 return FAIL;
5666 #endif
5667 }
5668
5669 /******************************************************************************
5670 * *
5671 * Function: zbx_vmware_service_add_perf_counter *
5672 * *
5673 * Purpose: start monitoring performance counter of the specified entity *
5674 * *
5675 * Parameters: service - [IN] the vmware service *
5676 * type - [IN] the entity type *
5677 * id - [IN] the entity id *
5678 * counterid - [IN] the performance counter id *
5679 * instance - [IN] the performance counter instance name *
5680 * *
5681 * Return value: SUCCEED - the entity counter was added to monitoring list. *
5682 * FAIL - the performance counter of the specified entity *
5683 * is already being monitored. *
5684 * *
5685 ******************************************************************************/
zbx_vmware_service_add_perf_counter(zbx_vmware_service_t * service,const char * type,const char * id,zbx_uint64_t counterid,const char * instance)5686 int zbx_vmware_service_add_perf_counter(zbx_vmware_service_t *service, const char *type, const char *id,
5687 zbx_uint64_t counterid, const char *instance)
5688 {
5689 zbx_vmware_perf_entity_t *pentity, entity;
5690 int ret = FAIL;
5691
5692 zabbix_log(LOG_LEVEL_DEBUG, "In %s() type:%s id:%s counterid:" ZBX_FS_UI64, __func__, type, id,
5693 counterid);
5694
5695 if (NULL == (pentity = zbx_vmware_service_get_perf_entity(service, type, id)))
5696 {
5697 entity.refresh = ZBX_VMWARE_PERF_INTERVAL_UNKNOWN;
5698 entity.last_seen = 0;
5699 entity.query_instance = vmware_shared_strdup(instance);
5700 entity.type = vmware_shared_strdup(type);
5701 entity.id = vmware_shared_strdup(id);
5702 entity.error = NULL;
5703 zbx_vector_ptr_create_ext(&entity.counters, __vm_mem_malloc_func, __vm_mem_realloc_func,
5704 __vm_mem_free_func);
5705
5706 pentity = (zbx_vmware_perf_entity_t *)zbx_hashset_insert(&service->entities, &entity,
5707 sizeof(zbx_vmware_perf_entity_t));
5708 }
5709
5710 if (FAIL == zbx_vector_ptr_search(&pentity->counters, &counterid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC))
5711 {
5712 vmware_counters_add_new(&pentity->counters, counterid);
5713 zbx_vector_ptr_sort(&pentity->counters, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
5714
5715 ret = SUCCEED;
5716 }
5717
5718 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
5719
5720 return ret;
5721 }
5722
5723 /******************************************************************************
5724 * *
5725 * Function: zbx_vmware_service_get_perf_entity *
5726 * *
5727 * Purpose: gets performance entity by type and id *
5728 * *
5729 * Parameters: service - [IN] the vmware service *
5730 * type - [IN] the performance entity type *
5731 * id - [IN] the performance entity id *
5732 * *
5733 * Return value: the performance entity or NULL if not found *
5734 * *
5735 ******************************************************************************/
zbx_vmware_service_get_perf_entity(zbx_vmware_service_t * service,const char * type,const char * id)5736 zbx_vmware_perf_entity_t *zbx_vmware_service_get_perf_entity(zbx_vmware_service_t *service, const char *type,
5737 const char *id)
5738 {
5739 zbx_vmware_perf_entity_t *pentity, entity = {.type = (char *)type, .id = (char *)id};
5740
5741 zabbix_log(LOG_LEVEL_DEBUG, "In %s() type:%s id:%s", __func__, type, id);
5742
5743 pentity = (zbx_vmware_perf_entity_t *)zbx_hashset_search(&service->entities, &entity);
5744
5745 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() entity:%p", __func__, (void *)pentity);
5746
5747 return pentity;
5748 }
5749 #endif
5750
5751 /******************************************************************************
5752 * *
5753 * Function: zbx_vmware_init *
5754 * *
5755 * Purpose: initializes vmware collector service *
5756 * *
5757 * Comments: This function must be called before worker threads are forked. *
5758 * *
5759 ******************************************************************************/
zbx_vmware_init(char ** error)5760 int zbx_vmware_init(char **error)
5761 {
5762 int ret = FAIL;
5763 zbx_uint64_t size_reserved;
5764
5765 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5766
5767 if (SUCCEED != zbx_mutex_create(&vmware_lock, ZBX_MUTEX_VMWARE, error))
5768 goto out;
5769
5770 size_reserved = zbx_mem_required_size(1, "vmware cache size", "VMwareCacheSize");
5771
5772 CONFIG_VMWARE_CACHE_SIZE -= size_reserved;
5773
5774 if (SUCCEED != zbx_mem_create(&vmware_mem, CONFIG_VMWARE_CACHE_SIZE, "vmware cache size", "VMwareCacheSize", 0,
5775 error))
5776 {
5777 goto out;
5778 }
5779
5780 vmware = (zbx_vmware_t *)__vm_mem_malloc_func(NULL, sizeof(zbx_vmware_t));
5781 memset(vmware, 0, sizeof(zbx_vmware_t));
5782
5783 VMWARE_VECTOR_CREATE(&vmware->services, ptr);
5784 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
5785 vmware->strpool_sz = 0;
5786 zbx_hashset_create_ext(&vmware->strpool, 100, vmware_strpool_hash_func, vmware_strpool_compare_func, NULL,
5787 __vm_mem_malloc_func, __vm_mem_realloc_func, __vm_mem_free_func);
5788 zbx_hashset_create(&evt_msg_strpool, 100, vmware_strpool_hash_func, vmware_strpool_compare_func);
5789 evt_req_chunk_size = zbx_mem_required_chunk_size(sizeof(zbx_vmware_event_t));
5790 #endif
5791 ret = SUCCEED;
5792 out:
5793 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5794
5795 return ret;
5796 }
5797
5798 /******************************************************************************
5799 * *
5800 * Function: zbx_vmware_destroy *
5801 * *
5802 * Purpose: destroys vmware collector service *
5803 * *
5804 ******************************************************************************/
zbx_vmware_destroy(void)5805 void zbx_vmware_destroy(void)
5806 {
5807 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
5808 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
5809 zbx_hashset_destroy(&vmware->strpool);
5810 zbx_hashset_destroy(&evt_msg_strpool);
5811 #endif
5812 zbx_mutex_destroy(&vmware_lock);
5813
5814 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
5815 }
5816
5817 #define ZBX_VMWARE_TASK_IDLE 1
5818 #define ZBX_VMWARE_TASK_UPDATE 2
5819 #define ZBX_VMWARE_TASK_UPDATE_PERF 3
5820 #define ZBX_VMWARE_TASK_REMOVE 4
5821
5822 /******************************************************************************
5823 * *
5824 * Function: main_vmware_loop *
5825 * *
5826 * Purpose: the vmware collector main loop *
5827 * *
5828 ******************************************************************************/
ZBX_THREAD_ENTRY(vmware_thread,args)5829 ZBX_THREAD_ENTRY(vmware_thread, args)
5830 {
5831 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
5832 int i, now, task, next_update, updated_services = 0, removed_services = 0,
5833 old_updated_services = 0, old_removed_services = 0, sleeptime = -1;
5834 zbx_vmware_service_t *service = NULL;
5835 double sec, total_sec = 0.0, old_total_sec = 0.0;
5836 time_t last_stat_time;
5837
5838 process_type = ((zbx_thread_args_t *)args)->process_type;
5839 server_num = ((zbx_thread_args_t *)args)->server_num;
5840 process_num = ((zbx_thread_args_t *)args)->process_num;
5841
5842 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
5843 server_num, get_process_type_string(process_type), process_num);
5844
5845 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
5846
5847 #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */
5848 /* once in STAT_INTERVAL seconds */
5849
5850 last_stat_time = time(NULL);
5851
5852 while (ZBX_IS_RUNNING())
5853 {
5854 sec = zbx_time();
5855 zbx_update_env(sec);
5856
5857 if (0 != sleeptime)
5858 {
5859 zbx_setproctitle("%s #%d [updated %d, removed %d VMware services in " ZBX_FS_DBL " sec, "
5860 "querying VMware services]", get_process_type_string(process_type), process_num,
5861 old_updated_services, old_removed_services, old_total_sec);
5862 }
5863
5864 do
5865 {
5866 task = ZBX_VMWARE_TASK_IDLE;
5867
5868 now = time(NULL);
5869 next_update = now + POLLER_DELAY;
5870
5871 zbx_vmware_lock();
5872
5873 /* find a task to be performed on a vmware service */
5874 for (i = 0; i < vmware->services.values_num; i++)
5875 {
5876 service = (zbx_vmware_service_t *)vmware->services.values[i];
5877
5878 /* check if the service isn't used and should be removed */
5879 if (0 == (service->state & ZBX_VMWARE_STATE_BUSY) &&
5880 now - service->lastaccess > ZBX_VMWARE_SERVICE_TTL)
5881 {
5882 service->state |= ZBX_VMWARE_STATE_REMOVING;
5883 task = ZBX_VMWARE_TASK_REMOVE;
5884 break;
5885 }
5886
5887 /* check if the performance statistics should be updated */
5888 if (0 != (service->state & ZBX_VMWARE_STATE_READY) &&
5889 0 == (service->state & ZBX_VMWARE_STATE_UPDATING_PERF) &&
5890 now - service->lastperfcheck >= ZBX_VMWARE_PERF_UPDATE_PERIOD)
5891 {
5892 service->state |= ZBX_VMWARE_STATE_UPDATING_PERF;
5893 task = ZBX_VMWARE_TASK_UPDATE_PERF;
5894 break;
5895 }
5896
5897 /* check if the service data should be updated */
5898 if (0 == (service->state & ZBX_VMWARE_STATE_UPDATING) &&
5899 now - service->lastcheck >= ZBX_VMWARE_CACHE_UPDATE_PERIOD)
5900 {
5901 service->state |= ZBX_VMWARE_STATE_UPDATING;
5902 task = ZBX_VMWARE_TASK_UPDATE;
5903 break;
5904 }
5905
5906 /* don't calculate nextcheck for services that are already updating something */
5907 if (0 != (service->state & ZBX_VMWARE_STATE_BUSY))
5908 continue;
5909
5910 /* calculate next service update time */
5911
5912 if (service->lastcheck + ZBX_VMWARE_CACHE_UPDATE_PERIOD < next_update)
5913 next_update = service->lastcheck + ZBX_VMWARE_CACHE_UPDATE_PERIOD;
5914
5915 if (0 != (service->state & ZBX_VMWARE_STATE_READY))
5916 {
5917 if (service->lastperfcheck + ZBX_VMWARE_PERF_UPDATE_PERIOD < next_update)
5918 next_update = service->lastperfcheck + ZBX_VMWARE_PERF_UPDATE_PERIOD;
5919 }
5920 }
5921
5922 zbx_vmware_unlock();
5923
5924 switch (task)
5925 {
5926 case ZBX_VMWARE_TASK_UPDATE:
5927 vmware_service_update(service);
5928 updated_services++;
5929 break;
5930 case ZBX_VMWARE_TASK_UPDATE_PERF:
5931 vmware_service_update_perf(service);
5932 updated_services++;
5933 break;
5934 case ZBX_VMWARE_TASK_REMOVE:
5935 vmware_service_remove(service);
5936 removed_services++;
5937 break;
5938 }
5939 }
5940 while (ZBX_VMWARE_TASK_IDLE != task && ZBX_IS_RUNNING());
5941
5942 total_sec += zbx_time() - sec;
5943 now = time(NULL);
5944
5945 sleeptime = 0 < next_update - now ? next_update - now : 0;
5946
5947 if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
5948 {
5949 if (0 == sleeptime)
5950 {
5951 zbx_setproctitle("%s #%d [updated %d, removed %d VMware services in " ZBX_FS_DBL " sec,"
5952 " querying VMware services]", get_process_type_string(process_type),
5953 process_num, updated_services, removed_services, total_sec);
5954 }
5955 else
5956 {
5957 zbx_setproctitle("%s #%d [updated %d, removed %d VMware services in " ZBX_FS_DBL " sec,"
5958 " idle %d sec]", get_process_type_string(process_type), process_num,
5959 updated_services, removed_services, total_sec, sleeptime);
5960 old_updated_services = updated_services;
5961 old_removed_services = removed_services;
5962 old_total_sec = total_sec;
5963 }
5964 updated_services = 0;
5965 removed_services = 0;
5966 total_sec = 0.0;
5967 last_stat_time = time(NULL);
5968 }
5969
5970 zbx_sleep_loop(sleeptime);
5971 }
5972
5973 zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
5974
5975 while (1)
5976 zbx_sleep(SEC_PER_MIN);
5977 #undef STAT_INTERVAL
5978 #else
5979 ZBX_UNUSED(args);
5980 THIS_SHOULD_NEVER_HAPPEN;
5981 zbx_thread_exit(EXIT_SUCCESS);
5982 #endif
5983 }
5984
5985 /******************************************************************************
5986 * *
5987 * Function: zbx_vmware_lock *
5988 * *
5989 * Purpose: locks vmware collector *
5990 * *
5991 ******************************************************************************/
zbx_vmware_lock(void)5992 void zbx_vmware_lock(void)
5993 {
5994 zbx_mutex_lock(vmware_lock);
5995 }
5996
5997 /******************************************************************************
5998 * *
5999 * Function: zbx_vmware_unlock *
6000 * *
6001 * Purpose: unlocks vmware collector *
6002 * *
6003 ******************************************************************************/
zbx_vmware_unlock(void)6004 void zbx_vmware_unlock(void)
6005 {
6006 zbx_mutex_unlock(vmware_lock);
6007 }
6008
6009 /******************************************************************************
6010 * *
6011 * Function: zbx_vmware_get_statistics *
6012 * *
6013 * Purpose: gets vmware collector statistics *
6014 * *
6015 * Parameters: stats - [OUT] the vmware collector statistics *
6016 * *
6017 * Return value: SUCCEEED - the statistics were retrieved successfully *
6018 * FAIL - no vmware collectors are running *
6019 * *
6020 ******************************************************************************/
zbx_vmware_get_statistics(zbx_vmware_stats_t * stats)6021 int zbx_vmware_get_statistics(zbx_vmware_stats_t *stats)
6022 {
6023 if (NULL == vmware_mem)
6024 return FAIL;
6025
6026 zbx_vmware_lock();
6027
6028 stats->memory_total = vmware_mem->total_size;
6029 stats->memory_used = vmware_mem->total_size - vmware_mem->free_size;
6030
6031 zbx_vmware_unlock();
6032
6033 return SUCCEED;
6034 }
6035
6036 #if defined(HAVE_LIBXML2) && defined(HAVE_LIBCURL)
6037
6038 /*
6039 * XML support
6040 */
6041 /******************************************************************************
6042 * *
6043 * Function: libxml_handle_error *
6044 * *
6045 * Purpose: libxml2 callback function for error handle *
6046 * *
6047 * Parameters: user_data - [IN/OUT] the user context *
6048 * err - [IN] the libxml2 error message *
6049 * *
6050 ******************************************************************************/
libxml_handle_error(void * user_data,xmlErrorPtr err)6051 static void libxml_handle_error(void *user_data, xmlErrorPtr err)
6052 {
6053 ZBX_UNUSED(user_data);
6054 ZBX_UNUSED(err);
6055 }
6056
6057 /******************************************************************************
6058 * *
6059 * Function: zbx_xml_try_read_value *
6060 * *
6061 * Purpose: retrieve a value from xml data and return status of operation *
6062 * *
6063 * Parameters: data - [IN] XML data *
6064 * len - [IN] XML data length (optional) *
6065 * xpath - [IN] XML XPath *
6066 * xdoc - [OUT] parsed xml document *
6067 * value - [OUT] selected xml node value *
6068 * error - [OUT] error of xml or xpath formats *
6069 * *
6070 * Return: SUCCEED - select xpath successfully, result stored in 'value' *
6071 * FAIL - failed select xpath expression *
6072 * *
6073 ******************************************************************************/
zbx_xml_try_read_value(const char * data,size_t len,const char * xpath,xmlDoc ** xdoc,char ** value,char ** error)6074 static int zbx_xml_try_read_value(const char *data, size_t len, const char *xpath, xmlDoc **xdoc, char **value,
6075 char **error)
6076 {
6077 xmlXPathContext *xpathCtx;
6078 xmlXPathObject *xpathObj;
6079 xmlNodeSetPtr nodeset;
6080 xmlChar *val;
6081 int ret = FAIL;
6082
6083 if (NULL == data)
6084 goto out;
6085
6086 xmlSetStructuredErrorFunc(NULL, &libxml_handle_error);
6087
6088 if (NULL == (*xdoc = xmlReadMemory(data, (0 == len ? strlen(data) : len), ZBX_VM_NONAME_XML, NULL,
6089 ZBX_XML_PARSE_OPTS)))
6090 {
6091 if (NULL != error)
6092 *error = zbx_dsprintf(*error, "Received response has no valid XML data.");
6093
6094 xmlSetStructuredErrorFunc(NULL, NULL);
6095 goto out;
6096 }
6097
6098 xpathCtx = xmlXPathNewContext(*xdoc);
6099
6100 if (NULL == (xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath, xpathCtx)))
6101 {
6102 if (NULL != error)
6103 *error = zbx_dsprintf(*error, "Invalid xpath expression: \"%s\".", xpath);
6104
6105 goto clean;
6106 }
6107
6108 ret = SUCCEED;
6109
6110 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
6111 goto clean;
6112
6113 nodeset = xpathObj->nodesetval;
6114
6115 if (NULL != (val = xmlNodeListGetString(*xdoc, nodeset->nodeTab[0]->xmlChildrenNode, 1)))
6116 {
6117 *value = zbx_strdup(*value, (const char *)val);
6118 xmlFree(val);
6119 }
6120 clean:
6121 if (NULL != xpathObj)
6122 xmlXPathFreeObject(xpathObj);
6123
6124 xmlSetStructuredErrorFunc(NULL, NULL);
6125 xmlXPathFreeContext(xpathCtx);
6126 xmlResetLastError();
6127 out:
6128 return ret;
6129 }
6130
6131 /******************************************************************************
6132 * *
6133 * Function: zbx_xml_read_node_value *
6134 * *
6135 * Purpose: retrieve a value from xml data relative to the specified node *
6136 * *
6137 * Parameters: doc - [IN] the XML document *
6138 * node - [IN] the XML node *
6139 * xpath - [IN] the XML XPath *
6140 * *
6141 * Return: The allocated value string or NULL if the xml data does not *
6142 * contain the value specified by xpath. *
6143 * *
6144 ******************************************************************************/
zbx_xml_read_node_value(xmlDoc * doc,xmlNode * node,const char * xpath)6145 static char *zbx_xml_read_node_value(xmlDoc *doc, xmlNode *node, const char *xpath)
6146 {
6147 xmlXPathContext *xpathCtx;
6148 xmlXPathObject *xpathObj;
6149 xmlNodeSetPtr nodeset;
6150 xmlChar *val;
6151 char *value = NULL;
6152
6153 xpathCtx = xmlXPathNewContext(doc);
6154
6155 xpathCtx->node = node;
6156
6157 if (NULL == (xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath, xpathCtx)))
6158 goto clean;
6159
6160 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
6161 goto clean;
6162
6163 nodeset = xpathObj->nodesetval;
6164
6165 if (NULL != (val = xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1)))
6166 {
6167 value = zbx_strdup(NULL, (const char *)val);
6168 xmlFree(val);
6169 }
6170 clean:
6171 if (NULL != xpathObj)
6172 xmlXPathFreeObject(xpathObj);
6173
6174 xmlXPathFreeContext(xpathCtx);
6175
6176 return value;
6177 }
6178
6179 /******************************************************************************
6180 * *
6181 * Function: zbx_xml_read_doc_value *
6182 * *
6183 * Purpose: retrieve a value from xml document relative to the root node *
6184 * *
6185 * Parameters: xdoc - [IN] the XML document *
6186 * xpath - [IN] the XML XPath *
6187 * *
6188 * Return: The allocated value string or NULL if the xml data does not *
6189 * contain the value specified by xpath. *
6190 * *
6191 ******************************************************************************/
zbx_xml_read_doc_value(xmlDoc * xdoc,const char * xpath)6192 static char *zbx_xml_read_doc_value(xmlDoc *xdoc, const char *xpath)
6193 {
6194 xmlNode *root_element;
6195
6196 root_element = xmlDocGetRootElement(xdoc);
6197 return zbx_xml_read_node_value(xdoc, root_element, xpath);
6198 }
6199
6200 /******************************************************************************
6201 * *
6202 * Function: zbx_xml_read_values *
6203 * *
6204 * Purpose: populate array of values from a xml data *
6205 * *
6206 * Parameters: xdoc - [IN] XML document *
6207 * xpath - [IN] XML XPath *
6208 * values - [OUT] list of requested values *
6209 * *
6210 * Return: Upon successful completion the function return SUCCEED. *
6211 * Otherwise, FAIL is returned. *
6212 * *
6213 ******************************************************************************/
zbx_xml_read_values(xmlDoc * xdoc,const char * xpath,zbx_vector_str_t * values)6214 static int zbx_xml_read_values(xmlDoc *xdoc, const char *xpath, zbx_vector_str_t *values)
6215 {
6216 xmlXPathContext *xpathCtx;
6217 xmlXPathObject *xpathObj;
6218 xmlNodeSetPtr nodeset;
6219 xmlChar *val;
6220 int i, ret = FAIL;
6221
6222 if (NULL == xdoc)
6223 goto out;
6224
6225 xpathCtx = xmlXPathNewContext(xdoc);
6226
6227 if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)xpath, xpathCtx)))
6228 goto clean;
6229
6230 if (0 != xmlXPathNodeSetIsEmpty(xpathObj->nodesetval))
6231 goto clean;
6232
6233 nodeset = xpathObj->nodesetval;
6234
6235 for (i = 0; i < nodeset->nodeNr; i++)
6236 {
6237 if (NULL != (val = xmlNodeListGetString(xdoc, nodeset->nodeTab[i]->xmlChildrenNode, 1)))
6238 {
6239 zbx_vector_str_append(values, zbx_strdup(NULL, (const char *)val));
6240 xmlFree(val);
6241 }
6242 }
6243
6244 ret = SUCCEED;
6245 clean:
6246 if (NULL != xpathObj)
6247 xmlXPathFreeObject(xpathObj);
6248
6249 xmlXPathFreeContext(xpathCtx);
6250 out:
6251 return ret;
6252 }
6253
6254 #endif
6255