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