我有一个使用Jsch shell频道连接到我的应用服务器的测试用例。如果我从test vm运行我的测试用例,我可以使用Jsch执行命令。但是在某种情况下,测试用例将在app服务器中运行,并使用相同的凭据对自身进行ssh。我的问题在这里。在这种情况下,命令不由Jsch执行。
代码:
import com.google.common.io.Files;
import com.jcraft.jsch.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
/**
* Created by prasantabiswas on 17/03/17.
*/
public class SSHManager
{
private static Session session;
private static Channel channel;
private static ChannelSftp channelSftp;
private static Logger log= LogManager.getLogger(SSHManager.class);
private static HelperClass helperClass=HelperClass.getInstance();
enum ChannelType
{
SHELL,
SFTP
}
public static void openConnection(String remoteHost) throws JSchException,SecurityException
{
if(session == null || !session.isConnected())
{
String userName=helperClass.getSshUser();
log.debug("Remote host: "+remoteHost);
log.debug("SSH user: "+userName);
if(helperClass.getSshAuthMode().equalsIgnoreCase("key"))
{
String key=helperClass.getSshKey();
log.debug("SSH key: "+key);
session=connectWithKey(remoteHost,userName,key);
}
else if(helperClass.getSshAuthMode().equalsIgnoreCase("password"))
{
String password=helperClass.getSshPassword();
log.debug("SSH password: "+password);
session=connectWithPassword(remoteHost,userName,password);
}
else
{
String password=helperClass.getSshPassword();
log.warn("No SSH authentication mode provided. It will try with the default mode that is with password: "+password);
session=connectWithPassword(remoteHost,userName,password);
}
}
else
log.warn("Session already connected. Disconnect first for new session.");
}
private static Session connectWithPassword(String hostname,String username,String password) throws JSchException,SecurityException
{
JSch jSch = new JSch();
Session _session = jSch.getSession(username, hostname, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
_session.setConfig(config);
_session.setPassword(password);
log.info("Connecting SSH to " + hostname + " - Please wait for few seconds... ");
_session.connect();
log.info("Connected!");
return _session;
}
private static Session connectWithKey(String hostname,String username,String key) throws JSchException,SecurityException
{
JSch jSch = new JSch();
log.debug("Key file path: "+key);
jSch.addIdentity(key);
Session _session = jSch.getSession(username, hostname, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications","publickey,keyboard-interactive,password");
_session.setConfig(config);
log.info("Connecting SSH to " + hostname + " - Please wait for few seconds... ");
_session.connect();
log.info("Connected!");
return _session;
}
private static void createChannel(ChannelType channelType)
{
if(channel == null || !channel.isConnected()){
try
{
if(channelType==ChannelType.SHELL)
{
channel = session.openChannel("shell");
log.info("Shell channel created!");
}
else if(channelType==ChannelType.SFTP)
{
channel = session.openChannel("sftp");
log.info("SFTP channel created!");
}
else
throw new JSchException("Invalid channel type");
channel.connect();
}
catch(JSchException e)
{
log.error("Error while opening channel: "+ e);
}
}
}
public static String executeCommand(List<String> commands,String remoteHost) throws JSchException,IOException
{
log.info("Opening SSH session...");
openConnection(remoteHost);
log.info("Creating shell channel...");
createChannel(ChannelType.SHELL);
log.info("Sending commands...");
PrintStream out = new PrintStream(channel.getOutputStream());
out.println("#!/bin/bash");
for(String command : commands){
out.println(command);
}
out.println("exit");
out.flush();
String output=getChannelOutput(channel);
log.info("Finished sending commands!");
log.info("Closing session...");
close();
log.info("Returning execution output...");
return output;
}
public static void copyFileToRemoteHost(String sourcePath,String destinationPath,String remoteHost) throws SftpException, IOException, JSchException
{
log.info("Opening SSH session...");
openConnection(remoteHost);
log.info("Creating SFTP channel...");
createChannel(ChannelType.SFTP);
log.info("Copying file to remote host: "+remoteHost+" from "+sourcePath+" to "+destinationPath);
channelSftp = (ChannelSftp) channel;
channelSftp.cd(destinationPath);
File sourceFile = new File(sourcePath);
channelSftp.put(new FileInputStream(sourceFile), sourceFile.getName(),channelSftp.OVERWRITE);
log.info("File transfer complete.");
log.info("Closing session...");
close();
}
public static void removeFileFromRemoteHost(String targetPath,String remoteHost) throws JSchException, SftpException, IOException
{
log.info("Opening SSH session...");
openConnection(remoteHost);
log.info("Creating SFTP channel...");
createChannel(ChannelType.SFTP);
log.info("Removing file from remote host: "+remoteHost+" at "+targetPath);
channelSftp = (ChannelSftp) channel;
channelSftp.rm(targetPath);
log.info("File removed");
log.info("Closing session...");
close();
}
private static String getChannelOutput(Channel channel) throws IOException
{
byte[] buffer = new byte[1024];
InputStream in = channel.getInputStream();
String line = "";
Calendar calendar= Calendar.getInstance();
calendar.setTime(new Date());
int minuteBefore=calendar.get(Calendar.MINUTE);
int minuteAfter=0;
while (true)
{
while (in.available() > 0)
{
int i = in.read(buffer, 0, 1024);
if (i < 0)
{
break;
}
line += "\n" + new String(buffer, 0, i);
}
if(line.contains("logout"))
{
break;
}
if (channel.isClosed())
{
break;
}
calendar.setTime(new Date());
minuteAfter=calendar.get(Calendar.MINUTE);
if(minuteAfter-minuteBefore>=3)
break;
try
{
Thread.sleep(1000);
} catch (Exception e)
{
}
}
return line;
}
public static void close()
{
channel.disconnect();
session.disconnect();
log.info("Disconnected channel and session");
}
}
我使用上面的类在远程主机上执行命令。这工作正常但是当我在本地机器上运行它时,remoteHost参数是localhost,命令没有被执行。但它成功登录我可以在日志中看到但不能执行通过打印流发送的命令。在发送命令后,它会被卡住一段时间...&#34;然后返回仅显示命令提示符而不是所有命令的日志。
假设我的ssh用户名是root,我发送两个命令:su - admin,txe restart和远程主机,我运行测试的主机与我的localhost相同。我应该得到像
这样的输出#!/bin/bash
su - admin
txe restart
exit
Last login: Thu Apr 13 23:17:10 2017 from 10.10.4.46
[root@platform15 ~]# #!/bin/bash
[root@platform15 ~]# su - admin
id: cannot find name for group ID 491000000
admin@platform15(ERS):~> txe restart
Stopping txe...
.
.
OK
Starting txe...OK (PID: 13083)
admin@platform15(ERS):~> exit
logout
但我得到了这个
Last login: Thu Apr 13 23:34:42 2017 from 10.10.4.27
[root@platform15 ~]#
仅当我在localhost中运行测试并且remoteHost设置为localhost时才会发生这种情况。否则它正常工作是remoteHost设置为其他主机。
对此有何建议?