001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-11-26 22:19:36 +0000 (Mon, 26 Nov 2012) $' 007 * '$Revision: 31113 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029package org.kepler.actor.gsissh; 030 031import java.io.ByteArrayOutputStream; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.kepler.ssh.ExecException; 036import org.kepler.ssh.ExecFactory; 037import org.kepler.ssh.ExecInterface; 038 039import ptolemy.actor.TypedAtomicActor; 040import ptolemy.actor.TypedIOPort; 041import ptolemy.actor.parameters.PortParameter; 042import ptolemy.data.BooleanToken; 043import ptolemy.data.IntToken; 044import ptolemy.data.StringToken; 045import ptolemy.data.expr.Parameter; 046import ptolemy.data.type.BaseType; 047import ptolemy.kernel.CompositeEntity; 048import ptolemy.kernel.util.IllegalActionException; 049import ptolemy.kernel.util.NameDuplicationException; 050 051/** 052* Connects to a remote host using gsissh and execute commands. 053* It also provides functionalities to copy files between two 054* machines using sftp. Currently doesn't support recursive copy. 055* <p> 056* If the <i>target</i> is empty string or equals <b>local</b>, the Java Runtime 057* will be used for local execution instead of ssh. It behaves similarly to 058* other local command-line exec actors of Kepler but you do not need to change 059* your workflow for remote/local executions by using this actor. 060* <p> 061* This actor works similar to ExecuteCmd( org.kepler.actor.ssh.ExecuteCmd ) 062* but additionally supports connecting to grid server using grid certificates 063* 064* @author Chandrika Sivaramakrishnan 065* 066*/ 067public class ExecGsisshCmd extends TypedAtomicActor { 068 private static Log log = LogFactory.getLog(ExecGsisshCmd.class); 069 boolean isDebugging = log.isDebugEnabled(); 070 071 public ExecGsisshCmd(CompositeEntity container, String name) 072 throws NameDuplicationException, IllegalActionException { 073 super(container, name); 074 075 // target selects the machine where to connect to 076 target = new PortParameter(this, "target", new StringToken( 077 "[user@]host[:port]")); 078 new Parameter(target.getPort(), "_showName", BooleanToken.TRUE); 079 080 command = new TypedIOPort(this, "command", true, false); 081 command.setTypeEquals(BaseType.STRING); 082 new Parameter(command, "_showName", BooleanToken.TRUE); 083 084 stdout = new TypedIOPort(this, "stdout", false, true); 085 stdout.setTypeEquals(BaseType.STRING); 086 new Parameter(stdout, "_showName", BooleanToken.TRUE); 087 088 stderr = new TypedIOPort(this, "stderr", false, true); 089 stderr.setTypeEquals(BaseType.STRING); 090 new Parameter(stderr, "_showName", BooleanToken.TRUE); 091 092 exitcode = new TypedIOPort(this, "exitcode", false, true); 093 exitcode.setTypeEquals(BaseType.INT); 094 new Parameter(exitcode, "_showName", BooleanToken.TRUE); 095 096 errors = new TypedIOPort(this, "errors", false, true); 097 errors.setTypeEquals(BaseType.STRING); 098 new Parameter(errors, "_showName", BooleanToken.TRUE); 099 100 timeoutSeconds = new Parameter(this, "timeoutSeconds", new IntToken(0)); 101 timeoutSeconds.setTypeEquals(BaseType.INT); 102 103 cleanupAfterError = new Parameter(this, "cleanupAfterError", 104 new BooleanToken(false)); 105 cleanupAfterError.setTypeEquals(BaseType.BOOLEAN); 106 107 thirdParty = new PortParameter(this, "thirdParty", new StringToken("")); 108 new Parameter(thirdParty.getPort(), "_showName", BooleanToken.TRUE); 109 110 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" " 111 + "width=\"75\" height=\"50\" style=\"fill:blue\"/>\n" 112 + "<text x=\"5\" y=\"30\"" 113 + "style=\"font-size:14; fill:yellow; font-family:SansSerif\">" 114 + "ExecCmd</text>\n" + "</svg>\n"); 115 } 116 // //////////////// Public ports and parameters /////////////////////// 117 118 /** 119 * Target in user@host:port format. If user is not provided, the local 120 * username will be used. If port is not provided, the default port 22 will 121 * be applied. If target is "local" or empty string, the command will be 122 * executed locally, using Java Runtime. 123 */ 124 public PortParameter target; 125 126 /** 127 * The command to be executed on the remote host. It needs to be provided as 128 * a string. 129 */ 130 public TypedIOPort command; 131 132 /** 133 * Third party target in user@host:port format. If user is not provided, the 134 * local username will be used. If port is not provided, the default port 22 135 * will be applied. 136 */ 137 public PortParameter thirdParty; 138 139 /** 140 * Output of the command as it would output to the standard shell output. 141 */ 142 public TypedIOPort stdout; 143 144 /** 145 * The error that were reported by the remote execution or while connecting. 146 */ 147 public TypedIOPort stderr; 148 149 /** 150 * The exit code of the command. 151 */ 152 public TypedIOPort exitcode; 153 154 /** 155 * The string representation of all the errors that happened during the 156 * execution of the actor, if there are any. 157 */ 158 public TypedIOPort errors; 159 160 /** 161 * Timeout in seconds for the command to be executed. 0 means waiting 162 * indefinitely for command termination. 163 */ 164 public Parameter timeoutSeconds; 165 166 /** 167 * Enforce killing remote process(es) after an error or timeout. Unix 168 * specific solution is used, therefore you should not set this flag if 169 * connecting to other servers. But it is very useful for unix as timeout 170 * leaves processes living there, and sometimes errors too. All processes 171 * belonging to the same group as the remote command (i.e. its children) 172 * will be killed. 173 */ 174 public Parameter cleanupAfterError; 175 176 177 /////////////////////////////////////////////////////////////////// 178 //// public methods //// 179 180 /** 181 * Send the token in the <i>value</i> parameter to the output. 182 * 183 * @exception IllegalActionException 184 * If it is thrown by the send() method sending out the 185 * token. 186 */ 187 public void fire() throws IllegalActionException { 188 super.fire(); 189 190 // process inputs 191 target.update(); 192 StringToken tg = (StringToken) target.getToken(); 193 String strTarget = tg.stringValue(); 194 String strCommand = ((StringToken) command.get(0)).stringValue(); 195 int timeout = ((IntToken) timeoutSeconds.getToken()).intValue(); 196 boolean cleanup = ((BooleanToken) cleanupAfterError.getToken()) 197 .booleanValue(); 198 199 // third party target 200 thirdParty.update(); 201 String strThirdParty = ((StringToken) thirdParty.getToken()) 202 .stringValue(); 203 204 // get the execution object 205 //ExecInterface execObj = ExecFactory.getExecObject(strTarget); 206 //ExecInterface execObj = new GsiSshExec(strTarget); 207 ExecInterface execObj; 208 try { 209 execObj = ExecFactory.getExecObject(strTarget); 210 } catch (ExecException e1) { 211 String errText = new String("ExecuteCmd error:\n" + e1.getMessage()); 212 log.error(errText); 213 stdout.send(0, new StringToken("")); 214 stderr.send(0, new StringToken("")); 215 exitcode.send(0, new IntToken(-32767)); 216 errors.send(0, new StringToken(errText)); 217 return; 218 } 219 execObj.setTimeout(timeout, false, false); 220 execObj.setForcedCleanUp(cleanup); 221 222 int exitCode = 0; 223 ByteArrayOutputStream cmdStdout = new ByteArrayOutputStream(); 224 ByteArrayOutputStream cmdStderr = new ByteArrayOutputStream(); 225 226 // execute command 227 try { 228 log.info("Exec cmd: " + strCommand); 229 exitCode = execObj.executeCmd(strCommand, cmdStdout, cmdStderr, 230 strThirdParty); 231 232 } catch (ExecException e) { 233 String errText = new String("ExecuteCmd error:\n" + e.getMessage()); 234 log.error(errText); 235 stdout.send(0, new StringToken("")); 236 stderr.send(0, new StringToken("")); 237 exitcode.send(0, new IntToken(-32767)); 238 errors.send(0, new StringToken(errText)); 239 return; 240 } 241 242 if (isDebugging) 243 log.debug("exit code = " + exitCode); 244 245 System.out.println("From cmdStderr="+cmdStderr.toString()); 246 System.out.println("From cmdStdout="+cmdStdout.toString()); 247 // send stdout, stderr and empty string as internal errors 248 exitcode.send(0, new IntToken(exitCode)); 249 stdout.send(0, new StringToken(cmdStdout.toString())); 250 stderr.send(0, new StringToken(cmdStderr.toString())); 251 errors.send(0, new StringToken("")); 252 253 } // end-method fire() 254 255}