Beispiel #1
0
static int noit_httptrap_init(noit_module_t *self) {
  const char *config_val;
  httptrap_mod_config_t *conf;
  conf = noit_module_get_userdata(self);

  conf->asynch_metrics = mtev_true;
  if(mtev_hash_retr_str(conf->options,
                        "asynch_metrics", strlen("asynch_metrics"),
                        (const char **)&config_val)) {
    if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
      conf->asynch_metrics = mtev_false;
  }

  httptrap_surrogate = mtev_false;
  if(mtev_hash_retr_str(conf->options,
                        "surrogate", strlen("surrogate"),
                        (const char **)&config_val)) {
    if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on"))
      httptrap_surrogate = mtev_true;
  }

  noit_module_set_userdata(self, conf);

  /* register rest handler */
  mtev_http_rest_register("PUT", "/module/httptrap/",
                          "^(" UUID_REGEX ")/([^/]*).*$",
                          rest_httptrap_handler);
  mtev_http_rest_register("POST", "/module/httptrap/",
                          "^(" UUID_REGEX ")/([^/]*).*$",
                          rest_httptrap_handler);
  return 0;
}
static int noit_rabbimq_driver_config(mtev_dso_generic_t *self, mtev_hash_table *o) {
  const char *intstr;
  if(mtev_hash_retr_str(o, "sndbuf", strlen("sndbuf"), &intstr))
    desired_sndbuf = atoi(intstr);
  if(mtev_hash_retr_str(o, "rcvbuf", strlen("rcvbuf"), &intstr))
    desired_rcvbuf = atoi(intstr);
  return 0;
}
Beispiel #3
0
static int
mtev_lua_web_driver_config(mtev_dso_generic_t *self, mtev_hash_table *o) {
  lua_web_conf_t *conf = get_config(self);
  conf->script_dir = NULL;
  conf->cpath = NULL;
  conf->dispatch = NULL;
  (void)mtev_hash_retr_str(o, "directory", strlen("directory"), &conf->script_dir);
  if(conf->script_dir) conf->script_dir = strdup(conf->script_dir);
  (void)mtev_hash_retr_str(o, "cpath", strlen("cpath"), &conf->cpath);
  if(conf->cpath) conf->cpath = strdup(conf->cpath);
  (void)mtev_hash_retr_str(o, "dispatch", strlen("dispatch"), &conf->dispatch);
  if(conf->dispatch) conf->dispatch = strdup(conf->dispatch);
  conf->max_post_size = DEFAULT_MAX_POST_SIZE;
  return 0;
}
Beispiel #4
0
mtev_reverse_acl_decision_t
reverse_check_allow(const char *id, acceptor_closure_t *ac) {
  mtev_hash_table *config;
  noit_check_t *check;
  const char *key;
  uuid_t uuid;
  char uuid_str[UUID_STR_LEN+1];
  char expected_id[256];

  if(strncmp(id, "check/", 6)) return MTEV_ACL_ABSTAIN;

  strlcpy(uuid_str, id + 6, sizeof(uuid_str));
  if(uuid_parse(uuid_str, uuid) != 0) return MTEV_ACL_DENY;
  uuid_unparse_lower(uuid, uuid_str);

  check = noit_poller_lookup(uuid);
  if(!check) return MTEV_ACL_DENY;

  config = noit_check_get_module_config(check, reverse_check_module_id);
  if(config && mtev_hash_retr_str(config, "secret_key", strlen("secret_key"), &key)) {
    snprintf(expected_id, sizeof(expected_id), "check/%s#%s", uuid_str, key);
  }
  else {
    snprintf(expected_id, sizeof(expected_id), "check/%s", uuid_str);
  }
  if(!strncmp(id, expected_id, strlen(id))) return MTEV_ACL_ALLOW;
  return MTEV_ACL_DENY;
}
Beispiel #5
0
static int
histogram_config(mtev_dso_generic_t *self, mtev_hash_table *o) {
  struct histogram_config *conf = mtev_image_get_userdata(&self->hdr);
  const char *duty;
  char *duty_copy, *cp, *brk;
  int i;

  if(!mtev_hash_retr_str(o, "duty", strlen("duty"), &duty)) {
    duty = "histogram";
  }
  if(!conf) conf = calloc(1, sizeof(*conf));
  mtev_image_set_userdata(&self->hdr, conf);

  duty_copy = strdup(duty);
  for(i = 0, cp = strtok_r(duty_copy, ",", &brk);
      cp; cp = strtok_r(NULL, ",", &brk), i++);
  free(duty_copy);
  conf->quantiles = calloc(1, sizeof(double)*i);
  duty_copy = strdup(duty);
  for(cp = strtok_r(duty_copy, ",", &brk);
      cp; cp = strtok_r(NULL, ",", &brk)) {
    if(!strcmp(cp,"histogram")) conf->histogram = mtev_true;
    else if(!strcmp(cp,"mean")) conf->mean = mtev_true;
    else if(!strcmp(cp,"sum")) conf->sum = mtev_true;
    else {
      char *endptr;
      double q;
      q = strtod(cp, &endptr);
      if(*endptr == '\0') conf->quantiles[conf->n_quantiles++] = q;
    }
  }
  qsort(conf->quantiles, conf->n_quantiles, sizeof(double), double_sort);
  free(duty_copy);
  return 0;
}
Beispiel #6
0
static void ping_icmp_log_results(noit_module_t *self, noit_check_t *check) {
  struct check_info *data;
  double avail = 0.0, min = MAXFLOAT, max = 0.0, avg = 0.0, cnt;
  int avail_needed = 100;
  const char *config_val = NULL;
  int i, points = 0;
  char human_buffer[256];
  struct timeval now, duration;

  data = (struct check_info *)check->closure;
  for(i=0; i<data->expected_count; i++) {
    if(data->turnaround[i] >= 0.0) {
      points++;
      avg += data->turnaround[i];
      if(data->turnaround[i] > max) max = data->turnaround[i];
      if(data->turnaround[i] < min) min = data->turnaround[i];
    }
  }
  cnt = data->expected_count;
  if(points == 0) {
    min = 0.0 / 0.0;
    max = 0.0 / 0.0;
    avg = 0.0 / 0.0;
  }
  else {
    avail = (float)points /cnt;
    avg /= (float)points;
  }

  if(mtev_hash_retr_str(check->config, "avail_needed", strlen("avail_needed"),
                        &config_val))
    avail_needed = atoi(config_val);

  snprintf(human_buffer, sizeof(human_buffer),
           "cnt=%d,avail=%0.0f,min=%0.4f,max=%0.4f,avg=%0.4f",
           (int)cnt, 100.0*avail, min, max, avg);
  mtevL(nldeb, "ping_icmp(%s) [%s]\n", check->target_ip, human_buffer);

  mtev_gettimeofday(&now, NULL);
  sub_timeval(now, check->last_fire_time, &duration);
  noit_stats_set_whence(check, &now);
  noit_stats_set_duration(check, duration.tv_sec * 1000 + duration.tv_usec / 1000);
  noit_stats_set_available(check, (avail > 0.0) ? NP_AVAILABLE : NP_UNAVAILABLE);
  noit_stats_set_state(check, (avail < ((float)avail_needed / 100.0)) ? NP_BAD : NP_GOOD);
  noit_stats_set_status(check, human_buffer);
  noit_stats_set_metric(check, "count",
                        METRIC_INT32, &data->expected_count);
  avail *= 100.0;
  noit_stats_set_metric(check, "available", METRIC_DOUBLE, &avail);
  noit_stats_set_metric(check, "minimum",
                        METRIC_DOUBLE, avail > 0.0 ? &min : NULL);
  noit_stats_set_metric(check, "maximum",
                        METRIC_DOUBLE, avail > 0.0 ? &max : NULL);
  noit_stats_set_metric(check, "average",
                        METRIC_DOUBLE, avail > 0.0 ? &avg : NULL);
  noit_check_set_stats(check);
}
Beispiel #7
0
static int
check_test_config(mtev_dso_generic_t *self, mtev_hash_table *o) {
  const char *str;
  int new_interval = 0;
  if(mtev_hash_retr_str(o, "sweep_interval", strlen("sweep_interval"),
                        &str))
    new_interval = atoi(str);
  if(new_interval > 0) default_sweep_interval = new_interval;
  return 0;
}
Beispiel #8
0
static mtev_hook_return_t
histogram_hook_special_impl(void *closure, noit_check_t *check, stats_t *stats,
                            const char *metric_name, metric_type_t type, const char *v,
                            mtev_boolean success) {
  void *vht;
  histotier *ht;
  mtev_hash_table *config, *metrics;
  const char *track = "";
  mtev_dso_generic_t *self = closure;
  struct histogram_config *conf = mtev_image_get_userdata(&self->hdr);

  if(success) return MTEV_HOOK_CONTINUE;

  config = noit_check_get_module_config(check, histogram_module_id);
  if(!config || mtev_hash_size(config) == 0) return MTEV_HOOK_CONTINUE;
  mtev_hash_retr_str(config, metric_name, strlen(metric_name), &track);
  if(!track || strcmp(track, "add"))
    return MTEV_HOOK_CONTINUE;

  metrics = noit_check_get_module_metadata(check, histogram_module_id);
  if(!metrics) {
    metrics = calloc(1, sizeof(*metrics));
    noit_check_set_module_metadata(check, histogram_module_id,
                                   metrics, free_hash_o_histotier);
  }
  if(!mtev_hash_retrieve(metrics, metric_name, strlen(metric_name),
                         &vht)) {
    ht = calloc(1, sizeof(*ht));
    vht = ht;
    mtev_hash_store(metrics, strdup(metric_name), strlen(metric_name),
                    vht);
  }
  else ht = vht;
  if(v != NULL) {
    /* We expect: H[<float>]=%d */
    const char *lhs;
    char *endptr;
    double bucket;
    u_int64_t cnt;
    if(v[0] != 'H' || v[1] != '[') return MTEV_HOOK_CONTINUE;
    if(NULL == (lhs = strchr(v+2, ']'))) return MTEV_HOOK_CONTINUE;
    lhs++;
    if(*lhs++ != '=') return MTEV_HOOK_CONTINUE;
    bucket = strtod(v+2, &endptr);
    if(endptr == v+2) return MTEV_HOOK_CONTINUE;
    cnt = strtoull(lhs, &endptr, 10);
    if(endptr == lhs) return MTEV_HOOK_CONTINUE;
    update_histotier(ht, time(NULL), conf, check, metric_name, bucket, cnt);
  }
  return MTEV_HOOK_CONTINUE;
}
Beispiel #9
0
static mtev_hook_return_t
histogram_hook_impl(void *closure, noit_check_t *check, stats_t *stats,
                    metric_t *m) {
  void *vht;
  histotier *ht;
  mtev_hash_table *config, *metrics;
  const char *track = "";
  mtev_dso_generic_t *self = closure;
  struct histogram_config *conf = mtev_image_get_userdata(&self->hdr);

  config = noit_check_get_module_config(check, histogram_module_id);
  if(!config || mtev_hash_size(config) == 0) return MTEV_HOOK_CONTINUE;
  mtev_hash_retr_str(config, m->metric_name, strlen(m->metric_name), &track);
  if(!track || strcmp(track, "add"))
    return MTEV_HOOK_CONTINUE;

  metrics = noit_check_get_module_metadata(check, histogram_module_id);
  if(!metrics) {
    metrics = calloc(1, sizeof(*metrics));
    noit_check_set_module_metadata(check, histogram_module_id,
                                   metrics, free_hash_o_histotier);
  }
  if(!mtev_hash_retrieve(metrics, m->metric_name, strlen(m->metric_name),
                         &vht)) {
    ht = calloc(1, sizeof(*ht));
    vht = ht;
    mtev_hash_store(metrics, strdup(m->metric_name), strlen(m->metric_name),
                    vht);
  }
  else ht = vht;
  if(m->metric_value.vp != NULL) {
#define UPDATE_HISTOTIER(a) update_histotier(ht, time(NULL), conf, check, m->metric_name, *m->metric_value.a, 1)
    switch(m->metric_type) {
      case METRIC_UINT64:
        UPDATE_HISTOTIER(L); break;
      case METRIC_INT64:
        UPDATE_HISTOTIER(l); break;
      case METRIC_UINT32:
        UPDATE_HISTOTIER(I); break;
      case METRIC_INT32:
        UPDATE_HISTOTIER(i); break;
      case METRIC_DOUBLE:
        UPDATE_HISTOTIER(n); break;
      default: /*noop*/
        break;
    }
  }
  return MTEV_HOOK_CONTINUE;
}
Beispiel #10
0
static mtev_hook_return_t
_histogram_logger_impl(void *closure, noit_check_t *check, mtev_boolean passive) {
  const char *track = "";
  mtev_hash_table *config;

  config = noit_check_get_module_config(check, histogram_module_id);
  if(!config || mtev_hash_size(config) == 0) return MTEV_HOOK_CONTINUE;

  mtev_hash_retr_str(config, "metrics", strlen("metrics"), &track);
  if(!track || strcmp(track, "replace"))
    return MTEV_HOOK_CONTINUE;
  /* If we're replacing other metrics, then we prevent logging */
  if(strcmp(track, "replace") == 0) return MTEV_HOOK_DONE;
  return MTEV_HOOK_CONTINUE;
}
Beispiel #11
0
static int test_abort_initiate(noit_module_t *self, noit_check_t *check,
                               noit_check_t *cause) {
  test_abort_check_info_t *ci = check->closure;
  struct timeval __now;
  const char *v;

  mtevL(nlerr, "test_abort_initiate\n");
  /* We cannot be running */
  BAIL_ON_RUNNING_CHECK(check);
  check->flags |= NP_RUNNING;

  ci->self = self;
  ci->check = check;
  ci->timeout = 30;
  if(mtev_hash_retr_str(check->config, "sleep", strlen("sleep"), &v)) {
    ci->timeout = atof(v);
  }
  ci->ignore_signals = 0;
  if(mtev_hash_retr_str(check->config, "ignore_signals", strlen("ignore_signals"), &v)) {
    if(!strcmp(v, "true")) ci->ignore_signals = 1;
  }
  ci->timed_out = 1;

  ci->method = 0;
  if(mtev_hash_retr_str(check->config, "method", strlen("method"), &v)) {
    if(!strcmp(v, "evil")) ci->method = EVENTER_EVIL_BRUTAL;
    else if(!strcmp(v, "deferred")) ci->method = EVENTER_CANCEL_DEFERRED;
    else if(!strcmp(v, "asynch")) ci->method = EVENTER_CANCEL_ASYNCH;
  }
  gettimeofday(&__now, NULL);
  memcpy(&check->last_fire_time, &__now, sizeof(__now));

  /* Register a handler for the worker */
  noit_check_run_full_asynch_opts(check, test_abort_drive_session, ci->method);
  return 0;
}
Beispiel #12
0
static int
mtev_lua_http_request_querystring(lua_State *L) {
  mtev_hash_table *h;
  CCALL_DECL(L, mtev_http_request, req, 0);
  h = mtev_http_request_querystring_table(req);
  if(lua_gettop(L) == 1)
    mtev_lua_hash_to_table(L, h);
  else if(lua_gettop(L) == 2) {
    const char *key = lua_tostring(L,2), *value;
    if(key == NULL) lua_pushnil(L);
    else {
      if(mtev_hash_retr_str(h, key, strlen(key), &value))
        lua_pushstring(L, value);
      else
        lua_pushnil(L);
    }
  }
  else luaL_error(L, "invalid arguments to mtev_http_request:querystring()");
  return 1;
}
Beispiel #13
0
static mtev_boolean
mtev_httptrap_check_aynsch(noit_module_t *self,
                           noit_check_t *check) {
  const char *config_val;
  httptrap_mod_config_t *conf;
  if(!self) return mtev_true;
  conf = noit_module_get_userdata(self);
  if(!conf) return mtev_true;
  mtev_boolean is_asynch = conf->asynch_metrics;
  if(mtev_hash_retr_str(check->config,
                        "asynch_metrics", strlen("asynch_metrics"),
                        (const char **)&config_val)) {
    if(!strcasecmp(config_val, "false") || !strcasecmp(config_val, "off"))
      is_asynch = mtev_false;
    else if(!strcasecmp(config_val, "true") || !strcasecmp(config_val, "on"))
      is_asynch = mtev_true;
  }

  if(is_asynch) check->flags |= NP_SUPPRESS_METRICS;
  else check->flags &= ~NP_SUPPRESS_METRICS;
  return is_asynch;
}
Beispiel #14
0
static int
mtev_lua_general_config(mtev_dso_generic_t *self, mtev_hash_table *o) {
  const char *bstr, *tt_val;
  lua_general_conf_t *conf = get_config(self);
  conf->script_dir = NULL;
  conf->cpath = NULL;
  conf->module = NULL;
  conf->function = NULL;
  (void)mtev_hash_retr_str(o, "directory", strlen("directory"), &conf->script_dir);
  if(conf->script_dir) conf->script_dir = strdup(conf->script_dir);
  (void)mtev_hash_retr_str(o, "cpath", strlen("cpath"), &conf->cpath);
  if(conf->cpath) conf->cpath = strdup(conf->cpath);
  (void)mtev_hash_retr_str(o, "lua_module", strlen("lua_module"), &conf->module);
  if(conf->module) conf->module = strdup(conf->module);
  (void)mtev_hash_retr_str(o, "lua_function", strlen("lua_function"), &conf->function);
  if(conf->function) conf->function = strdup(conf->function);
  if(mtev_hash_retr_str(o, "concurrent", strlen("concurrent"), &bstr)) {
    if(!strcasecmp(bstr, "on") || !strcasecmp(bstr, "true")) {
      conf->concurrent = mtev_true;
    }
  }
  conf->tragedy_terminates = mtev_false;
  if(mtev_hash_retr_str(o, "tragedy_terminates", strlen("tragedy_terminates"),
                        &tt_val)) {
    if(!strcasecmp(tt_val, "true") || !strcasecmp(tt_val, "yes"))
      conf->tragedy_terminates = mtev_true;
  }
  if(mtev_hash_retr_str(o, "Cpreloads", strlen("Cpreloads"), &bstr)) {
    int count = 1, i;
    char *brk = NULL, *cp, *copy;
    cp = copy = strdup(bstr);
    while(*cp) if(*cp++ == ',') count++; /* count terms (start with 1) */
    conf->Cpreloads = calloc(count+1, sizeof(char *)); /* null term */
    for(i = 0, cp = strtok_r(copy, ",", &brk);
      cp; cp = strtok_r(NULL, ",", &brk), i++) {
      conf->Cpreloads[i] = strdup(cp);
    }
    free(copy);
  }
  return 0;
}
Beispiel #15
0
static int
mtev_lua_http_request_headers(lua_State *L) {
  mtev_hash_table *h;
  CCALL_DECL(L, mtev_http_request, req, 0);
  h = mtev_http_request_headers_table(req);
  if(lua_gettop(L) == 1)
    mtev_lua_hash_to_table(L, h);
  else if(lua_gettop(L) == 2) {
    const char *hdr = lua_tostring(L,2);
    if(hdr == NULL) lua_pushnil(L);
    else {
      char *cp, *lower = alloca(strlen(hdr) + 1);
      memcpy(lower, hdr, strlen(hdr)+1);
      for(cp=lower; *cp; cp++) *cp = tolower(*cp);
      if(mtev_hash_retr_str(h, lower, strlen(lower), &hdr))
        lua_pushstring(L, hdr);
      else
        lua_pushnil(L);
    }
  }
  else luaL_error(L, "invalid arguments to mtev_http_request:headers()");
  return 1;
}
Beispiel #16
0
static int noit_statsd_init(noit_module_t *self) {
  unsigned short port = 8125;
  int packets_per_cycle = 100;
  int payload_len = 256*1024;
  struct sockaddr_in skaddr;
  int sockaddr_len;
  const char *config_val;
  statsd_mod_config_t *conf;
  conf = noit_module_get_userdata(self);

  eventer_name_callback("statsd/statsd_handler", statsd_handler);

  if(mtev_hash_retr_str(conf->options, "check", strlen("check"),
                        (const char **)&config_val)) {
    if(uuid_parse((char *)config_val, conf->primary) != 0)
      mtevL(noit_error, "statsd check isn't a UUID\n");
    conf->primary_active = 1;
    conf->check = NULL;
  }
  if(mtev_hash_retr_str(conf->options, "port", strlen("port"),
                        (const char **)&config_val)) {
    port = atoi(config_val);
  }
  conf->port = port;

  if(mtev_hash_retr_str(conf->options, "packets_per_cycle",
                        strlen("packets_per_cycle"),
                        (const char **)&config_val)) {
    packets_per_cycle = atoi(config_val);
  }
  conf->packets_per_cycle = packets_per_cycle;

  conf->payload_len = payload_len;
  conf->payload = malloc(conf->payload_len);
  if(!conf->payload) {
    mtevL(noit_error, "statsd malloc() failed\n");
    return -1;
  }

  conf->ipv4_fd = socket(PF_INET, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP);
  if(conf->ipv4_fd < 0) {
    mtevL(noit_error, "statsd: socket failed: %s\n", strerror(errno));
    return -1;
  }
  else {
    if(eventer_set_fd_nonblocking(conf->ipv4_fd)) {
      close(conf->ipv4_fd);
      conf->ipv4_fd = -1;
      mtevL(noit_error,
            "collectd: could not set socket non-blocking: %s\n",
            strerror(errno));
      return -1;
    }
  }
  memset(&skaddr, 0, sizeof(skaddr));
  skaddr.sin_family = AF_INET;
  skaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  skaddr.sin_port = htons(conf->port);
  sockaddr_len = sizeof(skaddr);
  if(bind(conf->ipv4_fd, (struct sockaddr *)&skaddr, sockaddr_len) < 0) {
    mtevL(noit_error, "bind failed[%d]: %s\n", conf->port, strerror(errno));
    close(conf->ipv4_fd);
    return -1;
  }

  if(conf->ipv4_fd >= 0) {
    eventer_t newe;
    newe = eventer_alloc();
    newe->fd = conf->ipv4_fd;
    newe->mask = EVENTER_READ | EVENTER_EXCEPTION;
    newe->callback = statsd_handler;
    newe->closure = self;
    eventer_add(newe);
  }

  conf->ipv6_fd = socket(AF_INET6, NE_SOCK_CLOEXEC|SOCK_DGRAM, IPPROTO_UDP);
  if(conf->ipv6_fd < 0) {
    mtevL(noit_error, "statsd: IPv6 socket failed: %s\n",
          strerror(errno));
  }
  else {
    if(eventer_set_fd_nonblocking(conf->ipv6_fd)) {
      close(conf->ipv6_fd);
      conf->ipv6_fd = -1;
      mtevL(noit_error,
            "statsd: could not set socket non-blocking: %s\n",
            strerror(errno));
    }
    else {
      struct sockaddr_in6 skaddr6;
      struct in6_addr in6addr_any;
      sockaddr_len = sizeof(skaddr6);
      memset(&skaddr6, 0, sizeof(skaddr6));
      skaddr6.sin6_family = AF_INET6;
      memset(&in6addr_any, 0, sizeof(in6addr_any));
      skaddr6.sin6_addr = in6addr_any;
      skaddr6.sin6_port = htons(conf->port);

      if(bind(conf->ipv6_fd, (struct sockaddr *)&skaddr6, sockaddr_len) < 0) {
        mtevL(noit_error, "bind(IPv6) failed[%d]: %s\n",
              conf->port, strerror(errno));
        close(conf->ipv6_fd);
        conf->ipv6_fd = -1;
      }
    }
  }

  if(conf->ipv6_fd >= 0) {
    eventer_t newe;
    newe = eventer_alloc();
    newe->fd = conf->ipv6_fd;
    newe->mask = EVENTER_READ | EVENTER_EXCEPTION;
    newe->callback = statsd_handler;
    newe->closure = self;
    eventer_add(newe);
  }

  noit_module_set_userdata(self, conf);
  return 0;
}
Beispiel #17
0
int
eventer_ssl_verify_cert(eventer_ssl_ctx_t *ctx, int ok,
                        X509_STORE_CTX *x509ctx, void *closure) {
  mtev_hash_table *options = closure;
  const char *opt_no_ca, *ignore_dates;
  int v_res;

  /* Clear any previous error */
  if(ctx->cert_error) free(ctx->cert_error);
  ctx->cert_error = NULL;

  if(!x509ctx) {
    int err;
    if((err = SSL_get_verify_result(ctx->ssl)) != X509_V_OK) {
      X509 *peer;
      peer = SSL_get_peer_certificate(ctx->ssl);
      if(peer) {
        ctx->cert_error = strdup(X509_verify_cert_error_string(err));
        X509_free(peer);
        return 0;
      }
    }
    ctx->cert_error = strdup("No certificate present.");
    return 0;
  }

  if(!mtev_hash_retr_str(options, "optional_no_ca", strlen("optional_no_ca"),
                         &opt_no_ca))
    opt_no_ca = "false";
  if(!mtev_hash_retr_str(options, "ignore_dates", strlen("ignore_dates"),
                         &ignore_dates))
    ignore_dates = "false";
  if(options == NULL) {
    /* Don't care about anything */
    opt_no_ca = "true";
    ignore_dates = "true";
  }
  eventer_ssl_get_san_values(ctx, x509ctx);
  X509_STORE_CTX_get_ex_data(x509ctx,
                             SSL_get_ex_data_X509_STORE_CTX_idx());
  v_res = X509_STORE_CTX_get_error(x509ctx);

  if((v_res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ||
     (v_res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) ||
     (v_res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) ||
     (v_res == X509_V_ERR_CERT_UNTRUSTED) ||
     (v_res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) {
    ctx->cert_error = strdup(X509_verify_cert_error_string(v_res));
    if(!strcmp(opt_no_ca, "true")) ok = 1;
    else {
      mtevL(eventer_deb, "SSL client cert invalid: %s\n",
            X509_verify_cert_error_string(v_res));
      ok = 0;
      goto set_out;
    }
  }
  v_res = eventer_ssl_verify_dates(ctx, ok, x509ctx, closure);
  if(v_res != 0) {
    if(!strcmp(ignore_dates, "true")) ok = 1;
    else {
      mtevL(eventer_deb, "SSL client cert is %s valid.\n",
            (v_res < 0) ? "not yet" : "no longer");
      ctx->cert_error = strdup((v_res < 0) ?
                               "Certificate not yet valid." :
                               "Certificate expired.");
      ok = 0;
      goto set_out;
    }
  }
 set_out:
  return ok;
}
Beispiel #18
0
static int
rest_httptrap_handler(mtev_http_rest_closure_t *restc,
                      int npats, char **pats) {
  int mask, complete = 0, cnt;
  struct rest_json_payload *rxc = NULL;
  const char *error = "internal error", *secret = NULL;
  mtev_http_session_ctx *ctx = restc->http_ctx;
  const unsigned int DEBUGDATA_OUT_SIZE=4096;
  const unsigned int JSON_OUT_SIZE=DEBUGDATA_OUT_SIZE+128;
  char json_out[JSON_OUT_SIZE];
  char debugdata_out[DEBUGDATA_OUT_SIZE];
  int debugflag=0;
  const char *debugchkflag;
  noit_check_t *check;
  uuid_t check_id;
  mtev_http_request *req;
  mtev_hash_table *hdrs;

  if(npats != 2) {
    error = "bad uri";
    goto error;
  }
  if(uuid_parse(pats[0], check_id)) {
    error = "uuid parse error";
    goto error;
  }

  if(restc->call_closure == NULL) {
    mtev_boolean allowed = mtev_false;
    httptrap_closure_t *ccl = NULL;
    const char *delimiter = NULL;
    rxc = restc->call_closure = calloc(1, sizeof(*rxc));
    rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
    check = noit_poller_lookup(check_id);
    if(!check) {
      error = "no such check";
      goto error;
    }
    if(!httptrap_surrogate && strcmp(check->module, "httptrap")) {
      error = "no such httptrap check";
      goto error;
    }
 
    /* check "secret" then "httptrap_secret" as a fallback */
    (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
    if(!secret) (void)mtev_hash_retr_str(check->config, "httptrap_secret", strlen("httptrap_secret"), &secret);
    if(secret && !strcmp(pats[1], secret)) allowed = mtev_true;
    if(!allowed && cross_module_reverse_allowed(check, pats[1])) allowed = mtev_true;

    if(!allowed) {
      error = "secret mismatch";
      goto error;
    }

    /* check "delimiter" then "httptrap_delimiter" as a fallback */
    (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
    if(!delimiter) (void)mtev_hash_retr_str(check->config, "httptrap_delimiter", strlen("httptrap_delimiter"), &delimiter);
    if(delimiter && *delimiter) rxc->delimiter = *delimiter;
    rxc->check = check;
    uuid_copy(rxc->check_id, check_id);
    rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
    rxc->depth = -1;
    yajl_config(rxc->parser, yajl_allow_comments, 1);
    yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
    yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
    yajl_config(rxc->parser, yajl_allow_partial_values, 1);
    restc->call_closure_free = rest_json_payload_free;
  }
  else rxc = restc->call_closure;

  /* flip threads */
  {
    mtev_http_connection *conn = mtev_http_session_connection(ctx);
    eventer_t e = mtev_http_connection_event(conn);
    if(e) {
      pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
      if(!pthread_equal(e->thr_owner, tgt)) {
        e->thr_owner = tgt;
        return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
      }
    }
  }

  rxc = rest_get_json_upload(restc, &mask, &complete);
  if(rxc == NULL && !complete) return mask;

  if(!rxc) goto error;
  if(rxc->error) goto error;

  cnt = rxc->cnt;

  mtev_http_response_status_set(ctx, 200, "OK"); 
  mtev_http_response_header_set(ctx, "Content-Type", "application/json");
  mtev_http_response_option_set(ctx, MTEV_HTTP_CLOSE); 
  
  /*Examine headers for x-circonus-httptrap-debug flag*/
  req = mtev_http_session_request(ctx);
  hdrs = mtev_http_request_headers_table(req); 
    
  /*Check if debug header passed in. If present and set to true, set debugflag value to one.*/
  if(mtev_hash_retr_str(hdrs, "x-circonus-httptrap-debug", strlen("x-circonus-httptrap-debug"), &debugchkflag))
  {
    if (strcmp(debugchkflag,"true")==0)
    {
      debugflag=1;
    }
  }
   
  /*If debugflag remains zero, simply output the number of metrics.*/
  if (debugflag==0)
  {
    snprintf(json_out, sizeof(json_out),
           "{ \"stats\": %d }", cnt);    
  }
  
  /*Otherwise, if set to one, output current metrics in addition to number of current metrics.*/
  else if (debugflag==1)
  {        
      stats_t *c;
      mtev_hash_table *metrics;
        
      /*Retrieve check information.*/        
      check = noit_poller_lookup(check_id);
      c = noit_check_get_stats_current(check);
      metrics = noit_check_stats_metrics(c);
      mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
      const char *k;
      int klen;
      void *data;
      int written=0;
      int offset=0;
      memset(debugdata_out,'\0',sizeof(debugdata_out));
      
      /*Extract metrics*/
      while(mtev_hash_next(metrics, &iter, &k, &klen, &data))
      {
        char buff[256];
        int toWrite = DEBUGDATA_OUT_SIZE-offset;
        metric_t *tmp=(metric_t *)data;
        char *metric_name=tmp->metric_name;
        metric_type_t metric_type=tmp->metric_type;
        noit_stats_snprint_metric_value(buff, sizeof(buff), tmp);
        written = snprintf(debugdata_out + offset, toWrite, "\"%s\": {\"_type\":\"%c\",\"_value\":\"%s\"},", metric_name,metric_type,buff);
        if(toWrite < written) 
        {
            break;
        }
        offset += written;
      }
        
      /*Set last character to empty-don't want extra comma in output*/
      if (offset>1)
      {
        snprintf(debugdata_out + (offset-1), 1, "%s"," ");
      }
      
      /*Output stats and metrics.*/
      snprintf(json_out, sizeof(json_out)+strlen(debugdata_out),
             "{ \"stats\": %d, \"metrics\": {%s } }", cnt, debugdata_out);
  }

  mtev_http_response_append(ctx, json_out, strlen(json_out));
  mtev_http_response_end(ctx);
  return 0;

 error:
  mtev_http_response_server_error(ctx, "application/json");
  mtev_http_response_append(ctx, "{ \"error\": \"", 12);
  if(rxc && rxc->error) error = rxc->error;
  mtev_http_response_append(ctx, error, strlen(error));
  mtev_http_response_append(ctx, "\" }", 3);
  mtev_http_response_end(ctx);
  return 0;
}
int
noit_jlog_handler(eventer_t e, int mask, void *closure,
                     struct timeval *now) {
  eventer_t newe;
  pthread_t tid;
  pthread_attr_t tattr;
  int newmask = EVENTER_READ | EVENTER_EXCEPTION;
  acceptor_closure_t *ac = closure;
  noit_jlog_closure_t *jcl = ac->service_ctx;
  char errbuff[256];
  const char *errstr = "unknown error";

  if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) {
    int len, nlen;
socket_error:
    /* Exceptions cause us to simply snip the connection */
    len = strlen(errstr);
    nlen = htonl(0 - len);
    e->opset->write(e->fd, &nlen, sizeof(nlen), &newmask, e);
    e->opset->write(e->fd, errstr, strlen(errstr), &newmask, e);
    eventer_remove_fd(e->fd);
    e->opset->close(e->fd, &newmask, e);
    if(jcl) noit_jlog_closure_free(jcl);
    acceptor_closure_free(ac);
    return 0;
  }

  if(!ac->service_ctx) {
    mtev_log_stream_t ls;
    const char *logname, *type;
    int first_attempt = 1;
    char path[PATH_MAX], subscriber[256], *sub;
    jcl = ac->service_ctx = noit_jlog_closure_alloc();
    if(!mtev_hash_retr_str(ac->config,
                           "log_transit_feed_name",
                           strlen("log_transit_feed_name"),
                           &logname)) {
      errstr = "No 'log_transit_feed_name' specified in log_transit.";
      mtevL(noit_error, "%s\n", errstr);
      goto socket_error;
    }
    ls = mtev_log_stream_find(logname);
    if(!ls) {
      snprintf(errbuff, sizeof(errbuff),
               "Could not find log '%s' for log_transit.", logname);
      errstr = errbuff;
      mtevL(noit_error, "%s\n", errstr);
      goto socket_error;
    }
    type = mtev_log_stream_get_type(ls);
    if(!type || strcmp(type, "jlog")) {
      snprintf(errbuff, sizeof(errbuff),
               "Log '%s' for log_transit is not a jlog.", logname);
      errstr = errbuff;
      mtevL(noit_error, "%s\n", errstr);
      goto socket_error;
    }
    if(ac->cmd == NOIT_JLOG_DATA_FEED) {
      if(!ac->remote_cn) {
        errstr = "jlog transit started to unidentified party.";
        mtevL(noit_error, "%s\n", errstr);
        goto socket_error;
      }
      strlcpy(subscriber, ac->remote_cn, sizeof(subscriber));
      jcl->feed_stats = noit_jlog_feed_stats(subscriber);
    }
    else {
      jcl->feed_stats = noit_jlog_feed_stats("~");
      snprintf(subscriber, sizeof(subscriber),
               "~%07d", mtev_atomic_inc32(&tmpfeedcounter));
    }
    jcl->subscriber = strdup(subscriber);

    strlcpy(path, mtev_log_stream_get_path(ls), sizeof(path));
    sub = strchr(path, '(');
    if(sub) {
      char *esub = strchr(sub, ')');
      if(esub) {
        *esub = '\0';
        *sub++ = '\0';
      }
    }

    jcl->jlog = jlog_new(path);
    if(ac->cmd == NOIT_JLOG_DATA_TEMP_FEED) {
 add_sub:
      if(jlog_ctx_add_subscriber(jcl->jlog, jcl->subscriber, JLOG_END) == -1) {
        snprintf(errbuff, sizeof(errbuff),
                 "jlog reader[%s] error: %s", jcl->subscriber,
                 jlog_ctx_err_string(jcl->jlog));
        errstr = errbuff;
        mtevL(noit_error, "%s\n", errstr);
      }
    }
    if(jlog_ctx_open_reader(jcl->jlog, jcl->subscriber) == -1) {
      if(sub && !strcmp(sub, "*")) {
        if(first_attempt) {
          jlog_ctx_close(jcl->jlog);
          jcl->jlog = jlog_new(path);
          first_attempt = 0;
          goto add_sub;
        }
      }
      snprintf(errbuff, sizeof(errbuff),
               "jlog reader[%s] error: %s", jcl->subscriber,
               jlog_ctx_err_string(jcl->jlog));
      errstr = errbuff;
      mtevL(noit_error, "%s\n", errstr);
      goto socket_error;
    }
  }

  /* The jlog stuff is disk I/O and can block us.
   * We'll create a new thread to just handle this connection.
   */
  eventer_remove_fd(e->fd);
  newe = eventer_alloc();
  memcpy(newe, e, sizeof(*e));
  pthread_attr_init(&tattr);
  pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
  mtev_gettimeofday(&jcl->feed_stats->last_connection, NULL);
  mtev_atomic_inc32(&jcl->feed_stats->connections);
  if(pthread_create(&tid, &tattr, noit_jlog_thread_main, newe) == 0) {
    return 0;
  }

  /* Undo our dup */
  eventer_free(newe);
  /* Creating the thread failed, close it down and deschedule. */
  e->opset->close(e->fd, &newmask, e);
  return 0;
}
static int rest_add_feed(mtev_http_rest_closure_t *restc,
                         int npats, char **pats) {
  mtev_http_session_ctx *ctx = restc->http_ctx;
  xmlXPathObjectPtr pobj = NULL;
  xmlDocPtr doc = NULL, indoc = NULL;
  xmlNodePtr node, root;
  acceptor_closure_t *ac = restc->ac;
  int error_code = 500, complete = 0, mask = 0, rv;
  const char *error = "internal error", *logname;
  char *name, *copy_from;
  mtev_log_stream_t feed;
  const char *jpath_with_sub;
  char jlogpath[PATH_MAX], *cp;
  jlog_ctx *jctx = NULL;
  jlog_id chkpt;

  if(npats != 0) goto error;

  indoc = rest_get_xml_upload(restc, &mask, &complete);
  if(!complete) return mask;
  if(indoc == NULL) {
    error = "xml parse error";
    goto error;
  }
  if(!mtev_hash_retr_str(ac->config,
                         "log_transit_feed_name",
                         strlen("log_transit_feed_name"),
                         &logname)) {
    goto error;

  }
  feed = mtev_log_stream_find("feed");
  if(!feed) { 
    error = "couldn't find feed";
    goto error; 
  }

  jpath_with_sub = mtev_log_stream_get_path(feed);
  strlcpy(jlogpath, jpath_with_sub, sizeof(jlogpath));
  cp = strchr(jlogpath, '(');
  if(cp) *cp = '\0';

  node = xmlDocGetRootElement(indoc);
  name = (char*)xmlGetProp(node, (xmlChar*)"name");
  copy_from = (char*)xmlGetProp(node, (xmlChar*)"checkpoint_copy");

  jctx = jlog_new(jlogpath);
  if (!jctx) {
    error = "couldn't open logpath";
    goto error;
  }

  if (!jlog_get_checkpoint(jctx, name, &chkpt)) {
    error = "subscriber already exists, can't add";
    goto error;
  }

  if (copy_from) {
    rv = jlog_ctx_add_subscriber_copy_checkpoint(jctx, name, copy_from);
  }
  else {
    rv = jlog_ctx_add_subscriber(jctx, name, JLOG_END);
  }
  if (rv == -1) {
    error = "couldn't add subscriber";
    goto error;
  }

  mtev_http_response_ok(restc->http_ctx, "text/xml");
  mtev_http_response_end(restc->http_ctx);
  goto cleanup;

 error:
  mtev_http_response_standard(ctx, error_code, "ERROR", "text/xml");
  doc = xmlNewDoc((xmlChar *)"1.0");
  root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL);
  xmlDocSetRootElement(doc, root);
  xmlNodeAddContent(root, (xmlChar *)error);
  mtev_http_response_xml(ctx, doc);
  mtev_http_response_end(ctx);

 cleanup:
  if (jctx) {
    jlog_ctx_close(jctx);
  }
  if(pobj) xmlXPathFreeObject(pobj);
  if(doc) xmlFreeDoc(doc);
  return 0;
}
Beispiel #21
0
static int
rest_httptrap_handler(mtev_http_rest_closure_t *restc,
                      int npats, char **pats) {
  int mask, complete = 0, cnt;
  struct rest_json_payload *rxc = NULL;
  const char *error = "internal error", *secret = NULL;
  mtev_http_session_ctx *ctx = restc->http_ctx;
  char json_out[128];
  noit_check_t *check;
  uuid_t check_id;

  if(npats != 2) {
    error = "bad uri";
    goto error;
  }
  if(uuid_parse(pats[0], check_id)) {
    error = "uuid parse error";
    goto error;
  }

  if(restc->call_closure == NULL) {
    httptrap_closure_t *ccl;
    const char *delimiter = NULL;
    rxc = restc->call_closure = calloc(1, sizeof(*rxc));
    rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
    check = noit_poller_lookup(check_id);
    if(!check || strcmp(check->module, "httptrap")) {
      error = "no such httptrap check";
      goto error;
    }
    (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
    if(!secret) secret = "";
    if(strcmp(pats[1], secret)) {
      error = "secret mismatch";
      goto error;
    }
    (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
    if(delimiter && *delimiter) rxc->delimiter = *delimiter;
    rxc->check = check;
    ccl = check->closure;
    if(!ccl) {
      error = "noitd is booting, try again in a bit";
      goto error;
    }
    rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
    rxc->depth = -1;
    yajl_config(rxc->parser, yajl_allow_comments, 1);
    yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
    yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
    yajl_config(rxc->parser, yajl_allow_partial_values, 1);
    restc->call_closure_free = rest_json_payload_free;
  }
  else rxc = restc->call_closure;

  /* flip threads */
  {
    mtev_http_connection *conn = mtev_http_session_connection(ctx);
    eventer_t e = mtev_http_connection_event(conn);
    if(e) {
      pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
      if(!pthread_equal(e->thr_owner, tgt)) {
        e->thr_owner = tgt;
        return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
      }
    }
  }

  rxc = rest_get_json_upload(restc, &mask, &complete);
  if(rxc == NULL && !complete) return mask;

  if(!rxc) goto error;
  if(rxc->error) goto error;

  cnt = push_payload_at_check(rxc);

  mtev_http_response_ok(ctx, "application/json");
  snprintf(json_out, sizeof(json_out),
           "{ \"stats\": %d }", cnt);
  mtev_http_response_append(ctx, json_out, strlen(json_out));
  mtev_http_response_end(ctx);
  return 0;

 error:
  mtev_http_response_server_error(ctx, "application/json");
  mtev_http_response_append(ctx, "{ error: \"", 10);
  if(rxc && rxc->error) error = rxc->error;
  mtev_http_response_append(ctx, error, strlen(error));
  mtev_http_response_append(ctx, "\" }", 3);
  mtev_http_response_end(ctx);
  return 0;
}