package com.soasta.jenkins.cloud.postbuild; import java.io.File; import java.io.IOException; import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.util.ArgumentListBuilder; import org.w3c.dom.*; import org.xml.sax.InputSource; import com.soasta.jenkins.cloud.CloudCommandBuilder; import com.soasta.jenkins.cloud.CloudStatus; import javax.xml.parsers.*; import java.io.*; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Recorder; public abstract class CloudCommandBasePostBuild extends Recorder { private final String name; private final String cloudTestServerID; private final String url; private final int timeOut; public CloudCommandBasePostBuild(String url, String cloudTestServerID, String name) { this.name = name; this.cloudTestServerID = cloudTestServerID; this.url = url; this.timeOut = -1; } public CloudCommandBasePostBuild(String url, String cloudTestServerID, String name, int timeOut) { this.name = name; this.cloudTestServerID = cloudTestServerID; this.url = url; if (timeOut == 0) { this.timeOut = getDefaultTimeout(); } else { this.timeOut = timeOut; } } public String getName() { return name; } public String getCloudTestServerID() { return cloudTestServerID; } public int getTimeOut() { return timeOut; } @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { String command = getCommand(); // Create a unique sub-directory to store all test results. String resultsDir = "." + command; // set the basic commands. ArgumentListBuilder args = new CloudCommandBuilder() .setBuild(build) .setUrl(url) .setListener(listener) .setCloudTestServerID(cloudTestServerID) .build(); args.add("cmd=" + command, "wait=true", "format=xml") .add("name=" + name); if (timeOut >= 0) { args.add("timeout=" + timeOut); } String fileName = name + ".xml"; // Strip off any leading slash characters (composition names // will typically be the full CloudTest folder path). if (fileName.startsWith("/")) { fileName = fileName.substring(1); } // Put the file in the test results directory. fileName = resultsDir + File.separator + fileName; FilePath xml = new FilePath(build.getWorkspace(), fileName); // Make sure the directory exists. xml.getParent().mkdirs(); // Run it! int exitCode = launcher .launch() .cmds(args) .pwd(build.getWorkspace()) .stdout(xml.write()) .stderr(listener.getLogger()) .join(); if (xml.length() == 0) { // SCommand did not produce any output. // This should never happen, but just in case... return false; } try { return isSucessful(xml.readToString()); } catch (Exception e) { e.printStackTrace(); return false; } } /** * Returns the specific cloud command. E.g 'start-grid', 'start-env', 'terminate-env' * @return */ public abstract String getCommand(); /** * Returns the expected str for a sucessful start / terminate. * @return */ public abstract CloudStatus getSuccessStatus(); /** * Returns the timeout until Checked Status, in Seconds. * @return */ public abstract int getDefaultTimeout(); /** * Parses the output xml for a success code. * @param xml * @return */ private boolean isSucessful(String xml) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); NodeList list = doc.getElementsByTagName("Status"); if (list != null && list.getLength() > 0) { String successCriteria = getSuccessStatus().name(); return list.item(0).getTextContent().equals(successCriteria); } return false; } @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } }