Пример #1
0
xmlNodePtr
noit_check_state_as_xml(noit_check_t *check) {
    xmlNodePtr state, tmp, metrics;
    noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
    const char *k;
    int klen;
    void *data;
    stats_t *c = &check->stats.current;

    state = xmlNewNode(NULL, (xmlChar *)"state");
    NODE_CONTENT(state, "running", NOIT_CHECK_RUNNING(check)?"true":"false");
    NODE_CONTENT(state, "killed", NOIT_CHECK_KILLED(check)?"true":"false");
    NODE_CONTENT(state, "configured",
                 NOIT_CHECK_CONFIGURED(check)?"true":"false");
    NODE_CONTENT(state, "disabled", NOIT_CHECK_DISABLED(check)?"true":"false");
    NODE_CONTENT(state, "target_ip", check->target_ip);
    xmlAddChild(state, (tmp = xmlNewNode(NULL, (xmlChar *)"last_run")));
    if(check->stats.current.whence.tv_sec) {
        struct timeval f = check->stats.current.whence;
        struct timeval n;
        char timestr[20];
        gettimeofday(&n, NULL);
        snprintf(timestr, sizeof(timestr), "%0.3f",
                 n.tv_sec + (n.tv_usec / 1000000.0));
        xmlSetProp(tmp, (xmlChar *)"now", (xmlChar *)timestr);
        snprintf(timestr, sizeof(timestr), "%0.3f",
                 f.tv_sec + (f.tv_usec / 1000000.0));
        xmlNodeAddContent(tmp, (xmlChar *)timestr);
    }
    if(c->available) { /* truth here means the check has been run */
        char buff[20], *compiler_warning;
        snprintf(buff, sizeof(buff), "%0.3f", (float)c->duration/1000.0);
        compiler_warning = buff;
        NODE_CONTENT(state, "runtime", compiler_warning);
    }
    NODE_CONTENT(state, "availability",
                 noit_check_available_string(c->available));
    NODE_CONTENT(state, "state", noit_check_state_string(c->state));
    NODE_CONTENT(state, "status", c->status ? c->status : "");
    memset(&iter, 0, sizeof(iter));
    xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics")));
    while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) {
        char buff[256];
        metric_t *m = (metric_t *)data;
        xmlAddChild(metrics, (tmp = xmlNewNode(NULL, (xmlChar *)"metric")));
        xmlSetProp(tmp, (xmlChar *)"name", (xmlChar *)m->metric_name);
        buff[0] = m->metric_type;
        buff[1] = '\0';
        xmlSetProp(tmp, (xmlChar *)"type", (xmlChar *)buff);
        if(m->metric_value.s) {
            int rv;
            rv = noit_stats_snprint_metric_value(buff, sizeof(buff), m);
            if(rv < 0)
                xmlSetProp(tmp, (xmlChar *)"error", (xmlChar *)"unknown type");
            else
                xmlNodeAddContent(tmp, (xmlChar *)buff);
        }
    }
    return state;
}
Пример #2
0
xmlNodePtr
noit_check_state_as_xml(noit_check_t *check, int full) {
  xmlNodePtr state, tmp, metrics;
  struct timeval now, *whence;
  stats_t *c = noit_check_get_stats_current(check);

  gettimeofday(&now, NULL);
  state = xmlNewNode(NULL, (xmlChar *)"state");
  NODE_CONTENT(state, "running", NOIT_CHECK_RUNNING(check)?"true":"false");
  NODE_CONTENT(state, "killed", NOIT_CHECK_KILLED(check)?"true":"false");
  NODE_CONTENT(state, "configured",
               NOIT_CHECK_CONFIGURED(check)?"true":"false");
  NODE_CONTENT(state, "disabled", NOIT_CHECK_DISABLED(check)?"true":"false");
  NODE_CONTENT(state, "target_ip", check->target_ip);
  xmlAddChild(state, (tmp = xmlNewNode(NULL, (xmlChar *)"last_run")));
  whence = noit_check_stats_whence(c, NULL);
  if(whence->tv_sec) {
    char timestr[20];
    snprintf(timestr, sizeof(timestr), "%0.3f",
             now.tv_sec + (now.tv_usec / 1000000.0));
    xmlSetProp(tmp, (xmlChar *)"now", (xmlChar *)timestr);
    snprintf(timestr, sizeof(timestr), "%0.3f",
             whence->tv_sec + (whence->tv_usec / 1000000.0));
    xmlNodeAddContent(tmp, (xmlChar *)timestr);
  }
  if(full) {
    stats_t *previous;
    struct timeval *whence;
    uint8_t available = noit_check_stats_available(c, NULL);
    if(available) { /* truth here means the check has been run */
      char buff[20], *compiler_warning;
      snprintf(buff, sizeof(buff), "%0.3f",
               (float)noit_check_stats_duration(c, NULL)/1000.0);
      compiler_warning = buff;
      NODE_CONTENT(state, "runtime", compiler_warning);
    }
    NODE_CONTENT(state, "availability",
                 noit_check_available_string(available));
    NODE_CONTENT(state, "state", noit_check_state_string(noit_check_stats_state(c, NULL)));
    NODE_CONTENT(state, "status", noit_check_stats_status(c, NULL));
    xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics")));

    add_metrics_to_node(noit_check_get_stats_inprogress(check), metrics, "inprogress", 0);
    whence = noit_check_stats_whence(c, NULL);
    if(whence->tv_sec) {
      xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics")));
      add_metrics_to_node(c, metrics, "current", 1);
    }
    previous = noit_check_get_stats_previous(check);
    whence = noit_check_stats_whence(previous, NULL);
    if(whence->tv_sec) {
      xmlAddChild(state, (metrics = xmlNewNode(NULL, (xmlChar *)"metrics")));
      add_metrics_to_node(previous, metrics, "previous", 1);
    }
  }
  return state;
}
Пример #3
0
int
noit_check_schedule_next(noit_module_t *self,
                         struct timeval *last_check, noit_check_t *check,
                         struct timeval *now, dispatch_func_t dispatch,
                         noit_check_t *cause) {
  eventer_t newe;
  struct timeval period, earliest;
  recur_closure_t *rcl;

  assert(cause == NULL);
  assert(check->fire_event == NULL);
  if(check->period == 0) return 0;
  if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) {
    if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check);
    return 0;
  }

  /* If we have an event, we know when we intended it to fire.  This means
   * we should schedule that point + period.
   */
  if(now)
    memcpy(&earliest, now, sizeof(earliest));
  else
    gettimeofday(&earliest, NULL);

  /* If the check is unconfigured and needs resolving, we'll set the
   * period down a bit lower so we can pick up the resolution quickly.
   */
  if(!NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) &&
      check->period > 1000) {
    period.tv_sec = 1;
    period.tv_usec = 0;
  }
  else {
    period.tv_sec = check->period / 1000;
    period.tv_usec = (check->period % 1000) * 1000;
  }

  newe = eventer_alloc();
  memcpy(&newe->whence, last_check, sizeof(*last_check));
  add_timeval(newe->whence, period, &newe->whence);
  if(compare_timeval(newe->whence, earliest) < 0)
    memcpy(&newe->whence, &earliest, sizeof(earliest));
  newe->mask = EVENTER_TIMER;
  newe->callback = noit_check_recur_handler;
  rcl = calloc(1, sizeof(*rcl));
  rcl->self = self;
  rcl->check = check;
  rcl->cause = cause;
  rcl->dispatch = dispatch;
  newe->closure = rcl;

  eventer_add(newe);
  check->fire_event = newe;
  return 0;
}
Пример #4
0
static int
statsd_submit(noit_module_t *self, noit_check_t *check,
              noit_check_t *cause) {
  statsd_closure_t *ccl;
  struct timeval duration;
  statsd_mod_config_t *conf;

  conf = noit_module_get_userdata(self);
  if(!conf->primary_active) conf->check = NULL;
  if(0 == memcmp(conf->primary, check->checkid, sizeof(uuid_t))) {
    conf->check = check;
    if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) {
      conf->check = NULL;
      return 0;
    }
  }

  /* We are passive, so we don't do anything for transient checks */
  if(check->flags & NP_TRANSIENT) return 0;

  if(!check->closure) {
    ccl = check->closure = calloc(1, sizeof(*ccl));
    ccl->self = self;
    memset(&check->stats.inprogress, 0, sizeof(check->stats.inprogress));
  } else {
    // Don't count the first run
    char human_buffer[256];
    ccl = (statsd_closure_t*)check->closure;
    gettimeofday(&check->stats.inprogress.whence, NULL);
    sub_timeval(check->stats.inprogress.whence, check->last_fire_time, &duration);
    check->stats.inprogress.duration = duration.tv_sec * 1000 + duration.tv_usec / 1000;

    snprintf(human_buffer, sizeof(human_buffer),
             "dur=%d,run=%d,stats=%d", check->stats.inprogress.duration,
             check->generation, ccl->stats_count);
    noitL(nldeb, "statsd(%s) [%s]\n", check->target, human_buffer);

    // Not sure what to do here
    check->stats.inprogress.available = (ccl->stats_count > 0) ?
        NP_AVAILABLE : NP_UNAVAILABLE;
    check->stats.inprogress.state = (ccl->stats_count > 0) ?
        NP_GOOD : NP_BAD;
    check->stats.inprogress.status = human_buffer;
    if(check->last_fire_time.tv_sec)
      noit_check_passive_set_stats(check, &check->stats.inprogress);

    memcpy(&check->last_fire_time, &check->stats.inprogress.whence, sizeof(duration));
  }
  ccl->stats_count = 0;
  noit_check_stats_clear(check, &check->stats.inprogress);
  return 0;
}
Пример #5
0
static int external_timeout(eventer_t e, int mask,
                            void *closure, struct timeval *now) {
  external_closure_t *ecl = (external_closure_t *)closure;
  struct check_info *data;
  if(!NOIT_CHECK_KILLED(ecl->check) && !NOIT_CHECK_DISABLED(ecl->check)) {
    data = (struct check_info *)ecl->check->closure;
    data->timedout = 1;
    data->exit_code = 3;
    external_log_results(ecl->self, ecl->check);
    data->timeout_event = NULL;
  }
  ecl->check->flags &= ~NP_RUNNING;
  free(ecl);
  return 0;
}
Пример #6
0
static int ping_icmp_timeout(eventer_t e, int mask,
                             void *closure, struct timeval *now) {
  struct ping_closure *pcl = (struct ping_closure *)closure;
  struct ping_session_key k;
  struct check_info *data;
  ping_icmp_data_t *ping_data;

  if(!NOIT_CHECK_KILLED(pcl->check) && !NOIT_CHECK_DISABLED(pcl->check)) {
    ping_icmp_log_results(pcl->self, pcl->check);
  }
  data = (struct check_info *)pcl->check->closure;
  data->timeout_event = NULL;
  pcl->check->flags &= ~NP_RUNNING;
  ping_data = noit_module_get_userdata(pcl->self);
  k.addr_of_check = (vpsized_uint)pcl->check ^ random_num;
  uuid_copy(k.checkid, pcl->check->checkid);
  mtev_hash_delete(ping_data->in_flight, (const char *)&k, sizeof(k),
                   free, NULL);
  free(pcl);
  return 0;
}
Пример #7
0
static int
noit_console_show_check(noit_console_closure_t ncct,
                        int argc, char **argv,
                        noit_console_state_t *state, void *closure) {
  int i, cnt;
  noit_conf_t_userdata_t *info;
  char xpath[1024];
  xmlXPathObjectPtr pobj = NULL;
  xmlXPathContextPtr xpath_ctxt = NULL;

  noit_conf_xml_xpath(NULL, &xpath_ctxt);
  if(argc > 1) {
    nc_printf(ncct, "requires zero or one arguments\n");
    return -1;
  }

  info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
  /* We many not be in conf-t mode -- that's fine */
  if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info,
                                argc ? argv[0] : NULL)) {
    nc_printf(ncct, "could not find check '%s'\n", argv[0]);
    return -1;
  }

  pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
  if(!pobj || pobj->type != XPATH_NODESET ||
     xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
    nc_printf(ncct, "no checks found\n");
    goto out;
  }
  cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
  if(info && cnt != 1) {
    nc_printf(ncct, "Ambiguous check specified\n");
    goto out;
  }
  for(i=0; i<cnt; i++) {
    noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
    const char *k;
    int klen;
    void *data;
    uuid_t checkid;
    noit_check_t *check;
    noit_hash_table *config;
    xmlNodePtr node, anode, mnode = NULL;
    char *uuid_conf;
    char *module, *value;

    node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
    uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
    if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
      nc_printf(ncct, "%s has invalid or missing UUID!\n",
                (char *)xmlGetNodePath(node) + strlen("/noit"));
      continue;
    }
    nc_printf(ncct, "==== %s ====\n", uuid_conf);

#define MYATTR(a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b))
#define INHERIT(a,n,b) \
  _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
#define SHOW_ATTR(a) do { \
  anode = NULL; \
  value = NULL; \
  INHERIT(a, anode, value); \
  nc_attr_show(ncct, #a, node, anode, value); \
} while(0)

    if(!INHERIT(module, mnode, module)) module = NULL;
    if(MYATTR(name, anode, value))
      nc_printf(ncct, " name: %s\n", value);
    else
      nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]");
    nc_attr_show(ncct, "module", node, mnode, module);
    SHOW_ATTR(target);
    SHOW_ATTR(period);
    SHOW_ATTR(timeout);
    SHOW_ATTR(oncheck);
    SHOW_ATTR(filterset);
    SHOW_ATTR(disable);
    /* Print out all the config settings */
    config = noit_conf_get_hash(node, "config");
    while(noit_hash_next(config, &iter, &k, &klen, &data)) {
      nc_printf(ncct, " config::%s: %s\n", k, (const char *)data);
    }
    noit_hash_destroy(config, free, free);
    free(config);

    check = noit_poller_lookup(checkid);
    if(!check) {
      nc_printf(ncct, " ERROR: not in running system\n");
    }
    else {
      int idx = 0;
      nc_printf(ncct, " currently: ");
      if(NOIT_CHECK_RUNNING(check)) nc_printf(ncct, "%srunning", idx++?",":"");
      if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":"");
      if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":"");
      if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":"");
      if(!idx) nc_printf(ncct, "idle");
      nc_write(ncct, "\n", 1);
      if(check->stats.current.whence.tv_sec == 0) {
        nc_printf(ncct, " last run: never\n");
      }
      else {
        stats_t *c = &check->stats.current;
        struct timeval now, diff;
        gettimeofday(&now, NULL);
        sub_timeval(now, c->whence, &diff);
        nc_printf(ncct, " last run: %0.3f seconds ago\n",
                  diff.tv_sec + (diff.tv_usec / 1000000.0));
        nc_printf(ncct, " availability/state: %s/%s\n",
                  noit_check_available_string(c->available),
                  noit_check_state_string(c->state));
        nc_printf(ncct, " status: %s\n", c->status ? c->status : "[[null]]");
        nc_printf(ncct, " metrics:\n");
        memset(&iter, 0, sizeof(iter));
        while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) {
          char buff[256];
          noit_boolean filtered;
          noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data);
          filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data);
          nc_printf(ncct, "  %c%s\n", filtered ? '*' : ' ', buff);
        }
      }
    }
  }
 out:
  if(pobj) xmlXPathFreeObject(pobj);
  return 0;
}
Пример #8
0
static int
noit_console_show_check(mtev_console_closure_t ncct,
                        int argc, char **argv,
                        mtev_console_state_t *state, void *closure) {
  int i, cnt;
  mtev_conf_t_userdata_t *info;
  char xpath[1024];
  xmlXPathObjectPtr pobj = NULL;
  xmlXPathContextPtr xpath_ctxt = NULL;

  mtev_conf_xml_xpath(NULL, &xpath_ctxt);
  if(argc > 1) {
    nc_printf(ncct, "requires zero or one arguments\n");
    return -1;
  }

  info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
  /* We many not be in conf-t mode -- that's fine */
  if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info,
                                argc ? argv[0] : NULL)) {
    nc_printf(ncct, "could not find check '%s'\n", argv[0]);
    return -1;
  }

  pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
  if(!pobj || pobj->type != XPATH_NODESET ||
     xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
    nc_printf(ncct, "no checks found\n");
    goto out;
  }
  cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
  if(info && cnt != 1) {
    nc_printf(ncct, "Ambiguous check specified\n");
    goto out;
  }
  for(i=0; i<cnt; i++) {
    mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
    const char *k;
    int klen;
    void *data;
    uuid_t checkid;
    noit_check_t *check;
    mtev_hash_table *config;
    xmlNodePtr node, anode, mnode = NULL;
    char *uuid_conf;
    char *module, *value;

    node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
    uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
    if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
      nc_printf(ncct, "%s has invalid or missing UUID!\n",
                (char *)xmlGetNodePath(node) + strlen("/noit"));
      continue;
    }
    nc_printf(ncct, "==== %s ====\n", uuid_conf);
    xmlFree(uuid_conf);

#define MYATTR(a,n,b) _mtev_conf_get_string(node, &(n), "@" #a, &(b))
#define INHERIT(a,n,b) \
  _mtev_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
#define SHOW_ATTR(a) do { \
  anode = NULL; \
  value = NULL; \
  INHERIT(a, anode, value); \
  nc_attr_show(ncct, #a, node, anode, value); \
  if(value != NULL) free(value); \
} while(0)

    if(!INHERIT(module, mnode, module)) module = NULL;
    if(MYATTR(name, anode, value)) {
      nc_printf(ncct, " name: %s\n", value);
      free(value);
    }
    else
      nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]");
    nc_attr_show(ncct, "module", node, mnode, module);
    if(module) free(module);
    SHOW_ATTR(target);
    SHOW_ATTR(seq);
    SHOW_ATTR(resolve_rtype);
    SHOW_ATTR(period);
    SHOW_ATTR(timeout);
    SHOW_ATTR(oncheck);
    SHOW_ATTR(filterset);
    SHOW_ATTR(disable);
    /* Print out all the config settings */
    config = mtev_conf_get_hash(node, "config");
    while(mtev_hash_next(config, &iter, &k, &klen, &data)) {
      nc_printf(ncct, " config::%s: %s\n", k, (const char *)data);
    }
    mtev_hash_destroy(config, free, free);
    free(config);

    check = noit_poller_lookup(checkid);
    if(!check) {
      nc_printf(ncct, " ERROR: not in running system\n");
    }
    else {
      int idx = 0;
      stats_t *c;
      struct timeval *whence;
      mtev_hash_table *metrics;
      nc_printf(ncct, " target_ip: %s\n", check->target_ip);
      nc_printf(ncct, " currently: %08x ", check->flags);
      if(NOIT_CHECK_RUNNING(check)) { nc_printf(ncct, "running"); idx++; }
      if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":"");
      if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":"");
      if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":"");
      if(!idx) nc_printf(ncct, "idle");
      nc_write(ncct, "\n", 1);
      if (check->fire_event != NULL) {
        struct timeval now, diff;
        mtev_gettimeofday(&now, NULL);
        sub_timeval(check->fire_event->whence, now, &diff);
        nc_printf(ncct, " next run: %0.3f seconds\n",
                diff.tv_sec + (diff.tv_usec / 1000000.0));
      }
      else {
        nc_printf(ncct, " next run: unscheduled\n");
      }

      c = noit_check_get_stats_current(check);
      whence = noit_check_stats_whence(c, NULL);
      if(whence->tv_sec == 0) {
        nc_printf(ncct, " last run: never\n");
      }
      else {
        const char *status;
        struct timeval now, *then, diff;
        mtev_gettimeofday(&now, NULL);
        then = noit_check_stats_whence(c, NULL);
        sub_timeval(now, *then, &diff);
        nc_printf(ncct, " last run: %0.3f seconds ago\n",
                  diff.tv_sec + (diff.tv_usec / 1000000.0));
        nc_printf(ncct, " availability/state: %s/%s\n",
                  noit_check_available_string(noit_check_stats_available(c, NULL)),
                  noit_check_state_string(noit_check_stats_state(c, NULL)));
        status = noit_check_stats_status(c, NULL);
        nc_printf(ncct, " status: %s\n", status);
        nc_printf(ncct, " feeds: %d\n", check->feeds ? check->feeds->size : 0);
      }

      c = noit_check_get_stats_inprogress(check);
      metrics = noit_check_stats_metrics(c);
      if(mtev_hash_size(metrics) > 0) {
        nc_printf(ncct, " metrics (inprogress):\n");
        nc_print_stat_metrics(ncct, check, c);
      }
      c = noit_check_get_stats_current(check);
      metrics = noit_check_stats_metrics(c);
      if(mtev_hash_size(metrics)) {
        nc_printf(ncct, " metrics (current):\n");
        nc_print_stat_metrics(ncct, check, c);
      }
      c = noit_check_get_stats_previous(check);
      metrics = noit_check_stats_metrics(c);
      if(mtev_hash_size(metrics) > 0) {
        nc_printf(ncct, " metrics (previous):\n");
        nc_print_stat_metrics(ncct, check, c);
      }
    }
  }
 out:
  if(pobj) xmlXPathFreeObject(pobj);
  return 0;
}
Пример #9
0
int
noit_check_schedule_next(noit_module_t *self,
                         struct timeval *last_check, noit_check_t *check,
                         struct timeval *now, dispatch_func_t dispatch,
                         noit_check_t *cause) {
  eventer_t newe;
  struct timeval period, earliest, diff;
  int64_t diffms, periodms, offsetms;
  recur_closure_t *rcl;
  int initial = last_check ? 1 : 0;

  assert(cause == NULL);
  assert(check->fire_event == NULL);
  if(check->period == 0) return 0;

  /* if last_check is not passed, we use the initial_schedule_time
   * otherwise, we set the initial_schedule_time
   */
  if(!last_check) last_check = &check->initial_schedule_time;
  else memcpy(&check->initial_schedule_time, last_check, sizeof(*last_check));

  if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) {
    if(!(check->flags & NP_TRANSIENT)) check_slots_dec_tv(last_check);
    memset(&check->initial_schedule_time, 0, sizeof(struct timeval));
    return 0;
  }

  /* If we have an event, we know when we intended it to fire.  This means
   * we should schedule that point + period.
   */
  if(now)
    memcpy(&earliest, now, sizeof(earliest));
  else
    gettimeofday(&earliest, NULL);

  /* If the check is unconfigured and needs resolving, we'll set the
   * period down a bit lower so we can pick up the resolution quickly.
   * The one exception is if this is the initial run.
   */
  if(!initial &&
     !NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) &&
     check->period > 1000) {
    period.tv_sec = 1;
    period.tv_usec = 0;
  }
  else {
    period.tv_sec = check->period / 1000;
    period.tv_usec = (check->period % 1000) * 1000;
  }
  periodms = period.tv_sec * 1000 + period.tv_usec / 1000;

  newe = eventer_alloc();
  /* calculate the differnet between the initial schedule time and "now" */
  if(compare_timeval(earliest, *last_check) >= 0) {
    sub_timeval(earliest, *last_check, &diff);
    diffms = (int64_t)diff.tv_sec * 1000 + diff.tv_usec / 1000;
  }
  else {
    noitL(noit_error, "time is going backwards. abort.\n");
    abort();
  }
  /* determine the offset from initial schedule time that would place
   * us at the next period-aligned point past "now" */
  offsetms = ((diffms / periodms) + 1) * periodms;
  diff.tv_sec = offsetms / 1000;
  diff.tv_usec = (offsetms % 1000) * 1000;

  memcpy(&newe->whence, last_check, sizeof(*last_check));
  add_timeval(newe->whence, diff, &newe->whence);

  sub_timeval(newe->whence, earliest, &diff);
  diffms = (int64_t)diff.tv_sec * 1000 + (int)diff.tv_usec / 1000;
  assert(compare_timeval(newe->whence, earliest) > 0);
  newe->mask = EVENTER_TIMER;
  newe->callback = noit_check_recur_handler;
  rcl = calloc(1, sizeof(*rcl));
  rcl->self = self;
  rcl->check = check;
  rcl->cause = cause;
  rcl->dispatch = dispatch;
  newe->closure = rcl;

  eventer_add(newe);
  check->fire_event = newe;
  return diffms;
}