vmware plugin: Small refactorings and avoid dispatching after error.
[collectd.git] / src / vmware.c
1 /**
2  * collectd - src/vmware.c
3  * Copyright (C) 2010  Edward Muller
4  * Copyright (C) 2011  Keith Chambers
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; only version 2.1 of the License is
9  * applicable.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Edward Muller <emuller at engineyard.com>
22  *   Keith Chambers <chambers_keith at yahoo.com>
23  **/
24
25 #include "collectd.h"
26 #include "common.h"
27 #include "plugin.h"
28 #include <dlfcn.h>
29
30 #include <vmGuestLib.h>
31
32 /* functions to dynamically load from the GuestLib library */
33 static char const * (*GuestLib_GetErrorText)(VMGuestLibError);
34 static VMGuestLibError (*GuestLib_OpenHandle)(VMGuestLibHandle*);
35 static VMGuestLibError (*GuestLib_CloseHandle)(VMGuestLibHandle);
36 static VMGuestLibError (*GuestLib_UpdateInfo)(VMGuestLibHandle handle);
37 static VMGuestLibError (*GuestLib_GetSessionId)(VMGuestLibHandle handle, VMSessionId *id);
38 static VMGuestLibError (*GuestLib_GetElapsedMs)(VMGuestLibHandle handle, uint64_t *elapsedMs);
39 static VMGuestLibError (*GuestLib_GetCpuUsedMs)(VMGuestLibHandle handle, uint64_t *cpuUsedMs);
40 static VMGuestLibError (*GuestLib_GetCpuStolenMs)(VMGuestLibHandle handle, uint64_t *cpuStolenMs);
41 static VMGuestLibError (*GuestLib_GetCpuReservationMHz)(VMGuestLibHandle handle, uint32_t *cpuReservationMHz);
42 static VMGuestLibError (*GuestLib_GetCpuLimitMHz)(VMGuestLibHandle handle, uint32_t *cpuLimitMHz);
43 static VMGuestLibError (*GuestLib_GetCpuShares)(VMGuestLibHandle handle, uint32_t *cpuShares);
44 static VMGuestLibError (*GuestLib_GetHostProcessorSpeed)(VMGuestLibHandle handle, uint32_t *mhz);
45 static VMGuestLibError (*GuestLib_GetMemUsedMB)(VMGuestLibHandle handle, uint32_t *memUsedMB);
46 static VMGuestLibError (*GuestLib_GetMemMappedMB)(VMGuestLibHandle handle, uint32_t *memMappedMB);
47 static VMGuestLibError (*GuestLib_GetMemActiveMB)(VMGuestLibHandle handle, uint32_t *memActiveMB);
48 static VMGuestLibError (*GuestLib_GetMemTargetSizeMB)(VMGuestLibHandle handle, uint64_t *memTargetSizeMB);
49 static VMGuestLibError (*GuestLib_GetMemOverheadMB)(VMGuestLibHandle handle, uint32_t *memOverheadMB);
50 static VMGuestLibError (*GuestLib_GetMemSharedMB)(VMGuestLibHandle handle, uint32_t *memSharedMB);
51 static VMGuestLibError (*GuestLib_GetMemSharedSavedMB)(VMGuestLibHandle handle, uint32_t *memSharedSavedMB);
52 static VMGuestLibError (*GuestLib_GetMemBalloonedMB)(VMGuestLibHandle handle, uint32_t *memBalloonedMB);
53 static VMGuestLibError (*GuestLib_GetMemSwappedMB)(VMGuestLibHandle handle, uint32_t *memSwappedMB);
54 static VMGuestLibError (*GuestLib_GetMemReservationMB)(VMGuestLibHandle handle, uint32_t *memReservationMB);
55 static VMGuestLibError (*GuestLib_GetMemLimitMB)(VMGuestLibHandle handle, uint32_t *memLimitMB);
56 static VMGuestLibError (*GuestLib_GetMemShares)(VMGuestLibHandle handle, uint32_t *memShares);
57
58 /* handle for use with shared library */
59 static VMGuestLibHandle gl_handle;
60 static VMSessionId gl_session;
61
62 /* used when converting megabytes to bytes for memory counters */
63 #define BYTES_PER_MB 1024*1024
64
65 /* macro to load a single GuestLib function from the shared library */
66 #define LOAD_ONE_FUNC(funcname) do {                                         \
67     char const *errmsg;                                                      \
68     funcname = dlsym(dl_handle, "VM" #funcname);                             \
69     if ((errmsg = dlerror()) != NULL) {                                      \
70       ERROR ("vmware plugin: Failed to load \"%s\": %s",                     \
71           #funcname, errmsg);                                                \
72       return (-1);                                                           \
73     }                                                                        \
74 } while (0)
75
76 _Bool static vmware_load_functions (void)
77 {
78   void *dl_handle;
79
80   dl_handle = dlopen("libvmGuestLib.so", RTLD_NOW);
81   if (!dl_handle)
82   {
83     char const *errmsg;
84
85     errmsg = dlerror();
86     ERROR("vmware plugin: dlopen (\"libvmGuestLib.so\") failed: %s",
87         errmsg);
88     return (-1);
89   }
90
91   /* Load all the individual library functions */
92   LOAD_ONE_FUNC(GuestLib_GetErrorText);
93   LOAD_ONE_FUNC(GuestLib_OpenHandle);
94   LOAD_ONE_FUNC(GuestLib_CloseHandle);
95   LOAD_ONE_FUNC(GuestLib_UpdateInfo);
96   LOAD_ONE_FUNC(GuestLib_GetSessionId);
97   LOAD_ONE_FUNC(GuestLib_GetElapsedMs);
98   LOAD_ONE_FUNC(GuestLib_GetCpuStolenMs);
99   LOAD_ONE_FUNC(GuestLib_GetCpuUsedMs);
100   LOAD_ONE_FUNC(GuestLib_GetCpuReservationMHz);
101   LOAD_ONE_FUNC(GuestLib_GetCpuLimitMHz);
102   LOAD_ONE_FUNC(GuestLib_GetCpuShares);
103   LOAD_ONE_FUNC(GuestLib_GetHostProcessorSpeed);
104   LOAD_ONE_FUNC(GuestLib_GetMemReservationMB);
105   LOAD_ONE_FUNC(GuestLib_GetMemLimitMB);
106   LOAD_ONE_FUNC(GuestLib_GetMemShares);
107   LOAD_ONE_FUNC(GuestLib_GetMemMappedMB);
108   LOAD_ONE_FUNC(GuestLib_GetMemActiveMB);
109   LOAD_ONE_FUNC(GuestLib_GetMemOverheadMB);
110   LOAD_ONE_FUNC(GuestLib_GetMemBalloonedMB);
111   LOAD_ONE_FUNC(GuestLib_GetMemSwappedMB);
112   LOAD_ONE_FUNC(GuestLib_GetMemSharedMB);
113   LOAD_ONE_FUNC(GuestLib_GetMemSharedSavedMB);
114   LOAD_ONE_FUNC(GuestLib_GetMemUsedMB);
115   LOAD_ONE_FUNC(GuestLib_GetMemTargetSizeMB);
116
117   return (0);
118 }
119
120 static int vmware_init (void)
121 {
122   VMGuestLibError status;
123
124   if (!vmware_load_functions()) {
125     ERROR ("vmware plugin: Unable to load GuestLib functions");
126     return (-1);
127   }
128
129   /* try to load the library */
130   status = GuestLib_OpenHandle(&gl_handle);
131   if (status != VMGUESTLIB_ERROR_SUCCESS)
132   {
133     ERROR ("vmware plugin: OpenHandle failed: %s",
134         GuestLib_GetErrorText (status));
135     return (-1);
136   }
137
138   return (0);
139 }
140
141 static void submit_vmw_counter (const char *type, const char *type_inst,
142     derive_t value)
143 {
144   value_t values[1];
145   value_list_t vl = VALUE_LIST_INIT;
146
147   values[0].derive = value;
148
149   vl.values = values;
150   vl.values_len = 1;
151
152   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
153   sstrncpy (vl.plugin, "vmware", sizeof (vl.plugin));
154   sstrncpy (vl.type, type, sizeof (vl.type));
155   sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
156
157   plugin_dispatch_values (&vl);
158 }
159
160 static void submit_vmw_gauge (const char *type, const char *type_inst,
161     gauge_t value)
162 {
163   value_t values[1];
164   value_list_t vl = VALUE_LIST_INIT;
165
166   values[0].gauge = value;
167
168   vl.values = values;
169   vl.values_len = 1;
170
171   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
172   sstrncpy (vl.plugin, "vmware", sizeof (vl.plugin));
173   sstrncpy (vl.type, type, sizeof (vl.type));
174   sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
175
176   plugin_dispatch_values (&vl);
177 }
178
179 static int vmw_query_memory (VMGuestLibHandle handle,
180     char const *function_name,
181     VMGuestLibError (*function) (VMGuestLibHandle, uint32_t *),
182     char const *type_instance)
183 {
184   uint32_t value;
185   VMGuestLibError status;
186
187   status = (*function) (handle, &value);
188   if (status != VMGUESTLIB_ERROR_SUCCESS)
189   {
190     WARNING ("vmware plugin: %s failed: %s",
191         function_name, GuestLib_GetErrorText (status));
192     return (-1);
193   }
194
195   /* The returned value is in megabytes, so multiply it by 2^20. It's not
196    * 10^6, because we're talking about memory. */
197   submit_vmw_gauge ("memory", type_instance,
198       (gauge_t) (BYTES_PER_MB * value));
199   return (0);
200 } /* }}} int vmw_query_megabyte */
201
202 static int vmware_read (void)
203 {
204
205   VMGuestLibError status;
206
207   uint32_t tmp32;
208   uint64_t tmp64;
209
210   status = GuestLib_UpdateInfo(gl_handle);
211   if (status != VMGUESTLIB_ERROR_SUCCESS) {
212     ERROR ("vmware plugin: UpdateInfo failed: %s",
213         GuestLib_GetErrorText(status));
214     return (-1);
215   }
216
217   /* retrieve and check the session ID */
218   status = GuestLib_GetSessionId(gl_handle, &gl_session);
219   if (status != VMGUESTLIB_ERROR_SUCCESS) {
220     ERROR ("vmware plugin: Failed to get session ID: %s",
221         GuestLib_GetErrorText(status));
222     return (-1);
223   }
224
225   if (gl_session == 0) {
226     ERROR ("vmware plugin: Error: Got zero sessionId from GuestLib");
227     return (-1);
228   }
229
230   /* GetElapsedMs */
231   status = GuestLib_GetElapsedMs(gl_handle, &tmp64);
232   if (status != VMGUESTLIB_ERROR_SUCCESS)
233     WARNING ("vmware plugin: Failed to get elapsed ms: %s",
234         GuestLib_GetErrorText(status));
235   else
236     submit_vmw_counter ("total_time_in_ms", "elapsed", (derive_t) tmp64);
237
238   /* GetCpuUsedMs */
239   status = GuestLib_GetCpuUsedMs(gl_handle, &tmp64);
240   if (status != VMGUESTLIB_ERROR_SUCCESS)
241     WARNING ("vmware plugin: Failed to get used ms: %s",
242         GuestLib_GetErrorText(status));
243   else
244     submit_vmw_counter ("virt_vcpu", "used", (derive_t) tmp64);
245
246   /* GetCpuStolenMs */
247   status = GuestLib_GetCpuStolenMs(gl_handle, &tmp64);
248   if (status == VMGUESTLIB_ERROR_UNSUPPORTED_VERSION)
249     /* ignore */;
250   else if (status != VMGUESTLIB_ERROR_SUCCESS)
251     WARNING ("vmware plugin: Failed to get CPU stolen: %s",
252         GuestLib_GetErrorText(status));
253   else
254     submit_vmw_counter ("virt_vcpu", "stolen", (derive_t) tmp64);
255
256   /* GetCpuReservationMHz */
257   status = GuestLib_GetCpuReservationMHz(gl_handle, &tmp32);
258   if (status != VMGUESTLIB_ERROR_SUCCESS)
259     WARNING ("vmware plugin: Failed to get CPU reservation: %s",
260         GuestLib_GetErrorText(status));
261   else
262     submit_vmw_gauge ("vcpu", "reservation", (gauge_t) tmp32);
263
264   /* GetCpuLimitMHz */
265   status = GuestLib_GetCpuLimitMHz(gl_handle, &tmp32);
266   if (status != VMGUESTLIB_ERROR_SUCCESS)
267     WARNING ("vmware plugin: Failed to get CPU limit: %s",
268         GuestLib_GetErrorText(status));
269   else
270     submit_vmw_gauge ("vcpu", "limit", (gauge_t) tmp32);
271
272   /* GetCpuShares */
273   status = GuestLib_GetCpuShares(gl_handle, &tmp32);
274   if (status != VMGUESTLIB_ERROR_SUCCESS)
275     WARNING ("vmware plugin: Failed to get cpu shares: %s",
276         GuestLib_GetErrorText(status));
277   else
278     submit_vmw_gauge ("vcpu", "shares", (gauge_t) tmp32);
279
280   /* GetHostProcessorSpeed */
281   status = GuestLib_GetHostProcessorSpeed(gl_handle, &tmp32);
282   if (status != VMGUESTLIB_ERROR_SUCCESS)
283     WARNING ("vmware plugin: Failed to get host proc speed: %s",
284         GuestLib_GetErrorText(status));
285   else
286     submit_vmw_gauge ("cpufreq", "", 1.0e6 * (gauge_t) tmp32);
287
288   /* GetMemTargetSizeMB */
289   status = GuestLib_GetMemTargetSizeMB(gl_handle, &tmp64);
290   if (status != VMGUESTLIB_ERROR_SUCCESS)
291     WARNING ("vmware plugin: GuestLib_GetMemTargetSizeMB failed: %s",
292         GuestLib_GetErrorText (status));
293   else
294     submit_vmw_gauge ("memory", "target", (gauge_t) (BYTES_PER_MB * tmp64));
295
296 #define VMW_QUERY_MEMORY(func, type) \
297   vmw_query_memory (gl_handle, #func, GuestLib_ ## func, type)
298
299   VMW_QUERY_MEMORY (GetMemUsedMB,        "used"); /* pysical; used = mapped - shared_saved */
300   VMW_QUERY_MEMORY (GetMemMappedMB,      "mapped"); /* mapped = used + shared_saved */
301   VMW_QUERY_MEMORY (GetMemActiveMB,      "active");
302   VMW_QUERY_MEMORY (GetMemOverheadMB,    "overhead");
303   VMW_QUERY_MEMORY (GetMemSharedMB,      "shared"); /* physical */
304   VMW_QUERY_MEMORY (GetMemSharedSavedMB, "shared_saved");
305   VMW_QUERY_MEMORY (GetMemBalloonedMB,   "ballooned");
306   VMW_QUERY_MEMORY (GetMemSwappedMB,     "swapped"); /* physical? */
307   /* min memory available to the guest */
308   VMW_QUERY_MEMORY (GetMemReservationMB, "reservation");
309   /* max memory available to the guest */
310   VMW_QUERY_MEMORY (GetMemLimitMB,       "limit");
311   /* ??? */
312   VMW_QUERY_MEMORY (GetMemShares,        "shares");
313
314 #undef VMW_QUERY_MEMORY
315
316   return (0);
317 }
318
319 void module_register (void)
320 {
321   plugin_register_init ("vmware", vmware_init);
322   plugin_register_read ("vmware", vmware_read);
323 }