1 /*
2 Copyright 2020 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25
26 #include <monitoring_read.h>
27
28 #include <file_lib.h> /* FILE_SEPARATOR */
29 #include <known_dirs.h>
30
31
32 /* GLOBALS */
33
34 static const char *UNITS[CF_OBSERVABLES] = /* constant */
35 {
36 "average users per 2.5 mins",
37 "processes",
38 "processes",
39 "percent",
40 "jobs",
41 "connections",
42 "connections",
43 "connections",
44 "connections",
45 "connections",
46 "connections",
47 "connections",
48 "connections",
49 "connections",
50 "connections",
51 "connections",
52 "connections",
53 "connections",
54 "connections",
55 "connections",
56 "connections",
57 "connections",
58 "connections",
59 "connections",
60 "connections",
61 "connections",
62 "connections",
63 "packets",
64 "packets",
65 "packets",
66 "packets",
67 "packets",
68 "packets",
69 "packets",
70 "packets",
71 "packets",
72 "packets",
73 "packets",
74 "packets",
75 "packets",
76 "packets",
77 "entries",
78 "entries",
79 "entries",
80 "entries",
81 "Celcius",
82 "Celcius",
83 "Celcius",
84 "Celcius",
85 "percent",
86 "percent",
87 "percent",
88 "percent",
89 "percent",
90 "packets",
91 "packets",
92 "connections",
93 "connections",
94 "connections",
95 "connections",
96 "connections",
97 "connections",
98 "connections",
99 "connections",
100
101 };
102
103 time_t slots_load_time = 0;
104 MonitoringSlot *SLOTS[CF_OBSERVABLES - ob_spare];
105
106
107 /*****************************************************************************/
108
Nova_FreeSlot(MonitoringSlot * slot)109 void Nova_FreeSlot(MonitoringSlot *slot)
110 {
111 if (slot)
112 {
113 free(slot->name);
114 free(slot->description);
115 free(slot->units);
116 free(slot);
117 }
118 }
119
Nova_MakeSlot(const char * name,const char * description,const char * units,double expected_minimum,double expected_maximum,bool consolidable)120 MonitoringSlot *Nova_MakeSlot(const char *name, const char *description,
121 const char *units,
122 double expected_minimum, double expected_maximum,
123 bool consolidable)
124 {
125 MonitoringSlot *slot = xmalloc(sizeof(MonitoringSlot));
126
127 slot->name = xstrdup(name);
128 slot->description = xstrdup(description);
129 slot->units = xstrdup(units);
130 slot->expected_minimum = expected_minimum;
131 slot->expected_maximum = expected_maximum;
132 slot->consolidable = consolidable;
133 return slot;
134 }
135
Nova_LoadSlots(void)136 void Nova_LoadSlots(void)
137 {
138 char filename[CF_BUFSIZE];
139 int i;
140
141 snprintf(filename, CF_BUFSIZE - 1, "%s%cts_key", GetStateDir(), FILE_SEPARATOR);
142
143 FILE *f = safe_fopen(filename, "r");
144 if (f == NULL)
145 {
146 return;
147 }
148
149 int fd = fileno(f);
150 struct stat sb;
151 if ((fstat(fd, &sb) != 0) ||
152 (sb.st_mtime <= slots_load_time))
153 {
154 fclose(f);
155 return;
156 }
157
158 slots_load_time = sb.st_mtime;
159
160 for (i = 0; i < CF_OBSERVABLES; ++i)
161 {
162 if (i < ob_spare)
163 {
164 int r;
165 do
166 {
167 r = fgetc(f);
168 } while (r != (int)'\n' && r != EOF);
169 if (r == EOF)
170 {
171 break;
172 }
173 }
174 else
175 {
176 char line[CF_MAXVARSIZE];
177
178 char name[CF_MAXVARSIZE], desc[CF_MAXVARSIZE];
179 char units[CF_MAXVARSIZE] = "unknown";
180 double expected_min = 0.0;
181 double expected_max = 100.0;
182 int consolidable = true;
183
184 if (fgets(line, CF_MAXVARSIZE, f) == NULL)
185 {
186 Log(LOG_LEVEL_ERR, "Error trying to read ts_key from file '%s'. (fgets: %s)", filename, GetErrorStr());
187 break;
188 }
189
190 int fields = sscanf(line, "%*d,%1023[^,],%1023[^,],%1023[^,],%lf,%lf,%d",
191 name, desc, units, &expected_min, &expected_max, &consolidable);
192
193 if (fields == 2)
194 {
195 /* Old-style ts_key with name and description */
196 }
197 else if (fields == 6)
198 {
199 /* New-style ts_key with additional parameters */
200 }
201 else
202 {
203 Log(LOG_LEVEL_ERR, "Wrong line format in ts_key: %s", line);
204 }
205
206 if (strcmp(name, "spare") != 0)
207 {
208 Nova_FreeSlot(SLOTS[i - ob_spare]);
209 SLOTS[i - ob_spare] = Nova_MakeSlot(name, desc, units, expected_min, expected_max, consolidable);
210 }
211 }
212 }
213 fclose(f);
214 }
215
216
NovaHasSlot(int idx)217 bool NovaHasSlot(int idx)
218 {
219 Nova_LoadSlots();
220
221 return idx < ob_spare || SLOTS[idx - ob_spare];
222 }
223
NovaGetSlotName(int idx)224 const char *NovaGetSlotName(int idx)
225 {
226 Nova_LoadSlots();
227
228 return idx < ob_spare ? OBSERVABLES[idx][0] : SLOTS[idx - ob_spare]->name;
229 }
230
NovaGetSlotDescription(int idx)231 const char *NovaGetSlotDescription(int idx)
232 {
233 Nova_LoadSlots();
234
235 return idx < ob_spare ? OBSERVABLES[idx][1] : SLOTS[idx - ob_spare]->description;
236 }
237
NovaGetSlotUnits(int idx)238 const char *NovaGetSlotUnits(int idx)
239 {
240 Nova_LoadSlots();
241
242 return idx < ob_spare ? UNITS[idx] : SLOTS[idx - ob_spare]->units;
243 }
244
245 // TODO: real expected minimum/maximum/consolidable for core slots
246
NovaGetSlotExpectedMinimum(int idx)247 double NovaGetSlotExpectedMinimum(int idx)
248 {
249 Nova_LoadSlots();
250
251 return idx < ob_spare ? 0.0f : SLOTS[idx - ob_spare]->expected_minimum;
252 }
253
NovaGetSlotExpectedMaximum(int idx)254 double NovaGetSlotExpectedMaximum(int idx)
255 {
256 Nova_LoadSlots();
257
258 return idx < ob_spare ? 100.0f : SLOTS[idx - ob_spare]->expected_maximum;
259 }
260
NovaIsSlotConsolidable(int idx)261 bool NovaIsSlotConsolidable(int idx)
262 {
263 Nova_LoadSlots();
264
265 return idx < ob_spare ? true : SLOTS[idx - ob_spare]->consolidable;
266 }
267
268
269
270
271 /*
272 * This function returns beginning of last Monday relative to 'time'. If 'time'
273 * is Monday, beginning of the same day is returned.
274 */
WeekBegin(time_t time)275 time_t WeekBegin(time_t time)
276 {
277 struct tm tm;
278
279 gmtime_r(&time, &tm);
280
281 /* Move back in time to reach Monday. */
282
283 time -= ((tm.tm_wday == 0 ? 6 : tm.tm_wday - 1) * SECONDS_PER_DAY);
284
285 /* Move to the beginning of day */
286
287 time -= tm.tm_hour * SECONDS_PER_HOUR;
288 time -= tm.tm_min * SECONDS_PER_MINUTE;
289 time -= tm.tm_sec;
290
291 return time;
292 }
293
SubtractWeeks(time_t time,int weeks)294 time_t SubtractWeeks(time_t time, int weeks)
295 {
296 return time - weeks * SECONDS_PER_WEEK;
297 }
298
NextShift(time_t time)299 time_t NextShift(time_t time)
300 {
301 return time + SECONDS_PER_SHIFT;
302 }
303
304
MakeTimekey(time_t time,char * result)305 void MakeTimekey(time_t time, char *result)
306 {
307 /* Generate timekey for database */
308 struct tm tm;
309
310 gmtime_r(&time, &tm);
311
312 snprintf(result, 64, "%d_%.3s_Lcycle_%d_%s",
313 tm.tm_mday, MONTH_TEXT[tm.tm_mon], (tm.tm_year + 1900) % 3, SHIFT_TEXT[tm.tm_hour / 6]);
314 }
315
316 /* Returns true if entry was found, false otherwise */
GetRecordForTime(CF_DB * db,time_t time,Averages * result)317 bool GetRecordForTime(CF_DB *db, time_t time, Averages *result)
318 {
319 char timekey[CF_MAXVARSIZE];
320
321 MakeTimekey(time, timekey);
322
323 return ReadDB(db, timekey, result, sizeof(Averages));
324 }
325
326