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