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; }
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; }
static int rest_show_check(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; xmlDocPtr doc = NULL; xmlNodePtr node, root, attr, config, state, tmp, anode; uuid_t checkid; noit_check_t *check; char xpath[1024], *uuid_conf, *module = NULL, *value = NULL; int rv, mod, mod_cnt, cnt, error_code = 500; mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *k; int klen; void *data; mtev_hash_table *configh; if(npats != 2 && npats != 3) goto error; rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]); if(rv == 0) goto not_found; if(rv < 0) goto error; mtev_conf_xml_xpath(NULL, &xpath_ctxt); pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto not_found; cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(cnt != 1) goto error; node = (mtev_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) goto error; if(npats == 3 && !strcmp(pats[2], ".json")) { return rest_show_check_json(restc, checkid); } doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"check", NULL); xmlDocSetRootElement(doc, root); #define MYATTR(node,a,n,b) _mtev_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(node,a,n,b) \ _mtev_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(parent, node, a) do { \ char *_value = NULL; \ INHERIT(node, a, anode, _value); \ if(_value != NULL) { \ int clen, plen;\ char *_cpath, *_apath; \ xmlNodePtr child; \ _cpath = node ? (char *)xmlGetNodePath(node) : strdup(""); \ _apath = anode ? (char *)xmlGetNodePath(anode) : strdup(""); \ clen = strlen(_cpath); \ plen = strlen("/noit/checks"); \ child = xmlNewNode(NULL, (xmlChar *)#a); \ xmlNodeAddContent(child, (xmlChar *)_value); \ if(!strncmp(_cpath, _apath, clen) && _apath[clen] == '/') { \ } \ else { \ xmlSetProp(child, (xmlChar *)"inherited", (xmlChar *)_apath+plen); \ } \ xmlAddChild(parent, child); \ free(_cpath); \ free(_apath); \ free(_value); \ } \ } while(0) attr = xmlNewNode(NULL, (xmlChar *)"attributes"); xmlAddChild(root, attr); SHOW_ATTR(attr,node,uuid); SHOW_ATTR(attr,node,seq); /* Name is odd, it falls back transparently to module */ if(!INHERIT(node, module, tmp, module)) module = NULL; xmlAddChild(attr, (tmp = xmlNewNode(NULL, (xmlChar *)"name"))); if(MYATTR(node, name, anode, value)) xmlNodeAddContent(tmp, (xmlChar *)value); else if(module) xmlNodeAddContent(tmp, (xmlChar *)module); if(value) free(value); if(module) free(module); SHOW_ATTR(attr,node,module); SHOW_ATTR(attr,node,target); SHOW_ATTR(attr,node,resolve_rtype); SHOW_ATTR(attr,node,seq); SHOW_ATTR(attr,node,period); SHOW_ATTR(attr,node,timeout); SHOW_ATTR(attr,node,oncheck); SHOW_ATTR(attr,node,filterset); SHOW_ATTR(attr,node,disable); /* Add the config */ config = xmlNewNode(NULL, (xmlChar *)"config"); configh = mtev_conf_get_hash(node, "config"); while(mtev_hash_next(configh, &iter, &k, &klen, &data)) NODE_CONTENT(config, k, data); mtev_hash_destroy(configh, free, free); free(configh); mod_cnt = noit_check_registered_module_cnt(); for(mod=0; mod<mod_cnt; mod++) { xmlNsPtr ns; const char *nsname; char buff[256]; nsname = noit_check_registered_module(mod); snprintf(buff, sizeof(buff), "noit://module/%s", nsname); ns = xmlSearchNs(root->doc, root, (xmlChar *)nsname); if(!ns) ns = xmlNewNs(root, (xmlChar *)buff, (xmlChar *)nsname); if(ns) { configh = mtev_conf_get_namespaced_hash(node, "config", nsname); if(configh) { memset(&iter, 0, sizeof(iter)); while(mtev_hash_next(configh, &iter, &k, &klen, &data)) { NS_NODE_CONTENT(config, ns, "value", data, xmlSetProp(tmp, (xmlChar *)"name", (xmlChar *)k); ); } mtev_hash_destroy(configh, free, free); free(configh); } } }
static int rest_show_check(noit_http_rest_closure_t *restc, int npats, char **pats) { noit_http_session_ctx *ctx = restc->http_ctx; xmlXPathObjectPtr pobj = NULL; xmlXPathContextPtr xpath_ctxt = NULL; xmlDocPtr doc = NULL; xmlNodePtr node, root, attr, config, state, tmp, anode; uuid_t checkid; noit_check_t *check; char xpath[1024], *uuid_conf, *module, *value; int rv, cnt, error_code = 500; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *k; int klen; void *data; noit_hash_table *configh; if(npats != 2) goto error; rv = noit_check_xpath(xpath, sizeof(xpath), pats[0], pats[1]); if(rv == 0) goto not_found; if(rv < 0) goto error; noit_conf_xml_xpath(NULL, &xpath_ctxt); pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt); if(!pobj || pobj->type != XPATH_NODESET || xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto not_found; cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); if(cnt != 1) goto error; node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid"); if(!uuid_conf || uuid_parse(uuid_conf, checkid)) goto error; doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"check", NULL); xmlDocSetRootElement(doc, root); #define MYATTR(node,a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b)) #define INHERIT(node,a,n,b) \ _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b)) #define SHOW_ATTR(parent, node, a) do { \ xmlNodePtr anode = NULL; \ char *value = NULL; \ INHERIT(node, a, anode, value); \ if(value != NULL) { \ int clen, plen;\ const char *cpath, *apath; \ xmlNodePtr child; \ cpath = node ? (char *)xmlGetNodePath(node) : ""; \ apath = anode ? (char *)xmlGetNodePath(anode) : ""; \ clen = strlen(cpath); \ plen = strlen("/noit/checks"); \ child = xmlNewNode(NULL, (xmlChar *)#a); \ xmlNodeAddContent(child, (xmlChar *)value); \ if(!strncmp(cpath, apath, clen) && apath[clen] == '/') { \ } \ else { \ xmlSetProp(child, (xmlChar *)"inherited", (xmlChar *)apath+plen); \ } \ xmlAddChild(parent, child); \ } \ } while(0) attr = xmlNewNode(NULL, (xmlChar *)"attributes"); xmlAddChild(root, attr); SHOW_ATTR(attr,node,uuid); /* Name is odd, it falls back transparently to module */ if(!INHERIT(node, module, tmp, module)) module = NULL; xmlAddChild(attr, (tmp = xmlNewNode(NULL, (xmlChar *)"name"))); if(MYATTR(node, name, anode, value)) xmlNodeAddContent(tmp, (xmlChar *)value); else if(module) xmlNodeAddContent(tmp, (xmlChar *)module); SHOW_ATTR(attr,node,module); SHOW_ATTR(attr,node,target); SHOW_ATTR(attr,node,period); SHOW_ATTR(attr,node,timeout); SHOW_ATTR(attr,node,oncheck); SHOW_ATTR(attr,node,filterset); SHOW_ATTR(attr,node,disable); /* Add the config */ config = xmlNewNode(NULL, (xmlChar *)"config"); configh = noit_conf_get_hash(node, "config"); while(noit_hash_next(configh, &iter, &k, &klen, &data)) NODE_CONTENT(config, k, data); noit_hash_destroy(configh, free, free); free(configh); xmlAddChild(root, config); /* Add the state */ check = noit_poller_lookup(checkid); if(!check) { state = xmlNewNode(NULL, (xmlChar *)"state"); xmlSetProp(state, (xmlChar *)"error", (xmlChar *)"true"); } else state = noit_check_state_as_xml(check); xmlAddChild(root, state); noit_http_response_ok(ctx, "text/xml"); noit_http_response_xml(ctx, doc); noit_http_response_end(ctx); goto cleanup; not_found: noit_http_response_not_found(ctx, "text/html"); noit_http_response_end(ctx); goto cleanup; error: noit_http_response_standard(ctx, error_code, "ERROR", "text/html"); noit_http_response_end(ctx); goto cleanup; cleanup: if(pobj) xmlXPathFreeObject(pobj); if(doc) xmlFreeDoc(doc); return 0; }