Configure Cisco Routers/Switches Using SSH
I have some use cases where SSH is used to configure Cisco routers/switches. For example, to enable a WAN interface, the following commands are executed:
en
password
configure terminal
int Fa0/0/0
ip address 172.0.0.1255.255.255.252
description Link to 408
bandwidth 8000
service-policy output shape-8Mb
no shutdown
end
copy run start
exit
Apache Camel SSH Component
Apache Camel has a SSH component. However, I found that it did not work when configuring Cisco routers/switches.
The problem is that it cannot execute the "en password" command.
Ganymed SSH2 Library
Fortunately I could solve it by using another SSH library called Ganymed.
The following is the code I used to execute IOS commands.
private static final String PROMPT_SYMBOL = "%";
private static final char ERROR_SYMBOL = '^';
private static final String ACCESS_DENIED_MESSAGE = "Access denied";
private static final int MAX_OUTPUT_BUFFER_SIZE = 1024 * 1024;
public void executeCommand(String host, String username, String password, int timeout, String command) throws IOException, AccessDeniedException
{
Connection connection = new Connection(host);
connection.connect(null, timeout, timeout);
boolean authenticated = connection.authenticateWithPassword(username, password);
if (!authenticated)
return;
Session session = connection.openSession();
session.startShell();
executeCommand(session, timeout, command);
}
private SshResponse executeCommand(Session session, int timeout, String command) throws IOException, AccessDeniedException
{
OutputStream in = session.getStdin();
in.write(command.getBytes());
InputStream stdout = session.getStdout();
InputStream stderr = session.getStderr();
StringBuilder sb = new StringBuilder();
boolean valid = false;
String line = null;
boolean flag = true;
while (flag)
{
int conditions = session.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF, timeout);
if ((conditions & ChannelCondition.TIMEOUT) != 0)
{
break;
}
if ((conditions & ChannelCondition.EOF) != 0)
{
if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0)
{
break;
}
}
BufferedReader reader = null;
try
{
if ((ChannelCondition.STDOUT_DATA & conditions) != 0)
{
reader = new BufferedReader(new InputStreamReader(stdout));
}
else
{
reader = new BufferedReader(new InputStreamReader(stderr));
}
//Reader.readLine() may hang if 'exit' is not added to the command as the last line (use the 'exit' to exit the shell)
boolean toAppend = true;
while (true)
{
line = reader.readLine();
if (line == null)
{
valid = true;
flag = false;
break;
}
if (toAppend)
{
toAppend = this.append(sb, line);
}
if (line.trim().startsWith(PROMPT_SYMBOL))
{
if (line.trim().indexOf(ERROR_SYMBOL) >= 0)
{
valid = false;
flag = false;
break;
}
else if (line.trim().contains(ACCESS_DENIED_MESSAGE))
{
throw new AccessDeniedException(line.trim());
}
}
line = reader.readLine();
}
}
finally
{
if (reader != null)
reader.close();
}
}
String message = sb.toString().trim();
SshResponse response = new SshResponse();
response.setCommand(command);
response.setValid(valid);
response.setOut(message);
//keep all output
//r4(config)#int Fastethernet1/0
// ^
//% Invalid input detected at '^' marker.
response.setErr(message);
return response;
}
private boolean append(StringBuilder sb, String line)
{
if (sb.length() >= MAX_OUTPUT_BUFFER_SIZE)
{
sb.setLength(MAX_OUTPUT_BUFFER_SIZE - 3);
sb.append("...");
return false;
}
if (sb.length() + line.length() > MAX_OUTPUT_BUFFER_SIZE)
{
//Minimum abbreviation width is 4
if (MAX_OUTPUT_BUFFER_SIZE - sb.length() < 4)
{
sb.setLength(MAX_OUTPUT_BUFFER_SIZE - 3);
sb.append("...");
}
else
{
String abbreviated = StringUtils.abbreviate(line, MAX_OUTPUT_BUFFER_SIZE - sb.length());
sb.append(abbreviated);
}
sb.append('\n');
return false;
}
sb.append(line);
sb.append('\n');
return true;
}
Keep in mind that the last command "exit" should not be omitted otherwise the SSH session may hang up for ever.