I want to:
Log in to putty using Hostname, username, password and port number.
This I have achieved.
Once I logged in, I want to connect to server1. Usually in putty we
connect using ssh command (ssh user#server1).
Once I connected to that server.I need to run multiple commands like:
df -kh ps -ef|grep www
And after executing above commands, I need to log out from
server1 and need to log in to server2.
How can I do it in JSCH?
JSch jsch=new JSch();
Session session=jsch.getSession(remoteHostUserName, RemoteHostName, remoteHostPortNo);
session.setPassword(remoteHostpassword);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
System.out.println("Please wait...");
session.connect();
System.out.println("Connected "+remoteHostUserName+"#"+RemoteHostName);
ChannelExec channel=(ChannelExec) session.openChannel("shell");
BufferedReader in=new BufferedReader(new InputStreamReader(channel.getInputStream()));
channel.setCommand("df -kh");
channel.setCommand("pwd");
channel.connect();
Try ChannelShell channel = (ChannelShell) session.openChannel("shell"); setup inputStream and outputStream and subsequently perform the following loop:
write into the connected inputStream and flush it
read from the connected outputStream
This way you can even construct your second commands based on the outcome of the first one.
In order to create an interactive session, you can refer the Example class provided jsch developers.
http://www.jcraft.com/jsch/examples/UserAuthKI.java
Create the Channel object as an instance of Shell
ie
Channel channel=session.openChannel("shell");
And then set the Input and Output Streams for that Channel object.
channel.setInputStream(System.in);
channel.setOutputStream(System.out);
And then connect the channel.
This way, after each comand execution, the channel won't be closed and the state of the previous command can be persisted.
Using the above code, you can create an interactive session in your console
You can run multiple commands by using below approach
put all the commands in a string separated by ;
"command1;command2...."
Related
I need to execute commands on remote SSH server in Java. I'm using JSch for that.
A Command 1 is a command to setup an environment on Linux machine and which requires some time to execute (about 20 minutes). Command 1 is a one time operation.
If I open a PuTTY session I need to execute the Command 1 only once.
A Command 2 dependents on the Command 1. It does not execute without the Command 1.
Once the Command 1 is executed (one time operation), the Command 2 (requires 2-3 seconds to execute) can be executed for different entities without the Command 1 being executed again.
I know I can do it with commands separated by &&, but in that way the Command 1 will execute unnecessarily degrading overall performance.
Code:
String host = "1.1.1.1";
String user = "parag";
String password = "abcdf";
String command1 = "command1";
String command2 = "command2";
try {
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setConfig(config);
session.setPassword(password);
session.connect();
System.out.println("Connected");
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command1 + " && " + command2);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if (channel.isClosed()) {
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
channel.disconnect();
session.disconnect();
System.out.println("DONE");
} catch (Exception e) {
e.printStackTrace();
}
Please let me know if this is possible. Also suggest an alternative if any, in case this is not possible with JSch.
What you have now is the correct way.
If you really really need to optimize it, you have to feed the commands to a remote shell session. Either start a shell explicitly using the "exec" channel. Or use "shell" channel directly. And then write the individual commands to the shell input.
See also:
Providing input/subcommands to command executed over SSH with JSch
What is the difference between the 'shell' channel and the 'exec' channel in JSch
Multiple commands through JSch shell
JSch Shell channel execute commands one by one testing result before proceeding
Obligatory warning: Do not use StrictHostKeyChecking=no to blindly accept all host keys. That is a security flaw. You lose a protection against MITM attacks. For the correct (and secure) approach, see: How to resolve Java UnknownHostKey, while using JSch SFTP library?
I have a program that implements the Eclipse Console as follows:
FAQ How do I write to the console from a plug-in?
Then i use the (MessageConsole) mainConsole).newMessageStream() to redirect the OutputStream of a Jsch Channel to my new console.
PrintStream printStream = new PrintStream(((MessageConsole) mainConsole.newMessageStream());
JSch jsch = new JSch();
Session session = jsch.getSession(username, host, port);
Channel channel = session.openChannel("shell");
channel.setOutputStream(printStream);
Now i want redirect the same OutputStream of the Jsch Channel to a file, the problem is that is already redirect to my console.
How i can do it at the same time.
Thanks.
If you're simply outputting text, you can try :
PrintWriter out = new PrintWriter("filename.txt");
Then, write your String to it, just like you would to any output stream:
out.println(text);
You'll need exception handling, as ever. Be sure to call out.close() when you've finished writing.
If you are using Java 7 or later, you can use the "try-with-resources statement" which will automatically close your PrintStream when you are done with it (ie exit the block) like so:
try (PrintWriter out = new PrintWriter("filename.txt")) {
out.println(text);
}
You will still need to explicitly throw the java.io.FileNotFoundException as before.
I am using Jsch 0.1.51 on RHEl 6 with Jdk 1.7_51. While making session to a remote machine I am getting exception that is :
com.jcraft.jsch.JSchException: Packet corrupt
at com.jcraft.jsch.Session.start_discard(Session.java:1049)
at com.jcraft.jsch.Session.read(Session.java:919)
at com.jcraft.jsch.UserAuthNone.start(UserAuthNone.java:56)
at com.jcraft.jsch.Session.connect(Session.java:389)
at com.jcraft.jsch.Session.connect(Session.java:183)
at TestSFTP.checkException(TestSFTP.java:130)
at TestSFTP.moveFileToDir(TestSFTP.java:78)
at TestSFTP.main(TestSFTP.java:73)
Same code was working fine with RHEL 5. Can any body provide some suggestions .. Thanks
code used is :
Session session = null;
ChannelSftp channelSftp = null;
JSch jsch = new JSch();
session = jsch.getSession(this.sftpUser,this.sftpHost,this.sftpPort);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(this.sftpPassword);
session.connect();
channelSftp = (ChannelSftp)session.openChannel("sftp");
channelSftp.connect();
I am getting error at session.connect();
This exception can occur if you are trying to connect on an already existent session. A work around is closing the session and then starting a new session. This helped me. Found some help from this site:
http://flyingjxswithjava.blogspot.com/2015/03/comjcraftjschjschexception-packet.html
Quoting essential points from the site to understand the problem:
This exception occurs when the Session is reused repeatedly in a loop where the session is disconnected intentionally or due to time out and needs to reconnect again.
The reason that such an exception is thrown is that the first time the Session is connected to the remote site, a random number called Packet is generated for the session.
When the thread is having its 1 hour sleep, the session gets automatically disconnected due to no activity for a certain period of time.
When the Session is disconnected, the Packet is lost.
When the Session is trying to reconnect, it could not find the Packet, thus the exception is thrown.
I've using expect4j with JSch to connect to a remote shell and pull a config file. The code I'm using to connect to the machine is as follows:
Session session = jsch.getSession(
host.getUser(),
host.toString(),
SSH_PORT);
session.setPassword(host.getPass());
//If this line isn't present, every host must be in known_hosts
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("shell");
channel.connect();
InputStream in = channel.getInputStream();
OutputStream out = channel.getOutputStream();
Expect4j expect = new Expect4j(in, out);
for(String command : commands) { //List of commands
int returnVal = expect.expect(prompts); //List of Match[] objects that correspond to different possible prompts
if (returnVal != COMMAND_SUCCESS_OPCODE) {
System.err.println("ERROR: tried to run " + command + " and got opcode " + returnVal);
}
expect.send(command);
expect.send(ENTER_BUTTON); //Constant that corresponds to newline
}
When run, the code gives me the following messages:
<Current Date & Time> expect4j.BlockingConsumer run
INFO: Stop Requested
<Current Date & Time> expect4j.BlockingConsumer run
INFO: Found EOF to stop while loop
I believe that the problem stems from that fact that it takes a second or two for the last command to complete. Is there a way to get expect4j to wait for the command to finish?
Additionally, the commands each return a different returncode from the expect command (0,1,2,2). Is there a place where I can look up those codes? Do they have any significance?
this is how I use it.
notice that since jsch-0.1.50, I had to start using this to make it work
Hashtable<String,String> config = new Hashtable<String,String>();
config.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications",
"publickey,keyboard-interactive,password");//makes kerberos happy
session.setConfig(config);
So basically I use the very same code provided by the tutorial except that my libraries are up to date
expect4j-1.0.jar
jakarta-oro-2.0.8.jar
jsch-0.1.51.jar
And since my user is not root,
private static String[] linuxPromptRegEx = new String[]{"\\$"};
good luck
ps. I'd give this alternative a try. Looks a very well made expect library.
use expect4j
expect4j not waiting for full output
for example AIX's command 'prtconf'
I am new to SSH and JSch. When I connect from my client to the server I want to do two tasks:
Upload a file (using ChannelSFTP)
Perform commands, like creating a directory, and searching through a MySQL database
At the moment I am using two separate shell logins to perform each task (actually I haven't started programming the MySQL queries yet).
For the upload the relevant code is
session.connect();
Channel channel=session.openChannel("sftp");
channel.connect();
ChannelSftp c=(ChannelSftp)channel;
c.put(source, destination);
And for the command I have
String command = "ls -l";//just an example
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
Should I disconnect the session after the first channel and then open the second channel? Or close the session entirely and open a new session? As I said, I'm new to this.
One SSH session can support any number of channels - both in parallel and sequentially. (There is some theoretical limit in the channel identifier size, but you won't hit it in practice.) This is also valid for JSch. This saves redoing the costly key exchange operations.
So, there is normally no need to close the session and reconnect before opening a new channel. The only reason I can think about would be when you need to login with different credentials for both actions.
To safe some memory, you might want to close the SFTP channel before opening the exec channel, though.
To give multiple commands through Jsch
use shell instead of exec.
Shell only support native commands of the connecting system.
For example, when you are connecting windows system you can't give commands like dir using the exec channel.
So it is better to use shell.
The following code can be used to send multiple commands through Jsch
Channel channel = session.openChannel("shell");
OutputStream ops = channel.getOutputStream();
PrintStream ps = new PrintStream(ops, true);
channel.connect();
ps.println("mkdir folder");
ps.println("dir");
//give commands to be executed inside println.and can have any no of commands sent.
ps.close();
InputStream in = channel.getInputStream();
byte[] bt = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(bt, 0, 1024);
if (i < 0) {
break;
}
String str = new String(bt, 0, i);
//displays the output of the command executed.
System.out.print(str);
}
if (channel.isClosed()) {
break;
}
Thread.sleep(1000);
channel.disconnect();
session.disconnect();
}