Reputation: 11
I'm dealing with a tough one:
For testing purposes I use Apache Mina SSHD and JIMFS to mock a remote sftp server - only locally and in test environment. Never in production.
In my Spring Boot application I start a Apache Mina sshd during application startup. I create a virtual filesystem with jimfs (tried unix and osX) for the FileSystemFactory
.
My business code calls a remote sftp server in production and in test environment it calls the mina sshd server on localhost instead.
It does nothing else than uploading a file to the sftp server.
This works very well on my machine locally but i get a "file or directory not found" error message when I run this in our test environment (a docker container).
com.jcraft.jsch.SftpException: No such file or directory
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)
at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:594)
at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:475)
at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:365)
at our.service.core.client.sftp.SftpClient.upload(SftpClient.java:89)
Creation of JIMFS file system during Application startup:
public class MockSftpServerInitializer implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setHost("localhost");
sshd.setPort(1234);
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("host-key.ser")));
sshd.setPublickeyAuthenticator(getPublickeyAuthenticator());
sshd.setFileSystemFactory(getInMemoryFileSystemFactory());
List<NamedFactory<Command>> sftpCommandFactory = new ArrayList<>();
sftpCommandFactory.add(new SftpSubsystemFactory());
sshd.setSubsystemFactories(sftpCommandFactory);
try {
sshd.start();
} catch (Exception e) {
throw new RuntimeException("Unable to start sshd", e);
}
}
private FileSystemFactory getInMemoryFileSystemFactory() {
return session -> getInMemoryFileSystem();
}
private FileSystem getInMemoryFileSystem() {
return Jimfs.newFileSystem(
Configuration.osX()
.toBuilder()
.setWorkingDirectory("/")
.setMaxSize(1024*1024*4)
.setDefaultAttributeValue("posix:permissions", "rwxrw-rw-")
.setAttributeViews("basic", "owner", "posix", "unix", "acl", "user")
.build());
}
}
File upload:
public class SftpClient {
public boolean upload(String source, String destination) {
Session session = null;
ChannelSftp sftpChannel = null;
try {
sftpProvider.addIdentity("Identity", privateKey.getBytes(), publicKey.getBytes(), null);
session = sftpProvider.getSession(username, host, port);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
sftpChannel = (ChannelSftp) channel;
sftpChannel.put(source, destination);
log.info("Successful upload of file {} to SFTP server {}.", source, host);
return true;
} catch (SftpException | JSchException ex) {
log.error("Failed upload of file {} to SFTP server {}.", source, host);
log.error("{}", ex);
return false;
} finally {
if (sftpChannel != null) {
sftpChannel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
}
I'm grateful for any hint on why this works locally but not in our docker container.
Upvotes: 0
Views: 2426