/** * Returns control when task is complete. * * @param json * @param logger */ private String waitForDeploymentCompletion(JSON json, OctopusApi api, Log logger) { final long WAIT_TIME = 5000; final double WAIT_RANDOM_SCALER = 100.0; JSONObject jsonObj = (JSONObject) json; String id = jsonObj.getString("TaskId"); Task task = null; String lastState = "Unknown"; try { task = api.getTask(id); } catch (IOException ex) { logger.error("Error getting task: " + ex.getMessage()); return null; } logger.info("Task info:"); logger.info("\tId: " + task.getId()); logger.info("\tName: " + task.getName()); logger.info("\tDesc: " + task.getDescription()); logger.info("\tState: " + task.getState()); logger.info("\n\nStarting wait..."); boolean completed = task.getIsCompleted(); while (!completed) { try { task = api.getTask(id); } catch (IOException ex) { logger.error("Error getting task: " + ex.getMessage()); return null; } completed = task.getIsCompleted(); lastState = task.getState(); logger.info("Task state: " + lastState); if (completed) { break; } try { Thread.sleep(WAIT_TIME + (long) (Math.random() * WAIT_RANDOM_SCALER)); } catch (InterruptedException ex) { logger.info("Wait interrupted!"); logger.info(ex.getMessage()); completed = true; // bail out of wait loop } } logger.info("Wait complete!"); return lastState; }
/** * Update the tags stored in EC2 with the specified information. Re-try 5 times if instances isn't * up by catchErrorCode - e.g. InvalidSpotInstanceRequestID.NotFound or * InvalidInstanceRequestID.NotFound * * @param ec2 * @param instTags * @param catchErrorCode * @param params * @throws InterruptedException */ private void updateRemoteTags( AmazonEC2 ec2, Collection<Tag> instTags, String catchErrorCode, String... params) throws InterruptedException { for (int i = 0; i < 5; i++) { try { CreateTagsRequest tagRequest = new CreateTagsRequest(); tagRequest.withResources(params).setTags(instTags); ec2.createTags(tagRequest); break; } catch (AmazonServiceException e) { if (e.getErrorCode().equals(catchErrorCode)) { Thread.sleep(5000); continue; } LOGGER.log(Level.SEVERE, e.getErrorMessage(), e); } } }
/** * Schedules the given configuration. * * <p>Copied from the {@link * DefaultMatrixExecutionStrategyImpl#scheduleConfigurationBuild(hudson.matrix.MatrixBuild.MatrixBuildExecution, * hudson.matrix.MatrixConfiguration)} * * @param execution Contains information about the general build, including the listener used to * log queue blockage. * @param configuration The configuration to schedule. * @param upstreamCause The cause of the build. Will either be an {@link * hudson.model.Cause.UpstreamCause} or {@link * com.attask.jenkins.healingmatrixproject.SelfHealingCause}. */ private void scheduleConfigurationBuild( MatrixBuild.MatrixBuildExecution execution, MatrixConfiguration configuration, Cause.UpstreamCause upstreamCause) throws InterruptedException { MatrixBuild build = (MatrixBuild) execution.getBuild(); execution .getListener() .getLogger() .println(Messages.MatrixBuild_Triggering(ModelHyperlinkNote.encodeTo(configuration))); // filter the parent actions for those that can be passed to the individual jobs. List<MatrixChildAction> childActions = Util.filter(build.getActions(), MatrixChildAction.class); BuildListener listener = execution.getListener(); while (!configuration.scheduleBuild(childActions, upstreamCause)) { String msg = "Unable to schedule build " + configuration.getFullDisplayName() + ". Retrying."; listener.error(msg); Thread.sleep(500); } }
@Override public void onCompleted(AbstractBuild run, TaskListener listener) { Lamps plugin = Lamps.getInstance(); Set<String> jobs = plugin.getJobs(); String jobName = run.getParent().getFullName(); XfEventMessage xfEventMessage = new XfEventMessage(); if (jobs.contains(jobName)) { Result result = run.getResult(); Set<Lamp> activeLamps = plugin.getLampsContainingJob(jobName); for (Lamp lamp : activeLamps) { Result lampResult = result; xfEventMessage.sendColorMessage(lamp, lampResult, States.Action.SOLID); // Create Notification for LCD StringBuilder infoMsg = new StringBuilder(64); infoMsg.append(jobName).append(' ').append(run.getDisplayName()).append('\n'); if (Result.FAILURE.equals(result)) { ArrayList<String> blame = Lists.newArrayList(); if (lamp.isBlame()) { Set<User> culprits = run.getCulprits(); for (User user : culprits) { blame.add(user.getDisplayName()); } } if (blame.isEmpty()) { blame.add("Somebody"); } infoMsg.insert(0, Joiner.on(", ").join(blame) + " broke the build: "); infoMsg.append(result.toString()); listener.getLogger().println("[XFD] Updating Lamp display: " + infoMsg.toString()); } else if (Result.ABORTED.equals(result)) { String causeMsg = "BUILD ABORTED"; infoMsg.append(causeMsg); listener.getLogger().println("[XFD] Updating Lamp display: " + infoMsg.toString()); } else { infoMsg.append(result.toString()); } xfEventMessage.sendLCDMessage(lamp, infoMsg.toString()); if (lamp.isSfx()) { try { Thread.sleep(1000); xfEventMessage.sendSfxMessage(lamp, lampResult); } catch (InterruptedException e) { e.printStackTrace(); } } if (States.resultColorMap.get(lampResult).equals(States.Color.RED) && lamp.isNoisy()) { try { Thread.sleep(1000); xfEventMessage.sendBuzzerMessage(lamp); } catch (InterruptedException e) { e.printStackTrace(); } } if (lamp.isAggregate()) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } plugin.updateAggregateStatus(lamp); } } } }
/** * Waits for the given configurations to finish, retrying any that qualify to be rerun. * * @param execution Provided by the plugin. * @param patterns List of regular expression patterns used to scan the log to determine if a * build should be rerun. * @param retries Mutable map that tracks the number of times a specific configuration has been * retried. * @param configurations The configurations that have already been scheduled to run that should be * waited for to finish. * @return The worst result of all the runs. If a build was rerun, only the result of the rerun is * considered. * @throws InterruptedException * @throws IOException */ private Result waitForMatrixRuns( MatrixBuild.MatrixBuildExecution execution, List<Pattern> patterns, Map<MatrixConfiguration, Integer> retries, LinkedList<MatrixConfiguration> configurations) throws InterruptedException, IOException { BuildListener listener = execution.getListener(); PrintStream logger = listener.getLogger(); Map<String, String> whyBlockedMap = new HashMap< String, String>(); // keep track of why builds are blocked so we can print unique messages when // they change. Result finalResult = Result.SUCCESS; int iteration = 0; boolean continueRetrying = true; while (!configurations.isEmpty()) { ++iteration; MatrixConfiguration configuration = configurations.removeFirst(); if (isBuilding(execution, configuration, whyBlockedMap)) { if (iteration >= configurations.size()) { // Every time we loop through all the configurations, sleep for a bit. // This is to prevent polling too often while everything is still building. iteration = 0; Thread.sleep(1000); } configurations.add(configuration); continue; } Run parentBuild = execution.getBuild(); MatrixRun matrixRun = configuration.getBuildByNumber(parentBuild.getNumber()); Result runResult = matrixRun.getResult(); if (continueRetrying && runResult.isWorseOrEqualTo(getWorseThanOrEqualTo()) && runResult.isBetterOrEqualTo(getBetterThanOrEqualTo())) { if (matchesPattern(matrixRun, patterns)) { int retriedCount = retries.get(configuration); if (retriedCount < getMaxRetries()) { ++retriedCount; retries.put(configuration, retriedCount); // rerun String logMessage = String.format( "%s was %s. Matched pattern to rerun. Rerunning (%d).", matrixRun, runResult, retriedCount); listener.error(logMessage); HealedAction action = parentBuild.getAction(HealedAction.class); if (action == null) { //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (parentBuild.getActions()) { action = parentBuild.getAction(HealedAction.class); if (action == null) { action = new HealedAction(matrixRun.getCharset()); parentBuild.addAction(action); } } } action.addAutoHealedJob(matrixRun); MatrixConfiguration parent = matrixRun.getParent(); if (parent != null) { // I'm paranoid about NPEs parent.removeRun(matrixRun); matrixRun.delete(); } else { LOGGER.severe( "couldn't remove old run, parent was null. This is a Jenkins core bug."); } scheduleConfigurationBuild( execution, configuration, new SelfHealingCause(parentBuild, retriedCount)); configurations.add(configuration); continue; } else { String logMessage = String.format( "%s was %s. Matched pattern to rerun, but the max number of retries (%d) has been met.", matrixRun, runResult, getMaxRetries()); listener.error(logMessage); if (getStopRetryingAfterOneFails()) { listener.error("Not retrying any more builds."); continueRetrying = false; } } } else { String logMessage = String.format( "%s was %s. It did not match the pattern to rerun. Accepting result.", matrixRun, runResult); logger.println(logMessage); } } notifyEndRun(matrixRun, execution.getAggregators(), execution.getListener()); finalResult = finalResult.combine(runResult); } return finalResult; }