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