0a941b08220384e32893d11dea2992c312adbf2e
[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 glHandle;
60
61 /* used when converting megabytes to bytes for memory counters */
62 #define BYTES_PER_MB 1024*1024
63
64 /* macro to load a single GuestLib function from the shared library */
65 #define LOAD_ONE_FUNC(funcname)                               \
66   do {                                                       \
67     funcname = dlsym(dlHandle, "VM" #funcname);             \
68     if ((dlErrStr = dlerror()) != NULL) {                   \
69       ERROR ("vmware plugin: Failed to load \"%s\": %s",   \
70 #funcname, dlErrStr);                         \
71       return (-1);                                         \
72     }                                                       \
73   } while (0)
74
75   _Bool
76 static LoadFunctions(void)
77 {
78   void *dlHandle = NULL;
79
80   /* first try to load the shared library */
81   char const *dlErrStr;
82
83   dlHandle = dlopen("libvmGuestLib.so", RTLD_NOW);
84   if (!dlHandle) {
85     dlErrStr = dlerror();
86     ERROR("vmware plugin: dlopen (\"libvmGuestLib.so\") failed: %s",
87         dlErrStr);
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 glError;
123
124   if (!LoadFunctions()) {
125     ERROR ("vmware plugin: Unable to load GuestLib functions");
126     return (-1);
127   }
128
129   /* try to load the library */
130   glError = GuestLib_OpenHandle(&glHandle);
131   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
132     ERROR ("vmware plugin: OpenHandle failed: %s", GuestLib_GetErrorText(glError));
133     return (-1);
134   }
135
136   return (0);
137 }
138
139 static void submit_vmw_counter (const char *type, const char *type_inst,
140     derive_t value)
141 {
142   value_t values[1];
143   value_list_t vl = VALUE_LIST_INIT;
144
145   values[0].derive = value;
146
147   vl.values = values;
148   vl.values_len = 1;
149
150   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
151   sstrncpy (vl.plugin, "vmware", sizeof (vl.plugin));
152   sstrncpy (vl.type, type, sizeof (vl.type));
153   sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
154
155   plugin_dispatch_values (&vl);
156 }
157
158 static void submit_vmw_gauge (const char *type, const char *type_inst,
159     gauge_t value)
160 {
161   value_t values[1];
162   value_list_t vl = VALUE_LIST_INIT;
163
164   values[0].gauge = value;
165
166   vl.values = values;
167   vl.values_len = 1;
168
169   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
170   sstrncpy (vl.plugin, "vmware", sizeof (vl.plugin));
171   sstrncpy (vl.type, type, sizeof (vl.type));
172   sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
173
174   plugin_dispatch_values (&vl);
175 }
176
177 static int vmw_query_memory (VMGuestLibHandle handle, const char *function_name,
178     VMGuestLibError (*function) (VMGuestLibHandle handle, uint32_t *ret_data),
179     const char *type_instance)
180 {
181   uint32_t value;
182   VMGuestLibError status;
183
184   status = (*function) (handle, &value);
185   if (status != VMGUESTLIB_ERROR_SUCCESS) {
186     WARNING ("vmware plugin: %s failed: %s",
187         function_name,
188         GuestLib_GetErrorText(glError));
189     return (-1);
190   }
191
192   /* The returned value is in megabytes, so multiply it by 2^20. It's not
193    * 10^6, because we're talking about memory. */
194   submit_vmw_gauge ("memory", type_instance,
195       (gauge_t) (BYTES_PER_MB * value));
196   return (0);
197 } /* }}} int vmw_query_megabyte */
198
199 static int vmware_read (void)
200 {
201   VMGuestLibError glError;
202
203   /* total_time_in_ms */
204   uint64_t elapsedMs = 0;
205
206   /* virt_vcpu */
207   uint64_t cpuUsedMs = 0;
208   uint64_t cpuStolenMs = 0;
209
210   /* vcpu (quality of service) */
211   uint32_t cpuReservationMHz = 0;
212   uint32_t cpuLimitMHz = 0;
213   uint32_t cpuShares = 0;
214
215   /* cpufreq */
216   uint32_t hostMHz = 0;
217
218   /* memory (quality of service) */
219   uint32_t memShares = 0;
220
221   VMSessionId sessionId = 0;
222
223   /* attempt to retrieve info from the host */
224   VMSessionId tmpSession;
225
226   glError = GuestLib_UpdateInfo(glHandle);
227   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
228     ERROR ("vmware plugin: UpdateInfo failed: %s", GuestLib_GetErrorText(glError));
229     return (-1);
230   }
231
232   /* retrieve and check the session ID */
233   glError = GuestLib_GetSessionId(glHandle, &tmpSession);
234   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
235     ERROR ("vmware plugin: Failed to get session ID: %s", GuestLib_GetErrorText(glError));
236     return (-1);
237   }
238
239   if (tmpSession == 0) {
240     ERROR ("vmware plugin: Error: Got zero sessionId from GuestLib");
241     return (-1);
242   }
243
244   if (sessionId == 0) {
245     sessionId = tmpSession;
246     DEBUG ("vmware plugin: Initial session ID is %#"PRIx64, (uint64_t) sessionId);
247   } else if (tmpSession != sessionId) {
248     sessionId = tmpSession;
249     DEBUG ("vmware plugin: Session ID changed to %#"PRIx64, (uint64_t) sessionId);
250   }
251
252   /* GetElapsedMs */
253   glError = GuestLib_GetElapsedMs(glHandle, &elapsedMs);
254   if (glError != VMGUESTLIB_ERROR_SUCCESS)
255     WARNING ("vmware plugin: Failed to get elapsed ms: %s", GuestLib_GetErrorText(glError));
256   else
257     submit_vmw_counter ("total_time_in_ms", "elapsed", (derive_t) elapsedMs);
258
259   /* GetCpuUsedMs */
260   glError = GuestLib_GetCpuUsedMs(glHandle, &cpuUsedMs);
261   if (glError != VMGUESTLIB_ERROR_SUCCESS)
262     WARNING ("vmware plugin: Failed to get used ms: %s",
263         GuestLib_GetErrorText(glError));
264   else
265     submit_vmw_counter ("virt_vcpu", "used", (derive_t) cpuUsedMs);
266
267   /* GetCpuStolenMs */
268   glError = GuestLib_GetCpuStolenMs(glHandle, &cpuStolenMs);
269   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
270     DEBUG ("vmware plugin: Failed to get CPU stolen: %s\n", GuestLib_GetErrorText(glError));
271     if (glError == VMGUESTLIB_ERROR_UNSUPPORTED_VERSION) {
272       cpuStolenMs = 0;
273     }
274   }
275   submit_vmw_counter ("virt_vcpu", "stolen", (derive_t) cpuStolenMs);
276
277   /* GetCpuReservationMHz */
278   glError = GuestLib_GetCpuReservationMHz(glHandle, &cpuReservationMHz);
279   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
280     DEBUG ("vmware plugin: Failed to get CPU reservation: %s\n", GuestLib_GetErrorText(glError));
281   }
282   submit_vmw_gauge ("vcpu", "reservation", (gauge_t) cpuReservationMHz);
283
284   /* GetCpuLimitMHz */
285   glError = GuestLib_GetCpuLimitMHz(glHandle, &cpuLimitMHz);
286   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
287     DEBUG ("vmware plugin: Failed to get CPU limit: %s\n", GuestLib_GetErrorText(glError));
288   }
289   submit_vmw_gauge ("vcpu", "limit", (gauge_t) cpuLimitMHz);
290
291   /* GetCpuShares */
292   glError = GuestLib_GetCpuShares(glHandle, &cpuShares);
293   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
294     DEBUG ("vmware plugin: Failed to get cpu shares: %s\n", GuestLib_GetErrorText(glError));
295   }
296   submit_vmw_gauge ("vcpu", "shares", (gauge_t) cpuShares);
297
298   /* GetHostProcessorSpeed */
299   glError = GuestLib_GetHostProcessorSpeed(glHandle, &hostMHz);
300   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
301     DEBUG ("vmware plugin: Failed to get host proc speed: %s\n", GuestLib_GetErrorText(glError));
302   }
303   submit_vmw_gauge ("cpufreq", "", 1.0e6 * (gauge_t) hostMHz);
304
305 #define VMW_QUERY_MEMORY(func, type) \
306   vmw_query_memory (glHandle, #func, GuestLib_ ## func, type)
307
308   VMW_QUERY_MEMORY (GetMemTargetSizeMB,  "target");
309   VMW_QUERY_MEMORY (GetMemUsedMB,        "used");
310   VMW_QUERY_MEMORY (GetMemMappedMB,      "mapped");
311   VMW_QUERY_MEMORY (GetMemActiveMB,      "active");
312   VMW_QUERY_MEMORY (GetMemOverheadMB,    "overhead");
313   VMW_QUERY_MEMORY (GetMemSharedMB,      "shared");
314   VMW_QUERY_MEMORY (GetMemSharedSavedMB, "shared_saved");
315   VMW_QUERY_MEMORY (GetMemBalloonedMB,   "ballooned");
316   VMW_QUERY_MEMORY (GetMemSwappedMB,     "swapped");
317   VMW_QUERY_MEMORY (GetMemReservationMB, "reservation");
318   VMW_QUERY_MEMORY (GetMemLimitMB,       "limit");
319
320 #undef VMW_QUERY_MEMORY
321
322   /* GetMemShares */
323   glError = GuestLib_GetMemShares(glHandle, &memShares);
324   if (glError != VMGUESTLIB_ERROR_SUCCESS) {
325     DEBUG ("vmware plugin: Failed to get mem shares: %s\n", GuestLib_GetErrorText(glError));
326     memShares = 0;
327   }
328   submit_vmw_gauge ("memory", "shares", (gauge_t) memShares);
329
330   return (0);
331 }
332
333 void module_register (void)
334 {
335   plugin_register_init ("vmware", vmware_init);
336   plugin_register_read ("vmware", vmware_read);
337 }