feat:ssh 管理
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -155,6 +155,13 @@
|
|||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ssh -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jsch</artifactId>
|
||||||
|
<version>0.1.55</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<artifactId>xservice-basic</artifactId>
|
<artifactId>xservice-basic</artifactId>
|
||||||
<version>1.1</version>
|
<version>1.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<version>1.2</version>
|
<version>1.3</version>
|
||||||
|
|
||||||
<artifactId>xservice-common</artifactId>
|
<artifactId>xservice-common</artifactId>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.xiang.xservice.basic.utils;
|
||||||
|
|
||||||
|
import com.jcraft.jsch.JSch;
|
||||||
|
import com.jcraft.jsch.Session;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class SSHManager {
|
||||||
|
private static final ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public static void createTunnel(String key, String sshHost, int sshPort,
|
||||||
|
String sshUser, String sshPassword,
|
||||||
|
int localPort, String remoteHost, int remotePort) throws Exception {
|
||||||
|
if (sessionMap.containsKey(key) && sessionMap.get(key).isConnected()) {
|
||||||
|
return; // 已存在
|
||||||
|
}
|
||||||
|
JSch jsch = new JSch();
|
||||||
|
Session session = jsch.getSession(sshUser, sshHost, sshPort);
|
||||||
|
session.setPassword(sshPassword);
|
||||||
|
|
||||||
|
java.util.Properties config = new java.util.Properties();
|
||||||
|
config.put("StrictHostKeyChecking", "no");
|
||||||
|
session.setConfig(config);
|
||||||
|
|
||||||
|
session.connect();
|
||||||
|
session.setPortForwardingL(localPort, remoteHost, remotePort);
|
||||||
|
|
||||||
|
sessionMap.put(key, session);
|
||||||
|
System.out.println("SSH Tunnel for [" + key + "] established.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeTunnel(String key) {
|
||||||
|
Session session = sessionMap.get(key);
|
||||||
|
if (session != null && session.isConnected()) {
|
||||||
|
session.disconnect();
|
||||||
|
sessionMap.remove(key);
|
||||||
|
System.out.println("SSH Tunnel for [" + key + "] closed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,19 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>xservice-mysql-starter</artifactId>
|
<artifactId>xservice-mysql-starter</artifactId>
|
||||||
<version>1.1</version>
|
<version>2.0-SNAPSHOT</version>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xiang</groupId>
|
||||||
|
<artifactId>xservice-common</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -29,7 +29,7 @@ public class DynamicDataSourceConfig {
|
|||||||
targetDataSources.put(key, builder.build());
|
targetDataSources.put(key, builder.build());
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicRoutingDataSource routing = new DynamicRoutingDataSource();
|
DynamicRoutingDataSource routing = new DynamicRoutingDataSource(props);
|
||||||
routing.setDefaultTargetDataSource(targetDataSources.get(props.getPrimary()));
|
routing.setDefaultTargetDataSource(targetDataSources.get(props.getPrimary()));
|
||||||
routing.setTargetDataSources(targetDataSources);
|
routing.setTargetDataSources(targetDataSources);
|
||||||
return routing;
|
return routing;
|
||||||
|
|||||||
@@ -12,5 +12,12 @@ public class DataSourceProperty {
|
|||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
private String driverClassName = "com.mysql.cj.jdbc.Driver";
|
private String driverClassName = "com.mysql.cj.jdbc.Driver";
|
||||||
|
private Boolean sshConnect;
|
||||||
|
private String sshHost;
|
||||||
|
private Integer sshPort = 22;
|
||||||
|
private String sshUser;
|
||||||
|
private String sshPassword;
|
||||||
|
private Integer localPort; // 本地转发端口
|
||||||
|
private String remoteHost; // 远端数据库 host
|
||||||
|
private Integer remotePort; // 远端数据库 port
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,37 @@
|
|||||||
package com.xiang.xservice.mysql.service;
|
package com.xiang.xservice.mysql.service;
|
||||||
|
|
||||||
|
import com.xiang.xservice.basic.utils.SSHManager;
|
||||||
import com.xiang.xservice.mysql.config.DynamicDataSourceContext;
|
import com.xiang.xservice.mysql.config.DynamicDataSourceContext;
|
||||||
|
import com.xiang.xservice.mysql.entity.DataSourceProperty;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||||
|
import com.xiang.xservice.mysql.entity.DynamicDataSourceProperties;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
|
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
|
||||||
|
|
||||||
|
private final DynamicDataSourceProperties dynamicDataSourceProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object determineCurrentLookupKey() {
|
protected Object determineCurrentLookupKey() {
|
||||||
return DynamicDataSourceContext.get();
|
String key = DynamicDataSourceContext.get();
|
||||||
|
DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(key);
|
||||||
|
if (Boolean.TRUE.equals(dataSourceProperty.getSshConnect())) {
|
||||||
|
try {
|
||||||
|
SSHManager.createTunnel(
|
||||||
|
key,
|
||||||
|
dataSourceProperty.getSshHost(),
|
||||||
|
dataSourceProperty.getSshPort(),
|
||||||
|
dataSourceProperty.getSshUser(),
|
||||||
|
dataSourceProperty.getSshPassword(),
|
||||||
|
dataSourceProperty.getLocalPort(),
|
||||||
|
dataSourceProperty.getRemoteHost(),
|
||||||
|
dataSourceProperty.getRemotePort()
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to establish SSH tunnel for " + key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user