Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright @year, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.pnc.pvt.execution; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.io.IOUtils; import org.jboss.logging.Logger; import org.jboss.pnc.pvt.execution.Execution.JenkinsExecution; import org.jboss.pnc.pvt.report.Report; import org.jboss.pnc.pvt.report.Report.ReportLog; import com.offbytwo.jenkins.JenkinsServer; import com.offbytwo.jenkins.model.Artifact; import com.offbytwo.jenkins.model.Build; import com.offbytwo.jenkins.model.BuildResult; import com.offbytwo.jenkins.model.BuildWithDetails; import com.offbytwo.jenkins.model.JobWithDetails; /** * @author <a href="mailto:lgao@redhat.com">Lin Gao</a> * */ class JenkinsExecutor extends Executor { static JenkinsExecutor INSTANCE = new JenkinsExecutor(null); private static final Logger logger = Logger.getLogger(JenkinsExecutor.class); private final JenkinsConfiguration jenkinsConfig; JenkinsExecutor(JenkinsConfiguration jenkinsConfig) { super(); try { if (jenkinsConfig == null) { this.jenkinsConfig = JenkinsConfiguration.defaultJenkinsProps(); } else { this.jenkinsConfig = jenkinsConfig; } } catch (IOException e) { throw new IllegalStateException("Can't initialize Jenkins Executor.", e); } } @Override public void execute(final Execution execution, final CallBack callBack) throws ExecutionException { JenkinsExecution jenkinsExe = (JenkinsExecution) execution; jenkinsExe.setReport(new Report()); // report will be initialized when it is started. String jobId = jenkinsExe.getName(); String jobContent = jenkinsExe.getJobContent(); try { JobWithDetails jobDetail = getOrCreateJenkinsJob(jobId, jobContent); if (jobDetail == null) { throw new ExecutionException("Jenkins Job: " + jobId + " does not exist."); } final int buildNumber = buildJenkinsJob(jobDetail, jenkinsExe.getJobParams()); StringBuilder url = new StringBuilder(this.jenkinsConfig.getUrl()); url.append("/job/"); url.append(jobId); url.append("/"); url.append(buildNumber); url.append("/"); execution.setLink(url.toString()); startMonitor(jobId, buildNumber, jenkinsExe, callBack); } catch (IOException e) { execution.setException(e); if (callBack != null) { callBack.onException(execution); } throw new ExecutionException(String.format("Failed to execute Jenkins job: %s", jobId), e); } } private void startMonitor(String jobName, int buildNumber, final JenkinsExecution execution, final CallBack callBack) { AtomicInteger statusRetrieveFailed = new AtomicInteger(0); final Runnable checking = new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); try { Build jenkinsBuild = getBuild(jobName, buildNumber); if (jenkinsBuild == null) { getMonitorExecutorService().schedule(this, getMonitorInterval(), TimeUnit.SECONDS); return; } BuildWithDetails jenkinsBuildDetails = jenkinsBuild.details(); String log = jenkinsBuildDetails.getConsoleOutputText(); if (log != null) { execution.getReport().setMainLog(log); if (callBack != null) { callBack.onLogChanged(execution); } } BuildResult result = jenkinsBuildDetails.getResult(); long timeout = jenkinsConfig.getJobTimeOut(); if (timeout > 0) { long end = System.currentTimeMillis(); if (end - start >= timeout) { throw new RuntimeException("Timeout to check build status of Jenkins job: " + jobName); } } if (result == null) { getMonitorExecutorService().schedule(this, getMonitorInterval(), TimeUnit.SECONDS); return; } switch (result) { case BUILDING: case REBUILDING: { execution.setStatus(Execution.Status.RUNNING); if (callBack != null) { callBack.onStatus(execution); } getMonitorExecutorService().schedule(this, getMonitorInterval(), TimeUnit.SECONDS); break; } case FAILURE: case UNSTABLE: case ABORTED: { execution.setStatus(Execution.Status.FAILED); List<Artifact> artiFacts = jenkinsBuildDetails.getArtifacts(); if (artiFacts != null && artiFacts.size() > 0) { for (Artifact arti : artiFacts) { String logFilePattern = execution.getLogFilePattern(); if (logFilePattern != null && logFilePattern.trim().length() > 0) { if (arti.getRelativePath().matches(logFilePattern) == false) { continue; } } try (InputStream input = jenkinsBuildDetails.downloadArtifact(arti)) { String artiLog = IOUtils.toString(input); ReportLog reportLog = new ReportLog(arti.getFileName(), artiLog); execution.getReport().addReportLog(reportLog); } } if (callBack != null) { callBack.onLogChanged(execution); } } if (callBack != null) { callBack.onStatus(execution); callBack.onTerminated(execution); } break; } case SUCCESS: { execution.setStatus(Execution.Status.SUCCEEDED); List<Artifact> artiFacts = jenkinsBuildDetails.getArtifacts(); if (artiFacts != null && artiFacts.size() > 0) { for (Artifact arti : artiFacts) { String logFilePattern = execution.getLogFilePattern(); if (logFilePattern != null && logFilePattern.trim().length() > 0) { if (arti.getRelativePath().matches(logFilePattern) == false) { continue; } } try (InputStream input = jenkinsBuildDetails.downloadArtifact(arti)) { String artiLog = IOUtils.toString(input); ReportLog reportLog = new ReportLog(arti.getFileName(), artiLog); execution.getReport().addReportLog(reportLog); } } if (callBack != null) { callBack.onLogChanged(execution); } } if (callBack != null) { callBack.onStatus(execution); callBack.onTerminated(execution); } break; } default: { execution.setStatus(Execution.Status.UNKNOWN); if (callBack != null) { callBack.onStatus(execution); } getMonitorExecutorService().schedule(this, getMonitorInterval(), TimeUnit.SECONDS); break; } } } catch (IOException e) { execution.setException(e); if (callBack != null) { callBack.onException(execution); } int failed = statusRetrieveFailed.getAndIncrement(); if (failed >= getMaxRetryTime()) { logger.error("Failed to check Build Detail. Give up!", e); if (callBack != null) { callBack.onTerminated(execution); } } else { logger.warn("Failed to check Build Detail. Continue.", e); getMonitorExecutorService().schedule(this, getMonitorInterval(), TimeUnit.SECONDS); } } catch (Throwable t) { logger.error("Failed to Monitor the execution.", t); if (callBack != null) { callBack.onTerminated(execution); } } } }; getMonitorExecutorService().schedule(checking, getMonitorInterval(), TimeUnit.SECONDS); } private Build getBuild(String jobName, int buildNumber) throws IOException { JenkinsServer jenkinsServer = getJenkinsServer(this.jenkinsConfig); JobWithDetails jenkinsJob = jenkinsServer.getJob(jobName); if (jenkinsJob != null) { for (Build build : jenkinsJob.getBuilds()) { if (buildNumber == build.getNumber()) { return build; } } } return null; } private int buildJenkinsJob(JobWithDetails jobDetail, Map<String, String> params) throws IOException { int buildNumber = jobDetail.getNextBuildNumber(); if (params != null && !params.isEmpty()) { jobDetail.build(params); } else { jobDetail.build(); } return buildNumber; } /** * Gets or create a job by its name */ private JobWithDetails getOrCreateJenkinsJob(String jobName, String jobContent) throws IOException, ExecutionException { JenkinsServer jenkinsServer = getJenkinsServer(this.jenkinsConfig); JobWithDetails jenkinsJob = jenkinsServer.getJob(jobName); if (jenkinsJob == null && this.jenkinsConfig.isCreateIfJobMissing()) { logger.info("Start to create the Jenkins job"); jenkinsJob = createJenkinsJob(jobName, jobContent); } else { if (this.jenkinsConfig.isOverrideJob()) { jenkinsJob = updateJenkinsJob(jobName, jobContent); } } return jenkinsJob; } private JobWithDetails updateJenkinsJob(String jobName, String jobContent) throws IOException, ExecutionException { JenkinsServer jenkinsServer = getJenkinsServer(this.jenkinsConfig); if (jobContent == null) { throw new ExecutionException("No job content found for: " + jobName); } jenkinsServer.updateJob(jobName, jobContent, this.jenkinsConfig.isCrumbFlag()); return jenkinsServer.getJob(jobName); } /** * Creates jenkins job, check crumbFlag * */ private JobWithDetails createJenkinsJob(String jobName, String jobContent) throws IOException, ExecutionException { JenkinsServer jenkinsServer = getJenkinsServer(this.jenkinsConfig); if (jobContent == null) { throw new ExecutionException("No job content found for: " + jobName); } jenkinsServer.createJob(jobName, jobContent, this.jenkinsConfig.isCrumbFlag()); return jenkinsServer.getJob(jobName); } }