int main(int argc, char* argv[]) { Collectors = NULL; HistorySnapshot *historySnapshot; SQLQuery queryhor; SQLQuery queryver; QuillErrCode st; void **parameters; char *dbconn=NULL; bool readfromfile = false,remotequill=false; char *dbIpAddr=NULL, *dbName=NULL,*queryPassword=NULL,*quillName=NULL; AttrList *ad=0; int flag = 1; MyString tmp; int i; parameters = (void **) malloc(NUM_PARAMETERS * sizeof(void *)); myDistro->Init( argc, argv ); queryhor.setQuery(HISTORY_ALL_HOR, NULL); queryver.setQuery(HISTORY_ALL_VER, NULL); longformat=TRUE; for(i=1; i<argc; i++) { if(strcmp(argv[i], "-name")==0) { i++; if (argc <= i) { fprintf( stderr, "Error: Argument -name requires the name of a quilld as a parameter\n" ); exit(1); } if( !(quillName = get_daemon_name(argv[i])) ) { fprintf( stderr, "Error: unknown host %s\n", get_host_part(argv[i]) ); printf("\n"); print_wrapped_text("Extra Info: The name given with the -name " "should be the name of a condor_quilld process. " "Normally it is either a hostname, or " "\"name@hostname\". " "In either case, the hostname should be the " "Internet host name, but it appears that it " "wasn't.", stderr); exit(1); } tmp.sprintf ("%s == \"%s\"", ATTR_NAME, quillName); quillQuery.addORConstraint (tmp.Value()); tmp.sprintf ("%s == \"%s\"", ATTR_SCHEDD_NAME, quillName); quillQuery.addORConstraint (tmp.Value()); remotequill = true; readfromfile = false; } else if (strcmp(argv[i],"-help")==0) { Usage(argv[0],0); } } if (i<argc) Usage(argv[0]); config(); /* This call must happen AFTER config() is called */ if (checkDBconfig() == true && !readfromfile) { readfromfile = false; } else { /* couldn't get DB configuration, so bail out */ printf("Error: Cannot use DB to get history information\n"); exit(1); } if(readfromfile == false) { if(remotequill) { if (Collectors == NULL) { Collectors = CollectorList::create(); if(Collectors == NULL ) { printf("Error: Unable to get list of known collectors\n"); exit(1); } } result = Collectors->query ( quillQuery, quillList ); if(result != Q_OK) { printf("Fatal Error querying collectors\n"); exit(1); } if(quillList.MyLength() == 0) { printf("Error: Unknown quill server %s\n", quillName); exit(1); } quillList.Open(); while ((ad = quillList.Next())) { // get the address of the database dbIpAddr = dbName = queryPassword = NULL; if (!ad->LookupString(ATTR_QUILL_DB_IP_ADDR, &dbIpAddr) || !ad->LookupString(ATTR_QUILL_DB_NAME, &dbName) || !ad->LookupString(ATTR_QUILL_DB_QUERY_PASSWORD, &queryPassword) || (ad->LookupBool(ATTR_QUILL_IS_REMOTELY_QUERYABLE,flag) && !flag)) { printf("Error: The quill daemon \"%s\" is not set up " "for database queries\n", quillName); exit(1); } } } dbconn = getDBConnStr(quillName,dbIpAddr,dbName,queryPassword); historySnapshot = new HistorySnapshot(dbconn); //printf ("\n\n-- Quill: %s : %s : %s\n", quillName, dbIpAddr, dbName); st = historySnapshot->sendQuery(&queryhor, &queryver, longformat, true); //if there's a failure here and if we're not posing a query on a //remote quill daemon, we should instead query the local file if(st == QUILL_FAILURE) { printf( "-- Database at %s not reachable\n", dbIpAddr); } // query history table if (historySnapshot->isHistoryEmpty()) { printf("No historical jobs in the database\n"); } historySnapshot->release(); delete(historySnapshot); } if(parameters) free(parameters); if(dbIpAddr) free(dbIpAddr); if(dbName) free(dbName); if(queryPassword) free(queryPassword); if(quillName) free(quillName); if(dbconn) free(dbconn); return 0; }
void JobQueueDBManager::config(bool reconfig) { char *tmp; MyString sql_str; int bndcnt = 0; const char *data_arr[3]; QuillAttrDataType data_typ[3]; if (param_boolean("QUILL_ENABLED", false) == false) { EXCEPT("Quill++ is currently disabled. Please set QUILL_ENABLED to " "TRUE if you want this functionality and read the manual " "about this feature since it requires other attributes to be " "set properly."); } //bail out if no SPOOL variable is defined since its used to //figure out the location of the job_queue.log file char *spool = param("SPOOL"); if(!spool) { EXCEPT("No SPOOL variable found in config file\n"); } jobQueueLogFile = (char *) malloc(_POSIX_PATH_MAX * sizeof(char)); snprintf(jobQueueLogFile,_POSIX_PATH_MAX * sizeof(char), "%s/job_queue.log", spool); /* Here we try to read the database parameters in config the db ip address format is <ipaddress:port> */ dt = getConfigDBType(); jobQueueDBIpAddress = param("QUILL_DB_IP_ADDR"); jobQueueDBName = param("QUILL_DB_NAME"); jobQueueDBUser = param("QUILL_DB_USER"); jobQueueDBConn = getDBConnStr(jobQueueDBIpAddress, jobQueueDBName, jobQueueDBUser, spool); dprintf(D_ALWAYS, "Using Job Queue File %s\n", jobQueueLogFile); dprintf(D_ALWAYS, "Using Database Type = Postgres\n"); dprintf(D_ALWAYS, "Using Database IpAddress = %s\n", jobQueueDBIpAddress?jobQueueDBIpAddress:""); dprintf(D_ALWAYS, "Using Database Name = %s\n", jobQueueDBName?jobQueueDBName:""); dprintf(D_ALWAYS, "Using Database User = %s\n", jobQueueDBUser?jobQueueDBUser:""); if(spool) { free(spool); spool = NULL; } // this function is also called when condor_reconfig is issued // and so we dont want to recreate all essential objects if(!reconfig) { prober = new ClassAdLogProber(); caLogParser = new ClassAdLogParser(); switch (dt) { case T_PGSQL: DBObj = new PGSQLDatabase(jobQueueDBConn); break; default: break;; } xactState = NOT_IN_XACT; QuillErrCode ret_st; ret_st = DBObj->connectDB(); if (ret_st == QUILL_FAILURE) { displayErrorMsg("config: unable to connect to DB--- ERROR"); EXCEPT("config: unable to connect to DB\n"); } /* the following will also throw an exception if the schema version is not correct */ DBObj->assertSchemaVersion(); tmp = param( "SCHEDD_NAME" ); if( tmp ) { scheddname = build_valid_daemon_name( tmp ); dprintf(D_FULLDEBUG, "scheddname %s built from param value %s\n", scheddname, tmp); free(tmp); } else { scheddname = default_daemon_name(); dprintf(D_FULLDEBUG, "scheddname built from default daemon name: %s\n", scheddname); } { /* create an entry in jobqueuepollinginfo if this schedd is the * first time being logged to database */ sql_str.formatstr("INSERT INTO jobqueuepollinginfo (scheddname, last_file_mtime, last_file_size) SELECT '%s', 0, 0 FROM dummy_single_row_table WHERE NOT EXISTS (SELECT * FROM jobqueuepollinginfo WHERE scheddname = '%s')", scheddname, scheddname); ret_st = DBObj->execCommand(sql_str.Value()); if (ret_st == QUILL_FAILURE) { dprintf(D_ALWAYS, "Insert JobQueuePollInfo --- ERROR [SQL] %s\n", sql_str.Value()); } } { /* create an entry in currency table if this schedd is the first * time being logged to database */ sql_str.formatstr("INSERT INTO currencies (datasource) SELECT '%s' FROM dummy_single_row_table WHERE NOT EXISTS (SELECT * FROM currencies WHERE datasource = '%s')", scheddname, scheddname); ret_st = DBObj->execCommand(sql_str.Value()); if (ret_st == QUILL_FAILURE) { dprintf(D_ALWAYS, "Insert Currency --- ERROR [SQL] %s\n", sql_str.Value()); } } ret_st = DBObj->commitTransaction(); if (ret_st == QUILL_FAILURE) { dprintf(D_ALWAYS, "Commit transaction failed in JobQueueDBManager::config\n"); } if (param_boolean("QUILL_MAINTAIN_DB_CONN", true) == false) { ret_st = DBObj->disconnectDB(); if (ret_st == QUILL_FAILURE) { dprintf(D_ALWAYS, "JobQueueDBManager:config: unable to disconnect database --- ERROR\n"); } } } //this function assumes that certain members have been initialized // (specifically prober and caLogParser) and so the order is important. setJobQueueFileName(jobQueueLogFile); }
int main(int argc, char* argv[]) { Collectors = NULL; #ifdef HAVE_EXT_POSTGRESQL HistorySnapshot *historySnapshot; SQLQuery queryhor; SQLQuery queryver; QuillErrCode st; bool remotequill=false; char *quillName=NULL; AttrList *ad=0; int flag = 1; void **parameters; char *dbconn=NULL; char *completedsince = NULL; char *dbIpAddr=NULL, *dbName=NULL,*queryPassword=NULL; bool remoteread = false; #endif /* HAVE_EXT_POSTGRESQL */ const char *owner=NULL; bool readfromfile = true; bool fileisuserlog = false; char* JobHistoryFileName=NULL; const char * pcolon=NULL; GenericQuery constraint; // used to build a complex constraint. ExprTree *constraintExpr=NULL; std::string tmp; int i; myDistro->Init( argc, argv ); config(); #ifdef HAVE_EXT_POSTGRESQL parameters = (void **) malloc(NUM_PARAMETERS * sizeof(void *)); queryhor.setQuery(HISTORY_ALL_HOR, NULL); queryver.setQuery(HISTORY_ALL_VER, NULL); #endif /* HAVE_EXT_POSTGRESQL */ for(i=1; i<argc; i++) { if (is_dash_arg_prefix(argv[i],"long",1)) { longformat=TRUE; } else if (is_dash_arg_prefix(argv[i],"xml",3)) { use_xml = true; longformat = true; } else if (is_dash_arg_prefix(argv[i],"backwards",1)) { backwards=TRUE; } // must be at least -forw to avoid conflict with -f (for file) and -format else if (is_dash_arg_prefix(argv[i],"nobackwards",3) || is_dash_arg_prefix(argv[i],"forwards",4)) { backwards=FALSE; } else if (is_dash_arg_colon_prefix(argv[i],"wide", &pcolon, 1)) { wide_format=TRUE; if (pcolon) { wide_format_width = atoi(++pcolon); if ( ! mask.IsEmpty()) mask.SetOverallWidth(getDisplayWidth()-1); if (wide_format_width <= 80) wide_format = FALSE; } } else if (is_dash_arg_prefix(argv[i],"match",1) || is_dash_arg_prefix(argv[i],"limit",3)) { i++; if (argc <= i) { fprintf(stderr, "Error: Argument -match requires a number value " " as a parameter.\n"); exit(1); } specifiedMatch = atoi(argv[i]); } #ifdef HAVE_EXT_POSTGRESQL else if(is_dash_arg_prefix(argv[i], "dbname",1)) { i++; if (argc <= i) { fprintf( stderr, "Error: Argument -dbname requires the name of a quilld as a parameter\n" ); exit(1); } /* if( !(quillName = get_daemon_name(argv[i])) ) { fprintf( stderr, "Error: unknown host %s\n", get_host_part(argv[i]) ); printf("\n"); print_wrapped_text("Extra Info: The name given with the -dbname " "should be the name of a condor_quilld process. " "Normally it is either a hostname, or " "\"name@hostname\". " "In either case, the hostname should be the " "Internet host name, but it appears that it " "wasn't.", stderr); exit(1); } sprintf (tmp, "%s == \"%s\"", ATTR_NAME, quillName); quillQuery.addORConstraint (tmp); */ quillName = argv[i]; sprintf (tmp, "%s == \"%s\"", ATTR_SCHEDD_NAME, quillName); quillQuery.addORConstraint (tmp.c_str()); remotequill = false; readfromfile = false; } #endif /* HAVE_EXT_POSTGRESQL */ else if (is_dash_arg_prefix(argv[i],"file",2)) { if (i+1==argc || JobHistoryFileName) break; i++; JobHistoryFileName=argv[i]; readfromfile = true; } else if (is_dash_arg_prefix(argv[i],"userlog",1)) { if (i+1==argc || JobHistoryFileName) break; i++; JobHistoryFileName=argv[i]; readfromfile = true; fileisuserlog = true; } else if (is_dash_arg_prefix(argv[i],"help",1)) { Usage(argv[0],0); } else if (is_dash_arg_prefix(argv[i],"format",1)) { if (argc <= i + 2) { fprintf(stderr, "Error: Argument -format requires a spec and " "classad attribute name as parameters.\n"); fprintf(stderr, "\t\te.g. condor_history -format '%%d' ClusterId\n"); exit(1); } mask.registerFormat(argv[i + 1], argv[i + 2]); customFormat = true; i += 2; } else if (*(argv[i]) == '-' && (is_arg_colon_prefix(argv[i]+1,"af", &pcolon, 2) || is_arg_colon_prefix(argv[i]+1,"autoformat", &pcolon, 5))) { // make sure we have at least one argument to autoformat if (argc <= i+1 || *(argv[i+1]) == '-') { fprintf (stderr, "Error: Argument %s requires at last one attribute parameter\n", argv[i]); fprintf(stderr, "\t\te.g. condor_history %s ClusterId\n", argv[i]); exit(1); } if (pcolon) ++pcolon; // if there are options, skip over the colon to the options. int ixNext = parse_autoformat_args(argc, argv, i+1, pcolon, mask, diagnostic); if (ixNext > i) i = ixNext-1; customFormat = true; } else if (is_dash_arg_colon_prefix(argv[i], "print-format", &pcolon, 2)) { if ( (argc <= i+1) || (*(argv[i+1]) == '-' && (argv[i+1])[1] != 0)) { fprintf( stderr, "Error: Argument -print-format requires a filename argument\n"); exit( 1 ); } // hack allow -pr ! to disable use of user-default print format files. if (MATCH == strcmp(argv[i+1], "!")) { ++i; disable_user_print_files = true; continue; } if ( ! wide_format) mask.SetOverallWidth(getDisplayWidth()-1); customFormat = true; ++i; std::string where_expr; if (set_print_mask_from_stream(mask, where_expr, argv[i], true) < 0) { fprintf(stderr, "Error: cannot execute print-format file %s\n", argv[i]); exit (1); } if ( ! where_expr.empty()) { constraint.addCustomAND(where_expr.c_str()); } } else if (is_dash_arg_prefix(argv[i],"constraint",1)) { // make sure we have at least one more argument if (argc <= i+1) { fprintf( stderr, "Error: Argument %s requires another parameter\n", argv[i]); exit(1); } i++; constraint.addCustomAND(argv[i]); } #ifdef HAVE_EXT_POSTGRESQL else if (is_dash_arg_prefix(argv[i],"completedsince",3)) { i++; if (argc <= i) { fprintf(stderr, "Error: Argument -completedsince requires a date and " "optional timestamp as a parameter.\n"); fprintf(stderr, "\t\te.g. condor_history -completedsince \"2004-10-19 10:23:54\"\n"); exit(1); } if (constraint!="") break; completedsince = strdup(argv[i]); parameters[0] = completedsince; queryhor.setQuery(HISTORY_COMPLETEDSINCE_HOR,parameters); queryver.setQuery(HISTORY_COMPLETEDSINCE_VER,parameters); } #endif /* HAVE_EXT_POSTGRESQL */ else if (sscanf (argv[i], "%d.%d", &cluster, &proc) == 2) { std::string jobconst; formatstr (jobconst, "%s == %d && %s == %d", ATTR_CLUSTER_ID, cluster,ATTR_PROC_ID, proc); constraint.addCustomOR(jobconst.c_str()); #ifdef HAVE_EXT_POSTGRESQL parameters[0] = &cluster; parameters[1] = &proc; queryhor.setQuery(HISTORY_CLUSTER_PROC_HOR, parameters); queryver.setQuery(HISTORY_CLUSTER_PROC_VER, parameters); #endif /* HAVE_EXT_POSTGRESQL */ } else if (sscanf (argv[i], "%d", &cluster) == 1) { std::string jobconst; formatstr (jobconst, "%s == %d", ATTR_CLUSTER_ID, cluster); constraint.addCustomOR(jobconst.c_str()); #ifdef HAVE_EXT_POSTGRESQL parameters[0] = &cluster; queryhor.setQuery(HISTORY_CLUSTER_HOR, parameters); queryver.setQuery(HISTORY_CLUSTER_VER, parameters); #endif /* HAVE_EXT_POSTGRESQL */ } else if (is_dash_arg_prefix(argv[i],"debug",1)) { // dprintf to console dprintf_set_tool_debug("TOOL", 0); } else if (is_dash_arg_prefix(argv[i],"diagnostic",4)) { // dprintf to console diagnostic = true; } else if (is_dash_arg_prefix(argv[i], "name", 1)) { i++; if (argc <= i) { fprintf(stderr, "Error: Argument -name requires name of a remote schedd\n"); fprintf(stderr, "\t\te.g. condor_history -name submit.example.com \n"); exit(1); } g_name = argv[i]; readfromfile = false; #ifdef HAVE_EXT_POSTGRESQL remoteread = true; #endif } else if (is_dash_arg_prefix(argv[i], "pool", 1)) { i++; if (argc <= i) { fprintf(stderr, "Error: Argument -name requires name of a remote schedd\n"); fprintf(stderr, "\t\te.g. condor_history -name submit.example.com \n"); exit(1); } g_pool = argv[i]; readfromfile = false; #ifdef HAVE_EXT_POSTGRESQL remoteread = true; #endif } else { std::string ownerconst; owner = argv[i]; formatstr(ownerconst, "%s == \"%s\"", ATTR_OWNER, owner); constraint.addCustomOR(ownerconst.c_str()); #ifdef HAVE_EXT_POSTGRESQL parameters[0] = owner; queryhor.setQuery(HISTORY_OWNER_HOR, parameters); queryver.setQuery(HISTORY_OWNER_VER, parameters); #endif /* HAVE_EXT_POSTGRESQL */ } } if (i<argc) Usage(argv[0]); MyString my_constraint; constraint.makeQuery(my_constraint); if (diagnostic) { fprintf(stderr, "Using effective constraint: %s\n", my_constraint.c_str()); } if ( ! my_constraint.empty() && ParseClassAdRvalExpr( my_constraint.c_str(), constraintExpr ) ) { fprintf( stderr, "Error: could not parse constraint %s\n", my_constraint.c_str() ); exit( 1 ); } #ifdef HAVE_EXT_POSTGRESQL /* This call must happen AFTER config() is called */ if (checkDBconfig() == true && !readfromfile) { readfromfile = false; } else { readfromfile = true; } #endif /* HAVE_EXT_POSTGRESQL */ #ifdef HAVE_EXT_POSTGRESQL if(!readfromfile && !remoteread) { if(remotequill) { if (Collectors == NULL) { Collectors = CollectorList::create(); if(Collectors == NULL ) { printf("Error: Unable to get list of known collectors\n"); exit(1); } } result = Collectors->query ( quillQuery, quillList ); if(result != Q_OK) { printf("Fatal Error querying collectors\n"); exit(1); } if(quillList.MyLength() == 0) { printf("Error: Unknown quill server %s\n", quillName); exit(1); } quillList.Open(); while ((ad = quillList.Next())) { // get the address of the database dbIpAddr = dbName = queryPassword = NULL; if (!ad->LookupString(ATTR_QUILL_DB_IP_ADDR, &dbIpAddr) || !ad->LookupString(ATTR_QUILL_DB_NAME, &dbName) || !ad->LookupString(ATTR_QUILL_DB_QUERY_PASSWORD, &queryPassword) || (ad->LookupBool(ATTR_QUILL_IS_REMOTELY_QUERYABLE,flag) && !flag)) { printf("Error: The quill daemon \"%s\" is not set up " "for database queries\n", quillName); exit(1); } } } else { // they just typed 'condor_history' on the command line and want // to use quill, so get the schedd ad for the local machine if // we can, figure out the name of the schedd and the // jobqueuebirthdate Daemon schedd( DT_SCHEDD, 0, 0 ); if ( schedd.locate(Daemon::LOCATE_FULL) ) { char *scheddname = quillName; if (scheddname == NULL) { // none set explictly, look it up in the daemon ad scheddname = schedd.name(); ClassAd *daemonAd = schedd.daemonAd(); int scheddbirthdate; if(daemonAd) { if(daemonAd->LookupInteger( ATTR_JOB_QUEUE_BIRTHDATE, scheddbirthdate) ) { queryhor.setJobqueuebirthdate( (time_t)scheddbirthdate); queryver.setJobqueuebirthdate( (time_t)scheddbirthdate); } } } else { queryhor.setJobqueuebirthdate(0); queryver.setJobqueuebirthdate(0); } queryhor.setScheddname(scheddname); queryver.setScheddname(scheddname); } } dbconn = getDBConnStr(quillName,dbIpAddr,dbName,queryPassword); historySnapshot = new HistorySnapshot(dbconn); if (!customFormat) { printf ("\n\n-- Quill: %s : %s : %s\n", quillName, dbIpAddr, dbName); } queryhor.prepareQuery(); // create the query strings before sending off to historySnapshot queryver.prepareQuery(); st = historySnapshot->sendQuery(&queryhor, &queryver, longformat, false, customFormat, &mask, constraint.c_str()); //if there's a failure here and if we're not posing a query on a //remote quill daemon, we should instead query the local file if(st == QUILL_FAILURE) { printf( "-- Database at %s not reachable\n", dbIpAddr); if(!remotequill) { char *tmp_hist = param("HISTORY"); if (!customFormat) { printf( "--Failing over to the history file at %s instead --\n", tmp_hist ? tmp_hist : "(null)" ); } if(!tmp_hist) { free(tmp_hist); } readfromfile = true; } } // query history table if (historySnapshot->isHistoryEmpty()) { printf("No historical jobs in the database match your query\n"); } historySnapshot->release(); delete(historySnapshot); } #endif /* HAVE_EXT_POSTGRESQL */ if(readfromfile == true) { readHistoryFromFiles(fileisuserlog, JobHistoryFileName, my_constraint.c_str(), constraintExpr); } else { readHistoryRemote(constraintExpr); } #ifdef HAVE_EXT_POSTGRESQL if(completedsince) free(completedsince); if(parameters) free(parameters); if(dbIpAddr) free(dbIpAddr); if(dbName) free(dbName); if(queryPassword) free(queryPassword); if(dbconn) free(dbconn); #endif return 0; }