executing kafka sh script remotely from java program - java

I am trying to execute a kafka script to retrieve the topic, consumergroups and lag info. I keep getting the error and searching through this and other forums reveals conflicting information. Some say it is not possible to execute a remote script on Unix from windows while others give some advice on what to try to correct this error. I am able to connect and run a simple ping command and able to retrieve the response. Perhaps I am missing a simple overlooked error here.
Here is the code:
try {
jsch.setKnownHosts("C:\\Users\\.ssh\\ssh_host_rsa_key.pub");
Session session = jsch.getSession(uname, host, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(pword);
session.connect();
Process p = Runtime.getRuntime().exec("./usr/kafka/bin/
kafka-consumer-groups.sh --bootstrap-server 192.xxx.xx.xxx:9092
--describe -group OPSII");
InputStream scriptStdout = p.getInputStream();
BufferedReader scriptReader= new BufferedReader(new
InputStreamReader(scriptStdout));
String scriptOutput = scriptReader.readLine();
StringBuilder sb = new StringBuilder();
while ((scriptOutput = scriptReader.readLine())!= null) {
sb.append(scriptOutput + "\n");
}
scriptStdout.close();
The error:
Exception in thread "main" java.io.IOException: Cannot run program
"./usr/kafka/bin/kafka-consumer-groups.sh": CreateProcess
error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
I have confirmed that the script works on the remote unix machine and that the directory is correct. Is it perhaps the format and should it be '//' instead of '/'? What exactly would cause this error? Please this is not a duplicate question as none of the other proposed solutions worked.

You can use the following code to run a script via JSch
// open a channel
channel = session.openChannel("exec");
// type in your command
String command = "./path/to/your_script.sh --add_params \n";
//Below command will execute the data you set in the previous line
((ChannelExec) channel).setCommand(command);
channel.connect();
Note this is using the JSch library only.
EDIT:
As per your comment you want to fetch the output from the console as well for that use :
InputStream in = channel.getInputStream();

Related

Flow execution Java JSsh

I'm very nubby at Java, so please excuse me if is a dummy question.
I have the following piece of code, and the execution flow is different from my intention:
channel = session.openChannel("shell");
OutputStream ops = channel.getOutputStream();
PrintStream ps = new PrintStream(ops, true);
channel.connect();
String sudo = "sudo su - user";
String copy = "copy from a to b;
String cd = "cd a directory";
String runload = "run a scrip in unix;
String cd1 = "cd a directoryu";
String executeload = "run a scrip in unix";
ps.println(sudo);
ps.println(copy);
ps.println(cd);
ps.println(runload);
ps.println(cd1 );
if (db.runload().contains("SUCCESS")) {
ps.println(executeload);
//execute this only if runload was success
} else {
System.exit(1);
}
The point is that "if block" is executed before previous lines. runload is script which load information in a table and is a precondition for executeload. In this case executeload will throw java.lang.NullPointerException.
My question is: it Is a way to control the flow in this piece of code? Every previous line is a precondition to the next one. My intention is to execute the next line when the current is finally executed.
The println just sends ("types") the command to the server. It does not wait for the command to be completed.
There's actually no way to wait for a command to be completed. A "shell" is a just a black-box with an input and an output. There's even no way to tell, what parts of the output corresponds to which input.
In general, you should use an "exec" channel for automation. The "shell" channel is intended for implementing an interactive terminal.
The "exec" channel closes with its command, so you can clearly tell that a command has finished. You can then open a new "exec" channel for further commands.
See JSch example for "exec" channel.
See also JSch Shell channel execute commands one by one testing result before proceeding.
Things get complicated though with your use of sudo.
See Running command after sudo login.

How to execute Multiple commands

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...."

passing password using process builder not working for "net use" command

I am trying to run the "net use" command by invoking it using process builder. As I pass the password to the OutputStream using PrintWriter it fails with the following error :
System error 1219 has occurred.
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
I have checked the username, password and the command, by running it manually. Its working fine
The code snippet :
ProcessBuilder pb = new ProcessBuilder("net","use","\\\\<SERVERNAME>\\<SharedLocation>","/USER:<username>","*");
Process p = pb.start();
OutputStream out = p.getOutputStream();
PrintWriter writer = new PrintWriter(out);
writer.println("<pwd>".toCharArray());
int exitCode = p.waitFor();
System.out.println("Exit Code :"+ exitCode);
A couple of suggestions:
Run net use * /delete /y as your first step to remove all connections before you start. You can also try removing specific connections.
Use a pure Java solution instead of net use -- see https://stackoverflow.com/a/208896/4803

expect4j not waiting for full output

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'

Jsch shell commands with x11forwarding - reuse channel and run new command

I need to run ssh command that opens GUI applications.
I was able to get Jsch to run the commands and the GUIs are showing up on the client machine. My problem is I can't seem to get beyond 20 Jsch channel. I realize that the server has a setting that controls the number of ssh connection a user can make which here seems to be 20. What I can't understand is how to reuse an existing connection but run a different command....
I tried to run the commands two different ways:
EXAMPLE Command:
String command = "cd /home/test;xterm ";
String command = "cd /home/test;nedit myfile.txt ";
"1 way") each run command creates a new Jsch channel:
private void connect (String command) {
Channel channel = session.getChannel("shell");
channel.setXForwarding(true);
StringBufferInputStream reader = new StringBufferInputStream(command + " \n");
channel.setInputStream(reader);
channel.connect();
}
[ This code creates a new channel for each new command. works but hitting 20 ssh connection limitation. ]
or
"another way") tried to reuse the channel to run a new command where channel is a global variable:
int numruns =0;
private void connect (String command, int channelId) {
String cmd = command + " \n";
if (channel == null) {
numruns = 0;
channel = session.openChannel("shell");
channel.setXForwarding(true);
channel.connect();
stdIn = channel.getOutputStream();
stdOut = channel.getInputStream();
} else {
channel.connect(channelId);
}
((OutputStream)stdIn).write(cmd.getBytes());
stdIn.flush();
numruns++;
}
[ "other way" opens the application but it seems to create new ssh connections. so i still have 20 ssh connection limitations.]
So it seems like the server is only allowing maximum of 20 ssh connections.
But why doesn't it work with the "other way"?
So when I close my GUI applications, it doesn't seems to release the ssh connections because it still thinks I have maxed out so I get JschException on channel.connect();
My problem is all the command opens GUI applications so I can't tell when that application is closed to close the channel connection.
I wrote the "other way" method thinking that it will not create a new ssh connection but I should be allowed to use the existing connection but send a new command. Obviously it doesn't work that way.
How can I accomplish using one ssh connection to run different command when connect(command) is called? Is that possible with Jsch?
Not Solved! The following works to a point. It hides the fact that any "xterm" no longer has display information once Jsch channel connection closes.
=====================================
To keep the GUI from disappearing when the channel was disconnected, needed to kick off the command with "nohup" preceding the command or "xterm -hold -e"
So...
EXAMPLE Command:
String command = "cd /home/test;xterm";
String command = "cd /home/test;nohup nedit myfile.txt"; // this will only keep the GUI opened
String command = "cd /home/test;xterm -hold -e gedit myfile.txt"; // this one keeps the xterm window that kick off the program opened
So after making changes to the command, Thread.sleep(1000) was added so give application time to come up before disconnecting the channel.
This seems to work!
private void connect (String command) {
Channel channel = session.getChannel("shell");
channel.setXForwarding(true);
StringBufferInputStream reader = new StringBufferInputStream(command + " \n");
// or use
// ByteArrayInputStream reader = new ByteArrayInputStream((command + " \n").getBytes());
channel.setInputStream(reader);
channel.setOuputStream(System.out);
channel.connect();
try {
Thread.sleep(1000); // give GUI time to come up
} catch (InterruptedException ex) {
// print message
}
channel.disconnect();
}

Categories

Resources