diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/util/LocalSshTunnel.java b/gemma-core/src/main/java/ubic/gemma/persistence/util/LocalSshTunnel.java new file mode 100644 index 0000000000..ab839b263b --- /dev/null +++ b/gemma-core/src/main/java/ubic/gemma/persistence/util/LocalSshTunnel.java @@ -0,0 +1,80 @@ +package ubic.gemma.persistence.util; + +import lombok.Setter; +import lombok.extern.apachecommons.CommonsLog; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.context.SmartLifecycle; +import org.springframework.util.Assert; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +/** + * Establishes a local SSH tunnel. + * @author poirigui + */ +@CommonsLog +@Setter +public class LocalSshTunnel implements SmartLifecycle { + + private String host; + @Nullable + private Integer port; + + // for the tunnel + private int localPort; + private String remoteHost; + private int remotePort; + + private boolean autoStart = false; + + private Process tunnelProcess; + + @Override + public void start() { + Assert.isTrue( host != null && localPort > 0 && remoteHost != null && remotePort > 0 ); + try { + String[] args = new String[] { "ssh", "-L", localPort + ":" + remoteHost + ":" + remotePort, host }; + if ( port != null ) { + args = ArrayUtils.addAll( args, "-p", String.valueOf( port ) ); + } + tunnelProcess = Runtime.getRuntime().exec( args ); + // quickly check if the process exited + if ( tunnelProcess.waitFor( 100, TimeUnit.MILLISECONDS ) ) { + throw new RuntimeException( IOUtils.toString( tunnelProcess.getErrorStream(), StandardCharsets.UTF_8 ) ); + } + } catch ( IOException | InterruptedException e ) { + throw new RuntimeException( e ); + } + log.info( String.format( "Established a SSH tunnel to %s%s: %d -> %s:%d.", + host, port != null ? ":" + port : "", localPort, remoteHost, remotePort ) ); + } + + @Override + public void stop() { + tunnelProcess.destroy(); + } + + @Override + public boolean isRunning() { + return tunnelProcess != null && tunnelProcess.isAlive(); + } + + @Override + public boolean isAutoStartup() { + return autoStart; + } + + @Override + public void stop( Runnable callback ) { + stop(); + } + + @Override + public int getPhase() { + return 0; + } +} diff --git a/gemma-core/src/main/resources/default.properties b/gemma-core/src/main/resources/default.properties index f27e7170c4..9da196ff26 100755 --- a/gemma-core/src/main/resources/default.properties +++ b/gemma-core/src/main/resources/default.properties @@ -50,6 +50,13 @@ gemma.db.user=gemmauser gemma.db.password=XXXXXX # Maximum size for the connections pool gemma.db.maximumPoolSize=10 +# Establish an SSH tunnel to connect to the database (only if the dev profile is active) +gemma.db.tunnel.enabled=false +gemma.db.tunnel.host= +gemma.db.tunnel.port= +gemma.db.tunnel.localPort=0 +gemma.db.tunnel.remoteHost= +gemma.db.tunnel.remotePort=0 ############################################################ # SECURITY # Used to elevate authorities for some methods. @@ -205,6 +212,13 @@ gemma.testdb.agent.userName=gemmaAgent gemma.testdb.agent.password=XXXXXXXX # Initialize the test database, this can be disabled to make integration tests faster gemma.testdb.initialize=true +# Establish an SSH tunnel to connect to the test database (only if the dev profile is active) +gemma.testdb.tunnel.enabled=false +gemma.testdb.tunnel.host= +gemma.testdb.tunnel.port= +gemma.testdb.tunnel.localPort=0 +gemma.testdb.tunnel.remoteHost= +gemma.testdb.tunnel.remotePort=0 #the external database id to exclude by default in phenocarta gemma.neurocarta.exluded_database_id=85 # Featured external databases in Gemma Web About page and Gemma REST main endpoint diff --git a/gemma-core/src/main/resources/ubic/gemma/applicationContext-dataSource.xml b/gemma-core/src/main/resources/ubic/gemma/applicationContext-dataSource.xml index d28d0d40d1..0993f94311 100644 --- a/gemma-core/src/main/resources/ubic/gemma/applicationContext-dataSource.xml +++ b/gemma-core/src/main/resources/ubic/gemma/applicationContext-dataSource.xml @@ -12,10 +12,35 @@ sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -36,7 +61,7 @@ - +