Reputation: 281606
I am working on monitoring the logs for an error on a set of remote servers. For that I am monitoring logs that were modified within some time period.
I am using Jsch Java library
to make a SSH connection
and excute the commands. As I have searched, multiple commands can be remote machine by separating different commands by ;
For that I have a text file which contains the list on remote hosts on which I am establishing the connection. I realise that I can get the list of all files that were modified by the following command
find . -mmin -60 -type f -exec ls {} +
No I can loop over the files and grep for the Error
. For this I have written the following script
logTestScript.sh
#!/bin/bash
cd /log
searchString='<Error ErrorCode="java.sql.SQLException"'
files=`find . -mmin -60 -type f -exec ls {} +`
pwd
hostname
echo ${files}
for file in ${files[@]}
do
if grep -Fq "$searchString" $file
then
echo "String found in $file"
fi
done
Now this script is present in the current package from which I am running a java program and I wish to run this script on each of the remote host.
Below is my current code making use of ChannelExec
private void getSSHConnection() throws IOException, JSchException {
username = props.getProperty("host_username");
password = props.getProperty("host_password");
log_traceback_interval = props.getProperty("fetch_logs_interval_minutes");
errorString = props.getProperty("error_message_log");
System.out.println(username + " " + password + " " + errorString);
// Get the hostnames resource file
String hostnameResourcePath = envObj.getAgentHostnamesConfig(TargetEnvironment, ManagementSystem);
InputStream hostInpStream = this.getClass().getResourceAsStream(hostnameResourcePath);
BufferedReader hostnameReader = new BufferedReader(new InputStreamReader(hostInpStream));
String host = null;
while((host = hostnameReader.readLine()) != null) {
System.out.println(host);
// get a JSch connection object
JSch jschObj = new JSch();
Session session = jschObj.getSession(username, host);
// Disable StrictHost key checking
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
//Execute channel instance
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
InputStream in = channelExec.getInputStream();
//Bash script command with arguments
StringBuilder sb = new StringBuilder();
String command = sb.append("cd /log").append(";")
.append("echo `find . -mmin -60 -type f -exec ls {} +`").append(";")
.toString();
System.out.println(command);
//Run the script on host
channelExec.setCommand(command); //I want to run the script here instead of each command as it uses for loop
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
InputStream monitorLogs = channelExec.getInputStream();
channelExec.connect();
//Read the logs
BufferedReader logReader = new BufferedReader(new InputStreamReader(monitorLogs));
String logLine;
while((logLine = logReader.readLine()) != null) {
System.out.println(logLine);
}
//Close the connections
channelExec.disconnect();
session.disconnect();
}
}
One solution that I can think of if to SCP the script on to the remote host and then executing it there.
However Is there some simple solution, with which I can acieve the same result even without writing the script and only executing commands or executing the script on the remote server.
Thanks for help
Upvotes: 1
Views: 4150
Reputation: 202088
You cannot execute a local script on a server.
You have two options (that you are obviously aware of):
Execute the contents of the script. As you already know, just concatenate all lines with ;
.
Though be careful about the for
and if
. There should be no ;
after the do
and then
.
cd /log ; searchString='<Error ErrorCode="java.sql.SQLException"' ; files=`find . -mmin -60 -type f -exec ls {} +` ; echo `pwd` ; echo `hostname` ; echo ${files} ; for file in ${files[@]} ; do if grep -Fq "$searchString" $file ; then echo "String found in $file" ; fi ; done
Similarly to the previous approach, you can execute the bash -s
and write the contents of the script (the commands) to its input.
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
channelExec.setCommand("bash -s");
channelExec.connect();
OutputStream out = channel.getOutputStream();
FileInputStream fis = new FileInputStream("testScript.sh");
byte[] buf = new byte[1024];
while (true)
{
int len = fis.read(buf, 0, buf.length);
if (len <= 0) break;
out.write(buf, 0, len);
}
The above is basically copied from seemingly unrelated SCP upload example - That example actually feeds a local file to remote scp
process - So it's actually pretty related.
Ntb, "echo `pwd`" and "echo `hostname`" do not make sense. Use "pwd" and "hostname" directly.
Upvotes: 3
Reputation: 3127
In order to execute the script script.sh
on a remote server, you can use below code -
#!/usr/bin/expect
export PASSD="User@123"
expect -c 'spawn sftp [email protected];
expect "*Password: ";
send "$env(PASSD)\r";
expect "ssh>";
send "cd /home/user \r";
expect "ssh>";
send "sh -x script.sh \r";
expect "ssh>";
send "exit \r"'
You can put above code in a script and then add after the success condition of your if loop.
Upvotes: -1