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; }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }