/* * Jopr Management Platform * Copyright (C) 2005-2008 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, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * 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 and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.plugins.jbossas.script; import java.io.File; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.pluginapi.inventory.ResourceComponent; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.pluginapi.operation.OperationFacet; import org.rhq.core.pluginapi.operation.OperationResult; import org.rhq.core.pluginapi.util.ProcessExecutionUtility; import org.rhq.core.system.ProcessExecution; import org.rhq.core.system.ProcessExecutionResults; import org.rhq.core.system.SystemInfo; import org.rhq.plugins.jbossas.JBossASServerComponent; /** * A JON service that provides the ability to execute a script. * * @author Ian Springer */ public class ScriptComponent implements ResourceComponent<JBossASServerComponent<?>>, OperationFacet { public static final String PATH_CONFIG_PROP = "path"; public static final String ENVIRONMENT_VARIABLES_CONFIG_PROP = "environmentVariables"; public static final String EXECUTE_OPERATION = "execute"; public static final String COMMAND_LINE_ARGUMENTS_PARAM_PROP = "commandLineArguments"; private static final String EXIT_CODE_RESULT_PROP = "exitCode"; private static final String OUTPUT_RESULT_PROP = "output"; private final Log log = LogFactory.getLog(this.getClass()); private ResourceContext<JBossASServerComponent<?>> resourceContext; public void start(ResourceContext<JBossASServerComponent<?>> resourceContext) { this.resourceContext = resourceContext; } public void stop() { this.resourceContext = null; } public AvailabilityType getAvailability() { File scriptFile = getScriptFile(); return (scriptFile.exists()) ? AvailabilityType.UP : AvailabilityType.DOWN; } public OperationResult invokeOperation(String name, Configuration params) throws Exception { if (name.equals(EXECUTE_OPERATION)) { OperationResult operationResult = new OperationResult(); File scriptFile = getScriptFile(); SystemInfo systemInfo = this.resourceContext.getSystemInformation(); ProcessExecution processExecution = ProcessExecutionUtility.createProcessExecution(scriptFile); processExecution.setWaitForCompletion(1000L * 60 * 60); // 1 hour processExecution.setCaptureOutput(true); // TODO: Make the script's cwd configurable, but default it to the directory containing the script. processExecution.setWorkingDirectory(scriptFile.getParent()); setEnvironmentVariables(processExecution); setCommandLineArguments(params, processExecution); if (log.isDebugEnabled()) { log.debug(processExecution); } ProcessExecutionResults processExecutionResults = systemInfo.executeProcess(processExecution); if (processExecutionResults.getError() != null) { throw new Exception(processExecutionResults.getError()); } Integer exitCode = processExecutionResults.getExitCode(); String output = processExecutionResults.getCapturedOutput(); // NOTE: this is stdout + stderr Configuration complexResults = operationResult.getComplexResults(); complexResults.put(new PropertySimple(EXIT_CODE_RESULT_PROP, exitCode)); complexResults.put(new PropertySimple(OUTPUT_RESULT_PROP, output)); if (exitCode != null && exitCode != 0) { operationResult.setErrorMessage("Exit code was '" + exitCode + "', see operation results for details"); } return operationResult; } else { throw new IllegalArgumentException("Unsupported operation: " + name); } } private void setCommandLineArguments(Configuration params, ProcessExecution processExecution) { List<String> processExecutionArguments = processExecution.getArguments(); if (null == processExecutionArguments) { processExecutionArguments = new ArrayList<String>(); processExecution.setArguments(processExecutionArguments); } String cmdLineArgsString = params.getSimpleValue(COMMAND_LINE_ARGUMENTS_PARAM_PROP, null); List<String> cmdLineArgs = createCommandLineArgumentList(cmdLineArgsString); processExecutionArguments.addAll(cmdLineArgs); } private void setEnvironmentVariables(ProcessExecution processExecution) { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); Map<String, String> processExecutionEnvironmentVariables = processExecution.getEnvironmentVariables(); if (null == processExecutionEnvironmentVariables) { processExecutionEnvironmentVariables = new LinkedHashMap<String, String>(); processExecution.setEnvironmentVariables(processExecutionEnvironmentVariables); } String envVars = pluginConfig.getSimpleValue(ENVIRONMENT_VARIABLES_CONFIG_PROP, null); Map<String, String> envVarsMap = createEnvironmentVariableMap(envVars); if (null != envVarsMap) { processExecutionEnvironmentVariables.putAll(envVarsMap); } } @NotNull private List<String> createCommandLineArgumentList(String cmdLineArgsString) { if (cmdLineArgsString == null) { return new ArrayList<String>(); } StringTokenizer tokenizer = new StringTokenizer(cmdLineArgsString, "\n"); List<String> cmdLineArgs = new ArrayList<String>(tokenizer.countTokens()); while (tokenizer.hasMoreTokens()) { String cmdLineArg = tokenizer.nextToken().trim(); cmdLineArg = replacePropertyPatterns(cmdLineArg); cmdLineArgs.add(cmdLineArg); } return cmdLineArgs; } private Map<String, String> createEnvironmentVariableMap(String envVarsString) { if (envVarsString == null) { return null; } StringTokenizer tokenizer = new StringTokenizer(envVarsString, "\n"); Map<String, String> envVars = new LinkedHashMap<String, String>(tokenizer.countTokens()); while (tokenizer.hasMoreTokens()) { String var = tokenizer.nextToken().trim(); int equalsIndex = var.indexOf('='); if (equalsIndex == -1) { throw new IllegalStateException("Malformed environment entry: " + var); } String varName = var.substring(0, equalsIndex); String varValue = var.substring(equalsIndex + 1); varValue = replacePropertyPatterns(varValue); envVars.put(varName, varValue); } return envVars; } private String replacePropertyPatterns(String value) { Pattern pattern = Pattern.compile("(%([^%]*)%)"); Matcher matcher = pattern.matcher(value); Configuration parentPluginConfig = this.resourceContext.getParentResourceComponent().getPluginConfiguration(); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { String propName = matcher.group(2); PropertySimple prop = parentPluginConfig.getSimple(propName); String propValue = ((prop != null) && (prop.getStringValue() != null)) ? prop.getStringValue() : ""; String propPattern = matcher.group(1); String replacement = (prop != null) ? propValue : propPattern; matcher.appendReplacement(buffer, Matcher.quoteReplacement(replacement)); } matcher.appendTail(buffer); return buffer.toString(); } private File getScriptFile() { Configuration pluginConfig = this.resourceContext.getPluginConfiguration(); String scriptFilePath = pluginConfig.getSimple(PATH_CONFIG_PROP).getStringValue(); return new File(scriptFilePath); } }