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