-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this already allows connecting to OpenSearch using basic authentication. note: the `liquibase.nosql` package has been copied from [`liquibase-mongodb`] and adapted where needed (it is not 100% generic). no authorship is claimed for this content! [`liquibase-mongodb`]: https://github.com/liquibase/liquibase-mongodb
- Loading branch information
1 parent
ef873a6
commit 7ea8322
Showing
10 changed files
with
831 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/main/java/liquibase/ext/opensearch/database/OpenSearchClientDriver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package liquibase.ext.opensearch.database; | ||
|
||
import liquibase.Scope; | ||
import liquibase.util.StringUtil; | ||
|
||
import java.sql.Connection; | ||
import java.sql.Driver; | ||
import java.sql.DriverPropertyInfo; | ||
import java.sql.SQLException; | ||
import java.util.Properties; | ||
import java.util.logging.Logger; | ||
|
||
import static liquibase.ext.opensearch.database.OpenSearchLiquibaseDatabase.OPENSEARCH_PREFIX; | ||
|
||
public class OpenSearchClientDriver implements Driver { | ||
@Override | ||
public Connection connect(final String url, final Properties info) { | ||
//Not applicable for non JDBC DBs | ||
throw new UnsupportedOperationException("Cannot initiate a SQL Connection for a NoSql DB"); | ||
} | ||
|
||
public static boolean isOpenSearchURL(final String url) { | ||
return StringUtil.trimToEmpty(url).startsWith(OPENSEARCH_PREFIX); | ||
} | ||
|
||
@Override | ||
public boolean acceptsURL(final String url) { | ||
return isOpenSearchURL(url); | ||
} | ||
|
||
@Override | ||
public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) throws SQLException { | ||
return new DriverPropertyInfo[0]; | ||
} | ||
|
||
@Override | ||
public int getMajorVersion() { | ||
return 0; | ||
} | ||
|
||
@Override | ||
public int getMinorVersion() { | ||
return 0; | ||
} | ||
|
||
@Override | ||
public boolean jdbcCompliant() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public Logger getParentLogger() { | ||
return (Logger) Scope.getCurrentScope().getLog(getClass()); | ||
} | ||
} |
151 changes: 151 additions & 0 deletions
151
src/main/java/liquibase/ext/opensearch/database/OpenSearchConnection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package liquibase.ext.opensearch.database; | ||
|
||
import liquibase.exception.DatabaseException; | ||
import liquibase.nosql.database.AbstractNoSqlConnection; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
import org.apache.hc.client5.http.auth.AuthScope; | ||
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; | ||
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; | ||
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; | ||
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; | ||
import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder; | ||
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; | ||
import org.apache.hc.core5.http.HttpHost; | ||
import org.apache.hc.core5.http.nio.ssl.TlsStrategy; | ||
import org.apache.hc.core5.reactor.ssl.TlsDetails; | ||
import org.apache.hc.core5.ssl.SSLContextBuilder; | ||
import org.opensearch.client.json.jackson.JacksonJsonpMapper; | ||
import org.opensearch.client.opensearch.OpenSearchClient; | ||
import org.opensearch.client.transport.httpclient5.ApacheHttpClient5TransportBuilder; | ||
|
||
import javax.net.ssl.SSLContext; | ||
import java.net.URI; | ||
import java.security.KeyManagementException; | ||
import java.security.KeyStoreException; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.sql.Driver; | ||
import java.util.Optional; | ||
import java.util.Properties; | ||
|
||
import static liquibase.ext.opensearch.database.OpenSearchLiquibaseDatabase.OPENSEARCH_PREFIX; | ||
|
||
@Getter | ||
@Setter | ||
@NoArgsConstructor | ||
public class OpenSearchConnection extends AbstractNoSqlConnection { | ||
|
||
// FIXME: protected due to tests using it | ||
protected OpenSearchClient openSearchClient; | ||
|
||
protected URI uri; | ||
protected Properties connectionProperties; | ||
|
||
@Override | ||
public boolean supports(final String url) { | ||
if (url == null) { | ||
return false; | ||
} | ||
return url.toLowerCase().startsWith(OPENSEARCH_PREFIX); | ||
} | ||
|
||
@Override | ||
public void open(final String url, final Driver driverObject, final Properties driverProperties) throws DatabaseException { | ||
String realUrl = url; | ||
if (realUrl.toLowerCase().startsWith(OPENSEARCH_PREFIX)) { | ||
realUrl = realUrl.substring(OPENSEARCH_PREFIX.length()); | ||
} | ||
|
||
this.connectionProperties = driverProperties; | ||
|
||
try { | ||
this.uri = new URI(realUrl); | ||
this.connect(this.uri, driverProperties); | ||
} catch (final Exception e) { | ||
throw new DatabaseException("Could not open connection to database: " + realUrl); | ||
} | ||
} | ||
|
||
@Override | ||
public void close() throws DatabaseException { | ||
this.openSearchClient = null; | ||
this.connectionProperties = null; | ||
this.uri = null; | ||
} | ||
|
||
@Override | ||
public String getCatalog() throws DatabaseException { | ||
return null; // OpenSearch doesn't have catalogs (called schemas in various RDBMS) | ||
} | ||
|
||
@Override | ||
public String getDatabaseProductName() throws DatabaseException { | ||
return OpenSearchLiquibaseDatabase.PRODUCT_NAME; | ||
} | ||
|
||
@Override | ||
public String getURL() { | ||
return this.uri.toString(); | ||
} | ||
|
||
@Override | ||
public String getConnectionUserName() { | ||
return this.connectionProperties.getProperty("username"); | ||
} | ||
|
||
@Override | ||
public boolean isClosed() throws DatabaseException { | ||
return this.openSearchClient == null; | ||
} | ||
|
||
private void connect(final URI uri, final Properties info) throws DatabaseException { | ||
final HttpHost host = HttpHost.create(uri); | ||
|
||
final var transport = ApacheHttpClient5TransportBuilder | ||
.builder(host) | ||
.setHttpClientConfigCallback(httpClientBuilder -> { | ||
// TODO: support other credential providers | ||
final var username = Optional.ofNullable(info.getProperty("user")); | ||
final var password = Optional.ofNullable(info.getProperty("password")); | ||
|
||
if (username.isPresent()) { | ||
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); | ||
credentialsProvider.setCredentials(new AuthScope(host), | ||
new UsernamePasswordCredentials(username.get(), password.orElse("").toCharArray())); | ||
|
||
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); | ||
} | ||
|
||
final SSLContext sslcontext; | ||
try { | ||
sslcontext = SSLContextBuilder | ||
.create() | ||
.loadTrustMaterial(null, (chains, authType) -> true) | ||
.build(); | ||
} catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
final TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create() | ||
.setSslContext(sslcontext) | ||
// disable the certificate since our testing cluster just uses the default security configuration | ||
.setHostnameVerifier(NoopHostnameVerifier.INSTANCE) | ||
// See https://issues.apache.org/jira/browse/HTTPCLIENT-2219 | ||
.setTlsDetailsFactory(sslEngine -> new TlsDetails(sslEngine.getSession(), sslEngine.getApplicationProtocol())) | ||
.build(); | ||
|
||
final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create() | ||
.setTlsStrategy(tlsStrategy) | ||
.build(); | ||
|
||
return httpClientBuilder | ||
.setConnectionManager(connectionManager); | ||
}) | ||
.setMapper(new JacksonJsonpMapper()) | ||
.build(); | ||
|
||
this.openSearchClient = new OpenSearchClient(transport); | ||
} | ||
|
||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/liquibase/ext/opensearch/database/OpenSearchLiquibaseDatabase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package liquibase.ext.opensearch.database; | ||
|
||
import liquibase.CatalogAndSchema; | ||
import liquibase.exception.LiquibaseException; | ||
import liquibase.nosql.database.AbstractNoSqlDatabase; | ||
import lombok.NoArgsConstructor; | ||
|
||
@NoArgsConstructor | ||
public class OpenSearchLiquibaseDatabase extends AbstractNoSqlDatabase { | ||
public static final String PRODUCT_NAME = "OpenSearch"; | ||
public static final String PRODUCT_SHORT_NAME = "opensearch"; | ||
public static final String OPENSEARCH_PREFIX = PRODUCT_SHORT_NAME + ":"; | ||
|
||
@Override | ||
public void dropDatabaseObjects(final CatalogAndSchema schemaToDrop) throws LiquibaseException { | ||
// TODO: implement | ||
} | ||
|
||
@Override | ||
public String getDefaultDriver(final String url) { | ||
if (OpenSearchClientDriver.isOpenSearchURL(url)) { | ||
return OpenSearchClientDriver.class.getName(); | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public String getDatabaseProductName() { | ||
return PRODUCT_NAME; | ||
} | ||
|
||
@Override | ||
public String getShortName() { | ||
return PRODUCT_SHORT_NAME; | ||
} | ||
|
||
@Override | ||
public Integer getDefaultPort() { | ||
return 9200; | ||
} | ||
|
||
@Override | ||
protected String getDefaultDatabaseProductName() { | ||
return PRODUCT_NAME; | ||
} | ||
|
||
@Override | ||
public String getDatabaseChangeLogTableName() { | ||
// OpenSearch only supports lowercase index names | ||
return super.getDatabaseChangeLogTableName().toLowerCase(); | ||
} | ||
|
||
@Override | ||
public String getDatabaseChangeLogLockTableName() { | ||
// OpenSearch only supports lowercase index names | ||
return super.getDatabaseChangeLogLockTableName().toLowerCase(); | ||
} | ||
} |
Oops, something went wrong.