#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include static Arc::Logger logger(Arc::Logger::rootLogger, "arc-blahp-logger"); static void usage(char *pname) { logger.msg(Arc::ERROR,"Usage: %s -I -U -P -L [-c ] [-p ] [-d ]", pname); } int main(int argc, char *argv[]) { int opt; const char *user_proxy_f = NULL; const char *job_local_f = NULL; const char *jobid_s = NULL; const char *user_s = NULL; const char *ceid_s = NULL; std::string logprefix = "/var/log/arc/accounting/blahp.log"; // log Arc::LogLevel debuglevel = Arc::ERROR; Arc::LogStream logcerr(std::cerr); Arc::Logger::getRootLogger().addDestination(logcerr); Arc::Logger::getRootLogger().setThreshold(debuglevel); // Parse command line options while ((opt = getopt(argc, argv, "I:U:P:L:c:p:d:")) != -1) { switch (opt) { case 'I': jobid_s = optarg; break; case 'U': user_s = optarg; break; case 'P': user_proxy_f = optarg; break; case 'L': job_local_f = optarg; break; case 'c': ceid_s = optarg; break; case 'p': logprefix = std::string(optarg); break; case 'd': debuglevel = Arc::old_level_to_level(atoi(optarg)); Arc::Logger::getRootLogger().setThreshold(debuglevel); break; default: usage(argv[0]); return EXIT_FAILURE; } } if ( !jobid_s ) { logger.msg(Arc::ERROR,"Job ID argument is required."); usage(argv[0]); return EXIT_FAILURE; } if ( !user_proxy_f ) { logger.msg(Arc::ERROR,"Path to user's proxy file should be specified."); usage(argv[0]); return EXIT_FAILURE; } if ( !user_s ) { logger.msg(Arc::ERROR,"User name should be specified."); usage(argv[0]); return EXIT_FAILURE; } if ( !job_local_f ) { logger.msg(Arc::ERROR,"Path to .local job status file is required."); usage(argv[0]); return EXIT_FAILURE; } // Get or generate ceID prefix std::string ceid; if ( !ceid_s ) { logger.msg(Arc::DEBUG,"Generating ceID prefix from hostname automatically"); char host[256]; if (gethostname(host, sizeof(host)) != 0) { logger.msg(Arc::ERROR, "Cannot determine hostname from gethostname() to generate ceID automatically."); return EXIT_FAILURE; } else { host[sizeof(host)-1] = 0; ceid = std::string(host) + ":2811/nordugrid-torque"; } } else { ceid = std::string(ceid_s); } logger.msg(Arc::DEBUG,"ceID prefix is set to %s", ceid); // Get the current timestamp for log and logsuffix Arc::SetEnv("TZ","UTC"); tzset(); Arc::Time exectime; std::string timestamp = exectime.str(Arc::UserTime); std::string logsuffix = exectime.str(Arc::MDSTime).substr(0,8); logger.msg(Arc::DEBUG,"Getting currect timestamp for BLAH parser log: %s", timestamp); // Parse .local file to get required information std::string globalid; std::string localid; std::string queue; std::string subject; std::string interface; std::string headnode; logger.msg(Arc::DEBUG,"Parsing .local file to obtain job-specific identifiers and info"); std::ifstream job_local; job_local.open(job_local_f, std::ios::in); if ( job_local.is_open() ) { std::string line; while ( job_local.good() ) { getline(job_local,line); if ( ! line.compare(0,9,"globalid=") ) { globalid = line.substr(9); logger.msg(Arc::DEBUG,"globalid is set to %s", globalid); } else if ( ! line.compare(0,9,"headnode=") ) { headnode = line.substr(9); logger.msg(Arc::DEBUG,"headnode is set to %s", headnode); } else if ( ! line.compare(0,10,"interface=") ) { interface = line.substr(10); logger.msg(Arc::DEBUG,"interface is set to %s", interface); } else if ( ! line.compare(0,8,"localid=") ) { localid = line.substr(8); if ( localid.empty() ) { logger.msg(Arc::ERROR,"There is no local LRMS ID. Message will not be written to BLAH log."); return EXIT_FAILURE; } logger.msg(Arc::DEBUG,"localid is set to %s", localid); } else if ( ! line.compare(0,6,"queue=") ) { queue = line.substr(6); logger.msg(Arc::DEBUG,"queue name is set to %s", queue); } else if ( ! line.compare(0,8,"subject=") ) { subject = line.substr(8); logger.msg(Arc::DEBUG,"owner subject is set to %s", subject); } else if ( ! line.compare(0,12,"failedstate=") ) { logger.msg(Arc::ERROR,"Job did not finished successfully. Message will not be written to BLAH log."); return EXIT_FAILURE; } } } else { logger.msg(Arc::ERROR,"Can not read information from the local job status file"); return EXIT_FAILURE; } // Just in case subject escape subject = Arc::escape_chars(subject, "\"\\", '\\', false); // Construct clientID depend on submission interface std::string clientid; if ( interface == "org.nordugrid.gridftpjob" ) { clientid = globalid; } else if ( interface == "org.ogf.glue.emies.activitycreation" ) { clientid = headnode + "/" + globalid; } else if ( interface == "org.nordugrid.xbes" ) { clientid = headnode + "/" + std::string(jobid_s); } else { logger.msg(Arc::ERROR,"Unsupported submission interface %s. Seems arc-blahp-logger need to be updated accordingly :-) Please submit the bug to bugzilla."); return EXIT_FAILURE; } // Get FQANs information from user's proxy // P.S. validity check is not enforced, proxy can be even expired long time before job finished Arc::Credential holder(user_proxy_f, "", "", ""); std::vector voms_attributes; Arc::VOMSTrustList vomscert_trust_dn; logger.msg(Arc::DEBUG, "Parsing VOMS AC to get FQANs information"); // suppress expired 'ERROR' from Arc.Credential output if ( debuglevel == Arc::ERROR ) Arc::Logger::getRootLogger().setThreshold(Arc::FATAL); Arc::parseVOMSAC(holder, "", "", "", vomscert_trust_dn, voms_attributes, false, true); Arc::Logger::getRootLogger().setThreshold(debuglevel); std::string fqans_logentry; std::string fqan; std::size_t pos; if(voms_attributes.size() > 0) { for (std::vector::iterator iAC = voms_attributes.begin(); iAC != voms_attributes.end(); iAC++) { for (int acnt = 1; acnt < iAC->attributes.size(); acnt++ ) { fqan = iAC->attributes[acnt]; pos = fqan.find("/Role="); if ( pos == std::string::npos ) fqan = fqan + "/Role=NULL"; fqans_logentry += "\"userFQAN=" + Arc::trim(Arc::escape_chars(fqan, "\"\\", '\\', false)) + "\" "; } } } else { logger.msg(Arc::DEBUG, "No FQAN found. Using NULL as userFQAN value"); fqans_logentry = "\"userFQAN=/None/Role=NULL\" "; } // Assemble BLAH logentry std::string logentry = "\"timestamp=" + timestamp + "\" \"userDN=" + Arc::trim(subject) + "\" " + fqans_logentry + "\"ceID=" + ceid + "-" + queue + "\" \"jobID=" + std::string(jobid_s) + "\" \"lrmsID=" + Arc::trim(localid) + "\" \"localUser=" + std::string(user_s) + "\" \"clientID=" + clientid + "\""; logger.msg(Arc::DEBUG, "Assembling BLAH parser log entry: %s", logentry); // Write entry to BLAH log with locking to exclude possible simultaneous writes when several jobs are finished std::string fname = logprefix + "-" + logsuffix; Arc::FileLock lock(fname); logger.msg(Arc::DEBUG,"Writting the info the the BLAH parser log: %s", fname); for (int i = 10; !lock.acquire() && i >= 0; --i) { if (i == 0) return false; sleep(1); } std::ofstream logfile; logfile.open(fname.c_str(),std::ofstream::app); if(!logfile.is_open()) { logger.msg(Arc::ERROR,"Cannot open BLAH log file '%s'", fname); lock.release(); return EXIT_FAILURE; } logfile << logentry << std::endl; logfile.close(); lock.release(); return EXIT_SUCCESS; }