/* * RHQ Management Platform * Copyright (C) 2005-2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.plugins.filetemplate; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.bundle.filetemplate.recipe.RecipeContext; import org.rhq.bundle.filetemplate.recipe.RecipeParser; import org.rhq.core.domain.bundle.BundleResourceDeployment; import org.rhq.core.domain.bundle.BundleResourceDeploymentHistory; import org.rhq.core.domain.content.PackageVersion; import org.rhq.core.pluginapi.bundle.BundleManagerProvider; import org.rhq.core.system.ProcessExecution; import org.rhq.core.system.ProcessExecutionResults; import org.rhq.core.system.SystemInfo; import org.rhq.core.util.file.FileUtil; /** * A recipe context that processes the recipe as it adds stuff to the context * * @author John Mazzitelli */ public class ProcessingRecipeContext extends RecipeContext { private final Log log = LogFactory.getLog(this.getClass()); private final SystemInfo systemInfo; private final String baseWorkingDirectory; private final BundleResourceDeployment bundleResourceDeployment; private final BundleManagerProvider bundleManagerProvider; public ProcessingRecipeContext(String recipe, Map<PackageVersion, File> packageVersionFiles, SystemInfo systemInfo, String baseWorkingDirectory, BundleResourceDeployment bundleResourceDeployment, BundleManagerProvider bundleManagerProvider) { super(recipe); this.systemInfo = systemInfo; this.baseWorkingDirectory = baseWorkingDirectory; // the directory that existing bundle filenames will be relative to this.bundleResourceDeployment = bundleResourceDeployment; this.bundleManagerProvider = bundleManagerProvider; } @Override public void addDeployFile(String filename, String directory) { super.addDeployFile(filename, directory); String msg; File existingFile = new File(this.baseWorkingDirectory, filename); ProcessExecution pe = getUnzipExecution(existingFile, directory); if (pe != null) { ProcessExecutionResults results = this.systemInfo.executeProcess(pe); if (results.getError() != null) { msg = "Could not unbundle file [" + pe + "]: " + results; audit("deploy", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg, results.getError()); } else if (results.getExitCode() == null || results.getExitCode().intValue() > 0) { msg = "Failed to unbundle file [" + pe + "]: " + results; audit("deploy", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg); } else { msg = "extracted files from [" + existingFile + "] to [" + directory + "]"; } // existingFile.delete(); WOULD WE WANT TO REMOVE THE COMPRESSED FILE? audit("deploy", BundleResourceDeploymentHistory.Status.SUCCESS, msg); } else { // not a zipped format - just move the file to the directory as-is File newFile = new File(directory, filename); if (!existingFile.renameTo(newFile)) { msg = "Failed to move [" + existingFile + "] to [" + newFile + "]"; audit("deploy", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg); } audit("deploy", BundleResourceDeploymentHistory.Status.SUCCESS, "renamed [" + existingFile + "] to [" + newFile + "]"); } } @Override public void addFile(String source, String destination) { super.addFile(source, destination); File sourceFile = new File(this.baseWorkingDirectory, source); File destinationFile = new File(destination); try { destinationFile.getParentFile().mkdirs(); FileUtil.copyFile(sourceFile, destinationFile); audit("file", BundleResourceDeploymentHistory.Status.SUCCESS, "copied file [" + sourceFile + "] to [" + destinationFile + "]"); } catch (Exception e) { String msg = "Failed to copy file [" + sourceFile + "] to [" + destinationFile + "]"; audit("file", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg, e); } return; } @Override public void addRealizedFile(String file) { super.addRealizedFile(file); String msg; File trueFile = new File(file); RecipeParser parser = getParser(); File realizedTmpFile = null; FileWriter realizedTmpFileWriter = null; BufferedReader reader = null; try { realizedTmpFile = File.createTempFile("rhq-realize-", ".tmp", trueFile.getParentFile()); realizedTmpFileWriter = new FileWriter(realizedTmpFile); reader = new BufferedReader(new FileReader(trueFile)); String line = reader.readLine(); while (line != null) { line = parser.replaceReplacementVariables(this, line); realizedTmpFileWriter.write(line); realizedTmpFileWriter.write("\n"); line = reader.readLine(); } realizedTmpFileWriter.close(); realizedTmpFileWriter = null; reader.close(); reader = null; audit("realize", BundleResourceDeploymentHistory.Status.SUCCESS, "realized [" + file + "]"); trueFile.delete(); // remove the one with the replacement variables in it if (!realizedTmpFile.renameTo(trueFile)) { msg = "Failed to rename realized tmp file [" + realizedTmpFile + "] to [" + trueFile + "]"; audit("realize", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg); } audit("realize", BundleResourceDeploymentHistory.Status.SUCCESS, "renamed realized file [" + realizedTmpFile + "] to [" + trueFile + "]"); } catch (Exception e) { msg = "Cannot realize file [" + file + "]"; audit("realize", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg, e); } finally { if (realizedTmpFileWriter != null) { try { realizedTmpFileWriter.close(); } catch (Exception e) { } } if (reader != null) { try { reader.close(); } catch (Exception e) { } } if (realizedTmpFile != null && realizedTmpFile.exists()) { realizedTmpFile.delete(); } } } @Override public void addReplacementVariables(Set<String> replacementVariables) { super.addReplacementVariables(replacementVariables); } @Override public void addScript(String exe, List<String> exeArgs) { super.addScript(exe, exeArgs); File scriptFile = new File(this.baseWorkingDirectory, exe); ensureExecutable(scriptFile); ProcessExecution pe = new ProcessExecution(scriptFile.getAbsolutePath()); pe.setArguments(exeArgs); pe.setWaitForCompletion(30 * 60 * 1000L); pe.setWorkingDirectory(scriptFile.getParent()); String msg; ProcessExecutionResults results = this.systemInfo.executeProcess(pe); if (results.getError() != null) { msg = "Could not execute script [" + pe + "]: " + results; audit("script", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg, results.getError()); } else { msg = "Executed script [" + pe + "]"; audit("script", BundleResourceDeploymentHistory.Status.SUCCESS, msg); } return; } @Override public void addCommand(String exe, List<String> exeArgs) { super.addCommand(exe, exeArgs); ProcessExecution pe = new ProcessExecution(exe); pe.setArguments(exeArgs); pe.setWaitForCompletion(30 * 60 * 1000L); pe.setCheckExecutableExists(false); pe.setWorkingDirectory(this.baseWorkingDirectory); String msg; ProcessExecutionResults results = this.systemInfo.executeProcess(pe); if (results.getError() != null) { msg = "Could not execute command [" + pe + "]: " + results; audit("command", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg, results.getError()); } else { msg = "Executed command [" + pe + "]"; audit("command", BundleResourceDeploymentHistory.Status.SUCCESS, msg); } return; } private void audit(String action, BundleResourceDeploymentHistory.Status status, String message) { try { bundleManagerProvider.auditDeployment(bundleResourceDeployment, action, "recipe", null, status, message, null); if (log.isDebugEnabled()) { log.debug("Deployment [" + bundleResourceDeployment.getBundleDeployment().getBundleVersion() + "] audit: action=[" + action + "], status=[" + status + "], message: " + message); } } catch (Exception e) { log.warn("Failed to send audit message for deployment of [" + bundleResourceDeployment.getBundleDeployment().getBundleVersion() + "]. audit action=[" + action + "], status=[" + status + "], message: " + message); } } private void ensureExecutable(File scriptFile) { boolean success = scriptFile.setExecutable(true, true); if (!success) { String msg = "Cannot ensure that script [" + scriptFile + "] is executable"; audit("ensureExecutable", BundleResourceDeploymentHistory.Status.FAILURE, msg); throw new RuntimeException(msg); } return; } private ProcessExecution getUnzipExecution(File file, String directory) { String exe; List<String> args = null; String filepath = file.getAbsolutePath(); if (filepath.endsWith(".tar")) { exe = "tar"; args = new ArrayList<String>(); args.add("xf"); args.add(filepath); args.add("-C"); args.add(directory); } else if (filepath.endsWith(".tar.bz2") || filepath.endsWith(".tbz2") || filepath.endsWith(".tbz")) { exe = "tar"; args = new ArrayList<String>(); args.add("xfj"); args.add(filepath); args.add("-C"); args.add(directory); } else if (filepath.endsWith(".tar.gz") || filepath.endsWith(".tgz")) { exe = "tar"; args = new ArrayList<String>(); args.add("xfz"); args.add(filepath); args.add("-C"); args.add(directory); } else if (filepath.endsWith(".zip")) { exe = "unzip"; args = new ArrayList<String>(); args.add("-o"); args.add(filepath); args.add("-d"); args.add(directory); } else if (filepath.endsWith(".rpm")) { exe = "rpm"; args = new ArrayList<String>(); args.add("-i"); args.add(filepath); if (directory != null && directory.length() > 0) { args.add("--prefix"); args.add(directory); } } else { return null; // isn't a unzippable package, we'll just copy it as is } ProcessExecution pe = new ProcessExecution(exe); pe.setArguments(args); pe.setWaitForCompletion(30 * 60 * 1000L); pe.setCheckExecutableExists(false); pe.setWorkingDirectory(this.baseWorkingDirectory); return pe; } }