mirror of https://github.com/BOINC/boinc.git
Daemons: enhance validator framework
The validator handler can now pass unknown arguments to the project specific handler. Projects that have there own validator need to implement the validate_handler_init() function and handle project specific arguments there. They also need to supply a validate_handler_usage() function that printf()'s a description of the custom options. For examples see sample_substr_validator.cpp or script_validator.cpp The validator test harness was also adopted to use this new functions. This brings the implementation of the validator framework on the same level as the assimilator framework where similar changes where made in0038d275c
anddd004404a
.
This commit is contained in:
parent
3b3c575694
commit
2c36e7246d
|
@ -153,6 +153,7 @@ sched/trickle_credit
|
|||
sched/trickle_deadline
|
||||
sched/trickle_echo
|
||||
sched/update_stats
|
||||
sched/validator_test
|
||||
sched/wu_check
|
||||
tools/cancel_jobs
|
||||
tools/create_work
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
VALIDATOR_SRC = sample_bitwise_validator.cpp
|
||||
|
||||
# where libmysqlclient is
|
||||
MYSQL_LIB_DIR = /usr/lib64/mysql
|
||||
MYSQL_LIB := $(shell mysql_config --libs)
|
||||
MYSQL_INC := $(shell mysql_config --include)
|
||||
|
||||
validator_test: validator_test.cpp $(VALIDATOR_SRC)
|
||||
g++ -g -I.. -I../lib -I../db -o validator_test validator_test.cpp $(VALIDATOR_SRC) validate_util.o -L . -lsched -L ../lib -lboinc -L $(MYSQL_LIB_DIR) -lmysqlclient
|
||||
validator_test: validator_test.cpp $(VALIDATOR_SRC) makefile_validator_test
|
||||
g++ -g -I.. -I../lib -I../db $(MYSQL_INC) -o validator_test validator_test.cpp $(VALIDATOR_SRC) validate_util.o -L . -lsched -L ../lib -lboinc $(MYSQL_LIB)
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
bool first = true;
|
||||
bool is_gzip = false;
|
||||
// if true, files are gzipped; skip header when comparing
|
||||
|
||||
|
@ -47,6 +46,25 @@ struct FILE_CKSUM_LIST {
|
|||
~FILE_CKSUM_LIST(){}
|
||||
};
|
||||
|
||||
int validate_handler_init(int argc, char** argv) {
|
||||
// handle project specific arguments here
|
||||
for (int i=1; i<argc; i++) {
|
||||
if (is_arg(argv[i], "is_gzip")) {
|
||||
is_gzip = true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void validate_handler_usage() {
|
||||
// describe the project specific arguments here
|
||||
fprintf(stderr,
|
||||
" Custom options:\n"
|
||||
" [--is_gzip] files are gzipped; skip header when comparing\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool files_match(FILE_CKSUM_LIST& f1, FILE_CKSUM_LIST& f2) {
|
||||
if (f1.files.size() != f2.files.size()) return false;
|
||||
for (unsigned int i=0; i<f1.files.size(); i++) {
|
||||
|
@ -55,14 +73,6 @@ bool files_match(FILE_CKSUM_LIST& f1, FILE_CKSUM_LIST& f2) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void parse_cmdline() {
|
||||
for (int i=1; i<g_argc; i++) {
|
||||
if (!strcmp(g_argv[i], "--is_gzip")) {
|
||||
is_gzip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int init_result(RESULT& result, void*& data) {
|
||||
int retval;
|
||||
FILE_CKSUM_LIST* fcl = new FILE_CKSUM_LIST;
|
||||
|
@ -70,11 +80,6 @@ int init_result(RESULT& result, void*& data) {
|
|||
char md5_buf[MD5_LEN];
|
||||
double nbytes;
|
||||
|
||||
if (first) {
|
||||
parse_cmdline();
|
||||
first = false;
|
||||
}
|
||||
|
||||
retval = get_output_file_infos(result, files);
|
||||
if (retval) {
|
||||
log_messages.printf(MSG_CRITICAL,
|
||||
|
|
|
@ -23,37 +23,44 @@
|
|||
// (default: accept it if the string is present)
|
||||
|
||||
#include "sched_msgs.h"
|
||||
#include "sched_util_basic.h"
|
||||
#include "validate_util2.h"
|
||||
#include "validator.h"
|
||||
|
||||
bool first = true;
|
||||
char* stderr_string;
|
||||
bool reject_if_present = false;
|
||||
|
||||
void parse_cmdline() {
|
||||
int validate_handler_init(int argc, char** argv) {
|
||||
// handle project specific arguments here
|
||||
bool found = false;
|
||||
for (int i=1; i<g_argc; i++) {
|
||||
if (!strcmp(g_argv[i], "--stderr_string")) {
|
||||
stderr_string = g_argv[++i];
|
||||
for (int i=1; i<argc; i++) {
|
||||
if (is_arg(argv[i], "stderr_string")) {
|
||||
stderr_string = argv[++i];
|
||||
found = true;
|
||||
}
|
||||
if (!strcmp(g_argv[i], "--reject_if_present")) {
|
||||
} else if (is_arg(argv[i], "reject_if_present")) {
|
||||
reject_if_present = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
log_messages.printf(MSG_CRITICAL,
|
||||
"--stderr_string missing from command line\n"
|
||||
);
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void validate_handler_usage() {
|
||||
// describe the project specific arguments here
|
||||
fprintf(stderr,
|
||||
" Custom options:\n"
|
||||
" --stderr_string X accept task if X is present in stderr_out\n"
|
||||
" [--reject_if_present] reject (invalidate) the task if X is present\n"
|
||||
);
|
||||
}
|
||||
|
||||
int init_result(RESULT& r, void*&) {
|
||||
if (first) {
|
||||
parse_cmdline();
|
||||
first = false;
|
||||
}
|
||||
if (strstr(r.stderr_out, stderr_string)) {
|
||||
return reject_if_present?-1:0;
|
||||
} else {
|
||||
|
|
|
@ -19,6 +19,19 @@
|
|||
|
||||
#include "validate_util2.h"
|
||||
|
||||
int validate_handler_init(int, char**) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void validate_handler_usage() {
|
||||
// describe the project specific arguments here
|
||||
//fprintf(stderr,
|
||||
// " Custom options:\n"
|
||||
// " [--project_option X] a project specific option\n"
|
||||
//);
|
||||
}
|
||||
|
||||
|
||||
int init_result(RESULT&, void*&) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -56,42 +56,53 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
bool first = true;
|
||||
vector<string> init_script, compare_script;
|
||||
// first element is script path, other elements are args
|
||||
|
||||
void parse_cmdline() {
|
||||
for (int i=1; i<g_argc; i++) {
|
||||
if (!strcmp(g_argv[i], "--init_script")) {
|
||||
init_script = split(g_argv[++i], ' ');
|
||||
int validate_handler_init(int argc, char** argv) {
|
||||
// handle project specific arguments here
|
||||
for (int i=1; i<argc; i++) {
|
||||
if (is_arg(argv[i], "init_script")) {
|
||||
init_script = split(argv[++i], ' ');
|
||||
if (init_script.size() == 1) {
|
||||
init_script.push_back(string("files"));
|
||||
}
|
||||
} else if (!strcmp(g_argv[i], "--compare_script")) {
|
||||
compare_script = split(g_argv[++i], ' ');
|
||||
} else if (is_arg(argv[i], "compare_script")) {
|
||||
compare_script = split(argv[++i], ' ');
|
||||
if (compare_script.size() == 1) {
|
||||
compare_script.push_back("files");
|
||||
compare_script.push_back("files2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!init_script.size() && !compare_script.size()) {
|
||||
log_messages.printf(MSG_CRITICAL,
|
||||
"script names missing from command line\n"
|
||||
);
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void validate_handler_usage() {
|
||||
// describe the project specific arguments here
|
||||
fprintf(stderr,
|
||||
" A validator that runs scripts to check and compare results, \n"
|
||||
" so that you can do your validation in Python, PHP, Perl, bash, etc.\n"
|
||||
" Custom options:\n"
|
||||
" --init_script \"scriptname arg1 ... argn\" checks the validity of a task,\n"
|
||||
" e.g. that the output files have the proper format. Needs to exit with zero if the files are valid.\n"
|
||||
" --compare_script \"scriptname arg1 ... argn\" compares two tasks. \n"
|
||||
" Needs to return zero if the output files are equivalent.\n"
|
||||
" See script_validator.cpp for more usage information.\n"
|
||||
);
|
||||
}
|
||||
|
||||
int init_result(RESULT& result, void*&) {
|
||||
unsigned int i, j;
|
||||
char buf[256];
|
||||
|
||||
if (first) {
|
||||
parse_cmdline();
|
||||
first = false;
|
||||
}
|
||||
if (!init_script.size()) return 0;
|
||||
vector<string> paths;
|
||||
int retval;
|
||||
retval = get_output_file_paths(result, paths);
|
||||
|
@ -127,14 +138,6 @@ int compare_results(RESULT& r1, void*, RESULT const& r2, void*, bool& match) {
|
|||
unsigned int i, j;
|
||||
char buf[256];
|
||||
|
||||
if (first) {
|
||||
parse_cmdline();
|
||||
first = false;
|
||||
}
|
||||
if (!compare_script.size()) {
|
||||
match = true;
|
||||
return 0;
|
||||
}
|
||||
vector<string> paths1, paths2;
|
||||
int retval;
|
||||
retval = get_output_file_paths(r1, paths1);
|
||||
|
|
|
@ -53,5 +53,8 @@ extern bool standalone;
|
|||
// used by validator_test.
|
||||
extern void remove_random_from_filename(const char* in, char* out);
|
||||
|
||||
extern int validate_handler_init(int argc, char** argv);
|
||||
extern void validate_handler_usage();
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -772,6 +772,40 @@ int main_loop() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void usage(char* name) {
|
||||
fprintf(stderr,
|
||||
"This program is a 'validator'; it handles completed tasks.\n"
|
||||
"Normally it is run as a daemon from config.xml.\n"
|
||||
"See: https://boinc.berkeley.edu/trac/wiki/BackendPrograms\n\n"
|
||||
);
|
||||
|
||||
fprintf(stderr, "usage: %s [options]\n"
|
||||
" Options:\n"
|
||||
" --app name Process tasks for the given application\n"
|
||||
" [--one_pass_N_WU N] Validate at most N WUs, then exit\n"
|
||||
" [--one_pass] Make one pass through WU table, then exit\n"
|
||||
" [--dry_run] Don't update db, just write logs (for debugging)\n"
|
||||
" [--mod n i] Process only WUs with (id mod n) == i\n"
|
||||
" [--max_wu_id n] Process only WUs with id <= n\n"
|
||||
" [--min_wu_id n] Process only WUs with id >= n\n"
|
||||
" [--max_granted_credit X] Grant no more than this amount of credit to a result\n"
|
||||
" [--grant_claimed_credit] Grant the claimed credit, regardless of what other results for this workunit claimed\n"
|
||||
" [--update_credited_job] Add record to credited_job table after granting credit\n"
|
||||
" [--credit_from_wu] Credit is specified in WU XML\n"
|
||||
" [--credit_from_runtime X] Grant credit based on runtime (max X seconds)and estimated FLOPS\n"
|
||||
" [--no_credit] Don't grant credit\n"
|
||||
" [--sleep_interval n] Set sleep-interval to n\n"
|
||||
" [--wu_id n] Process WU with given ID\n"
|
||||
" [-d level|--debug_level n] Set log verbosity level\n"
|
||||
" [-h|--help] Print this usage information and exit\n"
|
||||
" [-v|--version] Print version information and exit\n"
|
||||
"\n",
|
||||
name
|
||||
);
|
||||
validate_handler_usage();
|
||||
|
||||
}
|
||||
|
||||
// For use by project-supplied routines check_set() and check_pair()
|
||||
//
|
||||
int debug_level=0;
|
||||
|
@ -779,30 +813,9 @@ int debug_level=0;
|
|||
int main(int argc, char** argv) {
|
||||
int i, retval;
|
||||
|
||||
const char *usage =
|
||||
"\nUsage: %s --app <app-name> [OPTIONS]\n"
|
||||
"Start validator for application <app-name>\n\n"
|
||||
"Optional arguments:\n"
|
||||
" --one_pass_N_WU N Validate at most N WUs, then exit\n"
|
||||
" --one_pass Make one pass through WU table, then exit\n"
|
||||
" --dry_run Don't update db, just write logs (for debugging)\n"
|
||||
" --mod n i Process only WUs with (id mod n) == i\n"
|
||||
" --max_wu_id n Process only WUs with id <= n\n"
|
||||
" --min_wu_id n Process only WUs with id >= n\n"
|
||||
" --max_granted_credit X Grant no more than this amount of credit to a result\n"
|
||||
" --update_credited_job Add record to credited_job table after granting credit\n"
|
||||
" --credit_from_wu Credit is specified in WU XML\n"
|
||||
" --credit_from_runtime X Grant credit based on runtime (max X seconds)and estimated FLOPS\n"
|
||||
" --no_credit Don't grant credit\n"
|
||||
" --sleep_interval n Set sleep-interval to n\n"
|
||||
" --wu_id n Process WU with given ID\n"
|
||||
" -d n, --debug_level n Set log verbosity level, 1-4\n"
|
||||
" -h | --help Show this\n"
|
||||
" -v | --version Show version information\n";
|
||||
|
||||
if (argc > 1) {
|
||||
if (is_arg(argv[1], "h") || is_arg(argv[1], "help")) {
|
||||
printf (usage, argv[0] );
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
} else if (is_arg(argv[1], "v") || is_arg(argv[1], "version")) {
|
||||
printf("%s\n", SVN_VERSION);
|
||||
|
@ -812,6 +825,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
check_stop_daemons();
|
||||
|
||||
int j=1;
|
||||
for (i=1; i<argc; i++) {
|
||||
if (is_arg(argv[i], "one_pass_N_WU")) {
|
||||
one_pass_N_WU = atoi(argv[++i]);
|
||||
|
@ -850,17 +864,16 @@ int main(int argc, char** argv) {
|
|||
wu_id = atoi(argv[++i]);
|
||||
one_pass = true;
|
||||
} else {
|
||||
//log_messages.printf(MSG_CRITICAL, "unrecognized arg: %s\n", argv[i]);
|
||||
// unknown arg - pass to handler
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
|
||||
if (app_name[0] == 0) {
|
||||
log_messages.printf(MSG_CRITICAL,
|
||||
"must use '--app' to specify an application\n"
|
||||
);
|
||||
printf (usage, argv[0] );
|
||||
usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -882,10 +895,6 @@ int main(int argc, char** argv) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
log_messages.printf(MSG_NORMAL,
|
||||
"Starting validator, debug level %d\n", log_messages.debug_level
|
||||
);
|
||||
|
||||
if (credit_from_runtime) {
|
||||
log_messages.printf(MSG_NORMAL,
|
||||
"using credit from runtime, max runtime: %f\n", max_runtime
|
||||
|
@ -908,6 +917,14 @@ int main(int argc, char** argv) {
|
|||
);
|
||||
}
|
||||
|
||||
argv[j] = 0;
|
||||
retval = validate_handler_init(j, argv);
|
||||
if (retval) exit(1);
|
||||
|
||||
log_messages.printf(MSG_NORMAL,
|
||||
"Starting validator, debug level %d\n", log_messages.debug_level
|
||||
);
|
||||
|
||||
install_stop_signal_handler();
|
||||
|
||||
main_loop();
|
||||
|
|
|
@ -24,6 +24,3 @@ extern WORKUNIT* g_wup;
|
|||
// A pointer to the WU currently being processed;
|
||||
// you can access this in your init_result() etc. functions
|
||||
// (which are passed RESULT but not WORKUNIT)
|
||||
|
||||
extern int g_argc;
|
||||
extern char** g_argv;
|
||||
|
|
|
@ -28,17 +28,25 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "svn_version.h"
|
||||
#include "sched_util_basic.h"
|
||||
#include "validate_util.h"
|
||||
#include "validate_util2.h"
|
||||
|
||||
int g_argc;
|
||||
char **g_argv;
|
||||
|
||||
void usage(char* prog) {
|
||||
fprintf(stderr,
|
||||
"usage: %s file1 file2\n", prog
|
||||
"This program is a test validator; \n"
|
||||
"You can test your custom handler with this\n"
|
||||
);
|
||||
exit(1);
|
||||
fprintf(stderr, "usage: %s [options] file1 file2\n"
|
||||
" Options:\n"
|
||||
" [-h|--help] Print this usage information and exit\n"
|
||||
" [-v|--version] Print version information and exit\n"
|
||||
" file1 Path to file to be compared (must be second to last)\n"
|
||||
" file2 Path to file to be compared (must be last)\n"
|
||||
"\n",
|
||||
prog);
|
||||
validate_handler_usage();
|
||||
}
|
||||
|
||||
int get_output_file_info(RESULT r, OUTPUT_FILE_INFO& fi) {
|
||||
|
@ -47,18 +55,34 @@ int get_output_file_info(RESULT r, OUTPUT_FILE_INFO& fi) {
|
|||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
int retval;
|
||||
|
||||
if (argc > 1) {
|
||||
if (is_arg(argv[1], "h") || is_arg(argv[1], "help")) {
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
} else if (is_arg(argv[1], "v") || is_arg(argv[1], "version")) {
|
||||
printf("%s\n", SVN_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
retval = validate_handler_init(argc, argv);
|
||||
if (retval) exit(1);
|
||||
|
||||
void* data1, *data2;
|
||||
RESULT r1, r2;
|
||||
bool match;
|
||||
|
||||
standalone = true;
|
||||
|
||||
sprintf(r1.xml_doc_in, "<file_ref><file_name>%s</file_name></file_ref>", argv[1]);
|
||||
sprintf(r2.xml_doc_in, "<file_ref><file_name>%s</file_name></file_ref>", argv[2]);
|
||||
int retval;
|
||||
sprintf(r1.xml_doc_in, "<file_ref><file_name>%s</file_name></file_ref>", argv[argc-2]);
|
||||
sprintf(r2.xml_doc_in, "<file_ref><file_name>%s</file_name></file_ref>", argv[argc-1]);
|
||||
|
||||
retval = init_result(r1, data1);
|
||||
if (retval) {
|
||||
fprintf(stderr, "init_result(r1) returned %d\n", retval);
|
||||
|
|
Loading…
Reference in New Issue