Apache Camel SSH Component
- 6 minutes read - 1275 wordsThis article is about troubleshooting issues we have faced while using apache camel’s SSH routes. It also covers step wise guide to setup apache camel routes.
Prerequisites
- Windows7
- Eclipse Juno
- Java 1.7
Problem Statement
We were getting following issues in the logs when connecting to one of the SSH server using Apache Camel-SSH. This was happening in one of the instance in production environment.
Here are few logs :
Server A :
Session created...
2013-11-28 18:12:44:855 | DEBUG [MSC service thread 1-15] Connected to
2013-11-28 18:12:44:855 | DEBUG [MSC service thread 1-15] Attempting to authenticate username ******* using Password...
2013-11-28 18:12:44:857 | INFO [NioProcessor-2] Server version string: SSH-2.0-SSHD-CORE-0.6.0
2013-11-28 18:12:45:165 | DEBUG [ClientInputStreamPump] Send SSH_MSG_CHANNEL_DATA on channel 0
2013-11-28 18:12:45:166 | DEBUG [ClientInputStreamPump] Send SSH_MSG_CHANNEL_EOF on channel 0
2013-11-28 18:12:45:178 | DEBUG [NioProcessor-2] Received packet SSH_MSG_CHANNEL_FAILURE
2013-11-28 18:12:45:178 | DEBUG [NioProcessor-2] Received SSH_MSG_CHANNEL_FAILURE on channel 0
2013-11-28 18:12:45:193 | DEBUG [NioProcessor-2] Closing session
2013-11-28 18:12:45:193 | DEBUG [NioProcessor-2] Closing channel 0
2013-11-28 18:12:45:193 | DEBUG [NioProcessor-2] Closing channel 0 immediately
2013-11-28 18:12:45:194 | DEBUG [NioProcessor-2] Closing IoSession
2013-11-28 18:12:45:194 | DEBUG [NioProcessor-2] IoSession closed
2013-11-28 18:12:45:195 | INFO [NioProcessor-2] Session ***@/***:** closed
Server B :
2013-11-29 13:53:09:280 | INFO [NioProcessor-2] Session created...
2013-11-29 13:53:09:297 | DEBUG [MSC service thread 1-13] Connected to
2013-11-29 13:53:09:297 | DEBUG [MSC service thread 1-13] Attempting to authenticate username ***** using Password...
2013-11-29 13:53:09:300 | INFO [NioProcessor-2] Server version string: SSH-2.0-OpenSSH_5.3
22013-11-29 13:53:09:472 | DEBUG [ClientInputStreamPump] Space available for client remote window
2013-11-29 13:53:09:472 | DEBUG [ClientInputStreamPump] Send SSH_MSG_CHANNEL_DATA on channel 0
2013-11-29 13:53:09:472 | DEBUG [ClientInputStreamPump] Send SSH_MSG_CHANNEL_EOF on channel 0
2013-11-29 13:53:09:494 | DEBUG [NioProcessor-2] Received packet SSH_MSG_CHANNEL_DATA
2013-11-29 13:53:09:494 | DEBUG [NioProcessor-2] Received SSH_MSG_CHANNEL_DATA on channel 0
2013-11-29 13:53:09:494 | DEBUG [NioProcessor-2] Received packet SSH_MSG_CHANNEL_EOF
2013-11-29 13:53:09:494 | DEBUG [NioProcessor-2] Received SSH_MSG_CHANNEL_EOF on channel 0
2013-11-29 13:53:09:495 | DEBUG [NioProcessor-2] Received packet SSH_MSG_CHANNEL_REQUEST
2013-11-29 13:53:09:495 | INFO [NioProcessor-2] Received SSH_MSG_CHANNEL_REQUEST on channel 0
2013-11-29 13:53:09:495 | DEBUG [NioProcessor-2] Received packet SSH_MSG_CHANNEL_CLOSE
2013-11-29 13:53:09:495 | DEBUG [NioProcessor-2] Received SSH_MSG_CHANNEL_CLOSE on channel 0
2013-11-29 13:53:09:495 | DEBUG [NioProcessor-2] Send SSH_MSG_CHANNEL_CLOSE on channel 0
Solving the Chaos!
We have taken following steps to resole the issues
-
Validate SSH - Checked SSH connection with putty and it was working fine, we were able to execute the commands.
-
Analyze Logs -
SSH_MSG_CHANNEL_FAILURE
error was coming on server A, but is working fine when trying to connect server B. We have noticed following logsServer A:
2013-11-28 18:12:44:857 | INFO [NioProcessor-2] Server version string: SSH-2.0-SSHD-CORE-0.6.0
Server B:
2013-11-29 13:53:09:300 | INFO [NioProcessor-2] Server version string: SSH-2.0-OpenSSH_5.3
So different SSH servers are being used.
Resolution 1 – Use same version of SSH Server
Install SSHD-CORE-0.6.0 on Server A /local system
-
Download http://mina.apache.org/sshd-project/download_0.6.0.html Extract download zip
-
Go to /bin
-
Run Server : Run
sshd.bat
(windows) orsshd.sh
(linux) -
Run Client:
ssh.bat
-l [loginuser] -p [port] [hostname] [command]ssh.bat -l login -p 8000 localhost
-
Enter password same as login name “login” It will open up the OS shell where you can run commands.
-
You can also try to connect ssh using
Putty.exe
on host and port. -
So now our new SSH server is ready to use, but if we try to connect SSH as execution channel
ssh.sh
orssh.bat
with some command It always returns withssh.bat -l login -p 8000 localhost dir Exception in thread "main" java.lang.IllegalArgumentException: command must not be null at org.apache.sshd.client.channel.ChannelExec.<init>(ChannelExec.java:35) at org.apache.sshd.client.session.ClientSessionImpl.createExecChannel(ClientSessionImpl.java:175) at org.apache.sshd.client.session.ClientSessionImpl.createChannel(ClientSessionImpl.java:160) at org.apache.sshd.client.session.ClientSessionImpl.createChannel(ClientSessionImpl.java:153) at org.apache.sshd.SshClient.main(SshClient.java:402) 53352 [NioProcessor-2] INFO org.apache.sshd.client.session.ClientSessionImpl - Closing session
This is because the execution channel at client side is not well implemented. Only SCP command has been implemented. For now we can ignore this client error and try the camel example with new SSH server.
Try Camel-SSH with new SSH Server (SSHD-CORE)
Create Sample Camel-SSH Example
- Create eclipse project using archetype “
camel-archetype-spring
"
mvn archetype:generate DarchetypeGroupId=com.tk.poc.camel -DarchetypeArtifactId=camel-archetype-spring - DarchetypeVersion=2.11.0 -DarchetypeRepository=https://repository.apache.org/content/groups/snapshots-group
-
Create following Java file
package com.tk.poc.camel; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.spring.Main; /** * A simple example router from a file system to an ActiveMQ queue and then to a file system * * @version */ public class MyRouteBuilder extends RouteBuilder { private static String source = ""; private static String url = ""; /** * Allow this route to be run as an application */ public static void main(String[] args) throws Exception { if (args.length > 0) { source = args[0]; url = args[1]; } String[] ar = {}; new Main().run(ar); } public void configure() { from("file:" + source + "?noop=true&consumer.useFixedDelay=true&consumer.delay=60000").process(new Processor() { public void process(Exchange exchange) throws Exception { Endpoint ePoint = exchange.getContext().getEndpoint(url); Producer producer = ePoint.createProducer(); producer.process(exchange); } }).bean(new SomeBean()); } public static class SomeBean { public void someMethod(String body) { System.out.println("Received: " + body); } } }
-
Pom.xml - dependencies
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-ssh</artifactId> <version>2.11.0</version> <!-- use the same version as your Camel core version --> </dependency>
-
Clean up src/main/resources/META-INF/spring/
camel-context.xml
<camel:camelContext xmlns="http://camel.apache.org/schema/spring"> <camel:package>com.tk.poc.camel</camel:package> </camel:camelContext>
-
Run mvn eclipse:eclipse to include dependencies in class path of eclipse.
mvn eclipse:eclipse
-
You can now directly run the
MyRouteBuilder.java
in eclipse with required argument-
Source – a folder path, where folder is containing a text file having command to execute on server.
-
Camel URL for SSH component
ssh://[username]@[host]?password=[password]&port=[port]
-
-
Let’s export the project as executable jars keeping the dependencies in separate folder
-
Lets create a
run.bat
java -jar ssh.jar "D:/TK/Testing/data" "ssh://login@localhost?password=login&port=8000" pause
-
Place the run.bat in the directory where jar has been exported.
Run the camel SSH example
- Execute run.bat
- We get same error as we see on production
- So problem is now reproducible locally.
Resolution 2: Implement Exec channel support in SSH component
After looking at the component code, we found that only SCP command has been implemented, EXEC channel is not working correctly.
Extract as eclipse project
-
Download the camel-ssh source and import it as eclipse project
-
Update its pom.xml as follows
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ssh</artifactId>
<packaging>jar</packaging>
<version>2.11.0</version>
<name>Camel :: SSH</name>
<description>Camel SSH support</description>
<properties>
<camel.osgi.export.pkg>org.apache.camel.component.ssh.*</camel.osgi.export.pkg>
<camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=ssh</camel.osgi.export.service>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.6.0</version>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
<version>140</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>
-
Update the component - Change the “
SshEndpoint.java
”From :
public SshResult sendExecCommand(String command) throws Exception { SshResult result = null; ... ... ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_EXEC, command); ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0}); channel.setIn(in); ... ... }
To:
public SshResult sendExecCommand(String command) throws Exception { SshResult result = null; ... ... ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL); log.debug("Command : " + command); InputStream inputStream = new ByteArrayInputStream(command.getBytes()); channel.setIn(inputStream); ... ... }
-
Build Again - Build the jar
mvn install
Try Camel-SSH Again
-
Use updated jar - Rebuild Camel SSH example or place the camel-ssh-2.11.0.jar in the ssh_lib folder.
-
Specify Shell Termination command
/data/command.txt
ls exit
-
Execute Run.bat
It returns the result of command on server
SH_MSG_CHANNEL_EXTENDED_DATA on channel 0 [ NioProcessor-2] ClientSessionImpl DEBUG Received packet SSH_MSG_CHANNEL_EOF [ NioProcessor-2] ChannelShell INFO Received SSH_MSG_CHANNEL_EOF on channel 0 [ NioProcessor-2] ClientSessionImpl DEBUG Received packet SSH_MSG_CHANNEL_REQUEST [ NioProcessor-2] ChannelShell INFO Received SSH_MSG_CHANNEL_REQUEST on channel 0 [ NioProcessor-2] ClientSessionImpl DEBUG Received packet SSH_MSG_CHANNEL_CLOSE [ NioProcessor-2] ChannelShell INFO Received SSH_MSG_CHANNEL_CLOSE on channel 0 [ NioProcessor-2] ChannelShell INFO Send SSH_MSG_CHANNEL_CLOSE on channel 0 Received: 2 anaconda-ks.cfg key.pem Kuldeep logfile Music nohup.out Videos
Another Issue on Server
We have faced issue that channel is not being closed and following log is being printing
Resolution 3: Identify the termination command on Shell
We need to identify the termination command for the shell on server, we noticed that termination command on server’s default shell was “exit;” instead of “exit”. We updated /data/command.txt accordingly, /data/command.txt
ls
exit;
and things worked for us.
So here you have customized Apache Camel component.
#Apache Camel #java #ssh #tutorial #customization #technology