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