1 /*----------------------------------------------------------------------------*/
2 /* Xymon message daemon.                                                      */
3 /*                                                                            */
4 /* Client backend module for z/VM                                             */
5 /*                                                                            */
6 /* Copyright (C) 2005-2011 Henrik Storner <henrik@hswn.dk>                    */
7 /* Copyright (C) 2006-2008 Rich Smrcina                                       */
8 /*                                                                            */
9 /* This program is released under the GNU General Public License (GPL),       */
10 /* version 2. See the file "COPYING" for details.                             */
11 /*                                                                            */
12 /*----------------------------------------------------------------------------*/
13 
14 static char zvm_rcsid[] = "$Id: zvm.c 7608 2015-03-21 15:00:40Z jccleaver $";
15 
zvm_cpu_report(char * hostname,char * clientclass,enum ostype_t os,void * hinfo,char * fromline,char * timestr,char * cpuutilstr,char * uptimestr)16 static void zvm_cpu_report(char *hostname, char *clientclass, enum ostype_t os,
17                      void *hinfo, char *fromline, char *timestr,
18                      char *cpuutilstr, char *uptimestr)
19 {
20         char *p;
21         float load1, loadyellow, loadred;
22         int recentlimit, ancientlimit, uptimecolor, maxclockdiff, clockdiffcolor;
23         int  uphour, upmin;
24         char loadresult[100];
25         char myupstr[100];
26         long uptimesecs = -1;
27         long upday;
28 
29         int cpucolor = COL_GREEN;
30 
31         char msgline[1024];
32         strbuffer_t *upmsg;
33 
34 	if (!want_msgtype(hinfo, MSG_CPU)) return;
35 
36         if (!cpuutilstr) return;
37         if (!uptimestr) return;
38 
39         uptimesecs = 0;
40 
41         /*
42          * z/VM: "Uptime: 1 Days, 13 Hours, 38 Minutes"
43          */
44 
45 	sscanf(uptimestr,"Uptime: %ld Days, %d Hours, %d Minutes", &upday, &uphour, &upmin);
46         uptimesecs = upday * 86400;
47         uptimesecs += 60*(60*uphour + upmin);
48         sprintf(myupstr, "%s\n", uptimestr);
49 
50         /*
51          *  Looking for average CPU Utilization in 'IND' command response
52          *  AVGPROC-000%
53          */
54         *loadresult = '\0';
55         p = strstr(cpuutilstr, "AVGPROC-") + 8 ;
56         if (p) {
57                 if (sscanf(p, "%f%%", &load1) == 1) {
58                         sprintf(loadresult, "z/VM CPU Utilization %3.0f%%\n", load1);
59                 }
60         }
61 
62         get_cpu_thresholds(hinfo, clientclass, &loadyellow, &loadred, &recentlimit, &ancientlimit, &uptimecolor, &maxclockdiff, &clockdiffcolor);
63 
64         upmsg = newstrbuffer(0);
65 
66         if (load1 > loadred) {
67                 cpucolor = COL_RED;
68                 addtobuffer(upmsg, "&red Load is CRITICAL\n");
69         }
70         else if (load1 > loadyellow) {
71                 cpucolor = COL_YELLOW;
72                 addtobuffer(upmsg, "&yellow Load is HIGH\n");
73         }
74 
75         if ((uptimesecs != -1) && (recentlimit != -1) && (uptimesecs < recentlimit)) {
76                 if (cpucolor != COL_RED) cpucolor = uptimecolor;
77                 sprintf(msgline, "&%s Machine recently rebooted\n", colorname(uptimecolor));
78                 addtobuffer(upmsg, msgline);
79         }
80         if ((uptimesecs != -1) && (ancientlimit != -1) && (uptimesecs > ancientlimit)) {
81                 if (cpucolor != COL_RED) cpucolor = uptimecolor;
82                 sprintf(msgline, "&%s Machine has been up more than %d days\n", colorname(uptimecolor), (ancientlimit / 86400));
83                 addtobuffer(upmsg, msgline);
84         }
85 
86         init_status(cpucolor);
87         sprintf(msgline, "status %s.cpu %s %s %s %s %s\n",
88                 commafy(hostname), colorname(cpucolor),
89                 (timestr ? timestr : "<no timestamp data>"),
90                 loadresult,
91 		myupstr,
92 		cpuutilstr);
93         addtostatus(msgline);
94         if (STRBUFLEN(upmsg)) {
95                 addtostrstatus(upmsg);
96                 addtostatus("\n");
97         }
98 
99         if (fromline && !localmode) addtostatus(fromline);
100         finish_status();
101 
102         freestrbuffer(upmsg);
103 }
104 
zvm_paging_report(char * hostname,char * clientclass,enum ostype_t os,void * hinfo,char * fromline,char * timestr,char * cpuutilstr)105 static void zvm_paging_report(char *hostname, char *clientclass, enum ostype_t os,
106                      void *hinfo, char *fromline, char *timestr, char *cpuutilstr)
107 {
108         char *p;
109         int pagerate, pagingyellow, pagingred;
110         char pagingresult[100];
111 
112         int pagingcolor = COL_GREEN;
113         char msgline[256];
114         strbuffer_t *upmsg;
115 
116         if (!cpuutilstr) return;
117         /*
118          *  Looking for Paging rate info in 'IND' command response
119          *  PAGING-0000/SEC
120          */
121         *pagingresult = '\0';
122 	/*  Skip past three newlines in message to the PAGING text  */
123 	p=strstr(cpuutilstr,"PAGING-") + 7;
124 	if (sscanf(p, "%d/SEC", &pagerate) == 1) {
125                	sprintf(pagingresult, "z/VM Paging Rate %d per second\n", pagerate);
126         }
127 
128         get_paging_thresholds(hinfo, clientclass, &pagingyellow, &pagingred);
129 
130         upmsg = newstrbuffer(0);
131 
132         if (pagerate > pagingred) {
133                 pagingcolor = COL_RED;
134                 addtobuffer(upmsg, "&red Paging Rate is CRITICAL\n");
135         }
136         else if (pagerate > pagingyellow) {
137                 pagingcolor = COL_YELLOW;
138                 addtobuffer(upmsg, "&yellow Paging Rate is HIGH\n");
139         }
140 
141         init_status(pagingcolor);
142         sprintf(msgline, "status %s.paging %s %s %s %s\n",
143                 commafy(hostname), colorname(pagingcolor),
144                 (timestr ? timestr : "<no timestamp data>"),
145                 pagingresult,
146                 cpuutilstr);
147         addtostatus(msgline);
148         if (STRBUFLEN(upmsg)) {
149                 addtostrstatus(upmsg);
150                 addtostatus("\n");
151         }
152 
153         if (fromline && !localmode) addtostatus(fromline);
154         finish_status();
155 
156         freestrbuffer(upmsg);
157 }
158 
zvm_mdc_report(char * hostname,char * clientclass,enum ostype_t os,void * hinfo,char * fromline,char * timestr,char * cpuutilstr)159 static void zvm_mdc_report(char *hostname, char *clientclass, enum ostype_t os,
160                      void *hinfo, char *fromline, char *timestr, char *cpuutilstr)
161 {
162         char *p;
163         int mdcreads, mdcwrites, mdchitpct;
164         char mdcresult[100];
165 
166         char msgline[256];
167         strbuffer_t *msg;
168 
169         if (!cpuutilstr) return;
170         msg = newstrbuffer(0);
171 
172         /*
173          *  Looking for MDC info in 'IND' command response
174          *  MDC READS-000001/SEC WRITES-000001/SEC HIT RATIO-098%
175          */
176         *mdcresult = '\0';
177         /*  Skip past three newlines in message to the PAGING text  */
178         p=strstr(cpuutilstr,"READS-");
179         if (p) {
180 		p += 6;
181         	sscanf(p, "%d/SEC", &mdcreads);
182         	p=strstr(cpuutilstr,"WRITES-") + 7;
183         	sscanf(p, "%d/SEC", &mdcwrites);
184         	p=strstr(cpuutilstr,"RATIO-") + 6;
185         	sscanf(p, "%d", &mdchitpct);
186 
187 	        sprintf(msgline, "data %s.mdc\n%s\n%d:%d:%d\n", commafy(hostname), osname(os), mdcreads, mdcwrites, mdchitpct);
188         	addtobuffer(msg, msgline);
189 		combo_add(msg);
190         }
191 
192         freestrbuffer(msg);
193 }
194 
zvm_users_report(char * hostname,char * clientclass,enum ostype_t os,void * hinfo,char * fromline,char * timestr,char * psstr)195 static void zvm_users_report(char *hostname, char *clientclass, enum ostype_t os,
196                          void *hinfo, char *fromline, char *timestr,
197 		         char *psstr)
198 {
199         int pscolor = COL_GREEN;
200 
201         int pchecks;
202         int cmdofs = -1;
203         char msgline[4096];
204         strbuffer_t *monmsg;
205         static strbuffer_t *countdata = NULL;
206         int anycountdata = 0;
207         char *group;
208 
209         if (!want_msgtype(hinfo, MSG_PROCS)) return;
210         if (!psstr) return;
211 
212         if (!countdata) countdata = newstrbuffer(0);
213 
214         clearalertgroups();
215         monmsg = newstrbuffer(0);
216 
217         sprintf(msgline, "data %s.proccounts\n", commafy(hostname));
218         addtobuffer(countdata, msgline);
219 
220 	cmdofs = 0;   /*  Command offset for z/VM isn't necessary  */
221 
222         pchecks = clear_process_counts(hinfo, clientclass);
223 
224         if (pchecks == 0) {
225                 /* Nothing to check */
226                 sprintf(msgline, "&%s No process checks defined\n", colorname(noreportcolor));
227                 addtobuffer(monmsg, msgline);
228                 pscolor = noreportcolor;
229         }
230         else if (cmdofs >= 0) {
231                 /* Count how many instances of each monitored process is running */
232                 char *pname, *pid, *bol, *nl;
233                 int pcount, pmin, pmax, pcolor, ptrack;
234 
235                 bol = psstr;
236                 while (bol) {
237                         nl = strchr(bol, '\n');
238 
239                         /* Take care - the ps output line may be shorter than what we look at */
240                         if (nl) {
241                                 *nl = '\0';
242 
243                                 if ((nl-bol) > cmdofs) add_process_count(bol+cmdofs);
244 
245                                 *nl = '\n';
246                                 bol = nl+1;
247                         }
248                         else {
249                                 if (strlen(bol) > cmdofs) add_process_count(bol+cmdofs);
250 
251                                 bol = NULL;
252                         }
253                 }
254 
255                 /* Check the number found for each monitored process */
256                 while ((pname = check_process_count(&pcount, &pmin, &pmax, &pcolor, &pid, &ptrack, &group)) != NULL) {
257                         char limtxt[1024];
258 
259                         if (pmax == -1) {
260                                 if (pmin > 0) sprintf(limtxt, "%d or more", pmin);
261                                 else if (pmin == 0) sprintf(limtxt, "none");
262                         }
263                         else {
264                                 if (pmin > 0) sprintf(limtxt, "between %d and %d", pmin, pmax);
265                                 else if (pmin == 0) sprintf(limtxt, "at most %d", pmax);
266                         }
267 
268                         if (pcolor == COL_GREEN) {
269                                 sprintf(msgline, "&green %s (found %d, req. %s)\n", pname, pcount, limtxt);
270                                 addtobuffer(monmsg, msgline);
271                         }
272                         else {
273                                 if (pcolor > pscolor) pscolor = pcolor;
274                                 sprintf(msgline, "&%s %s (found %d, req. %s)\n",
275                                         colorname(pcolor), pname, pcount, limtxt);
276                                 addtobuffer(monmsg, msgline);
277                                 addalertgroup(group);
278                         }
279 
280                         if (ptrack) {
281                                 /* Save the count data for later DATA message to track process counts */
282                                 if (!pid) pid = "default";
283                                 sprintf(msgline, "%s:%u\n", pid, pcount);
284                                 addtobuffer(countdata, msgline);
285                                 anycountdata = 1;
286                         }
287                 }
288         }
289         else {
290                 pscolor = COL_YELLOW;
291                 sprintf(msgline, "&yellow Expected string not found in ps output header\n");
292                 addtobuffer(monmsg, msgline);
293         }
294 
295         /* Now we know the result, so generate a status message */
296         init_status(pscolor);
297 
298         group = getalertgroups();
299         if (group) sprintf(msgline, "status/group:%s ", group); else strcpy(msgline, "status ");
300         addtostatus(msgline);
301 
302         sprintf(msgline, "%s.procs %s %s - Processes %s\n",
303                 commafy(hostname), colorname(pscolor),
304                 (timestr ? timestr : "<No timestamp data>"),
305                 ((pscolor == COL_GREEN) ? "OK" : "NOT ok"));
306         addtostatus(msgline);
307 
308         /* And add the info about what's wrong */
309         if (STRBUFLEN(monmsg)) {
310                 addtostrstatus(monmsg);
311                 addtostatus("\n");
312         }
313 
314         /* And the full virtual machine names output for those who want it */
315         if (pslistinprocs) {
316                 /*
317                  * Format the list of virtual machines into four per line,
318                  * this list could be fairly long.
319                  */
320                 char *tmpstr, *tok, *nm[4];
321 		int nmidx = 0;
322 
323 		/*  Make a copy of psstr, strtok() will be changing it  */
324 		tmpstr = strdup(psstr);
325 
326 		/*  Use strtok() to split string into pieces delimited by newline  */
327 		tok = strtok(tmpstr, "\n");
328 
329 		while (tok) {
330                         nm[nmidx++] = tok;
331 
332 			if (nmidx == 4) {
333 				sprintf(msgline, "%-8s %-8s %-8s %-8s\n", nm[0], nm[1], nm[2], nm[3]);
334 				addtostatus(msgline);
335 				nmidx = 0;
336 				nm[0] = nm[1] = nm[2] = nm[3] = " ";
337 			}
338 			tok = strtok(NULL, "\n");
339 		}
340 		/*  Print any remaining names  */
341 		if (nmidx > 0) {
342 			sprintf(msgline, "%-8s %-8s %-8s %-8s\n", nm[0], nm[1], nm[2], nm[3]);
343 			addtostatus(msgline);
344 		}
345 
346 		free(tmpstr);
347         }
348 
349         if (fromline && !localmode) addtostatus(fromline);
350         finish_status();
351 
352         freestrbuffer(monmsg);
353 
354         if (anycountdata) combo_add(countdata);
355         clearstrbuffer(countdata);
356 }
357 
358 
handle_zvm_client(char * hostname,char * clienttype,enum ostype_t os,void * hinfo,char * sender,time_t timestamp,char * clientdata)359 void handle_zvm_client(char *hostname, char *clienttype, enum ostype_t os,
360 			 void *hinfo, char *sender, time_t timestamp,
361 			 char *clientdata)
362 {
363 	char *timestr;
364 	char *cpuutilstr;
365 	char *uptimestr;
366 	char *dfstr;
367 	char *usersstr;		/* Logged on z/VM Users  */
368 	char *msgsstr;
369 	char *ifstatstr;
370 	char *portsstr;
371 
372 	char fromline[1024];
373 
374 	sprintf(fromline, "\nStatus message received from %s\n", sender);
375 
376 	splitmsg(clientdata);
377 
378 	timestr = getdata("date");
379 	uptimestr = getdata("uptime");
380 	cpuutilstr = getdata("cpu");
381 	dfstr = getdata("df");
382 	usersstr = getdata("UserID");
383 	msgsstr = getdata("msgs");
384 	portsstr = getdata("ports");
385 	ifstatstr = getdata("ifstat");
386 
387 	zvm_cpu_report(hostname, clienttype, os, hinfo, fromline, timestr, cpuutilstr, uptimestr);
388 	zvm_paging_report(hostname, clienttype, os, hinfo, fromline, timestr, cpuutilstr);
389         zvm_mdc_report(hostname, clienttype, os, hinfo, fromline, timestr, cpuutilstr);
390 	zvm_users_report(hostname, clienttype, os, hinfo, fromline, timestr, usersstr);
391 	unix_disk_report(hostname, clienttype, os, hinfo, fromline, timestr, "Available", "Capacity", "Mounted", dfstr);
392 	unix_ports_report(hostname, clienttype, os, hinfo, fromline, timestr, 3, 4, 5, portsstr);
393 	unix_ifstat_report(hostname, clienttype, os, hinfo, fromline, timestr, ifstatstr);
394 	msgs_report(hostname, clienttype, os, hinfo, fromline, timestr, msgsstr);
395 	file_report(hostname, clienttype, os, hinfo, fromline, timestr);
396 	linecount_report(hostname, clienttype, os, hinfo, fromline, timestr);
397 	deltacount_report(hostname, clienttype, os, hinfo, fromline, timestr);
398 
399 
400 	splitmsg_done();
401 }
402