static int rest_get_noit_config(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; char *xml = NULL; if(npats != 0) { mtev_http_response_server_error(ctx, "text/xml"); mtev_http_response_end(ctx); return 0; } xml = ingestor->get_noit_config(restc->remote_cn); if(xml == NULL) { char buff[1024]; snprintf(buff, sizeof(buff), "<error><remote_cn>%s</remote_cn>" "<row_count>%d</row_count></error>\n", restc->remote_cn, 0); mtev_http_response_append(ctx, buff, strlen(buff)); mtev_http_response_not_found(ctx, "text/xml"); } else { mtev_http_response_append(ctx, xml, strlen(xml)); mtev_http_response_ok(ctx, "text/xml"); } if(xml) free(xml); mtev_http_response_end(ctx); return 0; }
static int rest_show_feed(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; const char *err = "unknown error"; const char *jpath_with_sub; char jlogpath[PATH_MAX], *cp, **subs = NULL; int nsubs, i; mtev_log_stream_t feed; jlog_ctx *jctx = NULL; xmlDocPtr doc = NULL; xmlNodePtr root = NULL, subnodes; feed = mtev_log_stream_find("feed"); if(!feed) { err = "cannot 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'; jctx = jlog_new(jlogpath); if((nsubs = jlog_ctx_list_subscribers(jctx, &subs)) == -1) { err = jlog_ctx_err_string(jctx); goto error; } doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"feed", NULL); xmlDocSetRootElement(doc, root); subnodes = xmlNewNode(NULL, (xmlChar *)"subscribers"); for(i=0; i<nsubs; i++) { xmlNewChild(subnodes, NULL, (xmlChar *)"subscriber", (xmlChar *)subs[i]); } xmlAddChild(root, subnodes); mtev_http_response_ok(restc->http_ctx, "text/xml"); mtev_http_response_xml(restc->http_ctx, doc); mtev_http_response_end(restc->http_ctx); if(subs) jlog_ctx_list_subscribers_dispose(jctx, subs); xmlFreeDoc(doc); jlog_ctx_close(jctx); return 0; error: if(doc) xmlFreeDoc(doc); if(subs) jlog_ctx_list_subscribers_dispose(jctx, subs); mtev_http_response_server_error(ctx, "text/plain"); mtev_http_response_append(ctx, err, strlen(err)); mtev_http_response_end(ctx); if(jctx) jlog_ctx_close(jctx); return 0; }
static int rest_delete_feed(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; const char *err = "unknown error"; const char *jpath_with_sub; char jlogpath[PATH_MAX], *cp; int rv; mtev_log_stream_t feed; jlog_ctx *jctx; feed = mtev_log_stream_find("feed"); if(!feed) { err = "cannot 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'; jctx = jlog_new(jlogpath); rv = jlog_ctx_remove_subscriber(jctx, pats[0]); jlog_ctx_close(jctx); if(rv < 0) { err = jlog_ctx_err_string(jctx); goto error; } /* removed or note, we should do a sweeping cleanup */ jlog_clean(jlogpath); if(rv == 0) { mtev_http_response_not_found(ctx, "text/plain"); mtev_http_response_end(ctx); return 0; } mtev_http_response_standard(ctx, 204, "OK", "text/plain"); mtev_http_response_end(ctx); return 0; error: mtev_http_response_server_error(ctx, "text/plain"); mtev_http_response_append(ctx, err, strlen(err)); mtev_http_response_end(ctx); return 0; }
static int mtev_capabilities_rest(mtev_http_rest_closure_t *restc, int n, char **p) { mtev_capsvc_closure_t cl = { 0 }; const char *mtype = "application/xml"; if(n > 0 && !strcmp(p[0], ".json")) { mtev_capabilities_tobuff_json(&cl, NULL); mtype = "application/json"; } else mtev_capabilities_tobuff(&cl, NULL); if(!cl.buff) goto error; mtev_http_response_ok(restc->http_ctx, mtype); mtev_http_response_append(restc->http_ctx, cl.buff, cl.towrite); mtev_http_response_end(restc->http_ctx); free(cl.buff); return 0; error: mtev_http_response_server_error(restc->http_ctx, "text/html"); mtev_http_response_end(restc->http_ctx); 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; }
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; }