diff --git a/dcapi/Makefile.am b/dcapi/Makefile.am new file mode 100644 index 0000000000..2c7210b394 --- /dev/null +++ b/dcapi/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = include common + +if WITH_BOINC +SUBDIRS += boinc +endif + +if WITH_CLGR +SUBDIRS += clgr +endif + +if WITH_LOCAL +SUBDIRS += local +endif diff --git a/dcapi/boinc/Makefile b/dcapi/boinc/Makefile deleted file mode 100644 index 059da0a729..0000000000 --- a/dcapi/boinc/Makefile +++ /dev/null @@ -1,27 +0,0 @@ - -#CC=cc -n32 -g -Xcpluscomm -#CC=gcc-3.4 -g -#CPP=g++-3.4 -g -CC=gcc -g -CPP=g++ -g -AR=ar -RANLIB=ranlib - -# User configurable items -BOINC=../../boinc -MYSQL_INC=/sw/include/mysql - -INC=-I../include -I/usr/local/include -BOINC_INC=-I${BOINC}/tools -I${BOINC}/sched -I${BOINC}/db -I${BOINC}/lib -I${MYSQL_INC} - -all: - ${CC} -c -Wall dc.c cfg.c logger.c result.c ${INC} - $(CPP) -c -Wall validate_util.C ${INC} ${BOINC_INC} - ${CPP} -c -Wall wu.C assimilator.C ${INC} ${BOINC_INC} - ${AR} rc libdc-boinc-local.a dc.o cfg.o logger.o result.o wu.o assimilator.o validate_util.o - ${RANLIB} libdc-boinc-local.a - -clean: - rm -rf core *~ *.o libdc-boinc-local.a - - diff --git a/dcapi/boinc/Makefile.am b/dcapi/boinc/Makefile.am new file mode 100644 index 0000000000..062bbb4231 --- /dev/null +++ b/dcapi/boinc/Makefile.am @@ -0,0 +1,18 @@ +lib_LTLIBRARIES = libdc-boinc.la + +AM_CPPFLAGS = -I$(top_srcdir)/common $(BOINC_CPPFLAGS) $(MYSQL_CPPFLAGS) + +libdc_boinc_la_SOURCES = \ + assimilator.C \ + assimilator.h \ + dc.c \ + result.c \ + result.h \ + validate_util.C \ + validate_util.h \ + wu.C \ + wu.h +libdc_boinc_la_LIBADD = \ + ../common/libdc-common.la \ + $(BOINC_LIBS) \ + $(MYSQL_LIBS) diff --git a/dcapi/boinc/cfg.h b/dcapi/boinc/cfg.h deleted file mode 100644 index 7f3bbc7a91..0000000000 --- a/dcapi/boinc/cfg.h +++ /dev/null @@ -1,27 +0,0 @@ - -#define DC_CFG_OK 0 -#define DC_CFG_FILENOTEXISTS 1 - -/** Parse the config file and store name=value pairs in memory - * - */ -int dc_cfg_parse(const char *cfgfile); - -/** Get a value for a given name - * - */ -char * dc_cfg_get(char *name); - -#define DC_CFG_OK 0 -#define DC_CFG_FILENOTEXISTS 1 -#define DC_CFG_OUTOFMEM 2 - -/** Parse the config file and store name=value pairs in memory - * - */ -int dc_cfg_parse(const char *cfgfile); - -/** Get a value for a given name - * - */ -char * dc_cfg_get(char *name); diff --git a/dcapi/boinc/logger.c b/dcapi/boinc/logger.c deleted file mode 100644 index 4402316381..0000000000 --- a/dcapi/boinc/logger.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "cfg.h" -#include "dc.h" - -static int loglevel = -1; -static FILE *logfile; - -static const char *levels[] = -{ - [LOG_DEBUG] = "Debug", - [LOG_INFO] = "Info", - [LOG_NOTICE] = "Notice", - [LOG_WARNING] = "Warning", - [LOG_ERR] = "Error" -}; - -static void init_log(void) -{ - char *val; - - /* Default level */ - loglevel = LOG_NOTICE; - - val = dc_cfg_get("LogLevel"); - if (val) - { - if (val[0] >= '0' && val[0] <= '9') - loglevel = atoi(val); - else - { - int i; - - for (i = 0; i < (int)sizeof(levels) / sizeof(levels[0]); i++) - { - if (levels[i] && !strcasecmp(levels[i], val)) - { - loglevel = i; - break; - } - } - } - } - - val = dc_cfg_get("LogFile"); - if (val) - { - logfile = fopen(val, "a"); - if (!logfile) - { - fprintf(stderr, "Failed to open the log file %s: %s", - val, strerror(errno)); - exit(1); - } - } - else - logfile = stdout; -} - -void DC_log(int level, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - DC_vlog(level, fmt, ap); - va_end(ap); -} - -void DC_vlog(int level, const char *fmt, va_list ap) -{ - const char *levstr; - char timebuf[32]; - struct tm *tm; - time_t now; - - if (loglevel < 0) - init_log(); - if (level > loglevel) - return; - - if (level >= 0 && level < sizeof(levels) / sizeof(levels[0]) && levels[level]) - levstr = levels[level]; - else - levstr = "Unknown"; - - now = time(NULL); - tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm); - - fprintf(logfile, "%s [%s] ", timebuf, levstr); - vfprintf(logfile, fmt, ap); - fprintf(logfile, "\n"); - fflush(logfile); -} diff --git a/dcapi/boinc/validate_util.C b/dcapi/boinc/validate_util.C index 37c2faadff..1ce998c8b5 100644 --- a/dcapi/boinc/validate_util.C +++ b/dcapi/boinc/validate_util.C @@ -34,6 +34,11 @@ #include #include +// Compatibility with Boinc 4.x +#if BOINC_VERSION == 4 +#define MSG_CRITICAL CRITICAL +#endif + using std::vector; using std::string; @@ -47,10 +52,15 @@ int get_output_file_path(RESULT const& result, string& path_str) { if (!parse_str(result.xml_doc_out, "", buf, sizeof(buf))) { return ERR_XML_PARSE; } - dir_hier_path(buf, config.upload_dir, config.uldl_dir_fanout, path, true); - if (!boinc_file_exists(path)) { - dir_hier_path(buf, config.upload_dir, config.uldl_dir_fanout, false, path); - } + +#if BOINC_VERSION == 4 + dir_hier_path(buf, config.upload_dir, config.uldl_dir_fanout, true, path); + if (!boinc_file_exists(path)) + dir_hier_path(buf, config.upload_dir, config.uldl_dir_fanout, false, path); +#else + dir_hier_path(buf, config.upload_dir, config.uldl_dir_fanout, path); +#endif + path_str = path; return 0; } diff --git a/dcapi/boinc/wu.C b/dcapi/boinc/wu.C index b140c45a6e..6786a137e2 100644 --- a/dcapi/boinc/wu.C +++ b/dcapi/boinc/wu.C @@ -11,11 +11,13 @@ #include #include //#include +#include #include "dc.h" #include "wu.h" #include "result.h" +extern SCHED_CONFIG config; /* PRIVATE */ @@ -177,7 +179,11 @@ int dc_wu_setInput(DC_Workunit wu, const char *url, const char* localfilename) // snprintf(downloadpath, 256, "%s/download/%s", dc_projectRootDir, downloadfilename); snprintf(download_dir, 256, "%s/download", dc_projectRootDir); - dir_hier_path(downloadfilename, download_dir, 1024, downloadpath, true); +#if BOINC_VERSION == 4 + dir_hier_path(downloadfilename, download_dir, config.uldl_dir_fanout, true, downloadpath, true); +#else + dir_hier_path(downloadfilename, download_dir, config.uldl_dir_fanout, downloadpath, true); +#endif snprintf(syscmd, 1024, "cp %s %s", url, downloadpath); DC_log(LOG_DEBUG, "system command: '%s'", syscmd); diff --git a/dcapi/clgr/Makefile.am b/dcapi/clgr/Makefile.am new file mode 100644 index 0000000000..436f5c8633 --- /dev/null +++ b/dcapi/clgr/Makefile.am @@ -0,0 +1,21 @@ +lib_LTLIBRARIES = libdc-clgr.la + +AM_CPPFLAGS = -I$(top_srcdir)/common + +libdc_clgr_la_SOURCES = \ + dc.c \ + dc_client.c \ + defines.h \ + get_out.c \ + get_out.h \ + remove.c \ + remove.h \ + result.c \ + result.h \ + status.c \ + status.h \ + submit.c \ + submit.h \ + wu.C \ + wu.h +libdc_clgr_la_LIBADD = ../common/libdc-common.la diff --git a/dcapi/clgr/dc.c b/dcapi/clgr/dc.c new file mode 100644 index 0000000000..a26b3793a4 --- /dev/null +++ b/dcapi/clgr/dc.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dc.h" +#include "cfg.h" +#include "wu.h" +//#include "assimilator.h" +#include "result.h" + +static char *projectname; /* project name under boinc */ +static char *appname; /* name of the application, used here in assimilation */ +static char *workdir; /* a working dir for this application */ +static char *executabledir; /* the executable file, with path */ +//static char *boincprojectrootdir; /* where projects are stored, e.g. /usr/boinc/projects */ +//static char *wutemplate; /* path and file name */ +//static char *resulttemplate; /* path and file name */ +//static char *uploadkeyfile; /* upload private key file */ +static char yesno[2][4] = {"no", "yes"}; + +static char *sleepinterval; + +/* CONSTRAINTS + + 1. One application client is supported (because of assimilation) + Client name is defined for each WU separately in the API + At DC_init, this one client name should be given as application_name. + + 2. One workunit and one result templates are supported, given in the config file. + +*/ +int DC_init(const char *project_name, const char *application_name, const char *configfile) +{ + char buf[512]; //, syscmd[2048]; + time_t ltime; + + projectname = strdup(project_name); + appname = strdup(application_name); + + if (dc_cfg_parse(configfile) != DC_CFG_OK) return DC_ERROR; + workdir = dc_cfg_get("WorkingDirectory"); + executabledir = dc_cfg_get("Executabledir"); + //boincprojectrootdir = dc_cfg_get("BoincProjectRootDirectory"); + //wutemplate = dc_cfg_get("WUTemplatePath"); + //resulttemplate = dc_cfg_get("ResultTemplatePath"); + //uploadkeyfile = dc_cfg_get("UploadPrivateKey"); + sleepinterval = dc_cfg_get("CheckResultSleepInterval"); + + if (workdir == NULL) { + DC_log(LOG_ERR, + "Working directory cannot be determined from the config file"); + return DC_ERROR; + } + + if (executabledir == NULL) { + DC_log(LOG_ERR, + "Executable file cannot be determined from the config file"); + return DC_ERROR; + } +/* + if (boincprojectrootdir == NULL) { + DC_log(LOG_ERR, + "BOINC project root directory cannot be determined from the config file"); + return DC_ERROR; + } + + if (wutemplate == NULL) { + DC_log(LOG_ERR, + "Template file for Workunit cannot be determined from the config file"); + return DC_ERROR; + } + + if (resulttemplate == NULL) { + DC_log(LOG_ERR, + "Template file for Result cannot be determined from the config file"); + return DC_ERROR; + } + + if (uploadkeyfile == NULL) { + DC_log(LOG_ERR, + "Upload private key file cannot be determined from the config file"); + return DC_ERROR; + } +*/ + if (sleepinterval == NULL) { + DC_log(LOG_ERR, + "Check for Result sleeping interval cannot be determined from the config file\nDefault value is 5 sec."); + strcpy(sleepinterval,"5"); + //return DC_ERROR; + } + + + + DC_log(LOG_DEBUG, "init: WorkingDir=%s", workdir); + DC_log(LOG_DEBUG, "init: Executabledir=%s", executabledir); +// DC_log(LOG_DEBUG, "init: Boinc Project Root Dir=%s", boincprojectrootdir); +// DC_log(LOG_DEBUG, "init: Template WU=%s", wutemplate); +// DC_log(LOG_DEBUG, "init: Template Result=%s", resulttemplate); +// DC_log(LOG_DEBUG, "init: Upload private key file=%s", uploadkeyfile); + DC_log(LOG_DEBUG, "init: Check Result sleeping interval=%s", sleepinterval); + + + /* Check config.xml in project's directory */ +/* snprintf(buf, 512, "%s/%s/config.xml", boincprojectrootdir, project_name); + if (access(buf, R_OK)) { + DC_log(LOG_ERR, + "Invalid project name, not valid configuration found: %s, error = %d %s", + buf, errno, strerror(errno)); + return DC_ERROR; + } +*/ + /* Copy template files into project's template/ dir. */ +/* snprintf(buf, 512, "%s/%s/templates", boincprojectrootdir, project_name); + snprintf(syscmd, 1024, "cp %s %s", resulttemplate, buf); + if (system(syscmd) == -1) { + DC_log(LOG_ERR, + "Cannot copy result template files into project's template/ dir.\n" + "Command '%s' failed.", syscmd); + return DC_ERROR; + } +*/ +// snprintf(buf, 512, "%s/%s", boincprojectrootdir, project_name); +// dc_wu_init(buf, uploadkeyfile); /* init WU manager */ + snprintf(buf, 512, "%s_%s_%ld", project_name, appname, time(<ime)); + + dc_wu_init(workdir, buf, executabledir); + + return DC_OK; +} + + +DC_Workunit DC_createWU (const char *application_client, + const char *arguments) +{ +// char dir[256]; + + + /* char inpf[256], syscmd[1024]; */ + + /* Create working directory for WU + / + */ +/* + snprintf(dir, 256, "%s/%s/%d", workdir, projectname, wundx); + DC_log(LOG_DEBUG, "Create WU in %s", dir); + if (mkdir(dir, S_IRWXU+S_IRGRP)) { + if (errno != 17) { // 17=directory exists + DC_log(LOG_ERR, + "Cannot create directory %s: %s", + dir, strerror(errno)); + return -1; + } + else { + + // errno 17: File exists + // Here should be checked if + // - it is a directory and + // - we can read/write into it + // + } + } +*/ + + return dc_wu_create(application_client, arguments); + + +} + + +int DC_setInput (DC_Workunit wu, char * URL, char * localFileName) +{ + + return dc_wu_setInput(wu, URL, localFileName); + +} + + +int DC_setPriority (DC_Workunit wu, int priority) +{ + return dc_wu_setPriority(wu, priority); +} + + +int DC_submitWU (DC_Workunit wu) +{ + //char boincRootDir[256]; + //snprintf(boincRootDir, 512, "%s/%s", boincprojectrootdir, projectname); + //return dc_wu_createBoincWU(wu, uploadkeyfile, boincRootDir); + return dc_wu_submitWU(wu); +} + +int DC_cancelWU (DC_Workunit wu) +{ + printf("DC_cancelWU is not implemented yet"); + return 1; +} + +int DC_destroyWU(DC_Workunit wu) +{ + return dc_wu_destroy(wu); +} + +int DC_suspendWU(DC_Workunit wu) +{ + return dc_wu_suspend(wu); +} + +int DC_resubmitWU(DC_Workunit wu) +{ + return dc_wu_resubmit(wu); +} + + +int DC_checkForResult(int timeout, + void (*cb_assimilate_result)(DC_Result result) + ) +{ + int retval; + int ex = 0; + int sleeptime = atoi(sleepinterval); + time_t tstart = time(NULL); +// static int initialized = 0; + //char buf[512]; + + if (sleeptime < 1) sleeptime = 1; + + DC_log(LOG_INFO, "Check for results, blocking=%s, sleep_interval=%d", + yesno[timeout>=0], sleeptime); + +/* + if (!initialized) { + snprintf(buf, 512, "%s/%s", boincprojectrootdir, projectname); + dc_assimilator_init(buf, appname); // init assimilator + initialized = 1; + } +*/ + + while (!ex) { + ex = 1; + DC_log(LOG_DEBUG, "Call dc_assimilator_dopass()"); + //retval = dc_assimilator_dopass(cb_assimilate_result); + retval = dc_wu_checkForResult(cb_assimilate_result); + if (retval == 0 && timeout == 0) /* no result and waiting forever */ + ex = 0; + if (retval == 0 && /* no result found yet */ + timeout > 0 && /* blocking mode */ + time(NULL) < tstart+timeout /* timeout (>0) not exceeded */ + ) ex = 0; + if (!ex) sleep(sleeptime); + } + if (retval == -1) return DC_ERROR; + else return DC_OK; +} + + + diff --git a/dcapi/clgr/dc_client.c b/dcapi/clgr/dc_client.c new file mode 100644 index 0000000000..17a9227421 --- /dev/null +++ b/dcapi/clgr/dc_client.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dc_client.h" +#include "dc.h" + +static time_t result_time = 0; +static time_t ckpt_time = 0; +static char statfilename[] = "job_out_stats.dat"; + + +/* Print out result_time and ckpt_time in the format "%d %d" + * into the file 'statfilename' + * ClusterGrid infrastructure takes care of delivering information + * up to the information system so that job status query results in + * subresult_time =