FIXED (edited code to reflect changes I made)
I'm trying to connect to a Mongo database through an SSH tunnel using Java.
I'm using the Mongo driver 3.0.2 and jcraft (JSch) to create an SSH tunnel.
The idea is that I:
connect to the machine hosting the MongoDB installation through SSH
set up port forwarding from a local port to the remote MongoDB port
connect to MongoDB remotely
My code looks like this:
// forwarding ports
private static final String LOCAL_HOST = "localhost";
private static final String REMOTE_HOST = "127.0.0.1";
private static final Integer LOCAL_PORT = 8988;
private static final Integer REMOTE_PORT = 27017; // Default mongodb port
// ssh connection info
private static final String SSH_USER = "<username>";
private static final String SSH_PASSWORD = "<password>";
private static final String SSH_HOST = "<remote host>";
private static final Integer SSH_PORT = 22;
private static Session sshSession;
public static void main(String[] args) {
try {
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
sshSession = null;
sshSession = jsch.getSession(SSH_USER, SSH_HOST, SSH_PORT);
sshSession.setPassword(SSH_PASSWORD);
sshSession.setConfig(config);
sshSession.connect();
sshSession.setPortForwardingL(LOCAL_PORT, REMOTE_HOST, REMOTE_PORT);
MongoClient mongoClient = new MongoClient(LOCAL_HOST, LOCAL_PORT);
mongoClient.setReadPreference(ReadPreference.nearest());
MongoCursor<String> dbNames = mongoClient.listDatabaseNames().iterator();
while (dbNames.hasNext()) {
System.out.println(dbNames.next());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sshSession.delPortForwardingL(LOCAL_PORT);
sshSession.disconnect();
}
}
This code, when run, doesn't EDIT: does work. Connecting to the SSH server works just fine, but connecting to the Mongo database behind it doesn't work and returns this error:
INFO: Exception in monitor thread while connecting to server localhost:8988
com.mongodb.MongoSocketReadException: Prematurely reached end of stream
at com.mongodb.connection.SocketStream.read(SocketStream.java:88)
at com.mongodb.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:491)
at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:221)
at com.mongodb.connection.CommandHelper.receiveReply(CommandHelper.java:134)
at com.mongodb.connection.CommandHelper.receiveCommandResult(CommandHelper.java:121)
at com.mongodb.connection.CommandHelper.executeCommand(CommandHelper.java:32)
at com.mongodb.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:83)
at com.mongodb.connection.InternalStreamConnectionInitializer.initialize(InternalStreamConnectionInitializer.java:43)
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:127)
at java.lang.Thread.run(Unknown Source)
I've tried doing this through command line as follows:
$ ssh <user>#<host> -p 22 -X -C
$ <enter requested password>
<user>#<host>$ mongo
<user>#<host>$ MongoDB shell version: 2.6.10
<user>#<host>$ connecting to: test
So this seems to work. I'm at a loss as to why the Java code (which should be doing roughly the same thing) doesn't work.
I managed to make it work (tried to forward port to "localhost" rather than "127.0.0.1", changing it fixed it) edit: I guess the server was listening specifically on localhost rather than 127.0.0.1
This code is run successfully, but the main problem is your mongo db is stopped. Please check the instance of the mongo is running or not.
sudo systemctl status mongod
if it is not running
sudo systemctl start mongod
Related
I have such test setup:
MyService connects to PostgtreSQL
MyService endpoint is being called from test suite
Both MyService and PostgreSQL are being run with Testcontainers.
Here is the network schema I want to achieve.
At first I tried to arrange communication by exposing ports.
static final PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>(DockerImageName.parse(POSTGRES_VERSION));
static final GenericContainer<?> myService = new GenericContainer<>(DockerImageName.parse(MY_SERVICE_IMAGE))
.withEnv(
Map.of(
"SPRING_DATASOURCE_URL", postgres.getJdbcUrl(),
"SPRING_DATASOURCE_USERNAME", postgres.getUsername(),
"SPRING_DATASOURCE_PASSWORD", postgres.getPassword()
)
)
.withExposedPorts(8080)
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("MyService")))
According to logs MyService couldn't establish connection to PostgreSQL.
Caused by: java.net.ConnectException: Connection refused
Then I configured both services to share the same network.
static final Network SHARED_NETWORK = Network.newNetwork();
static final PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>(DockerImageName.parse(POSTGRES_VERSION))
.withNetwork(SHARED_NETWORK)
.withNetworkAliases("postgres");
static final GenericContainer<?> myService = new GenericContainer<>(DockerImageName.parse(MY_SERVICE_IMAGE))
.withEnv(
Map.of(
"SPRING_DATASOURCE_URL", "jdbc:postgresql://postgres:5432/" + postgres.getDatabaseName(),
"SPRING_DATASOURCE_USERNAME", postgres.getUsername(),
"SPRING_DATASOURCE_PASSWORD", postgres.getPassword()
)
)
.withExposedPorts(8080)
.withNetwork(SHARED_NETWORK)
.withNetworkAliases("MyService")
.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("MyService")))
Now MyService has established connection with PostgreSQL successfully. But when I perform HTTP request to MyService from the test suite, I get the same error.
restTemplate.getForObject("http://" + myService.getHost() + ":" + myService.getMappedPort(8080) +"/api/endpoint", Void.class)
Caused by: java.net.ConnectException: Connection refused
My question is how can I setup the containers network to make this architecture work?
You need to specify port bindings to expose a port to the "outside world".
Example similar to what you want:
Network network = Network.newNetwork();
GenericContainer mariaDbServer = getMariaDbContainer(network);
GenericContainer flywayRunner = getFlywayContainer(network);
...
#SuppressWarnings("rawtypes")
private GenericContainer getMariaDbContainer(Network network) {
return new GenericContainer<>("mariadb:10.4.21-focal")
.withEnv(Map.of("MYSQL_ROOT_PASSWORD", "password", "MYSQL_DATABASE", "somedatabase"))
.withCommand(
"mysqld", "--default-authentication-plugin=mysql_native_password", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci").withNetwork(network).withNetworkAliases("somedatabasedb")
.withNetworkMode(network.getId())
.withExposedPorts(3306).withCreateContainerCmdModifier(
cmd -> cmd.withNetworkMode(network.getId()).withHostConfig(
new HostConfig()
.withPortBindings(new PortBinding(Ports.Binding.bindPort(20306), new ExposedPort(3306))))
.withNetworkMode(network.getId())).withStartupTimeout(Duration.ofMinutes(2L));
}
#SuppressWarnings("rawtypes")
private GenericContainer getFlywayContainer(Network network) {
return new GenericContainer<>("flyway/flyway:7.15.0-alpine")
.withEnv(Map.of("MYSQL_ROOT_PASSWORD", "password", "MYSQL_DATABASE", "somedatabase"))
.withCommand(
"-url=jdbc:mariadb://somedatabasedb -schemas=somedatabase-user=root -password=password -connectRetries=300 migrate")
.withFileSystemBind(Paths.get(".", "infrastructure/database/schema").toAbsolutePath().toString(),
"/flyway/sql", BindMode.READ_ONLY).withNetwork(network).waitingFor(
Wait.forLogMessage(".*Successfully applied.*", 1)
).withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS));
}
Container two communicates with container one using "internal" port.
Container one exposes 20306 (that redirects to 3306) port to the "outside world".
I have my Java Spring app that deals with HBase.
Here is my configuration:
#Configuration
public class HbaseConfiguration {
#Bean
public HbaseTemplate hbaseTemplate(#Value("${hadoop.home.dir}") final String hadoopHome,
#Value("${hbase.zookeeper.quorum}") final String quorum,
#Value("${hbase.zookeeper.property.clientPort}") final String port)
throws IOException, ServiceException {
System.setProperty("hadoop.home.dir", hadoopHome);
org.apache.hadoop.conf.Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", quorum);
configuration.set("hbase.zookeeper.property.clientPort", port);
HBaseAdmin.checkHBaseAvailable(configuration);
return new HbaseTemplate(configuration);
}
}
#HBASE
hbase.zookeeper.quorum = localhost
hbase.zookeeper.property.clientPort = 2181
hadoop.home.dir = C:/hadoop
Before asking the question I tried to figure out the problem on my own and found this link https://github.com/sel-fish/hbase.docker
But still, I get an error
org.apache.hadoop.net.ConnectTimeoutException: 10000 millis timeout while waiting for channel to be ready for connect. ch : java.nio.channels.SocketChannel[connection-pending remote=myhbase/192.168.99.100:60000]
Could I ask you to help me and clarify how can I connect my local Java app with HBase running in Docker?
I am getting the below error message when I try to connect mysql in remote server through SSH connection from my pc .
I installed all the required ssh, Java jars and trust am able to access SSH but unable to access mysql DB don’t know really where am I going wrong code below show variables for ports and Ssh session :
error message as hereunder :
com.jcraft.jsch.JSchException: PortForwardingL: local port 127.0.0.1:3306 cannot be bound.
at com.jcraft.jsch.PortWatcher.<init>(PortWatcher.java:158)
at com.jcraft.jsch.PortWatcher.addPort(PortWatcher.java:110)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1847)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1828)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1809)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1792)
at connectsshserver.CTestDriver.doSshTunnel(CTestDriver.java:29)
at connectsshserver.CTestDriver.main(CTestDriver.java:47)
Caused by: java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:106)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:190)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at com.jcraft.jsch.PortWatcher.<init>(PortWatcher.java:150)
and my code is like:
package connectsshserver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
public class CTestDriver {
private static void doSshTunnel(String strSshUser, String strSshPassword, String strSshHost, int nSshPort,
String strRemoteHost, int nLocalPort, int nRemotePort) throws JSchException {
final JSch jsch = new JSch();
Session session = jsch.getSession(strSshUser, strSshHost, 21098);
session.setPassword(strSshPassword);
final Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(30000);
// String boundaddress ="0.0.0.0";
//t assinged_port=session.setPortForwardingL(boundaddress,lport, rhost, rport);
session.setPortForwardingL(
nLocalPort, strRemoteHost, nRemotePort);
}
public static void main(String[] args) {
try {
String strSshUser = "softeuab"; // SSH loging username
String strSshPassword = "SP1234a1234b"; // SSH login password
String strSshHost = "host47.registrar-servers.com";//me or ip or // SSH server
int nSshPort = 21098; // remote SSH host port number
String strRemoteHost = "host47.registrar-servers.com"; // hostname or
// ip of
// your // database server
int nLocalPort =3306;//cal port number use to bind SSH tunnel
int nRemotePort = 3306; // remote port number of your database
String strDbUser = "softeuab_mohamed"; // database loging username
String strDbPassword = "1234a1234b"; // database login password
CTestDriver.doSshTunnel(strSshUser, strSshPassword, strSshHost, nSshPort, strRemoteHost, nLocalPort,
nRemotePort);
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:" + nLocalPort, strDbUser,
strDbPassword);
con.close();
// Connection con=Connect.ConnectDB();
// con.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.exit(0);
}
}
}
this line show error
session.setPortForwardingL(
nLocalPort, strRemoteHost, nRemotePort);
I just tried you code (except commented out the mysql code that runs after the port forwarding.) Everything worked for me - no errors on the call session.setPortForwardingL.
I am trying to run the following Java code using sshj :-
public static void main(String[] args) throws IOException {
SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("host", port);
try {
ssh.authPassword("user", "passwd");
ssh.useCompression();
final String src = System.getProperty("user.home") + File.separator + "test_file";
ssh.newSCPFileTransfer().upload(new FileSystemFile(src), "/tmp/");
} finally {
ssh.disconnect();
ssh.close();
}
}
But it is throwing exception -
Exception in thread "main" net.schmizz.sshj.userauth.UserAuthException: Exhausted available authentication methods
at net.schmizz.sshj.SSHClient.auth(SSHClient.java:231)
at net.schmizz.sshj.SSHClient.auth(SSHClient.java:206)
at net.schmizz.sshj.SSHClient.authPassword(SSHClient.java:292)
at net.schmizz.sshj.SSHClient.authPassword(SSHClient.java:262)
at net.schmizz.sshj.SSHClient.authPassword(SSHClient.java:246)
at sample.SCPUpload.main(SCPUpload.java:17)
I can connect the host using same credentials via Putty. I am using JDK "1.8.0_151". What is wrong here?
Typically it means that either your password is wrong, or you're not allowed to connect using the 'password' authentication method.
I am using smack libary to connect ejabberd xmpp server, I have hosted ejabberd in my locally . And it works fine, I can connect, send text message . The code I used to connect is following
public static final String HOST = "remote_host_ip_address";
public static final int PORT = 5222;
public static final int CONNECT_TIME_OUT = 20000;
public static final String RESOURCE = "Smack";
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setHost(HOST);
configBuilder.setPort(PORT);
//configBuilder.setServiceName("localhost");
configBuilder.setServiceName("hostname.com");
configBuilder.setResource(RESOURCE);
configBuilder.setCompressionEnabled(true);
configBuilder.setConnectTimeout(CONNECT_TIME_OUT);
//configBuilder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
connectionConfig = configBuilder.build();
connection = new XMPPTCPConnection(connectionConfig);
accountManager = AccountManager.getInstance(connection);
chatManager = ChatManager.getInstanceFor(connection);
chatManager.addChatListener(chatManagerListener);
When I assign HOST value to my local ip address like 192.168.101.1 and use configBuilder.setServiceName("localhost"); it works perfect but if I assign configBuilder.setServiceName("hostname.com"); and HOST variable to remote server ip address it throws the following error
org.jivesoftware.smack.SmackException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
But if use any xmpp client like gajim I can connect to remote server. I have used the following dependencies
compile 'org.igniterealtime.smack:smack-android-extensions:4.1.3'
compile 'org.igniterealtime.smack:smack-tcp:4.1.3'