diff --git a/esp/services/ws_workunits/ws_workunitsHelpers.cpp b/esp/services/ws_workunits/ws_workunitsHelpers.cpp index 2389e899d96..1192ac70634 100644 --- a/esp/services/ws_workunits/ws_workunitsHelpers.cpp +++ b/esp/services/ws_workunits/ws_workunitsHelpers.cpp @@ -45,6 +45,12 @@ namespace ws_workunits { +#ifdef _CONTAINERIZED +static const char* LOG_ACCESS_FEATURE = "WsLogAccess"; +#else +static const char* LOG_ACCESS_FEATURE = "ClusterTopologyAccess"; +#endif + const char * const timerFilterText = "measure[time],source[global],depth[1,]"; // Does not include hthor subgraph timings const char* zipFolder = "tempzipfiles" PATHSEPSTR; @@ -3991,13 +3997,12 @@ void CWsWuFileHelper::cleanFolder(IFile* folder, bool removeFolder) } #ifndef _CONTAINERIZED -void CWsWuFileHelper::createProcessLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* process, const char* path) +void CWsWuFileHelper::createProcessLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* process, const char* path, bool hasLogsAccess) { BoolHash uniqueProcesses; Owned procs = cwu->getProcesses(process, NULL); ForEach (*procs) { - StringBuffer logSpec; IPropertyTree& proc = procs->query(); const char* processName = proc.queryName(); if (isEmpty(processName)) @@ -4021,11 +4026,17 @@ void CWsWuFileHelper::createProcessLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, pid.appendf("%d", proc.getPropInt("@pid")); fileName.append("_eclagent.log"); + if (!hasLogsAccess) + throw makeStringExceptionV(ECLWATCH_ACCESS_TO_FILE_DENIED, "Access to log files is denied. You are missing permission %s:READ - check with your system admin.", LOG_ACCESS_FEATURE); + winfo.getWorkunitEclAgentLog(processName, nullptr, pid.str(), mb, fileName.str()); } else if (strieq(process, "Thor")) { fileName.append("_thormaster.log"); + if (!hasLogsAccess) + throw makeStringExceptionV(ECLWATCH_ACCESS_TO_FILE_DENIED, "Access to log files is denied. You are missing permission %s:READ - check with your system admin.", LOG_ACCESS_FEATURE); + winfo.getWorkunitThorMasterLog(processName, nullptr, mb, fileName.str()); } } @@ -4033,14 +4044,14 @@ void CWsWuFileHelper::createProcessLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, { StringBuffer s; e->errorMessage(s); - IERRLOG("Error accessing Process Log file %s: %s", logSpec.str(), s.str()); + IERRLOG("Error accessing Process Log file %s: %s", processName, s.str()); writeToFile(fileName.str(), s.length(), s.str()); e->Release(); } } } -void CWsWuFileHelper::createThorSlaveLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* path) +void CWsWuFileHelper::createThorSlaveLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* path, bool hasLogsAccess) { if (cwu->getWuidVersion() == 0) return; @@ -4055,6 +4066,18 @@ void CWsWuFileHelper::createThorSlaveLogfile(IConstWorkUnit* cwu, WsWuInfo& winf return; } + // Since there is not already a handler inserting exceptions into the thor slave log, + // make a simple case here to insert a message about permission failure and write it to + // a file that could be recognized as a thor slave log. + if (!hasLogsAccess) + { + StringBuffer msg; + msg.appendf("Access to log files is denied. You are missing permission %s:READ - check with your system admin.", LOG_ACCESS_FEATURE); + VStringBuffer fileName("%s%cthorslave.log", path, PATHSEPCHAR); + writeToFile(fileName.str(), msg.length(), msg.str()); + return; + } + Owned threadFactory = new CGetThorSlaveLogToFileThreadFactory(); Owned threadPool = createThreadPool("WsWuFileHelper GetThorSlaveLogToFile Thread Pool", threadFactory, false, nullptr, thorSlaveLogThreadPoolSize, INFINITE); @@ -4096,8 +4119,7 @@ void CWsWuFileHelper::createThorSlaveLogfile(IConstWorkUnit* cwu, WsWuInfo& winf } #endif -void CWsWuFileHelper::createZAPInfoFile(const char* url, const char* esp, const char* thor, const char* problemDesc, - const char* whatChanged, const char* timing, IConstWorkUnit* cwu, const char* tempDirName) +void CWsWuFileHelper::createZAPInfoFile(CWsWuZAPInfoReq &request, IConstWorkUnit* cwu, const char* tempDirName) { VStringBuffer fileName("%s%c%s.txt", tempDirName, PATHSEPCHAR, cwu->queryWuid()); Owned outFile = createBufferedIOStreamFromFile(fileName.str(), IFOcreate); @@ -4109,11 +4131,11 @@ void CWsWuFileHelper::createZAPInfoFile(const char* url, const char* esp, const sb.append("User: ").append(cwu->queryUser()).append("\r\n"); sb.append("Build Version:").append(getBuildVersion()).append("\r\n"); sb.append("Cluster: ").append(cwu->queryClusterName()).append("\r\n"); - sb.append("ESP: ").append(esp).append("\r\n"); - if (!isEmptyString(url)) - sb.append("URL: ").append(url).append("\r\n"); - if (!isEmptyString(thor)) - sb.append("Thor: ").append(thor).append("\r\n"); + sb.append("ESP: ").append(request.esp).append("\r\n"); + if (!isEmptyString(request.url)) + sb.append("URL: ").append(request.url).append("\r\n"); + if (!isEmptyString(request.thor)) + sb.append("Thor: ").append(request.thor).append("\r\n"); outFile->write(sb.length(), sb.str()); //Exceptions/Warnings/Info @@ -4147,9 +4169,9 @@ void CWsWuFileHelper::createZAPInfoFile(const char* url, const char* esp, const } //User provided Information - writeZAPWUInfoToIOStream(outFile, "Problem: ", problemDesc); - writeZAPWUInfoToIOStream(outFile, "What Changed: ", whatChanged); - writeZAPWUInfoToIOStream(outFile, "Timing: ", timing); + writeZAPWUInfoToIOStream(outFile, "Problem: ", request.problemDesc); + writeZAPWUInfoToIOStream(outFile, "What Changed: ", request.whatChanged); + writeZAPWUInfoToIOStream(outFile, "Timing: ", request.whereSlow); } void CWsWuFileHelper::writeZAPWUInfoToIOStream(IFileIOStream* outFile, const char* name, SCMStringBuffer& value) @@ -4281,6 +4303,8 @@ void CWsWuFileHelper::readWULogToFile(const char *logFileName, WsWuInfo &winfo, { try { + if (!zapLogFilterOptions.hasLogsAccess) + throw makeStringExceptionV(ECLWATCH_ACCESS_TO_FILE_DENIED, "Access to log files is denied. You are missing permission %s:READ - check with your system admin.", LOG_ACCESS_FEATURE); winfo.readWorkunitComponentLogs(logFileName, zapLogFilterOptions); } catch(IException* e) @@ -4517,14 +4541,14 @@ int CWsWuFileHelper::zipAFolder(const char* folder, bool gzip, const char* zipFi void CWsWuFileHelper::createWUZAPFile(IEspContext& context, IConstWorkUnit* cwu, CWsWuZAPInfoReq& request, const char* tempDirName, StringBuffer& zapFileName, StringBuffer& zipFileNameWithFullPath, unsigned _thorSlaveLogThreadPoolSize) { + request.hasLogsAccess = context.validateFeatureAccess(LOG_ACCESS_FEATURE, SecAccess_Read, false); setZAPReportName(request.zapFileName, cwu->queryWuid(), zapFileName); zipFileNameWithFullPath.set(tempDirName).append(PATHSEPCHAR).append("zapreport.zip"); thorSlaveLogThreadPoolSize = _thorSlaveLogThreadPoolSize; - //create WU ZAP files - createZAPInfoFile(request.url.str(), request.esp.str(), request.thor.str(), request.problemDesc.str(), request.whatChanged.str(), - request.whereSlow.str(), cwu, tempDirName); +//create WU ZAP files + createZAPInfoFile(request, cwu, tempDirName); createZAPECLQueryArchiveFiles(cwu, tempDirName); WsWuInfo winfo(context, cwu); @@ -4532,21 +4556,21 @@ void CWsWuFileHelper::createWUZAPFile(IEspContext& context, IConstWorkUnit* cwu, createZAPWUGraphProgressFile(request.wuid.str(), tempDirName); StringArray localFiles; - createZAPWUQueryAssociatedFiles(cwu, tempDirName, localFiles); + createZAPWUQueryAssociatedFiles(cwu, tempDirName, localFiles, request.hasLogsAccess); #ifndef _CONTAINERIZED - createProcessLogfile(cwu, winfo, "EclAgent", tempDirName); - createProcessLogfile(cwu, winfo, "Thor", tempDirName); - if (request.includeThorSlaveLog.isEmpty() || strieq(request.includeThorSlaveLog.str(), "on")) - createThorSlaveLogfile(cwu, winfo, tempDirName); + createProcessLogfile(cwu, winfo, "EclAgent", tempDirName, request.hasLogsAccess); + createProcessLogfile(cwu, winfo, "Thor", tempDirName, request.hasLogsAccess); + if (request.includeThorSlaveLog.isEmpty() || strieq(request.includeThorSlaveLog.str(), "on")) + createThorSlaveLogfile(cwu, winfo, tempDirName, request.hasLogsAccess); #else - readWULogToFiles(cwu, winfo, tempDirName, request); + readWULogToFiles(cwu, winfo, tempDirName, request); #endif //Write out to ZIP file zipAllZAPFiles(tempDirName, localFiles, request.password, zipFileNameWithFullPath); } -void CWsWuFileHelper::createZAPWUQueryAssociatedFiles(IConstWorkUnit* cwu, const char* tempDirName, StringArray& localFiles) +void CWsWuFileHelper::createZAPWUQueryAssociatedFiles(IConstWorkUnit* cwu, const char* tempDirName, StringArray& localFiles, bool hasLogsAccess) { Owned query = cwu->getQuery(); if (!query) @@ -4566,6 +4590,21 @@ void CWsWuFileHelper::createZAPWUQueryAssociatedFiles(IConstWorkUnit* cwu, const RemoteFilename rfn; SocketEndpoint ep(ip.str()); rfn.setPath(ep, name.str()); + StringBuffer fileName(name.str()); + getFileNameOnly(fileName, false); + + VStringBuffer outFileName("%s%c%s", tempDirName, PATHSEPCHAR, fileName.str()); + + // Since users are only accustomed to seeing error messages replacing log file contents, + // special case an access denied error message for the one log file processed here. + if (!hasLogsAccess && endsWith(name.str(), ".eclcc.log")) + { + StringBuffer msg; + msg.appendf("Access to log files is denied. You are missing permission %s:READ - check with your system admin.", LOG_ACCESS_FEATURE); + writeToFile(outFileName.str(), msg.length(), msg.str()); + continue; + } + if (rfn.isLocal()) { localFiles.append(name.str()); @@ -4579,11 +4618,6 @@ void CWsWuFileHelper::createZAPWUQueryAssociatedFiles(IConstWorkUnit* cwu, const continue; } - StringBuffer fileName(name.str()); - getFileNameOnly(fileName, false); - - VStringBuffer outFileName("%s%c%s", tempDirName, PATHSEPCHAR, fileName.str()); - OwnedIFile outFile = createIFile(outFileName); if (!outFile) { diff --git a/esp/services/ws_workunits/ws_workunitsHelpers.hpp b/esp/services/ws_workunits/ws_workunitsHelpers.hpp index d8b68ce724b..7dde648c6c1 100644 --- a/esp/services/ws_workunits/ws_workunitsHelpers.hpp +++ b/esp/services/ws_workunits/ws_workunitsHelpers.hpp @@ -369,6 +369,7 @@ struct CWsWuZAPInfoReq bool sendEmail, attachZAPReportToEmail; bool includeRelatedLogs = true, includePerComponentLogs = false; unsigned maxAttachmentSize, port; + bool hasLogsAccess = false; WUComponentLogOptions logFilter; @@ -381,6 +382,7 @@ struct CWsWuZAPInfoReq { logFilter.populateLogFilter(wuid.str(), httpRequest); } + }; class WsWuInfo @@ -890,15 +892,14 @@ class CWsWuFileHelper IFile *createWorkingFolder(IEspContext &context, const char *wuid, const char *namePrefix, StringBuffer &namePrefixStr, StringBuffer &folderName); - void createZAPInfoFile(const char *url, const char *espIP, const char *thorIP, const char *problemDesc, - const char *whatChanged, const char *timing, IConstWorkUnit *cwu, const char *pathNameStr); + void createZAPInfoFile(CWsWuZAPInfoReq &request, IConstWorkUnit *cwu, const char *pathNameStr); void createZAPWUXMLFile(WsWuInfo &winfo, const char *pathNameStr); void createZAPECLQueryArchiveFiles(IConstWorkUnit *cwu, const char *pathNameStr); - void createZAPWUQueryAssociatedFiles(IConstWorkUnit *cwu, const char *pathToCreate, StringArray &localFiles); + void createZAPWUQueryAssociatedFiles(IConstWorkUnit *cwu, const char *pathToCreate, StringArray &localFiles, bool hasLogsAccess); void createZAPWUGraphProgressFile(const char *wuid, const char *pathNameStr); #ifndef _CONTAINERIZED - void createProcessLogfile(IConstWorkUnit *cwu, WsWuInfo &winfo, const char *process, const char *path); - void createThorSlaveLogfile(IConstWorkUnit *cwu, WsWuInfo &winfo, const char *path); + void createProcessLogfile(IConstWorkUnit *cwu, WsWuInfo &winfo, const char *process, const char *path, bool hasLogsAccess); + void createThorSlaveLogfile(IConstWorkUnit *cwu, WsWuInfo &winfo, const char *path, bool hasLogsAccess); #endif LogAccessLogFormat getComponentLogFormatFromLogName(const char *log); void readWULogToFiles(IConstWorkUnit *cwu, WsWuInfo &winfo, const char *path, CWsWuZAPInfoReq &zapLogFilterOptions);