From 26b2e20640b2639f6f88c246a33413009fabe402 Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Sat, 2 Jan 2010 03:29:50 +0000 Subject: [PATCH] new demo javaoverssh git-svn-id: http://jclouds.googlecode.com/svn/trunk@2566 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../aws/ec2/demos/createlamp/MainApp.java | 6 +- tools/antcontrib/pom.xml | 87 +++ .../antcontrib/samples/javaoverssh/README.txt | 25 + .../antcontrib/samples/javaoverssh/build.xml | 83 +++ .../samples/javaoverssh/src/TestClass.java | 16 + .../org/jclouds/tools/ant/JavaOverSsh.java | 560 ++++++++++++++++++ .../jclouds/tools/ant/JavaOverSshTest.java | 107 ++++ .../java/org/jclouds/tools/ant/TestClass.java | 18 + tools/pom.xml | 1 + 9 files changed, 900 insertions(+), 3 deletions(-) create mode 100644 tools/antcontrib/pom.xml create mode 100755 tools/antcontrib/samples/javaoverssh/README.txt create mode 100644 tools/antcontrib/samples/javaoverssh/build.xml create mode 100644 tools/antcontrib/samples/javaoverssh/src/TestClass.java create mode 100644 tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java create mode 100644 tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java create mode 100644 tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java diff --git a/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java b/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java index 6391d2ffc6..7932474744 100755 --- a/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java +++ b/aws/demos/createlamp/src/main/java/org/jclouds/aws/ec2/demos/createlamp/MainApp.java @@ -157,10 +157,10 @@ public class MainApp { } static RunningInstance runInstance(EC2Client client, String securityGroupName, String keyPairName) { - String script = new ScriptBuilder() // lamp install script .addStatement(exec("runurl run.alestic.com/apt/upgrade"))// .addStatement(exec("runurl run.alestic.com/install/lamp"))// + .addStatement(exec("apt-get -y install openjdk-6-jdk"))// no license agreement! .build(OsFamily.UNIX); System.out.printf("%d: running instance%n", System.currentTimeMillis()); @@ -183,8 +183,6 @@ public class MainApp { // create utilities that wait for the instance to finish RetryablePredicate runningTester = new RetryablePredicate( new InstanceStateRunning(client.getInstanceServices()), 180, 5, TimeUnit.SECONDS); - RetryablePredicate socketTester = new RetryablePredicate( - new SocketOpen(), 180, 1, TimeUnit.SECONDS); System.out.printf("%d: %s awaiting instance to run %n", System.currentTimeMillis(), instance .getId()); @@ -193,6 +191,8 @@ public class MainApp { instance = findInstanceById(client, instance.getId()); + RetryablePredicate socketTester = new RetryablePredicate( + new SocketOpen(), 300, 1, TimeUnit.SECONDS); System.out.printf("%d: %s awaiting ssh service to start%n", System.currentTimeMillis(), instance.getIpAddress()); if (!socketTester.apply(new InetSocketAddress(instance.getIpAddress(), 22))) diff --git a/tools/antcontrib/pom.xml b/tools/antcontrib/pom.xml new file mode 100644 index 0000000000..b8b132697b --- /dev/null +++ b/tools/antcontrib/pom.xml @@ -0,0 +1,87 @@ + + + + + 4.0.0 + + org.jclouds + jclouds-tools-project + 1.0-SNAPSHOT + + jclouds-antcontrib + Ant test + + + + + + org.jboss.shrinkwrap + shrinkwrap-impl-base + 1.0.0-alpha-3 + + + ${project.groupId} + jclouds-scriptbuilder + ${project.version} + + + org.apache.ant + ant + 1.7.1 + provided + + + org.apache.ant + ant-jsch + 1.7.1 + + + com.jcraft + jsch + 0.1.42 + + + + + ${project.artifactId} + + + + maven-assembly-plugin + + + package + + single + + + + jar-with-dependencies + + + + + + + + + diff --git a/tools/antcontrib/samples/javaoverssh/README.txt b/tools/antcontrib/samples/javaoverssh/README.txt new file mode 100755 index 0000000000..39800928bc --- /dev/null +++ b/tools/antcontrib/samples/javaoverssh/README.txt @@ -0,0 +1,25 @@ +==== + + Copyright (C) 2009 Cloud Conscious, LLC. + + ==================================================================== + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ==================================================================== +==== + this is a simple ant script that executes a java command on a remote machine via ssh + 1. find or download a copy of jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar + - ex. ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar + - ex. curl http://jclouds.rimuhosting.com/maven2/snapshots/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-20091215.023231-1-jar-with-dependencies.jar >jclouds-antcontrib-all.jar + 2. invoke ant, adding the library above, and passing the properties 'host' 'username' 'keyfile' which corresponds to your remote credentials + - ex. ant -lib ~/.m2/repository/org/jclouds/jclouds-antcontrib/1.0-SNAPSHOT/jclouds-antcontrib-1.0-SNAPSHOT-jar-with-dependencies.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa + - ex. ant -lib jclouds-antcontrib-all.jar -Dhost=67.202.42.237 -Dusername=root -Dkeyfile=$HOME/.ssh/id_dsa diff --git a/tools/antcontrib/samples/javaoverssh/build.xml b/tools/antcontrib/samples/javaoverssh/build.xml new file mode 100644 index 0000000000..2b4f6637a3 --- /dev/null +++ b/tools/antcontrib/samples/javaoverssh/build.xml @@ -0,0 +1,83 @@ + + + + + simple example build file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/antcontrib/samples/javaoverssh/src/TestClass.java b/tools/antcontrib/samples/javaoverssh/src/TestClass.java new file mode 100644 index 0000000000..d081ee8510 --- /dev/null +++ b/tools/antcontrib/samples/javaoverssh/src/TestClass.java @@ -0,0 +1,16 @@ +import java.io.File; +import java.util.Arrays; + +public class TestClass { + public static void main(String... args) { + File cwd = new File(System.getProperty("user.dir")); + System.out.println("children:"); + for (File child : cwd.listFiles()) + System.out.println(" " + child); + System.out.println("what you wrote:"); + System.out.println(Arrays.asList(args)); + System.err.println("this is the error stream"); + System.out.println("will exit 3:"); + System.exit(3); + } +} diff --git a/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java new file mode 100644 index 0000000000..86b82603f2 --- /dev/null +++ b/tools/antcontrib/src/main/java/org/jclouds/tools/ant/JavaOverSsh.java @@ -0,0 +1,560 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.tools.ant; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.scriptbuilder.domain.Statements.exec; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.List; +import java.util.zip.ZipFile; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.Java; +import org.apache.tools.ant.taskdefs.optional.ssh.SSHUserInfo; +import org.apache.tools.ant.types.CommandlineJava; +import org.apache.tools.ant.types.Environment; +import org.apache.tools.ant.util.KeepAliveOutputStream; +import org.apache.tools.ant.util.TeeOutputStream; +import org.jboss.shrinkwrap.api.Archives; +import org.jboss.shrinkwrap.api.exporter.ZipExporter; +import org.jboss.shrinkwrap.api.importer.ExplodedImporter; +import org.jboss.shrinkwrap.api.importer.ZipImporter; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; + +import com.google.common.collect.Lists; +import com.google.common.io.Closeables; +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +/** + * Ported from Jsch SSHExec task. + * + * @author Adrian Cole + */ +public class JavaOverSsh extends Java { + /** Default listen port for SSH daemon */ + private static final int SSH_PORT = 22; + private String jvm = "/usr/bin/java"; + private File localDirectory; + private File remoteDirectory; + private Environment env = new Environment(); + private String host; + private String knownHosts; + private int port = SSH_PORT; + private SSHUserInfo userInfo = new SSHUserInfo(); + private OsFamily osFamily = OsFamily.UNIX; + + /** units are milliseconds, default is 0=infinite */ + private long maxwait = 0; + + /** for waiting for the command to finish */ + private Thread watchDog = null; + private File outputFile; + private String outputProperty; + private String resultProperty; + private File errorFile; + private String errorProperty; + private boolean append; + + private static final String TIMEOUT_MESSAGE = "Timeout period exceeded, connection dropped."; + + public JavaOverSsh() { + super(); + setFork(true); + } + + public JavaOverSsh(Task owner) { + super(owner); + setFork(true); + } + + @Override + public int executeJava() throws BuildException { + String command = convertJavaToScript(getCommandLine()); + + InputStream classpathJar = (getCommandLine().getClasspath() != null) ? makeClasspathJarOrNull(getCommandLine() + .getClasspath().list()) + : null; + + InputStream bootClasspathJar = (getCommandLine().getBootclasspath() != null) ? makeClasspathJarOrNull(getCommandLine() + .getBootclasspath().list()) + : null; + + InputStream currentDirectoryZip = Archives.create("cwd.zip", ZipExporter.class).as( + ExplodedImporter.class).importDirectory(localDirectory).as(ZipExporter.class) + .exportZip(); + + if (getHost() == null) { + throw new BuildException("Host is required."); + } + if (getUserInfo().getName() == null) { + throw new BuildException("Username is required."); + } + if (getUserInfo().getKeyfile() == null && getUserInfo().getPassword() == null) { + throw new BuildException("Password or Keyfile is required."); + } + + Session session = null; + try { + // execute the command + session = openSession(); + session.setTimeout((int) maxwait); + ChannelSftp sftp = null; + sftp = (ChannelSftp) session.openChannel("sftp"); + sftp.connect(); + sftp.put(currentDirectoryZip, remoteDirectory + "/cwd.zip"); + Closeables.closeQuietly(currentDirectoryZip); + + if (classpathJar != null || bootClasspathJar != null) { + if (classpathJar != null) { + sftp.put(classpathJar, remoteDirectory + "/classpath.jar"); + Closeables.closeQuietly(classpathJar); + } + if (bootClasspathJar != null) { + sftp.put(classpathJar, remoteDirectory + "/boot-classpath.jar"); + Closeables.closeQuietly(classpathJar); + } + } + + final ChannelExec channel = (ChannelExec) session.openChannel("exec"); + channel.setCommand(command); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TeeOutputStream teeOut = new TeeOutputStream(out, new KeepAliveOutputStream(System.out)); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + TeeOutputStream teeErr = new TeeOutputStream(err, new KeepAliveOutputStream(System.err)); + + channel.setOutputStream(teeOut); + channel.setExtOutputStream(teeOut); + channel.setErrStream(teeErr); + + channel.connect(); + + // wait for it to finish + watchDog = new Thread() { + public void run() { + while (!channel.isEOF()) { + if (watchDog == null) { + return; + } + try { + sleep(500); + } catch (Exception e) { + // ignored + } + } + } + }; + + watchDog.start(); + watchDog.join(maxwait); + + if (watchDog.isAlive()) { + // ran out of time + + throw new BuildException(TIMEOUT_MESSAGE); + } else { + // completed successfully + return writeOutputAndReturnExitStatus(channel, out, err); + } + } catch (BuildException e) { + throw e; + } catch (JSchException e) { + if (e.getMessage().indexOf("session is down") >= 0) { + throw new BuildException(TIMEOUT_MESSAGE, e); + } else { + throw new BuildException(e); + } + } catch (Exception e) { + throw new BuildException(e); + } finally { + if (session != null && session.isConnected()) { + session.disconnect(); + } + } + } + + InputStream makeClasspathJarOrNull(String... paths) { + if (paths != null && paths.length > 0) { + JavaArchive classpathArchive = Archives.create("classpath.jar", JavaArchive.class); + for (String path : paths) { + File file = new File(path); + if (file.exists()) { + if (file.isFile()) { + try { + classpathArchive.as(ZipImporter.class).importZip( + new ZipFile(file.getAbsolutePath())); + } catch (IOException e) { + throw new BuildException(e); + } + } else { + classpathArchive.as(ExplodedImporter.class).importDirectory(file); + } + } + } + return classpathArchive.as(ZipExporter.class).exportZip(); + } + return null; + } + + private int writeOutputAndReturnExitStatus(final ChannelExec channel, ByteArrayOutputStream out, + ByteArrayOutputStream err) throws IOException { + if (outputProperty != null) { + getProject().setProperty(outputProperty, out.toString()); + } + if (outputFile != null) { + writeToFile(err.toString(), append, outputFile); + } + if (errorProperty != null) { + getProject().setProperty(errorProperty, err.toString()); + } + if (errorFile != null) { + writeToFile(out.toString(), append, errorFile); + } + if (resultProperty != null) { + getProject().setProperty(resultProperty, channel.getExitStatus() + ""); + } + return channel.getExitStatus(); + } + + /** + * Writes a string to a file. If destination file exists, it may be overwritten depending on the + * "append" value. + * + * @param from + * string to write + * @param to + * file to write to + * @param append + * if true, append to existing file, else overwrite + * @exception Exception + * most likely an IOException + */ + private void writeToFile(String from, boolean append, File to) throws IOException { + FileWriter out = null; + try { + out = new FileWriter(to.getAbsolutePath(), append); + StringReader in = new StringReader(from); + char[] buffer = new char[8192]; + int bytesRead; + while (true) { + bytesRead = in.read(buffer); + if (bytesRead == -1) { + break; + } + out.write(buffer, 0, bytesRead); + } + out.flush(); + } finally { + if (out != null) { + out.close(); + } + } + } + + String convertJavaToScript(CommandlineJava commandLine) { + checkNotNull(jvm, "jvm must be set"); + checkNotNull(localDirectory, "dir must be set"); + checkNotNull(remoteDirectory, "remotedir must be set"); + List statements = Lists.newArrayList(); + String[] environment = env.getVariables(); + if (environment != null) { + for (int i = 0; i < environment.length; i++) { + log("Setting environment variable: " + environment[i], Project.MSG_VERBOSE); + statements.add(exec("{export} " + environment[i])); + } + } + statements.add(exec("{cd} " + remoteDirectory)); + statements.add(exec("jar -xf cwd.zip")); + + StringBuilder commandBuilder = new StringBuilder(jvm); + if (commandLine.getBootclasspath() != null + && commandLine.getBootclasspath().list().length > 0) { + commandBuilder.append(" -Xbootclasspath:boot-classpath.jar"); + } + + if (commandLine.getVmCommand().getArguments() != null + && commandLine.getVmCommand().getArguments().length > 0) { + commandBuilder.append(" "); + String[] variables = commandLine.getVmCommand().getArguments(); + for (int i = 0; i < variables.length; i++) { + commandBuilder.append(variables[i]); + if (i + 1 < variables.length) + commandBuilder.append(" "); + } + } + if (commandLine.getClasspath() != null && commandLine.getClasspath().list().length > 0) { + commandBuilder.append(" -cp classpath.jar"); + } + if (commandLine.getSystemProperties() != null + && commandLine.getSystemProperties().getVariables() != null + && commandLine.getSystemProperties().getVariables().length > 0) { + commandBuilder.append(" "); + String[] variables = commandLine.getSystemProperties().getVariables(); + for (int i = 0; i < variables.length; i++) { + commandBuilder.append(variables[i]); + if (i + 1 < variables.length) + commandBuilder.append(" "); + } + } + + commandBuilder.append(" ").append(commandLine.getClassname()); + + if (commandLine.getJavaCommand().getArguments() != null + && commandLine.getJavaCommand().getArguments().length > 0) { + commandBuilder.append(" "); + String[] variables = commandLine.getJavaCommand().getArguments(); + for (int i = 0; i < variables.length; i++) { + commandBuilder.append(variables[i]); + if (i + 1 < variables.length) + commandBuilder.append(" "); + } + } + statements.add(exec(commandBuilder.toString())); + + String command = new StatementList(statements).render(osFamily); + return command; + } + + @Override + public void addEnv(Environment.Variable var) { + env.addVariable(var); + } + + @Override + public void setDir(File localDir) { + this.localDirectory = checkNotNull(localDir, "dir"); + } + + public void setRemotedir(File remotedir) { + this.remoteDirectory = checkNotNull(remotedir, "remotedir"); + } + + @Override + public void setFork(boolean fork) { + if (!fork) + throw new IllegalArgumentException("this only operates when fork is set"); + } + + @Override + public void setJvm(String jvm) { + this.jvm = checkNotNull(jvm, "jvm"); + } + + /** + * Remote host, either DNS name or IP. + * + * @param host + * The new host value + */ + public void setHost(String host) { + this.host = host; + } + + /** + * Get the host. + * + * @return the host + */ + public String getHost() { + return host; + } + + /** + * Username known to remote host. + * + * @param username + * The new username value + */ + public void setUsername(String username) { + userInfo.setName(username); + } + + /** + * Sets the password for the user. + * + * @param password + * The new password value + */ + public void setPassword(String password) { + userInfo.setPassword(password); + } + + /** + * Sets the keyfile for the user. + * + * @param keyfile + * The new keyfile value + */ + public void setKeyfile(String keyfile) { + userInfo.setKeyfile(keyfile); + } + + /** + * Sets the passphrase for the users key. + * + * @param passphrase + * The new passphrase value + */ + public void setPassphrase(String passphrase) { + userInfo.setPassphrase(passphrase); + } + + /** + * Sets the path to the file that has the identities of all known hosts. This is used by SSH + * protocol to validate the identity of the host. The default is + * ${user.home}/.ssh/known_hosts. + * + * @param knownHosts + * a path to the known hosts file. + */ + public void setKnownhosts(String knownHosts) { + this.knownHosts = knownHosts; + } + + /** + * Setting this to true trusts hosts whose identity is unknown. + * + * @param yesOrNo + * if true trust the identity of unknown hosts. + */ + public void setTrust(boolean yesOrNo) { + userInfo.setTrust(yesOrNo); + } + + /** + * Changes the port used to connect to the remote host. + * + * @param port + * port number of remote host. + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Get the port attribute. + * + * @return the port + */ + public int getPort() { + return port; + } + + /** + * Initialize the task. This initializizs the known hosts and sets the default port. + * + * @throws BuildException + * on error + */ + public void init() throws BuildException { + super.init(); + this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts"; + this.port = SSH_PORT; + } + + /** + * Open an ssh seession. + * + * @return the opened session + * @throws JSchException + * on error + */ + protected Session openSession() throws JSchException { + JSch jsch = new JSch(); + if (null != userInfo.getKeyfile()) { + jsch.addIdentity(userInfo.getKeyfile()); + } + + if (!userInfo.getTrust() && knownHosts != null) { + log("Using known hosts: " + knownHosts, Project.MSG_DEBUG); + jsch.setKnownHosts(knownHosts); + } + + Session session = jsch.getSession(userInfo.getName(), host, port); + session.setUserInfo(userInfo); + log("Connecting to " + host + ":" + port); + session.connect(); + return session; + } + + /** + * Get the user information. + * + * @return the user information + */ + protected SSHUserInfo getUserInfo() { + return userInfo; + } + + /** + * The connection can be dropped after a specified number of milliseconds. This is sometimes + * useful when a connection may be flaky. Default is 0, which means "wait forever". + * + * @param timeout + * The new timeout value in seconds + */ + public void setTimeout(long timeout) { + maxwait = timeout; + } + + @Override + public void setError(File out) { + this.errorFile = out; + } + + @Override + public void setErrorProperty(String errorProp) { + this.errorProperty = errorProp; + } + + @Override + public void setOutput(File out) { + this.outputFile = out; + } + + @Override + public void setOutputproperty(String outputProp) { + this.outputProperty = outputProp; + } + + @Override + public void setResultProperty(String resultProperty) { + this.resultProperty = resultProperty; + } + + @Override + public void setAppend(boolean append) { + this.append = append; + } +} diff --git a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java new file mode 100644 index 0000000000..8e5bed33e9 --- /dev/null +++ b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/JavaOverSshTest.java @@ -0,0 +1,107 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.tools.ant; + +import static org.testng.Assert.assertEquals; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.InetAddress; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Environment; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Environment.Variable; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "jclouds.JavaOverSshTest") +public class JavaOverSshTest { + + public void testFull() throws SecurityException, NoSuchMethodException { + JavaOverSsh task = createTask(); + assertEquals( + String + .format( + "cd /tmp/foo\njar -xf cwd.zip\n%s -Xms256 -cp classpath.jar -Dfooble=baz -Dfoo=bar org.jclouds.tools.ant.TestClass hello world\n", + System.getProperty("java.home") + "/bin/java", System + .getProperty("user.dir")), task.convertJavaToScript(task + .getCommandLine())); + } + + private JavaOverSsh createTask() { + Project p = new Project(); + JavaOverSsh task = new JavaOverSsh(); + task.setProject(p); + task.setClassname(TestClass.class.getName()); + task.createClasspath().add(new Path(p, "target/test-classes")); + Variable prop1 = new Environment.Variable(); + prop1.setKey("fooble"); + prop1.setValue("baz"); + + task.addSysproperty(prop1); + Variable prop2 = new Environment.Variable(); + prop2.setKey("foo"); + prop2.setValue("bar"); + + task.addSysproperty(prop2); + task.createJvmarg().setValue("-Xms256"); + task.createArg().setValue("hello"); + task.createArg().setValue("world"); + task.setDir(new File(System.getProperty("user.dir"))); + task.setRemotedir(new File("/tmp/foo")); + task.setFork(true); + task.setJvm(System.getProperty("java.home") + "/bin/java"); + return task; + } + + @Test(enabled = false, groups = { "live" }) + public void testSsh() throws NumberFormatException, FileNotFoundException, IOException { + String sshHost = System.getProperty("jclouds.test.ssh.host"); + String sshPort = System.getProperty("jclouds.test.ssh.port"); + String sshUser = System.getProperty("jclouds.test.ssh.username"); + String sshPass = System.getProperty("jclouds.test.ssh.password"); + String sshKeyFile = System.getProperty("jclouds.test.ssh.keyfile"); + + int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22; + InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress + .getLocalHost(); + + JavaOverSsh task = createTask(); + task.setHost(host.getHostAddress()); + task.setPort(port); + task.setTrust(true); + task.setUsername(sshUser); + if (sshKeyFile != null && !sshKeyFile.trim().equals("")) { + task.setKeyfile(sshKeyFile); + } else { + task.setPassword(sshPass); + } + task.setOutputproperty("out"); + task.setErrorProperty("err"); + task.setResultProperty("result"); + task.execute(); + assertEquals(task.getProject().getProperty("out"), "[hello, world]\n"); + assertEquals(task.getProject().getProperty("err"), "err\n"); + assertEquals(task.getProject().getProperty("result"), "3"); + } +} diff --git a/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java new file mode 100644 index 0000000000..8cf6db3807 --- /dev/null +++ b/tools/antcontrib/src/test/java/org/jclouds/tools/ant/TestClass.java @@ -0,0 +1,18 @@ +package org.jclouds.tools.ant; + +import java.io.File; +import java.util.Arrays; + +public class TestClass { + public static void main(String... args) { + File cwd = new File(System.getProperty("user.dir")); + System.out.println("children:"); + for (File child : cwd.listFiles()) + System.out.println(" " + child); + System.out.println("what you wrote:"); + System.out.println(Arrays.asList(args)); + System.err.println("this is the error stream"); + System.out.println("will exit 3:"); + System.exit(3); + } +} \ No newline at end of file diff --git a/tools/pom.xml b/tools/pom.xml index ddc0fdd73f..cd60c78986 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -34,6 +34,7 @@ ant-plugin getpath + antcontrib vfs