A.Joly
A.Joly

Reputation: 2387

groovy executing shell commands on remote server

I have an issue about executing shell commands on a remote server.

I'm trying various solutions and I have one working but it is not optimized in terms of maintenance : I use a batch file that launches putty which connects to the remote server ans sends the command.

ie. in groovy :

def batchFile = "C:\\Validation\\Tests_Auto\\Scripts\\remote_process\\setOldDate.bat"
Runtime.runtime.exec(batchFile)

and in my batch file :

c:
cd C:\Validation\Tests_Auto\Scripts\remote_process\
putty.exe -ssh [email protected] -pw **** -m "C:\Validation\Tests_Auto\Scripts\remote_process\setOldDate.txt"

setOldDate.txt contains the command date -s @1522018800

This works. However I'd like to launch it in a cleaner way, either avoiding the use of text file for the command or, better, avoiding using putty. I tried several another way to do the same thing but it doesn't work. I think I'm not too far but I need a little help.

I tried to launch a direct command via ssh:

Runtime.getRuntime().exec('"c:\\Program Files\\OpenSSH\\bin\\ssh.exe" root:****@xx.xx.xx.xx date -s @1522018800')

I'd be grateful if anyone could help

thanks

Upvotes: 0

Views: 15695

Answers (2)

A.Joly
A.Joly

Reputation: 2387

Finally, compiling my various research and struggling to fit my environment constraints (groovy in soapui), I ended up with the following solution that works for me :

download jsch-0.1.54.jar and set it in C:\Program Files\SmartBear\ReadyAPI-2.3.0\bin\ext

use the following groovy script :

import java.util.Properties
import com.jcraft.jsch.ChannelExec
import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session


def ip = context.expand( '${#Project#projectEndpoint}' )


    try
    {
        JSch jsch = new JSch();
          Session session = jsch.getSession("root","$ip", 22);
          session.setPassword("****");

          // Avoid asking for key confirmation
          Properties prop = new Properties();
          prop.put("StrictHostKeyChecking", "no");
          session.setConfig(prop);

          session.connect();


        // SSH Channel
        ChannelExec channelssh = (ChannelExec)session.openChannel("exec");

            // Execute command
            //channelssh.setCommand("date -s @1520018000"); // change date
            channelssh.setCommand("ntpdate -u pool.ntp.org"); // restore date
            channelssh.connect();
            channelssh.disconnect();



    }
    catch (Exception e)
    {
        log.info "exception : " + e
      System.out.println(e.getMessage());
    }
    finally
    {
            session.disconnect();
    }

UPGRADE

Here is a generalization I've made as my needs evolved. The following script, still using jsch allows to send any command. This deals with host checking and eliminates hazards due to no host checking. User and password are passed as parameters

import java.util.Properties
import com.jcraft.jsch.ChannelExec
import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session

import java.util.regex.Pattern

def ip = context.expand( '${get endpoint#endpoint}' )
ip = ip.replaceFirst("http[s]?://","")

def user = context.expand( '${#Project#ssh_user}' )
def password = context.expand( '${#Project#ssh_password}' )

def command = context.expand( '${#TestCase#command}' )

def timeout = context.expand( '${#TestCase#timeout_ms}' )
if (timeout == "")
    timeout = 1000 // default timeout 1s
else
    timeout = timeout.toInteger()

log.info "command = " + command

Session session
try
{
    JSch jsch = new JSch();

    session = jsch.getSession(user,ip, 22);
    session.setPassword(password);
    //log.info "user : $user"
    //log.info "set password : $password"

    //log.info System.getProperty("user.home")+"/.ssh/known_hosts"
    jsch.setKnownHosts(System.getProperty("user.home")+"/.ssh/known_hosts");

    session.connect();
    //log.info "session connect"


    // SSH Channel
    ChannelExec channelssh = (ChannelExec)session.openChannel("exec");

    // Execute command
    channelssh.setCommand(command);
    InputStream commandOutput = channelssh.getInputStream();

    channelssh.connect();

    int readByte = commandOutput.read();

    outputBuffer = [];

    // timeout to avoid infinite loop
    while((readByte != -1) && (timeout > 0))
    {
        outputBuffer.add(readByte)
        readByte = commandOutput.read();
        timeout = timeout -1
    }

    // process output
    outputBuffer = outputBuffer as byte[]

    // convert byte array into string
    output = new String(outputBuffer, "UTF-8")

    sleep(3000)
    //log.info "disconnect"
    channelssh.disconnect();

    testRunner.testCase.setPropertyValue("cmd_output", output)
}
catch (Exception e)
{
    msg = "exception : " + e
    log.error msg
    testRunner.fail(msg)
}
finally
{
    session.disconnect();
}

Upvotes: 1

daggett
daggett

Reputation: 28624

@Grab(group='com.jcraft', module='jsch', version='0.1.54')

def ant = new AntBuilder()
ant.sshexec( host:"somehost", username:"dude", password:"yo", command:"touch somefile" )

for other sshexec and scp tasks parameters see doc:

https://ant.apache.org/manual/Tasks/sshexec.html

https://ant.apache.org/manual/Tasks/scp.html

for soapui

this method using apache ant + jsch-0.1.54.jar

the only way i know for soapui:

download the following libraries and put them into soapui\bin\endorsed directory (create the endorsed directory)

edit the soapui\bin\soapui.bat and add the following line where other JAVA_OPTS are defined:

set JAVA_OPTS=%JAVA_OPTS% -Djava.endorsed.dirs="%SOAPUI_HOME%endorsed"

that's because ant libs must be loaded before groovy.

then the code above should work in soapui (except @Grab)

Alternatively you can download only jsch-XXX.jar into existing soapui\bin\ext directory and use jsch library directly from groovy

see examples: http://www.jcraft.com/jsch/examples/

or search for groovy jsch examples

Upvotes: 3

Related Questions