/** * Copyright (c) 2010--2015 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.taskomatic; import org.apache.log4j.Logger; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Date; /** * TaskoRun * @version $Rev$ */ public class TaskoRun { private static Logger log = Logger.getLogger(TaskoTask.class); public static final String STATUS_READY_TO_RUN = "READY"; public static final String STATUS_RUNNING = "RUNNING"; public static final String STATUS_FINISHED = "FINISHED"; public static final String STATUS_FAILED = "FAILED"; public static final String STATUS_SKIPPED = "SKIPPED"; public static final String STATUS_INTERRUPTED = "INTERRUPTED"; private static final String STD_LOG_PREFIX = "/var/log/rhn/tasko/"; private Long id; private Integer orgId; private TaskoTemplate template; private Long scheduleId; private Date startTime; private Date endTime; private String stdOutputPath = null; private String stdErrorPath = null; private String status; private Date created; private Date modified; /** * default constructor required by hibernate */ public TaskoRun() { } /** * constructor * run is always associated with organization, template and schedule * @param orgIdIn organization id * @param templateIn template id * @param scheduleIdIn schedule id */ public TaskoRun(Integer orgIdIn, TaskoTemplate templateIn, Long scheduleIdIn) { setOrgId(orgIdIn); setTemplate(templateIn); setScheduleId(scheduleIdIn); File logDir = new File(getStdLogDirName()); if (!logDir.isDirectory()) { if (!logDir.exists()) { logDir.mkdirs(); } } saveStatus(STATUS_READY_TO_RUN); } /** * run start method * has to be called right before job execution */ public void start() { setStdOutputPath(buildStdOutputLogPath()); setStdErrorPath(buildStdErrorLogPath()); deleteLogFileIfExists(stdOutputPath); deleteLogFileIfExists(stdErrorPath); setStartTime(new Date()); saveStatus(STATUS_RUNNING); } /** * run finish method * has to be called right after job execution */ public void finished() { setEndTime(new Date()); updateLogPaths(); } private void updateLogPaths() { if (!logPresent(stdOutputPath)) { deleteLogFileIfExists(stdOutputPath); stdOutputPath = null; } if (!logPresent(stdErrorPath)) { deleteLogFileIfExists(stdErrorPath); stdErrorPath = null; } } /** * if task execution will be skipped (used for queue tasks) */ public void skipped() { Date now = new Date(); setStartTime(now); setEndTime(now); saveStatus(STATUS_SKIPPED); } /** * if task execution fails */ public void failed() { finished(); saveStatus(TaskoRun.STATUS_FAILED); } /** * appends a string to output log * usefull to log something if the run didn't start at all * @param outputLog error message to append */ public void appendToOutputLog(String outputLog) { if (getStdOutputPath() == null) { setStdOutputPath(buildStdOutputLogPath()); } appendLogToFile(getStdOutputPath(), outputLog); } /** * appends a string to error log * usefull for exception logging when the run doesn't get executed at all * @param errorLog error message to append */ public void appendToErrorLog(String errorLog) { if (getStdErrorPath() == null) { setStdErrorPath(buildStdErrorLogPath()); } appendLogToFile(getStdErrorPath(), errorLog); } /** * sets run status * @param statusIn status to set */ public void saveStatus(String statusIn) { setStatus(statusIn); TaskoFactory.save(this); } /** * returns last nBytes bytes of the std output log * @param nBytes number of bytes * @return last bytes of the output log */ public String getTailOfStdOutput(Integer nBytes) { return getTailOfFile(getStdOutputPath(), nBytes); } /** * returns last nBytes bytes of the std error log * @param nBytes number of bytes * @return last bytes of the error log */ public String getTailOfStdError(Integer nBytes) { return getTailOfFile(getStdErrorPath(), nBytes); } private String getTailOfFile(String fileName, Integer nBytes) { if (fileName != null) { RandomAccessFile file; try { file = new RandomAccessFile(fileName, "r"); if (nBytes >= 0) { long seekAmount = file.length() - nBytes; if (seekAmount < 0) { seekAmount = 0; } file.seek(seekAmount); } String tail = ""; String line; while ((line = file.readLine()) != null) { tail += line + "\n"; } file.close(); return tail; } catch (IOException e) { log.error("Can't tail " + fileName + ": " + e.toString()); // return ""; } } return ""; } /** * builds path to std output log file * @return path */ public String buildStdOutputLogPath() { return getStdLogDirName() + getStdLogFileName() + "_out"; } /** * builds path to std error log file * @return path */ public String buildStdErrorLogPath() { return getStdLogDirName() + getStdLogFileName() + "_err"; } private String getStdLogDirName() { String dirName = STD_LOG_PREFIX; if (orgId == null) { dirName += "sat"; } else { dirName += "org" + orgId; } dirName += "/" + template.getBunch().getName() + "/"; return dirName; } private String getStdLogFileName() { return template.getTask().getName() + "_" + getId(); } private void deleteLogFileIfExists(String fileName) { if (fileName != null) { new File(fileName).delete(); } } private boolean logPresent(String fileName) { if (fileName == null) { return false; } File logFile = new File(fileName); return logFile.length() > 0; } private void appendLogToFile(String fileName, String logContent) { try { BufferedWriter out = new BufferedWriter(new FileWriter(fileName, true)); out.write(logContent); out.close(); } catch (IOException e) { log.error("Unable to store log file to " + fileName); } } /** * @return Returns the id. */ public Long getId() { return id; } /** * @param idIn The id to set. */ public void setId(Long idIn) { this.id = idIn; } /** * @return Returns the templateId. */ public TaskoTemplate getTemplate() { return template; } /** * @param templateId The templateId to set. */ public void setTemplate(TaskoTemplate templateId) { this.template = templateId; } /** * @return Returns the startTime. */ public Date getStartTime() { return startTime; } /** * @param startTimeIn The startTime to set. */ public void setStartTime(Date startTimeIn) { this.startTime = startTimeIn; } /** * @return Returns the endTime. */ public Date getEndTime() { return endTime; } /** * @param endTimeIn The endTime to set. */ public void setEndTime(Date endTimeIn) { this.endTime = endTimeIn; } /** * @return Returns the stdOutputPath. */ public String getStdOutputPath() { return stdOutputPath; } /** * @param stdOutputPathIn The stdOutputPath to set. */ public void setStdOutputPath(String stdOutputPathIn) { this.stdOutputPath = stdOutputPathIn; } /** * @return Returns the stdErrorPath. */ public String getStdErrorPath() { return stdErrorPath; } /** * @param stdErrorPathIn The stdErrorPath to set. */ public void setStdErrorPath(String stdErrorPathIn) { this.stdErrorPath = stdErrorPathIn; } /** * @return Returns the status. */ public String getStatus() { return status; } /** * @param statusIn The status to set. */ public void setStatus(String statusIn) { this.status = statusIn; } /** * @return Returns the created. */ public Date getCreated() { return created; } /** * @param createdIn The created to set. */ public void setCreated(Date createdIn) { this.created = createdIn; } /** * @return Returns the modified. */ public Date getModified() { return modified; } /** * @param modifiedIn The modified to set. */ public void setModified(Date modifiedIn) { this.modified = modifiedIn; } /** * @return Returns the orgId. */ public Integer getOrgId() { return orgId; } /** * @param orgIdIn The orgId to set. */ public void setOrgId(Integer orgIdIn) { this.orgId = orgIdIn; } /** * @return Returns the jobLabel. */ public Long getScheduleId() { return scheduleId; } /** * @param scheduleIdIn The jobLabel to set. */ public void setScheduleId(Long scheduleIdIn) { this.scheduleId = scheduleIdIn; } }