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