/* * Lokomo OneCMDB - An Open Source Software for Configuration * Management of Datacenter Resources * * Copyright (C) 2006 Lokomo Systems AB * * 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; either version 2 of the License, or (at * your option) any later version. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * Lokomo Systems AB can be contacted via e-mail: info@lokomo.com or via * paper mail: Lokomo Systems AB, Sv�rdv�gen 27, SE-182 33 * Danderyd, Sweden. * */ package org.onecmdb.ui.gwt.desktop.server.command.exec; import java.io.File; import java.io.FileWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.onecmdb.core.IRfcResult; import org.onecmdb.core.utils.bean.CiBean; import org.onecmdb.core.utils.bean.ValueBean; import org.onecmdb.core.utils.graph.query.GraphQuery; import org.onecmdb.core.utils.graph.query.constraint.AttributeValueConstraint; import org.onecmdb.core.utils.graph.query.selector.ItemOffspringSelector; import org.onecmdb.core.utils.graph.query.selector.ItemRelationSelector; import org.onecmdb.core.utils.graph.result.Graph; import org.onecmdb.core.utils.graph.result.Template; import org.onecmdb.ui.gwt.desktop.client.service.CMDBRPCException; import org.onecmdb.ui.gwt.desktop.client.service.model.CIModel; import org.onecmdb.ui.gwt.desktop.client.service.model.mdr.MDRHistoryState; import org.onecmdb.ui.gwt.desktop.client.window.mdr.MDRConfigureWindow; import org.onecmdb.ui.gwt.desktop.server.command.ExecCommand; import org.onecmdb.ui.gwt.desktop.server.service.model.ShellMapper; import org.onecmdb.ui.gwt.desktop.server.service.model.Transform; public class MDRExecThread extends Thread { private ExecCommand cmd; Log logger = LogFactory.getLog(this.getClass()); private List<PrintWriter> logs = new ArrayList<PrintWriter>(); private boolean terminate; private JavaExec exec; StreamHandler streamHandler = null; private Date createDate; public MDRExecThread(ExecCommand cmd) { this.cmd = cmd; this.createDate = new Date(); } public void run() { CiBean historyBean = null; String stdErr = null; String stdOut = null; ExecResult result = null; String prgPath = null; try { CiBean[] beans = getMDRBeans(); CiBean mdrBean = beans[0]; CiBean configBean = beans[1]; /* final CiBean mdrBean = cmd.getCI("Ci", cmd.getMdr()); //final CiBean mdrBean = cmd.getCI("Ci", configBean.toStringValue("mdrRepository")); if (mdrBean == null) { throw new IllegalArgumentException("No MDR with name '" + cmd.getMdr() + "' found!"); } log("MDR '" + cmd.getMdr() + "' loaded..."); // Fetch Config. Collection<CiBean> configBeans = cmd.queryCI("MDR_ConfigEntry", "name", cmd.getConfig()); if (configBeans.size() != 1) { throw new IllegalArgumentException("Found " + configBeans.size() + " config CI's with name <" + cmd.getConfig() + "> is not found."); } final CiBean configBean = configBeans.iterator().next(); */ log("MDR Config loaded..."); historyBean = cmd.createHistory(configBean); log("History created [" + historyBean.getAlias() + "] ..."); final HashMap<String, String> params = new HashMap<String, String>(); log("Initilize Params START..."); for (ValueBean v : configBean.getAttributeValues()) { String value = v.getValue(); if (params.containsKey(v.getAlias())) { String oldValue = params.get(v.getAlias()); value = oldValue + "," + value; } params.put(v.getAlias(), value); log("\t" + v.getAlias() + "=" + value); } params.put("mdr_history", historyBean.getAlias()); params.put("onecmdb_token", cmd.getToken()); log("Initilize Params END..."); log("Exec Thread Started..."); // Create exec. synchronized(this) { if (this.terminate) { throw new InterruptedException("Terminate..."); } exec = new JavaExec(this); Properties p = ShellMapper.getShellProperties(); if (p != null) { exec.setShellMap(p); } } exec.setProgramArgs(params); String mdrName = mdrBean.toStringValue("name"); String configProgram = configBean.toStringValue("program"); String startPath = cmd.getRoot() + "/" + mdrName; File startFile = new File(startPath); log("Start path set to '" + startPath +"'"); if (!startFile.exists() || !startFile.isDirectory()) { throw new IllegalArgumentException("No 'program' specified in config!"); } if (configProgram.length() == 0) { throw new IllegalArgumentException("No 'program' specified in config!"); } prgPath = startPath + "/" + configProgram; log("Program path set to '" + prgPath +"'"); exec.setProgramPath(prgPath); exec.setStartDir(startPath); // Direct in/out/err... String logPath = startPath + "/logs/"; File logFile = new File(logPath);; if (!logFile.exists()) { logFile.mkdirs(); } File prgFile = new File(prgPath); String prgName = prgFile.getName(); // Time SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd-HHmmss"); String dateStr = fmt.format(new Date()); stdErr = logPath + "stderr-" + prgName + "-" + dateStr; stdOut = logPath + "stdout-" + prgName + "-" + dateStr; synchronized(this) { if (this.terminate) { throw new InterruptedException("Terminate..."); } streamHandler = new StreamHandler(this, mdrBean.toStringValue("name") + "/" + configBean.toStringValue("program")); } streamHandler.setStderr(new FileWriter(new File(stdErr))); streamHandler.setStdout(new FileWriter(new File(stdOut))); streamHandler.setAutoClose(true); //streamHandler.setStdin(writer); log("Direct stdout to " + stdOut); log("Direct stderr to " + stdErr); exec.setStreamHandler(streamHandler); // Do exec. log("Start Exec..."); long start = System.currentTimeMillis(); result = exec.doExec(); long stop = System.currentTimeMillis(); log("Exec Ended [" + (stop-start) + "ms], result=" + result.toString()); } catch (Throwable t) { log("Exec Exception: "); log(t); result = new ExecResult(); result.setMessage("Internal Exception: " + t.getMessage()); result.setRc(ExecResult.ERROR_EXCEPTION_INIT); cmd.setExecError(t); } finally { if (streamHandler != null) { streamHandler.terminate(); } if (historyBean != null) { try { log("Update History...."); // Reload historyBean: CiBean local = cmd.getCI(historyBean.getDerivedFrom(), historyBean.getAlias()); CiBean base = local.copy(); cmd.setValue(local, "exitCode", "" + result.getRc()); cmd.setValue(local, "execMessage", result.getMessage()); cmd.setValue(local, "stderr", stdErr); cmd.setValue(local, "stdout", stdOut); if (result.getRc() != 0) { cmd.setValue(local, "status", MDRHistoryState.FAILED); } else { String status = local.toStringValue("status"); if (status == null || status.length() == 0 || status.equals(MDRHistoryState.EXECUTING)) { cmd.setValue(local, "status", MDRHistoryState.READY); } } IRfcResult rfcResult = cmd.update(local, base); if (rfcResult.isRejected()) { log("History updated was rejected, cause " + rfcResult.getRejectCause()); } else { log("History update complete"); } } catch (Throwable t) { logger.error("Can't update history " + historyBean.getAlias() + " for " + prgPath); log("History update failed"); log(t); cmd.setExecError(t); } } log("Execution Completed"); cmd.unregister(this); } } private CiBean[] getMDRBeans() throws Exception { CiBean resultVector[] = new CiBean[2]; GraphQuery query = new GraphQuery(); ItemOffspringSelector mdrs = new ItemOffspringSelector("mdr", "MDR_Repository"); mdrs.setPrimary(true); AttributeValueConstraint mdrCon = new AttributeValueConstraint(); mdrCon.setAlias("name"); mdrCon.setOperation(AttributeValueConstraint.EQUALS); String mdrName = cmd.getMdr(); mdrCon.setValue(mdrName); mdrs.applyConstraint(mdrCon); ItemOffspringSelector mdrConfigs = new ItemOffspringSelector("config", "MDR_ConfigEntry"); AttributeValueConstraint mdrConfigCon = new AttributeValueConstraint(); mdrConfigCon.setAlias("name"); mdrConfigCon.setOperation(AttributeValueConstraint.EQUALS); String configName = cmd.getConfig(); mdrConfigCon.setValue(configName); mdrConfigs.applyConstraint(mdrConfigCon); ItemRelationSelector rel = new ItemRelationSelector("config2mdr", "Reference", "mdr", "config"); query.addSelector(mdrs); query.addSelector(mdrConfigs); query.addSelector(rel); Graph result = cmd.getService().queryGraph(cmd.getToken(), query); Template mdrTempl = result.fetchNode(mdrs.getId()); if (mdrTempl == null) { throw new IllegalArgumentException("No MDR with name '" + cmd.getMdr() + "' found!"); } if (mdrTempl.getOffsprings() == null || mdrTempl.getOffsprings().size() == 0) { throw new IllegalArgumentException("No MDR with name '" +cmd.getMdr() + "' found!", null); } if (mdrTempl.getOffsprings().size() != 1) { throw new IllegalArgumentException("More than one (" + mdrTempl.getOffsprings().size() + "' MDR with name '" + cmd.getMdr() + "' found!", null); } CiBean mdrBean = mdrTempl.getOffsprings().get(0); resultVector[0] = mdrBean; Template mdrConfigTempl = result.fetchNode(mdrConfigs.getId()); if (mdrConfigTempl == null) { throw new IllegalArgumentException("No MDR Config with name '" + cmd.getConfig() + "' found!", null); } if (mdrConfigTempl.getOffsprings() == null || mdrConfigTempl.getOffsprings().size() == 0) { throw new IllegalArgumentException("No MDR Config with name '" + cmd.getConfig() + "' found!", null); } if (mdrConfigTempl.getOffsprings().size() != 1) { throw new IllegalArgumentException("More than one(" + mdrConfigTempl.getOffsprings().size() + "MDR Config with name '" + cmd.getConfig() + "' found!", null); } CiBean mdrConfigBean = mdrConfigTempl.getOffsprings().get(0); resultVector[1] = mdrConfigBean; return(resultVector); } public void log(Throwable t) { for (PrintWriter pw : this.logs) { synchronized (pw) { pw.println("Error: " + t.getMessage()); t.printStackTrace(pw); pw.flush(); } } } public void log(String msg) { for (PrintWriter pw : this.logs) { synchronized (pw) { pw.println(msg); pw.flush(); } } } public void addLog(PrintWriter pw) { synchronized(this.logs) { this.logs.add(pw); } } public boolean isTerminate() { return(this.terminate); } public void terminate(PrintWriter pw) { this.terminate = true; synchronized(this) { if (exec != null) { exec.halt(); } if (streamHandler != null) { streamHandler.terminate(); } } } public Date getStart() { return(createDate); } public ExecCommand getCmd() { return(this.cmd); } }