static xmlNodePtr make_conf_path(char *path) { xmlNodePtr start, tmp; char fullpath[1024], *tok, *brk; if(!path || strlen(path) < 1) return NULL; snprintf(fullpath, sizeof(fullpath), "%s", path+1); fullpath[strlen(fullpath)-1] = '\0'; start = noit_conf_get_section(NULL, "/noit/filtersets"); if(!start) return NULL; for (tok = strtok_r(fullpath, "/", &brk); tok; tok = strtok_r(NULL, "/", &brk)) { if(!xmlValidateNameValue((xmlChar *)tok)) return NULL; if(!strcmp(tok, "filterset")) return NULL; for (tmp = start->children; tmp; tmp = tmp->next) { if(!strcmp((char *)tmp->name, tok)) break; } if(!tmp) { tmp = xmlNewNode(NULL, (xmlChar *)tok); xmlAddChild(start, tmp); CONF_DIRTY(tmp); } start = tmp; } return start; }
static int noit_console_filter_show(noit_console_closure_t ncct, int argc, char **argv, noit_console_state_t *state, void *closure) { noit_conf_t_userdata_t *info; char xpath[1024]; xmlNodePtr fsnode; noit_conf_section_t *rules; int i, rulecnt; info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA); snprintf(xpath, sizeof(xpath), "/%s", info->path); fsnode = noit_conf_get_section(NULL, xpath); if(!fsnode) { nc_printf(ncct, "internal error\n"); return -1; } rules = noit_conf_get_sections(fsnode, "rule", &rulecnt); for(i=0; i<rulecnt; i++) { char val[256]; val[0] = '\0'; noit_conf_get_stringbuf(rules[i], "@type", val, sizeof(val)); nc_printf(ncct, "Rule %d [%s]:\n", i+1, val); #define DUMP_ATTR(a) do { \ char *vstr; \ noit_conf_section_t ht; \ int cnt; \ ht = noit_conf_get_sections(rules[i], #a, &cnt); \ if(ht && cnt) { \ nc_printf(ncct, "\t%s: hash match of %d items\n", #a, cnt); \ } \ else if(noit_conf_get_string(rules[i], "@" #a, &vstr)) { \ nc_printf(ncct, "\t%s: /%s/\n", #a, val); \ free(vstr); \ } \ free(ht); \ } while(0) DUMP_ATTR(target); DUMP_ATTR(module); DUMP_ATTR(name); DUMP_ATTR(metric); } if(rules) free(rules); return 0; }
noit_check_t * noit_check_watch(uuid_t in, int period) { /* First look for a copy that is being watched */ int minimum_pi = 1000, granularity_pi = 500; noit_conf_section_t check_node; char uuid_str[UUID_STR_LEN + 1]; char xpath[1024]; noit_check_t n, *f; uuid_unparse_lower(in, uuid_str); /* Find the check */ snprintf(xpath, sizeof(xpath), "//checks//check[@uuid=\"%s\"]", uuid_str); check_node = noit_conf_get_section(NULL, xpath); noit_conf_get_int(NULL, "//checks/@transient_min_period", &minimum_pi); noit_conf_get_int(NULL, "//checks/@transient_period_granularity", &granularity_pi); if(check_node) { noit_conf_get_int(check_node, "ancestor-or-self::node()/@transient_min_period", &minimum_pi); noit_conf_get_int(check_node, "ancestor-or-self::node()/@transient_period_granularity", &granularity_pi); } /* apply the bounds */ period /= granularity_pi; period *= granularity_pi; period = MAX(period, minimum_pi); uuid_copy(n.checkid, in); n.period = period; f = noit_skiplist_find(&watchlist, &n, NULL); if(f) return f; f = noit_check_clone(in); if(!f) return NULL; f->period = period; f->timeout = period - 10; f->flags |= NP_TRANSIENT; noitL(noit_debug, "Watching %s@%d\n", uuid_str, period); noit_skiplist_insert(&watchlist, f); return f; }
static int rest_show_filter(noit_http_rest_closure_t *restc, int npats, char **pats) { noit_http_session_ctx *ctx = restc->http_ctx; xmlDocPtr doc = NULL; xmlNodePtr node, root; char xpath[1024]; int error_code = 500; if(npats != 2) goto error; snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = noit_conf_get_section(NULL, xpath); if(!node) goto not_found; doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlCopyNode(node, 1); xmlDocSetRootElement(doc, root); 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(doc) xmlFreeDoc(doc); return 0; }
static int rest_delete_filter(noit_http_rest_closure_t *restc, int npats, char **pats) { noit_http_session_ctx *ctx = restc->http_ctx; xmlNodePtr node; char xpath[1024]; int error_code = 500; if(npats != 2) goto error; snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = noit_conf_get_section(NULL, xpath); if(!node) goto not_found; if(noit_filter_remove(node) == 0) goto not_found; CONF_REMOVE(node); xmlUnlinkNode(node); xmlFreeNode(node); if(noit_conf_write_file(NULL) != 0) noitL(noit_error, "local config write failed\n"); noit_conf_mark_changed(); noit_http_response_ok(ctx, "text/html"); 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: return 0; }
static int noit_console_filter_configure(noit_console_closure_t ncct, int argc, char **argv, noit_console_state_t *state, void *closure) { xmlNodePtr parent, fsnode = NULL; int rv = -1; noit_conf_t_userdata_t *info; char xpath[1024]; info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA); if(!info) { nc_printf(ncct, "internal error\n"); goto cleanup; } if(strncmp(info->path, "/filtersets/", strlen("/filtersets/")) && strcmp(info->path, "/filtersets")) { nc_printf(ncct, "filterset only allows inside /filtersets (not %s)\n", info->path); goto cleanup; } if(argc != 1) { nc_printf(ncct, "filterset requires one argument\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "/%s", info->path); parent = noit_conf_get_section(NULL, xpath); if(!parent) { nc_printf(ncct, "internal error, can't final current working path\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "filterset[@name=\"%s\"]", argv[0]); fsnode = noit_conf_get_section(parent, xpath); if(closure) { int removed; removed = noit_filter_remove(fsnode); nc_printf(ncct, "%sremoved filterset '%s'\n", removed ? "" : "failed to ", argv[0]); if(removed) { xmlUnlinkNode(fsnode); xmlFreeNode(fsnode); } rv = !removed; goto cleanup; } if(!fsnode) { void *vfs; nc_printf(ncct, "Cannot find filterset '%s'\n", argv[0]); LOCKFS(); if(noit_hash_retrieve(filtersets, argv[0], strlen(argv[0]), &vfs)) { UNLOCKFS(); nc_printf(ncct, "filter of the same name already exists\n"); goto cleanup; } UNLOCKFS(); /* Fine the parent path */ fsnode = xmlNewNode(NULL, (xmlChar *)"filterset"); xmlSetProp(fsnode, (xmlChar *)"name", (xmlChar *)argv[0]); xmlAddChild(parent, fsnode); nc_printf(ncct, "created new filterset\n"); } if(info) { char *xmlpath = NULL; if(info->path) free(info->path); xmlpath = (char *)xmlGetNodePath(fsnode); info->path = strdup(xmlpath + strlen("/noit")); free(xmlpath); strlcpy(info->filter_name, argv[0], sizeof(info->filter_name)); if(state) { noit_console_state_push_state(ncct, state); noit_console_state_init(ncct); } } cleanup: return rv; }
static int noit_console_rule_configure(noit_console_closure_t ncct, int argc, char **argv, noit_console_state_t *state, void *closure) { xmlNodePtr fsnode = NULL; noit_conf_t_userdata_t *info; char xpath[1024]; info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA); snprintf(xpath, sizeof(xpath), "/%s", info->path); fsnode = noit_conf_get_section(NULL, xpath); if(!fsnode) { nc_printf(ncct, "internal error"); return -1; } if(closure) { int rulenum; xmlNodePtr byebye; /* removing a rule */ if(argc != 1) { nc_printf(ncct, "requires one argument\n"); return -1; } rulenum = atoi(argv[0]); snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum); byebye = noit_conf_get_section(fsnode, xpath); if(!byebye) { nc_printf(ncct, "cannot find rule\n"); return -1; } xmlUnlinkNode(byebye); xmlFreeNode(byebye); nc_printf(ncct, "removed\n"); } else { xmlNodePtr (*add_func)(xmlNodePtr, xmlNodePtr); xmlNodePtr add_arg, new_rule; int i, needs_type = 1; if(argc < 1 || argc % 2) { nc_printf(ncct, "even number of arguments required\n"); return -1; } if(!strcmp(argv[0], "before") || !strcmp(argv[0], "after")) { int rulenum = atoi(argv[1]); snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum); add_arg = noit_conf_get_section(fsnode, xpath); if(!add_arg) { nc_printf(ncct, "%s rule not found\n", xpath); return -1; } if(*argv[0] == 'b') add_func = xmlAddPrevSibling; else add_func = xmlAddNextSibling; argc -= 2; argv += 2; } else { add_func = xmlAddChild; add_arg = fsnode; } for(i=0;i<argc;i+=2) { if(!strcmp(argv[i], "type")) needs_type = 0; else if(strcmp(argv[i], "target") && strcmp(argv[i], "module") && strcmp(argv[i], "name") && strcmp(argv[i], "metric")) { nc_printf(ncct, "unknown attribute '%s'\n", argv[i]); return -1; } } if(needs_type) { nc_printf(ncct, "type <allow|deny> is required\n"); return -1; } new_rule = xmlNewNode(NULL, (xmlChar *)"rule"); for(i=0;i<argc;i+=2) xmlSetProp(new_rule, (xmlChar *)argv[i], (xmlChar *)argv[i+1]); add_func(add_arg, new_rule); noit_filter_compile_add((noit_conf_section_t *)fsnode); } return 0; }
noit_check_t * noit_fire_check(xmlNodePtr attr, xmlNodePtr config, const char **error) { char *target = NULL, *name = NULL, *module = NULL, *filterset = NULL; char *resolve_rtype = NULL; int timeout = 0, flags = NP_TRANSIENT, i, mod_cnt; noit_module_t *m; noit_check_t *c = NULL; xmlNodePtr a, co; noit_hash_table *conf_hash = NULL; noit_hash_table **moptions = NULL; for(a = attr->children; a; a = a->next) { if(!strcmp((char *)a->name, "target")) target = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "name")) name = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "module")) module = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "filterset")) filterset = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "timeout")) { char *timeout_str = (char *)xmlNodeGetContent(a); timeout = atoi(timeout_str); free(timeout_str); } else if(!strcmp((char *)a->name, "resolve_rtype")) resolve_rtype = (char *)xmlNodeGetContent(a); } m = noit_module_lookup(module); if(!m) { *error = "cannot find requested module"; goto error; } conf_hash = calloc(1, sizeof(*conf_hash)); if(config) { for(co = config->children; co; co = co->next) { char *name, *val; xmlChar *tmp_val; name = strdup((char *)co->name); tmp_val = xmlNodeGetContent(co); val = strdup(tmp_val ? (char *)tmp_val : ""); noit_hash_replace(conf_hash, name, strlen(name), val, free, free); xmlFree(tmp_val); } } mod_cnt = noit_check_registered_module_cnt(); if(mod_cnt > 0) { moptions = alloca(mod_cnt * sizeof(*moptions)); memset(moptions, 0, mod_cnt * sizeof(*moptions)); for(i=0; i<mod_cnt; i++) { const char *name; noit_conf_section_t checks; name = noit_check_registered_module(i); checks = noit_conf_get_section(NULL, "/noit/checks"); if(name) moptions[i] = noit_conf_get_namespaced_hash(checks, "config", name); } } if(!m->initiate_check) { *error = "that module cannot run checks"; goto error; } flags |= noit_calc_rtype_flag(resolve_rtype); c = calloc(1, sizeof(*c)); noit_check_update(c, target, name, filterset, conf_hash, moptions, 0, timeout, NULL, flags); c->module = strdup(module); uuid_generate(c->checkid); c->flags |= NP_DISABLED; /* this is hack to know we haven't run it yet */ if(NOIT_CHECK_SHOULD_RESOLVE(c)) noit_check_resolve(c); error: if(conf_hash) { noit_hash_destroy(conf_hash, free, free); free(conf_hash); } if(moptions) { for(i=0; i<mod_cnt; i++) { if(moptions[i]) { noit_hash_destroy(moptions[i], free, free); free(moptions[i]); } } } if(target) xmlFree(target); if(name) xmlFree(name); if(module) xmlFree(module); if(filterset) xmlFree(filterset); if (resolve_rtype) xmlFree(resolve_rtype); return c; }
static int rest_set_filter(noit_http_rest_closure_t *restc, int npats, char **pats) { noit_http_session_ctx *ctx = restc->http_ctx; xmlDocPtr doc = NULL, indoc = NULL; xmlNodePtr node, parent, root, newfilter; char xpath[1024]; int error_code = 500, complete = 0, mask = 0; const char *error = "internal error"; if(npats != 2) goto error; indoc = rest_get_xml_upload(restc, &mask, &complete); if(!complete) return mask; if(indoc == NULL) FAIL("xml parse error"); snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = noit_conf_get_section(NULL, xpath); if(!node && noit_filter_exists(pats[1])) { /* It's someone else's */ error_code = 403; goto error; } if((newfilter = validate_filter_post(indoc)) == NULL) goto error; xmlSetProp(newfilter, (xmlChar *)"name", (xmlChar *)pats[1]); parent = make_conf_path(pats[0]); if(!parent) FAIL("invalid path"); if(node) { xmlUnlinkNode(node); xmlFreeNode(node); } xmlUnlinkNode(newfilter); xmlAddChild(parent, newfilter); CONF_DIRTY(newfilter); noit_conf_mark_changed(); if(noit_conf_write_file(NULL) != 0) noitL(noit_error, "local config write failed\n"); noit_filter_compile_add(newfilter); if(restc->call_closure_free) restc->call_closure_free(restc->call_closure); restc->call_closure_free = NULL; restc->call_closure = NULL; restc->fastpath = rest_show_filter; return restc->fastpath(restc, restc->nparams, restc->params); error: noit_http_response_standard(ctx, error_code, "ERROR", "text/html"); doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL); xmlDocSetRootElement(doc, root); xmlNodeAddContent(root, (xmlChar *)error); noit_http_response_xml(ctx, doc); noit_http_response_end(ctx); goto cleanup; cleanup: if(doc) xmlFreeDoc(doc); return 0; }