package org.jenkinsci.plugins.openshift.util; import static java.util.Collections.EMPTY_LIST; import static org.apache.commons.io.FilenameUtils.getName; import hudson.AbortException; import hudson.FilePath; import hudson.model.BuildListener; import hudson.model.AbstractBuild; import hudson.model.Computer; import hudson.model.Hudson; import java.io.File; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import jenkins.model.Jenkins.MasterComputer; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.jenkinsci.plugins.openshift.DeployApplication; import org.jenkinsci.plugins.openshift.OpenShiftV2Client.DeploymentType; import org.jenkinsci.plugins.openshift.Server; /** * @author Siamak Sadeghianfar <ssadeghi@redhat.com> */ public final class Utils { private static final Logger LOG = Logger.getLogger(Utils.class.getName()); private Utils() { } public static boolean isURL(String str) { return str.startsWith("http://") || str.startsWith("https://"); } public static Server findServer(String selectedServer) { for (Server server : getServers()) { if(server.getName().equals(selectedServer)) { return server; } } return null; } public static void copyURLToFile(final URL source, final File destination, final int connectionTimeout, final int readTimeout) throws IOException { final URLConnection connection = source.openConnection(); connection.setConnectTimeout(connectionTimeout); connection.setReadTimeout(readTimeout); InputStream is = connection.getInputStream(); FileOutputStream output = openOutputStream(destination); try { IOUtils.copy(is, output); output.close(); } finally { IOUtils.closeQuietly(is); } } public static FileOutputStream openOutputStream(final File file) throws IOException { if (file.exists()) { if (file.isDirectory()) { throw new IOException("File '" + file + "' exists but is a directory"); } if (file.canWrite() == false) { throw new IOException("File '" + file + "' cannot be written to"); } } else { final File parent = file.getParentFile(); if (parent != null) { // TEMP LOG.info("Parent exists: " + parent.exists()); // TEMP if (!parent.mkdirs() && !parent.isDirectory()) { throw new IOException("Directory '" + parent + "' could not be created"); } } } return new FileOutputStream(file, false); } public static void abort(BuildListener listener, String msg) throws AbortException { listener.error("[OPENSHIFT] " + msg); throw new AbortException(); } public static void abort(BuildListener listener, Exception e) throws AbortException { abort(listener, ExceptionUtils.getStackTrace(e)); } public static void log(BuildListener listener, String msg) throws AbortException { listener.getLogger().println("[OPENSHIFT] " + msg); } public static String getBuildStepName(String name) { return "OpenShift: " + name; } private static DeployApplication.DeployApplicationDescriptor getDeployApplicationDescriptor() { return (DeployApplication.DeployApplicationDescriptor)Hudson.getInstance().getDescriptor(DeployApplication.class); } @SuppressWarnings("unchecked") public static List<Server> getServers() { DeployApplication.DeployApplicationDescriptor descriptor = getDeployApplicationDescriptor(); List<Server> servers = descriptor.getServers(); return servers == null ? (List<Server>) EMPTY_LIST : servers; } public static String getSSHPrivateKey() { DeployApplication.DeployApplicationDescriptor descriptor = getDeployApplicationDescriptor(); return descriptor.getPublicKeyPath() == null ? null : descriptor.getPublicKeyPath().replaceAll("^(.*)\\.pub$", "$1"); } public static File createDir(String path) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } return dir; } public static Boolean validateOpenshiftDirectory(String openshiftDirectory) { List<String> validNames = new ArrayList<String>() {{ add("openshift"); add(".openshift"); add("config"); add("action_hooks"); add("markers"); }}; File directory = null; if (openshiftDirectory.startsWith(File.separator)) directory = new File(openshiftDirectory); // Absolute Path else directory = new File(Utils.class.getResource("/").getPath() + File.separator + openshiftDirectory); // Relative Path // Make sure the path exists and is a directory if(!directory.exists()) return false; if(!directory.isDirectory()) return false; // Try to determine whether the user has configured a directory containing // a .openshift directory, or the .openshift directory itself */ String[] filesArray = directory.list(new FilenameFilter() { public boolean accept(File dir, String name) { if (name.equals(".") || name.equals("..")) return false; return true; } }); if(filesArray == null) return false; List<String> files = Arrays.asList(filesArray); // Check whether there are valid entries in the files list if(CollectionUtils.containsAny(files,validNames)) { // Looks like a valid directory return true; } // We did not find anything, meaning the directory is not valid return false; } public static String getBuildWorkspaceOnMaster(AbstractBuild<?, ?> build) { if (runingOnMaster()) { return build.getWorkspace().getRemote(); } // the current build dir on master + workspace: // jenkins/jobs/[jobname]/builds/[buildnumber]/workspace return build.getProject().getBuildDir() + File.separator + build.getNumber() + File.separator + "workspace"; } public static boolean runingOnMaster() { return Computer.currentComputer() instanceof MasterComputer; } public static void copyFileFromSlaveToMaster(AbstractBuild<?,?> build, String slavePath, String masterPath) throws IOException { FilePath slaveFile = new FilePath(build.getWorkspace().getChannel(), slavePath); File masterFile = new File(masterPath); try { if (!slaveFile.exists()) { return; } } catch (InterruptedException e) { throw new IOException(e); } try { if (slaveFile.isDirectory()) { // remove if dir exists on master if (masterFile.exists()) { FileUtils.deleteDirectory(masterFile); } // create dir on master if (!masterFile.mkdirs()) { throw new IOException("Failed to create the directory on master node: " + masterPath); } slaveFile.copyRecursiveTo(new FilePath(masterFile)); } else { slaveFile.copyTo(new FilePath(masterFile)); } } catch (InterruptedException e) { throw new IOException("Failed to copy file from slave node to master.", e); } } public static List<String> copyDeploymenstToMaster(AbstractBuild<?,?> build, BuildListener listener, List<String> deployments, File baseDir, DeploymentType deploymentType) throws IOException { List<String> localDeployments = new ArrayList<String>(); for (String deployment : deployments) { if (isURL(deployment)) { File localDeployment = new File (baseDir, getURLDeploymentName(deployment, deploymentType)); log(listener, "Downloading the deployment from '" + deployment + "' to '" + localDeployment.getAbsolutePath() + "'"); try { copyURLToFile(new URL(deployment), localDeployment, 10000, 10000); } catch (Exception e) { abort(listener, e); } localDeployments.add(localDeployment.getAbsolutePath()); } else { if (Utils.runingOnMaster()) { // deployment is already local localDeployments.add(deployment); } else { String localFile = baseDir + File.separator + getName(deployment); log(listener, "Copying the deployment from slave node to '" + localFile + "'"); copyFileFromSlaveToMaster(build, deployment, localFile); localDeployments.add(localFile); } } } return localDeployments; } private static String getURLDeploymentName(String deployment, DeploymentType deploymentType) { if (!isURL(deployment)) { throw new IllegalArgumentException("Deployment paht is not a url: " + deployment); } if (deploymentType == DeploymentType.BINARY) { return "app.tar.gz"; } else { String dep = deployment.toLowerCase(); if (dep.contains(".ear")) { return "ROOT.ear"; } else if (dep.contains(".war")) { return "ROOT.war"; } else if (dep.contains("ear")) { // TODO: fuzzy! make a better guess since it // might be just part of the url e.g. /bear return "ROOT.ear"; } else { return "ROOT.war"; } } } }