cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

history.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 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 <history.h>
27 
28 #include <monitoring.h> /* MakeTimekey */
29 #include <actuator.h>
30 #include <promises.h>
31 #include <ornaments.h>
32 #include <locks.h>
33 #include <policy.h>
34 #include <vars.h>
35 #include <known_dirs.h>
36 #include <sysinfo.h>
37 #include <unix.h>
38 #include <scope.h>
39 #include <eval_context.h>
40 #include <item_lib.h>
41 #include <exec_tools.h>
42 #include <conversion.h>
43 #include <instrumentation.h>
44 #include <files_interfaces.h>
45 #include <pipes.h>
46 #include <matching.h>
47 #include <string_lib.h>
48 #include <regex.h> /* StringMatchFull */
49 #include <timeout.h>
50 #include <constants.h>
51 #include <time_classes.h>
52 #include <file_lib.h>
53 #include <assert.h>
54 
55 
56 #define CF_DUNBAR_WORK 30
57 
58 
59 typedef struct
60 {
61  char *path;
64 
65 static int MONITOR_RESTARTED = true;
67 
68 static void PutRecordForTime(CF_DB *db, time_t time, const Averages *values)
69 {
70  char timekey[CF_MAXVARSIZE];
71 
72  MakeTimekey(time, timekey);
73 
74  WriteDB(db, timekey, values, sizeof(Averages));
75 }
76 
77 static void Nova_SaveFilePosition(const char *handle, const char *name, long fileptr)
78 {
79  CF_DB *dbp;
80  char *key = StringConcatenate(2, handle, name);
81 
82  if (!OpenDB(&dbp, dbid_static))
83  {
84  return;
85  }
86 
87  Log(LOG_LEVEL_VERBOSE, "Saving state for %s at %ld", key, fileptr);
88  WriteDB(dbp, key, &fileptr, sizeof(long));
89  CloseDB(dbp);
90  free(key);
91 }
92 
93 static long Nova_RestoreFilePosition(const char *handle, const char *name)
94 {
95  CF_DB *dbp;
96  long fileptr;
97  char *key = StringConcatenate(2, handle, name);
98 
99  if (!OpenDB(&dbp, dbid_static))
100  {
101  return 0L;
102  }
103 
104  ReadDB(dbp, key, &fileptr, sizeof(long));
105  Log(LOG_LEVEL_VERBOSE, "Resuming state for %s at %ld", key, fileptr);
106  CloseDB(dbp);
107  free(key);
108  return fileptr;
109 }
110 
112 {
113  CF_DB *dbp;
114  CF_DBC *dbcp;
115  char *key;
116  void *stored;
117  int ksize, vsize;
118  char name[CF_BUFSIZE];
119 
120  if (!OpenDB(&dbp, dbid_static))
121  {
122  return;
123  }
124 
125  snprintf(name, CF_BUFSIZE - 1, "%s%cstatic_data", GetStateDir(), FILE_SEPARATOR);
126 
127 
128  FILE *fout = safe_fopen(name, "w");
129  if (fout == NULL)
130  {
131  Log(LOG_LEVEL_ERR, "Unable to save discovery data in '%s'. (fopen: %s)", name, GetErrorStr());
132  CloseDB(dbp);
133  return;
134  }
135 
136 /* Acquire a cursor for the database. */
137 
138  if (!NewDBCursor(dbp, &dbcp))
139  {
140  Log(LOG_LEVEL_INFO, "Unable to scan class db");
141  CloseDB(dbp);
142  return;
143  }
144 
145  while (NextDB(dbcp, &key, &ksize, &stored, &vsize))
146  {
147  char buf[CF_MAXVARSIZE], lval[CF_MAXVARSIZE], rval[CF_BUFSIZE];
148 
149  strncpy(buf, key, CF_MAXVARSIZE - 1);
150 
151  sscanf(buf, "%s:", lval);
152 
153  if (stored != NULL)
154  {
155  strncpy(rval, stored, CF_BUFSIZE - 1);
156  fprintf(fout, "%s:%s\n", lval, rval);
157  }
158  }
159 
160  DeleteDBCursor(dbcp);
161  CloseDB(dbp);
162  fclose(fout);
163 }
164 
165 static void Nova_HistoryUpdate(time_t time, const Averages *newvals)
166 {
167  CF_DB *dbp;
168 
169  if (!OpenDB(&dbp, dbid_history))
170  {
171  return;
172  }
173 
174  PutRecordForTime(dbp, time, newvals);
175 
176  CloseDB(dbp);
177 }
178 
179 static Item *NovaReSample(EvalContext *ctx, int slot, const Attributes *attr, const Promise *pp, PromiseResult *result)
180 {
181  assert(attr != NULL);
182  Attributes a = *attr; // TODO: try to remove this local copy
183  CfLock thislock;
184  char eventname[CF_BUFSIZE];
185  struct timespec start;
186  FILE *fin = NULL;
187  mode_t maskval = 0;
188  const char *handle = PromiseGetHandle(pp);
189 
190  if (a.measure.stream_type && strcmp(a.measure.stream_type, "pipe") == 0)
191  {
192  if (!IsExecutable(CommandArg0(pp->promiser)))
193  {
194  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, &a, "%s promises to be executable but isn't\n", pp->promiser);
195  *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
196  return NULL;
197  }
198  else
199  {
200  Log(LOG_LEVEL_VERBOSE, "Promiser string contains a valid executable (%s) - ok", CommandArg0(pp->promiser));
201  }
202  }
203 
204  // Force a measurement if restarted:
205  const int ifelapsed = MONITOR_RESTARTED ? 0 : a.transaction.ifelapsed;
206  const int expireafter = a.transaction.expireafter;
207 
208  CFSTARTTIME = time(NULL);
209 
210  thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, ifelapsed, expireafter, pp, false);
211 
212  if (thislock.lock == NULL)
213  {
214  if (strcmp(a.measure.history_type, "log") == 0)
215  {
216  DeleteItemList(ENTERPRISE_DATA[slot].output);
217  ENTERPRISE_DATA[slot].output = NULL;
218  }
219  else
220  {
221  /* If static or time-series, and too soon or busy then use a cached value
222  to avoid artificial gaps in the history */
223  }
224 
225  MONITOR_RESTARTED = false;
226  return ENTERPRISE_DATA[slot].output;
227  }
228  else
229  {
230  DeleteItemList(ENTERPRISE_DATA[slot].output);
231  ENTERPRISE_DATA[slot].output = NULL;
232 
233  Log(LOG_LEVEL_INFO, "Sampling \'%s\' ...(timeout=%d,owner=%ju,group=%ju)", pp->promiser, a.contain.timeout,
234  (uintmax_t)a.contain.owner, (uintmax_t)a.contain.group);
235 
236  start = BeginMeasure();
237 
238  if (a.contain.timeout != 0)
239  {
241  }
242 
243  /* Stream types */
244 
245  if (a.measure.stream_type && strcmp(a.measure.stream_type, "file") == 0)
246  {
247  long filepos = 0;
248  struct stat sb;
249 
250  Log(LOG_LEVEL_VERBOSE, "Stream \"%s\" is a plain file", pp->promiser);
251 
252  if (stat(pp->promiser, &sb) == -1)
253  {
254  Log(LOG_LEVEL_INFO, "Unable to find stream '%s'. (stat: %s)",
255  pp->promiser, GetErrorStr());
256  YieldCurrentLock(thislock);
257  MONITOR_RESTARTED = false;
258 
259  return NULL;
260  }
261 
262  fin = safe_fopen(pp->promiser, "r");
263 
264  if (a.measure.growing)
265  {
266  filepos = Nova_RestoreFilePosition(handle, pp->promiser);
267 
268  if (sb.st_size >= filepos)
269  {
270  fseek(fin, filepos, SEEK_SET);
271  }
272  }
273  }
274  else if (a.measure.stream_type && strcmp(a.measure.stream_type, "pipe") == 0)
275  {
276  Log(LOG_LEVEL_VERBOSE, "(Setting pipe umask to %jo)", (uintmax_t)a.contain.umask);
277  maskval = umask(a.contain.umask);
278 
279  if (a.contain.umask == 0)
280  {
281  Log(LOG_LEVEL_VERBOSE, "Programming %s running with umask 0! Use umask= to set", pp->promiser);
282  }
283 
284 
285  // Mark: This is strange that we used these wrappers. Currently no way of setting these
286  a.contain.owner = -1;
287  a.contain.group = -1;
288  a.contain.chdir = NULL;
289  a.contain.chroot = NULL;
290  // Mark: they were unset, and would fail for non-root(!)
291 
293  {
294 #ifdef __MINGW32__
295  fin =
296  cf_popen_powershell_setuid(pp->promiser, "r", a.contain.owner, a.contain.group, a.contain.chdir,
297  a.contain.chroot, false);
298 #else // !__MINGW32__
299  Log(LOG_LEVEL_ERR, "Powershell is only supported on Windows");
300  YieldCurrentLock(thislock);
301  MONITOR_RESTARTED = false;
302  return NULL;
303 #endif // !__MINGW32__
304  }
305  else if (a.contain.shelltype == SHELL_TYPE_USE)
306  {
307  fin =
309  a.contain.chroot, false);
310  }
311  else
312  {
313  fin =
315  a.contain.chroot, false);
316  }
317  }
318 
319  /* generic file stream */
320 
321  if (fin == NULL)
322  {
323  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, &a,
324  "Couldn't open pipe to command '%s'. (cf_popen: %s)", pp->promiser, GetErrorStr());
325  *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
326  YieldCurrentLock(thislock);
327  MONITOR_RESTARTED = false;
328  return ENTERPRISE_DATA[slot].output;
329  }
330 
331  size_t line_size = CF_BUFSIZE;
332  char *line = xmalloc(line_size);
333 
334  for (;;)
335  {
336  ssize_t res = CfReadLine(&line, &line_size, fin);
337  if (res == -1)
338  {
339  if (!feof(fin))
340  {
341  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_TIMEOUT, pp, &a, "Sample stream '%s'. (fread: %s)",
342  pp->promiser, GetErrorStr());
343  *result = PromiseResultUpdate(*result, PROMISE_RESULT_TIMEOUT);
344  YieldCurrentLock(thislock);
345  free(line);
346  return ENTERPRISE_DATA[slot].output;
347  }
348  else
349  {
350  break;
351  }
352  }
353 
354  AppendItem(&(ENTERPRISE_DATA[slot].output), line, NULL);
355  Log(LOG_LEVEL_INFO, "Sampling => %s", line);
356  }
357 
358  free(line);
359 
360  if (a.measure.stream_type && strcmp(a.measure.stream_type, "file") == 0)
361  {
362  long fileptr = ftell(fin);
363 
364  fclose(fin);
365  Nova_SaveFilePosition(handle, pp->promiser, fileptr);
366  }
367  else if (a.measure.stream_type && strcmp(a.measure.stream_type, "pipe") == 0)
368  {
369  cf_pclose(fin);
370  }
371  }
372 
373  if (a.contain.timeout != 0)
374  {
375  alarm(0);
376  signal(SIGALRM, SIG_DFL);
377  }
378 
379  Log(LOG_LEVEL_INFO, "Collected sample of %s", pp->promiser);
380  umask(maskval);
381  YieldCurrentLock(thislock);
382  MONITOR_RESTARTED = false;
383 
384  snprintf(eventname, CF_BUFSIZE - 1, "Sample(%s)", pp->promiser);
385  EndMeasure(eventname, start);
386  return ENTERPRISE_DATA[slot].output;
387 }
388 
389 void HistoryUpdate(EvalContext *ctx, const Averages *const newvals)
390 {
391  CfLock thislock;
392  time_t now = time(NULL);
393 
394 /* We do this only once per hour - this should not be changed */
395 
396  Banner("Update long-term history");
397 
398  Policy *history_db_policy = PolicyNew();
399  Promise *pp = NULL;
400  {
401  Bundle *bp = PolicyAppendBundle(history_db_policy, NamespaceDefault(), "history_db_bundle", "agent", NULL, NULL);
402  PromiseType *tp = BundleAppendPromiseType(bp, "history_db");
403 
404  pp = PromiseTypeAppendPromise(tp, "the long term memory", (Rval) { NULL, RVAL_TYPE_NOPROMISEE }, NULL, NULL);
405  }
406  assert(pp);
407 
408  thislock = AcquireLock(ctx, pp->promiser, VUQNAME, now, 59, 0, pp, false);
409 
410  if (thislock.lock == NULL)
411  {
412  PolicyDestroy(history_db_policy);
413  return;
414  }
415 
416 /* Refresh the class context of the agent */
417 
418  EvalContextClear(ctx);
419 
420  DetectEnvironment(ctx);
421  time_t t = SetReferenceTime();
422  UpdateTimeClasses(ctx, t);
423 
425  LoadSystemConstants(ctx);
426 
427  YieldCurrentLock(thislock);
428  PolicyDestroy(history_db_policy);
429 
431 
433 }
434 
435 static Item *NovaGetMeasurementStream(EvalContext *ctx, const Attributes *a, const Promise *pp, PromiseResult *result)
436 {
437  int i;
438 
439  for (i = 0; i < CF_DUNBAR_WORK; i++)
440  {
441  if (ENTERPRISE_DATA[i].path == NULL)
442  {
443  break;
444  }
445 
446  if (strcmp(ENTERPRISE_DATA[i].path, pp->promiser) == 0)
447  {
448  ENTERPRISE_DATA[i].output = NovaReSample(ctx, i, a, pp, result);
449  return ENTERPRISE_DATA[i].output;
450  }
451  }
452 
454  ENTERPRISE_DATA[i].output = NovaReSample(ctx, i, a, pp, result);
455  return ENTERPRISE_DATA[i].output;
456 }
457 
458 static PromiseResult NovaExtractValueFromStream(EvalContext *ctx, const char *handle,
459  Item *stream, const Attributes *a,
460  const Promise *pp, double *value_out)
461 {
462  char value[CF_MAXVARSIZE];
463  int count = 1, found = false, match_count = 0, done = false;
464  double real_val = 0;
465  Item *ip, *match = NULL;
466  bool ok_conversion = true;
467 
468  for (ip = stream; ip != NULL; ip = ip->next)
469  {
470  if (count == a->measure.select_line_number)
471  {
472  found = true;
473  match = ip;
474  match_count++;
475  }
476 
478  {
479  Log(LOG_LEVEL_VERBOSE, " Found regex '%s' matches line '%s'", a->measure.select_line_matching, ip->name);
480  found = true;
481  match = ip;
482 
483  if (a->measure.extraction_regex)
484  {
485  switch (a->measure.data_type)
486  {
487  case CF_DATA_TYPE_INT:
488  case CF_DATA_TYPE_REAL:
490 
491  strncpy(value, ExtractFirstReference(a->measure.extraction_regex, match->name), CF_MAXVARSIZE - 1);
492 
493  if (strcmp(value, "CF_NOMATCH") == 0)
494  {
495  ok_conversion = false;
496  Log(LOG_LEVEL_VERBOSE, "Was not able to match a value with '%s' on '%s'",
497  a->measure.extraction_regex, match->name);
498  }
499  else
500  {
501  if (ok_conversion)
502  {
503  Log(LOG_LEVEL_VERBOSE, "Found candidate match value of '%s'", value);
504 
506  {
507  double delta = 0;
508  if (DoubleFromString(value, &delta))
509  {
510  real_val += delta;
511  }
512  else
513  {
514  Log(LOG_LEVEL_ERR, "Error in double conversion from string value: %s", value);
515  return PROMISE_RESULT_FAIL;
516  }
517  }
518  else
519  {
520  if (!DoubleFromString(value, &real_val))
521  {
522  Log(LOG_LEVEL_ERR, "Error in double conversion from string value: %s", value);
523  return PROMISE_RESULT_FAIL;
524  }
525  }
526 
527  match_count++;
528 
530  {
531  done = true;
532  }
533  }
534  }
535  break;
536 
537  default:
538  Log(LOG_LEVEL_ERR, "Unexpected data type in data_type attribute: %d", a->measure.data_type);
539  }
540  }
541 
542  }
543 
544  count++;
545 
546  if (done)
547  {
548  break;
549  }
550  }
551 
552  if (!found)
553  {
554  cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, a, "Could not locate the line for promise '%s'", handle);
555  *value_out = 0.0;
556  return PROMISE_RESULT_FAIL;
557  }
558 
559  switch (a->measure.data_type)
560  {
562 
563  real_val = (double) match_count;
564  break;
565 
566  case CF_DATA_TYPE_INT:
567 
568  if (match_count > 1)
569  {
570  Log(LOG_LEVEL_INFO, "Warning: %d lines matched the line_selection \"%s\"- making best average",
571  match_count, a->measure.select_line_matching);
572  }
573 
574  if (match_count > 0 && a->measure.policy == MEASURE_POLICY_AVERAGE) // If not "average" then "sum"
575  {
576  real_val /= match_count;
577  }
578  break;
579 
580  case CF_DATA_TYPE_REAL:
581 
582  if (match_count > 1)
583  {
584  Log(LOG_LEVEL_INFO, "Warning: %d lines matched the line_selection \"%s\"- making best average",
585  match_count, a->measure.select_line_matching);
586  }
587 
588  if (match_count > 0)
589  {
590  real_val /= match_count;
591  }
592 
593  break;
594 
595  default:
596  Log(LOG_LEVEL_ERR, "Unexpected data type in data_type attribute: %d", a->measure.data_type);
597  }
598 
599  if (!ok_conversion)
600  {
601  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Unable to extract a value from the matched line '%s'", match->name);
603  *value_out = 0.0;
604  return PROMISE_RESULT_FAIL;
605  }
606 
607  Log(LOG_LEVEL_INFO, "Extracted value \"%f\" for promise \"%s\"", real_val, handle);
608  *value_out = real_val;
609  return PROMISE_RESULT_NOOP;
610 }
611 
612 static void NovaLogSymbolicValue(EvalContext *ctx, const char *handle, Item *stream,
613  const Attributes *a, const Promise *pp, PromiseResult *result)
614 {
615  char value[CF_BUFSIZE], sdate[CF_MAXVARSIZE], filename[CF_BUFSIZE];
616  int count = 1, found = false, match_count = 0;
617  Item *ip, *match = NULL, *matches = NULL;
618  time_t now = time(NULL);
619 
620  if (stream == NULL)
621  {
622  Log(LOG_LEVEL_VERBOSE, "No stream to measure");
623  return;
624  }
625 
626  Log(LOG_LEVEL_VERBOSE, "Locate and log sample ...");
627 
628  for (ip = stream; ip != NULL; ip = ip->next)
629  {
630  if (ip->name == NULL)
631  {
632  continue;
633  }
634 
635  if (count == a->measure.select_line_number)
636  {
637  Log(LOG_LEVEL_VERBOSE, "Found line %d by number...", count);
638  found = true;
639  match_count = 1;
640  match = ip;
641 
642  if (a->measure.extraction_regex)
643  {
644  Log(LOG_LEVEL_VERBOSE, "Now looking for a matching extractor \"%s\"", a->measure.extraction_regex);
645  strncpy(value, ExtractFirstReference(a->measure.extraction_regex, match->name), CF_MAXVARSIZE - 1);
646  Log(LOG_LEVEL_INFO, "Extracted value \"%s\" for promise \"%s\"", value, handle);
647  AppendItem(&matches, value, NULL);
648  }
649  else
650  {
651  Log(LOG_LEVEL_INFO, "Using entire line \"%s\" for promise \"%s\"", match->name, handle);
652  AppendItem(&matches, match->name, NULL);
653  }
654  break;
655  }
656 
658  {
659  Log(LOG_LEVEL_VERBOSE, "Found line %d by pattern...", count);
660  found = true;
661  match = ip;
662  match_count++;
663 
664  if (a->measure.extraction_regex)
665  {
666  Log(LOG_LEVEL_VERBOSE, "Now looking for a matching extractor \"%s\"", a->measure.extraction_regex);
667  strncpy(value, ExtractFirstReference(a->measure.extraction_regex, match->name), CF_MAXVARSIZE - 1);
668  Log(LOG_LEVEL_INFO, "Extracted value \"%s\" for promise \"%s\"", value, handle);
669  AppendItem(&matches, value, NULL);
670  }
671  else
672  {
673  Log(LOG_LEVEL_INFO, "Using entire line \"%s\" for promise \"%s\"", match->name, handle);
674  AppendItem(&matches, match->name, NULL);
675  }
676  }
677 
678  count++;
679  }
680 
681  if (!found)
682  {
683  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Promiser '%s' found no matching line.", pp->promiser);
684  *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
685  return;
686  }
687 
688  if (match_count > 1)
689  {
690  Log(LOG_LEVEL_INFO, "Warning: %d lines matched the line_selection \"%s\"- matching to last", match_count,
692  }
693 
694  switch (a->measure.data_type)
695  {
697  Log(LOG_LEVEL_VERBOSE, "Counted %d for %s", match_count, handle);
698  snprintf(value, CF_MAXVARSIZE, "%d", match_count);
699  break;
700 
702  ItemList2CSV_bound(matches, value, sizeof(value), ',');
703  break;
704 
705  default:
706  snprintf(value, CF_BUFSIZE, "%s", matches->name);
707  }
708 
709  DeleteItemList(matches);
710 
711  if (a->measure.history_type && strcmp(a->measure.history_type, "log") == 0)
712  {
713  snprintf(filename, CF_BUFSIZE, "%s%c%s_measure.log", GetStateDir(), FILE_SEPARATOR, handle);
714 
715  FILE *fout = safe_fopen(filename, "a");
716  if (fout == NULL)
717  {
718  cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Unable to open the output log \"%s\"", filename);
719  *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
721  return;
722  }
723 
724  strncpy(sdate, ctime(&now), CF_MAXVARSIZE - 1);
725  if (Chop(sdate, CF_EXPANDSIZE) == -1)
726  {
727  Log(LOG_LEVEL_ERR, "Chop was called on a string that seemed to have no terminator");
728  }
729 
730  fprintf(fout, "%s,%ld,%s\n", sdate, (long) now, value);
731  Log(LOG_LEVEL_VERBOSE, "Logging: %s,%s to %s", sdate, value, filename);
732 
733  fclose(fout);
734  }
735  else // scalar or static
736  {
737  CF_DB *dbp;
738  char id[CF_MAXVARSIZE];
739 
740  if (!OpenDB(&dbp, dbid_static))
741  {
742  return;
743  }
744 
745  snprintf(id, CF_MAXVARSIZE - 1, "%s:%d", handle, a->measure.data_type);
746  WriteDB(dbp, id, value, strlen(value) + 1);
747  CloseDB(dbp);
748  }
749 }
750 
752  const Attributes *a, const Promise *pp)
753 {
754  const char *handle = PromiseGetHandle(pp);
755  Item *stream = NULL;
756  int slot = 0;
757  double new_value;
758 
759  if (!handle)
760  {
761  Log(LOG_LEVEL_ERR, "The promised measurement has no handle to register it by.");
762  return PROMISE_RESULT_NOOP;
763  }
764  else
765  {
766  Log(LOG_LEVEL_VERBOSE, "Considering promise \"%s\"", handle);
767  }
768 
770  switch (a->measure.data_type)
771  {
773  case CF_DATA_TYPE_INT:
774  case CF_DATA_TYPE_REAL:
775 
776  /* First see if we can accommodate this measurement */
777  Log(LOG_LEVEL_VERBOSE, "Promise '%s' is numerical in nature", handle);
778 
779  stream = NovaGetMeasurementStream(ctx, a, pp, &result);
780 
781  if (strcmp(a->measure.history_type, "weekly") == 0)
782  {
783  if ((slot = NovaRegisterSlot(handle, pp->comment ? pp->comment : "User defined measure",
784  a->measure.units ? a->measure.units : "unknown", 0.0f, 100.0f, true)) < 0)
785  {
786  return result;
787  }
788 
789  result = PromiseResultUpdate(result, NovaExtractValueFromStream(ctx, handle, stream, a, pp, &this[slot]));
790  Log(LOG_LEVEL_VERBOSE, "Setting Nova slot %d=%s to %lf", slot, handle, this[slot]);
791  }
792  else if (strcmp(a->measure.history_type, "log") == 0)
793  {
794  Log(LOG_LEVEL_VERBOSE, "Promise to log a numerical value");
795  NovaLogSymbolicValue(ctx, handle, stream, a, pp, &result);
796  }
797  else /* static */
798  {
799  Log(LOG_LEVEL_VERBOSE, "Promise to store a static numerical value");
800  result = PromiseResultUpdate(result, NovaExtractValueFromStream(ctx, handle, stream, a, pp, &new_value));
801  NovaNamedEvent(handle, new_value);
802  }
803  break;
804 
805  default:
806 
807  Log(LOG_LEVEL_VERBOSE, "Promise '%s' is symbolic in nature", handle);
808  stream = NovaGetMeasurementStream(ctx, a, pp, &result);
809  NovaLogSymbolicValue(ctx, handle, stream, a, pp, &result);
810  break;
811  }
812 
813  return result;
814 
815 // stream gets de-allocated in ReSample
816 }
PromiseResult PromiseResultUpdate(PromiseResult prior, PromiseResult evidence)
Definition: actuator.c:28
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
@ MEASURE_POLICY_FIRST
Definition: cf3.defs.h:1398
@ MEASURE_POLICY_SUM
Definition: cf3.defs.h:1397
@ MEASURE_POLICY_AVERAGE
Definition: cf3.defs.h:1396
@ SHELL_TYPE_USE
Definition: cf3.defs.h:1107
@ SHELL_TYPE_POWERSHELL
Definition: cf3.defs.h:1108
@ RVAL_TYPE_NOPROMISEE
Definition: cf3.defs.h:610
PromiseResult
Definition: cf3.defs.h:122
@ PROMISE_RESULT_NOOP
Definition: cf3.defs.h:124
@ PROMISE_RESULT_FAIL
Definition: cf3.defs.h:127
@ PROMISE_RESULT_TIMEOUT
Definition: cf3.defs.h:129
@ CF_DATA_TYPE_REAL
Definition: cf3.defs.h:371
@ CF_DATA_TYPE_STRING_LIST
Definition: cf3.defs.h:372
@ CF_DATA_TYPE_INT
Definition: cf3.defs.h:370
@ CF_DATA_TYPE_COUNTER
Definition: cf3.defs.h:383
time_t CFSTARTTIME
Definition: cf3globals.c:99
char VUQNAME[]
Definition: cf3globals.c:59
void free(void *)
const char * CommandArg0(const char *execstr)
Definition: conversion.c:882
bool DoubleFromString(const char *s, double *value_out)
Definition: conversion.c:521
bool NextDB(DBCursor *cursor, char **key, int *ksize, void **value, int *vsize)
Definition: dbm_api.c:601
bool OpenDB(DBHandle **dbp, dbid id)
Definition: dbm_api.c:441
bool ReadDB(DBHandle *handle, const char *key, void *dest, int destSz)
Definition: dbm_api.c:556
bool DeleteDBCursor(DBCursor *cursor)
Definition: dbm_api.c:617
bool WriteDB(DBHandle *handle, const char *key, const void *src, int srcSz)
Definition: dbm_api.c:561
void CloseDB(DBHandle *handle)
Definition: dbm_api.c:472
bool NewDBCursor(DBHandle *handle, DBCursor **cursor)
Definition: dbm_api.c:588
@ dbid_static
Definition: dbm_api.h:50
@ dbid_history
Definition: dbm_api.h:48
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_EXPANDSIZE
Definition: definitions.h:51
#define CF_MAXVARSIZE
Definition: definitions.h:36
void EvalContextClear(EvalContext *ctx)
void cfPS(EvalContext *ctx, LogLevel level, PromiseResult status, const Promise *pp, const Attributes *attr, const char *fmt,...)
void EvalContextHeapPersistentLoadAll(EvalContext *ctx)
Definition: eval_context.c:731
bool IsExecutable(const char *file)
Definition: unix.c:130
ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
Works exactly like posix 'getline', EXCEPT it does not include carriage return at the end.
Definition: file_lib.c:1476
FILE * safe_fopen(const char *const path, const char *const mode)
Definition: file_lib.c:812
#define FILE_SEPARATOR
Definition: file_lib.h:102
#define NULL
Definition: getopt1.c:56
static void Nova_SaveFilePosition(const char *handle, const char *name, long fileptr)
Definition: history.c:77
static void NovaLogSymbolicValue(EvalContext *ctx, const char *handle, Item *stream, const Attributes *a, const Promise *pp, PromiseResult *result)
Definition: history.c:612
void HistoryUpdate(EvalContext *ctx, const Averages *const newvals)
Definition: history.c:389
static PromiseResult NovaExtractValueFromStream(EvalContext *ctx, const char *handle, Item *stream, const Attributes *a, const Promise *pp, double *value_out)
Definition: history.c:458
static int MONITOR_RESTARTED
Definition: history.c:65
static void Nova_DumpSlowlyVaryingObservations(void)
Definition: history.c:111
static Item * NovaReSample(EvalContext *ctx, int slot, const Attributes *attr, const Promise *pp, PromiseResult *result)
Definition: history.c:179
PromiseResult VerifyMeasurement(EvalContext *ctx, double *this, const Attributes *a, const Promise *pp)
Definition: history.c:751
static Item * NovaGetMeasurementStream(EvalContext *ctx, const Attributes *a, const Promise *pp, PromiseResult *result)
Definition: history.c:435
static void Nova_HistoryUpdate(time_t time, const Averages *newvals)
Definition: history.c:165
static void PutRecordForTime(CF_DB *db, time_t time, const Averages *values)
Definition: history.c:68
static long Nova_RestoreFilePosition(const char *handle, const char *name)
Definition: history.c:93
#define CF_DUNBAR_WORK
Definition: history.c:56
static CustomMeasurement ENTERPRISE_DATA[30]
Definition: history.c:66
void EndMeasure(char *eventname, struct timespec start)
struct timespec BeginMeasure()
size_t ItemList2CSV_bound(const Item *list, char *buf, size_t buf_size, char separator)
Definition: item_lib.c:680
void AppendItem(Item **liststart, const char *itemstring, const char *classes)
Definition: item_lib.c:415
void DeleteItemList(Item *item)
Definition: item_lib.c:808
const char * GetStateDir(void)
Definition: known_dirs.c:186
void LoadSystemConstants(EvalContext *ctx)
Definition: constants.c:30
void YieldCurrentLock(CfLock lock)
Definition: locks.c:948
CfLock AcquireLock(EvalContext *ctx, const char *operand, const char *host, time_t now, int ifelapsed, int expireafter, const Promise *pp, bool ignoreProcesses)
Definition: locks.c:789
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
char * ExtractFirstReference(const char *regexp, const char *teststring)
Definition: matching.c:69
static PrevValue * values
int NovaRegisterSlot(const char *name, const char *description, const char *units, double expected_minimum, double expected_maximum, bool consolidable)
Definition: monitoring.c:311
void NovaNamedEvent(const char *eventname, double value)
Definition: monitoring.c:50
void MakeTimekey(time_t time, char *result)
void Banner(const char *s)
Definition: ornaments.c:219
FILE * cf_popensetuid(const char *command, const char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, int background)
Definition: pipes_unix.c:440
int cf_pclose(FILE *pp)
Definition: pipes_unix.c:812
FILE * cf_popen_shsetuid(const char *command, const char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, int background)
Definition: pipes_unix.c:649
unsigned int alarm(unsigned int seconds)
void PolicyDestroy(Policy *policy)
Definition: policy.c:121
const char * PromiseGetHandle(const Promise *pp)
Return handle of the promise.
Definition: policy.c:2713
Bundle * PolicyAppendBundle(Policy *policy, const char *ns, const char *name, const char *type, const Rlist *args, const char *source_path)
Definition: policy.c:1326
PromiseType * BundleAppendPromiseType(Bundle *bundle, const char *name)
Definition: policy.c:1376
Promise * PromiseTypeAppendPromise(PromiseType *type, const char *promiser, Rval promisee, const char *classes, const char *varclasses)
Definition: policy.c:1406
Policy * PolicyNew(void)
Definition: policy.c:100
const char * NamespaceDefault(void)
Definition: policy.c:93
void PromiseRef(LogLevel level, const Promise *pp)
Definition: promises.c:769
bool StringMatchFull(const char *regex, const char *str)
Definition: regex.c:106
int Chop(char *str, size_t max_length)
Remove trailing spaces.
Definition: string_lib.c:1174
char * StringConcatenate(size_t count, const char *first,...)
Definition: string_lib.c:348
ExecContain contain
Definition: cf3.defs.h:1570
TransactionContext transaction
Definition: cf3.defs.h:1567
Measurement measure
Definition: cf3.defs.h:1547
Definition: policy.h:70
char * lock
Definition: cf3.defs.h:895
Item * output
Definition: history.c:62
char * chdir
Definition: cf3.defs.h:1117
mode_t umask
Definition: cf3.defs.h:1114
gid_t group
Definition: cf3.defs.h:1116
char * chroot
Definition: cf3.defs.h:1118
ShellType shelltype
Definition: cf3.defs.h:1113
uid_t owner
Definition: cf3.defs.h:1115
Definition: item_lib.h:33
Item * next
Definition: item_lib.h:38
char * name
Definition: item_lib.h:34
char * units
Definition: cf3.defs.h:1412
int select_line_number
Definition: cf3.defs.h:1410
char * select_line_matching
Definition: cf3.defs.h:1409
char * history_type
Definition: cf3.defs.h:1408
DataType data_type
Definition: cf3.defs.h:1406
char * extraction_regex
Definition: cf3.defs.h:1411
MeasurePolicy policy
Definition: cf3.defs.h:1407
char * stream_type
Definition: cf3.defs.h:1405
Definition: policy.h:53
char * comment
Definition: policy.h:114
char * promiser
Definition: policy.h:115
Definition: cf3.defs.h:614
void DetectEnvironment(EvalContext *ctx)
Definition: sysinfo.c:3332
void UpdateTimeClasses(EvalContext *ctx, time_t t)
Definition: time_classes.c:133
time_t SetReferenceTime(void)
Definition: timeout.c:55
void SetTimeOut(int timeout)
Definition: timeout.c:29