From 8b5e371c7b8720327aefff1461efdbfbac41fd6f Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Tue, 13 May 2003 14:37:04 +0000 Subject: [PATCH] Add to accompany and/or . MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR: 19541 Submitted by: Fran�ois Rey git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274566 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 3 + build.xml | 1 + docs/manual/OptionalTasks/rexec.html | 96 ++++ docs/manual/install.html | 2 +- docs/manual/optionaltasklist.html | 1 + .../tools/ant/taskdefs/defaults.properties | 1 + .../ant/taskdefs/optional/net/RExecTask.java | 433 ++++++++++++++++++ .../ant/taskdefs/optional/net/TelnetTask.java | 6 +- 8 files changed, 539 insertions(+), 4 deletions(-) create mode 100644 docs/manual/OptionalTasks/rexec.html create mode 100644 src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java diff --git a/WHATSNEW b/WHATSNEW index fc5540f12..8bc95e87a 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -316,6 +316,9 @@ Other changes: * will detect the rpmbuild executable of RedHat 8.0 and newer and use that if it is on your PATH. Bugzilla Report 14650. +* A new task has been added that requires commons-net to work. + Bugzilla Report 19541. + Changes from Ant 1.5.2 to Ant 1.5.3 =================================== diff --git a/build.xml b/build.xml index fb18c6d49..807ef94c0 100644 --- a/build.xml +++ b/build.xml @@ -234,6 +234,7 @@ + diff --git a/docs/manual/OptionalTasks/rexec.html b/docs/manual/OptionalTasks/rexec.html new file mode 100644 index 000000000..504a7dc50 --- /dev/null +++ b/docs/manual/OptionalTasks/rexec.html @@ -0,0 +1,96 @@ + + + + +RExec Task + + + + +

RExec

+

Description

+Task to automate a remote rexec session. Just like the Telnet task, +it uses nested <read> to indicate strings to wait for, and +<write> tags to specify text to send to the remote process. + +

Note: This task depends on external libraries not included in the Ant distribution. +See Library Dependencies for more information.

+ +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeValuesRequired
useridthe login id to use on the remote server.Yes
passwordthe login password to use on the remote server.Yes
serverthe address of the remote rexec server.Yes
commandthe command to execute on the remote server.Yes
portthe port number of the remote rexec server. Defaults to port 512 in BSD Unix systems.No
timeoutset a default timeout to wait for a response. Specified in seconds. Default is no timeout.No
+

Nested Elements

+The input to send to the server, and responses to wait for, are +described as nested elements. + +

read

+ +

declare (as a text child of this element) a string to wait for. +The element supports the timeout attribute, which overrides any +timeout specified for the task as a whole. It also has a string +attribute, which is an alternative to specifying the string as +a text element. +

+It is not necessary to declare a closing <read> element like for the Telnet task. The connection is not broken until the command has completed and +the input stream (output of the command) is terminated. + +

write

+ +

describes the text to send to the server. The echo boolean +attribute controls whether the string is echoed to the local log; +this is "true" by default +

+

Example

+A simple example of connecting to a server and running a command. + +
+<rexec userid="bob" password="badpass" server="localhost" command="ls"/>
+
+ +The task can be used with other ports as well: +
+<rexec port="80" userid="bob" password="badpass" server="localhost" command="ls"/>
+
+ +
+

Copyright © 2003 Apache Software Foundation. All rights +Reserved.

+ + + + diff --git a/docs/manual/install.html b/docs/manual/install.html index 9c65fc539..7d37c0e46 100644 --- a/docs/manual/install.html +++ b/docs/manual/install.html @@ -378,7 +378,7 @@ Installing Ant / Optional Tasks section above.

commons-net.jar - ftp and telnet tasks + ftp, rexec and telnet tasks http://jakarta.apache.org/commons/net/index.html diff --git a/docs/manual/optionaltasklist.html b/docs/manual/optionaltasklist.html index 49b62f18c..4525ef004 100644 --- a/docs/manual/optionaltasklist.html +++ b/docs/manual/optionaltasklist.html @@ -53,6 +53,7 @@ Pvcs
RenameExtensions
ReplaceRegExp
+RExec
Rpm
ServerDeploy
Setproxy
diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index 9bf07e1d7..9237f6a48 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -189,6 +189,7 @@ attrib=org.apache.tools.ant.taskdefs.optional.windows.Attrib scp=org.apache.tools.ant.taskdefs.optional.ssh.Scp sshexec=org.apache.tools.ant.taskdefs.optional.ssh.SSHExec jsharpc=org.apache.tools.ant.taskdefs.optional.dotnet.JSharp +rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask # deprecated ant tasks (kept for back compatibility) starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java new file mode 100644 index 000000000..cf60f1c44 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java @@ -0,0 +1,433 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.tools.ant.taskdefs.optional.net; + +import org.apache.commons.net.bsd.RExecClient; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.Vector; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; + +/** + * Automates the rexec protocol. + * + * @since Ant 1.6 + */ + +public class RExecTask extends Task { + /** + * The userid to login with, if automated login is used + */ + private String userid = null; + + /** + * The password to login with, if automated login is used + */ + private String password = null; + + /** + * The command to execute + */ + private String command = null; + + /** + * The server to connect to. + */ + private String server = null; + + /** + * The tcp port to connect to. + */ + private int port = RExecClient.DEFAULT_PORT; + + /** + * The Object which handles the rexec session. + */ + private AntRExecClient rexec = null; + + /** + * The list of read/write commands for this session + */ + private Vector rexecTasks = new Vector(); + + /** + * If true, adds a CR to beginning of login script + */ + private boolean addCarriageReturn = false; + + /** + * Default time allowed for waiting for a valid response + * for all child reads. A value of 0 means no limit. + */ + private Integer defaultTimeout = null; + + /** + * This class is the parent of the Read and Write tasks. + * It handles the common attributes for both. + */ + public class RExecSubTask { + protected String taskString = ""; + public void execute(AntRExecClient rexec) + throws BuildException { + throw new BuildException("Shouldn't be able instantiate a SubTask directly"); + } + + /** + * the message as nested text + */ + public void addText(String s) { + setString(getProject().replaceProperties(s)); + } + + /** + * the message as an attribute + */ + public void setString(String s) { + taskString += s; + } + } + + /** + * Sends text to the connected server + */ + public class RExecWrite extends RExecSubTask { + private boolean echoString = true; + public void execute(AntRExecClient rexec) + throws BuildException { + rexec.sendString(taskString, echoString); + } + + /** + * Whether or not the message should be echoed to the log. + * Defaults to true. + */ + public void setEcho(boolean b) { + echoString = b; + } + } + + /** + * Reads the output from the connected server + * until the required string is found or we time out. + */ + public class RExecRead extends RExecSubTask { + private Integer timeout = null; + public void execute(AntRExecClient rexec) + throws BuildException { + rexec.waitForString(taskString, timeout); + } + /** + * a timeout value that overrides any task wide timeout. + */ + public void setTimeout(Integer i) { + this.timeout = i; + } + + /** + * Sets the default timeout if none has been set already + * @ant.attribute ignore="true" + */ + public void setDefaultTimeout(Integer defaultTimeout) { + if (timeout == null) { + timeout = defaultTimeout; + } + } + } + + /** + * This class handles the abstraction of the rexec protocol. + * Currently it is a wrapper around Jakarta + * Commons Net. + */ + public class AntRExecClient extends RExecClient { + /** + * Read from the rexec session until the string we are + * waiting for is found + * @param s The string to wait on + */ + public void waitForString(String s) { + waitForString(s, null); + } + + /** + * Read from the rexec session until the string we are + * waiting for is found or the timeout has been reached + * @param s The string to wait on + * @param timeout The maximum number of seconds to wait + */ + public void waitForString(String s, Integer timeout) { + InputStream is = this.getInputStream(); + try { + StringBuffer sb = new StringBuffer(); + if (timeout == null || timeout.intValue() == 0) { + while (sb.toString().indexOf(s) == -1) { + sb.append((char) is.read()); + } + } else { + Calendar endTime = Calendar.getInstance(); + endTime.add(Calendar.SECOND, timeout.intValue()); + while (sb.toString().indexOf(s) == -1) { + while (Calendar.getInstance().before(endTime) && + is.available() == 0) { + Thread.sleep(250); + } + if (is.available() == 0) { + throw new BuildException( + "Response timed-out waiting for \"" + s + '\"', + getLocation()); + } + sb.append((char) is.read()); + } + } + log(sb.toString(), Project.MSG_INFO); + } catch (BuildException be) { + throw be; + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + + /** + * Write this string to the rexec session. + * @param echoString Logs string sent + */ + public void sendString(String s, boolean echoString) { + OutputStream os = this.getOutputStream(); + try { + os.write((s + "\n").getBytes()); + if (echoString) { + log(s, Project.MSG_INFO); + } + os.flush(); + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + /** + * Read from the rexec session until the EOF is found or + * the timeout has been reached + * @param timeout The maximum number of seconds to wait + */ + public void waitForEOF(Integer timeout) { + InputStream is = this.getInputStream(); + try { + StringBuffer sb = new StringBuffer(); + if (timeout == null || timeout.intValue() == 0) { + int read; + while ((read = is.read()) != -1) { + char c = (char) read; + sb.append(c); + if (c == '\n') { + log(sb.toString(), Project.MSG_INFO); + sb.delete(0, sb.length()); + } + } + } else { + Calendar endTime = Calendar.getInstance(); + endTime.add(Calendar.SECOND, timeout.intValue()); + int read = 0; + while (read != -1) { + while (Calendar.getInstance().before(endTime) && is.available() == 0) { + Thread.sleep(250); + } + if (is.available() == 0) { + log(sb.toString(), Project.MSG_INFO); + throw new BuildException( + "Response timed-out waiting for EOF", + getLocation()); + } + read = is.read(); + if (read != -1) { + char c = (char) read; + sb.append(c); + if (c == '\n') { + log(sb.toString(), Project.MSG_INFO); + sb.delete(0, sb.length()); + } + } + } + } + if (sb.length() > 0) { + log(sb.toString(), Project.MSG_INFO); + } + } catch (BuildException be) { + throw be; + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + + } + /** + * A string to wait for from the server. + * A subTask <read> tag was found. Create the object, + * Save it in our list, and return it. + */ + + public RExecSubTask createRead() { + RExecSubTask task = (RExecSubTask) new RExecRead(); + rexecTasks.addElement(task); + return task; + } + /** + * Add text to send to the server + * A subTask <write> tag was found. Create the object, + * Save it in our list, and return it. + */ + public RExecSubTask createWrite() { + RExecSubTask task = (RExecSubTask) new RExecWrite(); + rexecTasks.addElement(task); + return task; + } + /** + * Verify that all parameters are included. + * Connect and possibly login + * Iterate through the list of Reads and writes + */ + public void execute() throws BuildException { + /** A server name is required to continue */ + if (server == null) { + throw new BuildException("No Server Specified"); + } + /** A userid and password must appear together + * if they appear. They are not required. + */ + if (userid == null && password != null) { + throw new BuildException("No Userid Specified"); + } + if (password == null && userid != null) { + throw new BuildException("No Password Specified"); + } + + /** Create the telnet client object */ + rexec = new AntRExecClient(); + try { + rexec.connect(server, port); + } catch (IOException e) { + throw new BuildException("Can't connect to " + server); + } + /** Login if userid and password were specified */ + if (userid != null && password != null) { + login(); + } + /** Process each sub command */ + Enumeration tasksToRun = rexecTasks.elements(); + while (tasksToRun != null && tasksToRun.hasMoreElements()) { + RExecSubTask task = (RExecSubTask) tasksToRun.nextElement(); + if (task instanceof RExecRead && defaultTimeout != null) { + ((RExecRead) task).setDefaultTimeout(defaultTimeout); + } + task.execute(rexec); + } + + /** Keep reading input stream until end of it or time-out */ + rexec.waitForEOF(defaultTimeout); + } + /** + * Process a 'typical' login. If it differs, use the read + * and write tasks explicitely + */ + private void login() { + if (addCarriageReturn) { + rexec.sendString("\n", true); + } + rexec.waitForString("ogin:"); + rexec.sendString(userid, true); + rexec.waitForString("assword:"); + rexec.sendString(password, false); + } + /** + * Set the the comand to execute on the server; + */ + public void setCommand(String c) { this.command = c; } + /** + * send a carriage return after connecting; optional, defaults to false. + */ + public void setInitialCR(boolean b) { + this.addCarriageReturn = b; + } + /** + * Set the the login password to use + * required if userid is set. + */ + public void setPassword(String p) { this.password = p; } + /** + * Set the tcp port to connect to; default is 23. + */ + public void setPort(int p) { this.port = p; } + /** + * Set the hostname or address of the remote server. + */ + public void setServer(String m) { this.server = m; } + /** + * set a default timeout in seconds to wait for a response, + * zero means forever (the default) + */ + public void setTimeout(Integer i) { + this.defaultTimeout = i; + } + /** + * Set the the login id to use on the server; + * required if password is set. + */ + public void setUserid(String u) { this.userid = u; } +} diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java index 77e50dc0e..d670b4636 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java @@ -330,7 +330,7 @@ public class TelnetTask extends Task { try { StringBuffer sb = new StringBuffer(); if (timeout == null || timeout.intValue() == 0) { - while (sb.toString().indexOf(s) == -1){ + while (sb.toString().indexOf(s) == -1) { sb.append((char) is.read()); } } else { @@ -338,12 +338,12 @@ public class TelnetTask extends Task { endTime.add(Calendar.SECOND, timeout.intValue()); while (sb.toString().indexOf(s) == -1) { while (Calendar.getInstance().before(endTime) && - is.available() == 0) { + is.available() == 0) { Thread.sleep(250); } if (is.available() == 0) { throw new BuildException( - "Response timed-out waiting for \""+s+'\"', + "Response timed-out waiting for \"" + s + '\"', getLocation()); } sb.append((char) is.read());