Source postgres: Add SSL certificates to source postgres (#13840)
* added ssl certificates for postgres source * added command for remove client private key after transformation to encrypted key with .pk8 extension * added connection with CA and client certificates for postgres destination * updated code style * moved common methods to the common class * moved common methods to the common class * fixed remarks * updated postgres source tests * added minor changes to spec and added fixes to password mechanism * updated postgres source tests * updated strict-encrypt postgres source and destination and added tests for SSL certificates for all postgres connectors * fixed check style * updated documentation and versions of connectors * updated ordrs in test spec * fixed minor remarks in specs and expected_specs * fixed minor remarks in specs and expected_specs * fixed Dockerfile * fixed remarks * fixed remarks * fixed remarks * fixed remarks * fixed remarks * rollback changes for postgres destination and move them to a new pull request * rollback changes for postgres destination and move them to a new pull request * fixed code style * fixed code style * fixed code style * fixed code style * fixed code style * auto-bump connector version * updated version of postgres strict-encrypt source Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
This commit is contained in:
@@ -754,7 +754,7 @@
|
||||
- name: Postgres
|
||||
sourceDefinitionId: decd338e-5647-4c0b-adf4-da0e75f5a750
|
||||
dockerRepository: airbyte/source-postgres
|
||||
dockerImageTag: 0.4.33
|
||||
dockerImageTag: 0.4.34
|
||||
documentationUrl: https://docs.airbyte.io/integrations/sources/postgres
|
||||
icon: postgresql.svg
|
||||
sourceType: database
|
||||
|
||||
@@ -6978,7 +6978,7 @@
|
||||
supportsNormalization: false
|
||||
supportsDBT: false
|
||||
supported_destination_sync_modes: []
|
||||
- dockerImage: "airbyte/source-postgres:0.4.33"
|
||||
- dockerImage: "airbyte/source-postgres:0.4.34"
|
||||
spec:
|
||||
documentationUrl: "https://docs.airbyte.com/integrations/sources/postgres"
|
||||
connectionSpecification:
|
||||
@@ -7045,10 +7045,153 @@
|
||||
order: 6
|
||||
ssl:
|
||||
title: "Connect using SSL"
|
||||
description: "Encrypt client/server communications for increased security."
|
||||
description: "Encrypt data using SSL. When activating SSL, please select\
|
||||
\ one of the connection modes."
|
||||
type: "boolean"
|
||||
default: false
|
||||
order: 7
|
||||
ssl_mode:
|
||||
title: "SSL modes"
|
||||
description: "SSL connection modes. \n <b>disable</b> - Chose this mode\
|
||||
\ to disable encryption of communication between Airbyte and source database\n\
|
||||
\ <b>allow</b> - Chose this mode to enable encryption only when required\
|
||||
\ by the source database\n <b>prefer</b> - Chose this mode to allow unencrypted\
|
||||
\ connection only if the source database does not support encryption\n\
|
||||
\ <b>require</b> - Chose this mode to always require encryption. If the\
|
||||
\ source database server does not support encryption, connection will\
|
||||
\ fail\n <b>verify-ca</b> - Chose this mode to always require encryption\
|
||||
\ and to verify that the source database server has a valid SSL certificate\n\
|
||||
\ <b>verify-full</b> - This is the most secure mode. Chose this mode\
|
||||
\ to always require encryption and to verify the identity of the source\
|
||||
\ database server\n See more information - <a href=\"https://jdbc.postgresql.org/documentation/head/ssl-client.html\"\
|
||||
> in the docs</a>."
|
||||
type: "object"
|
||||
order: 7
|
||||
oneOf:
|
||||
- title: "disable"
|
||||
additionalProperties: false
|
||||
description: "Disable SSL."
|
||||
required:
|
||||
- "mode"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "disable"
|
||||
enum:
|
||||
- "disable"
|
||||
default: "disable"
|
||||
order: 0
|
||||
- title: "allow"
|
||||
additionalProperties: false
|
||||
description: "Allow SSL mode."
|
||||
required:
|
||||
- "mode"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "allow"
|
||||
enum:
|
||||
- "allow"
|
||||
default: "allow"
|
||||
order: 0
|
||||
- title: "prefer"
|
||||
additionalProperties: false
|
||||
description: "Prefer SSL mode."
|
||||
required:
|
||||
- "mode"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "prefer"
|
||||
enum:
|
||||
- "prefer"
|
||||
default: "prefer"
|
||||
order: 0
|
||||
- title: "require"
|
||||
additionalProperties: false
|
||||
description: "Require SSL mode."
|
||||
required:
|
||||
- "mode"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "require"
|
||||
enum:
|
||||
- "require"
|
||||
default: "require"
|
||||
order: 0
|
||||
- title: "verify-ca"
|
||||
additionalProperties: false
|
||||
description: "Verify-ca SSL mode."
|
||||
required:
|
||||
- "mode"
|
||||
- "ca_certificate"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "verify-ca"
|
||||
enum:
|
||||
- "verify-ca"
|
||||
default: "verify-ca"
|
||||
order: 0
|
||||
ca_certificate:
|
||||
type: "string"
|
||||
title: "CA certificate"
|
||||
description: "CA certificate"
|
||||
airbyte_secret: true
|
||||
multiline: true
|
||||
order: 1
|
||||
client_key_password:
|
||||
type: "string"
|
||||
title: "Client key password (Optional)"
|
||||
description: "Password for keystorage. This field is optional. If\
|
||||
\ you do not add it - the password will be generated automatically."
|
||||
airbyte_secret: true
|
||||
order: 4
|
||||
- title: "verify-full"
|
||||
additionalProperties: false
|
||||
description: "Verify-full SSL mode."
|
||||
required:
|
||||
- "mode"
|
||||
- "ca_certificate"
|
||||
- "client_certificate"
|
||||
- "client_key"
|
||||
properties:
|
||||
mode:
|
||||
type: "string"
|
||||
const: "verify-full"
|
||||
enum:
|
||||
- "verify-full"
|
||||
default: "verify-full"
|
||||
order: 0
|
||||
ca_certificate:
|
||||
type: "string"
|
||||
title: "CA certificate"
|
||||
description: "CA certificate"
|
||||
airbyte_secret: true
|
||||
multiline: true
|
||||
order: 1
|
||||
client_certificate:
|
||||
type: "string"
|
||||
title: "Client certificate"
|
||||
description: "Client certificate"
|
||||
airbyte_secret: true
|
||||
multiline: true
|
||||
order: 2
|
||||
client_key:
|
||||
type: "string"
|
||||
title: "Client key"
|
||||
description: "Client key"
|
||||
airbyte_secret: true
|
||||
multiline: true
|
||||
order: 3
|
||||
client_key_password:
|
||||
type: "string"
|
||||
title: "Client key password (Optional)"
|
||||
description: "Password for keystorage. This field is optional. If\
|
||||
\ you do not add it - the password will be generated automatically."
|
||||
airbyte_secret: true
|
||||
order: 4
|
||||
replication_method:
|
||||
type: "object"
|
||||
title: "Replication Method"
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
package io.airbyte.db;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.airbyte.db.jdbc.JdbcDatabase;
|
||||
import io.airbyte.db.jdbc.JdbcUtils;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
public class PostgresUtils {
|
||||
|
||||
@@ -23,4 +26,74 @@ public class PostgresUtils {
|
||||
return PgLsn.fromPgString(jsonNodes.get(0).get("pg_current_wal_lsn").asText());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static Certificate getCertificate(final PostgreSQLContainer<?> container) throws IOException, InterruptedException {
|
||||
container.execInContainer("su", "-c", "psql -U test -c \"CREATE USER postgres WITH PASSWORD 'postgres';\"");
|
||||
container.execInContainer("su", "-c", "psql -U test -c \"GRANT CONNECT ON DATABASE \"test\" TO postgres;\"");
|
||||
container.execInContainer("su", "-c", "psql -U test -c \"ALTER USER postgres WITH SUPERUSER;\"");
|
||||
|
||||
container.execInContainer("su", "-c", "openssl ecparam -name prime256v1 -genkey -noout -out ca.key");
|
||||
container.execInContainer("su", "-c", "openssl req -new -x509 -sha256 -key ca.key -out ca.crt -subj \"/CN=localhost\"");
|
||||
container.execInContainer("su", "-c", "openssl ecparam -name prime256v1 -genkey -noout -out server.key");
|
||||
container.execInContainer("su", "-c", "openssl req -new -sha256 -key server.key -out server.csr -subj \"/CN=localhost\"");
|
||||
container.execInContainer("su", "-c",
|
||||
"openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256");
|
||||
container.execInContainer("su", "-c", "cp server.key /etc/ssl/private/");
|
||||
container.execInContainer("su", "-c", "cp server.crt /etc/ssl/private/");
|
||||
container.execInContainer("su", "-c", "cp ca.crt /etc/ssl/private/");
|
||||
container.execInContainer("su", "-c", "chmod og-rwx /etc/ssl/private/server.* /etc/ssl/private/ca.*");
|
||||
container.execInContainer("su", "-c", "chown postgres:postgres /etc/ssl/private/server.crt /etc/ssl/private/server.key /etc/ssl/private/ca.crt");
|
||||
container.execInContainer("su", "-c", "echo \"ssl = on\" >> /var/lib/postgresql/data/postgresql.conf");
|
||||
container.execInContainer("su", "-c", "echo \"ssl_cert_file = '/etc/ssl/private/server.crt'\" >> /var/lib/postgresql/data/postgresql.conf");
|
||||
container.execInContainer("su", "-c", "echo \"ssl_key_file = '/etc/ssl/private/server.key'\" >> /var/lib/postgresql/data/postgresql.conf");
|
||||
container.execInContainer("su", "-c", "echo \"ssl_ca_file = '/etc/ssl/private/ca.crt'\" >> /var/lib/postgresql/data/postgresql.conf");
|
||||
container.execInContainer("su", "-c", "mkdir root/.postgresql");
|
||||
container.execInContainer("su", "-c",
|
||||
"echo \"hostssl all all 127.0.0.1/32 cert clientcert=verify-full\" >> /var/lib/postgresql/data/pg_hba.conf");
|
||||
|
||||
var caCert = container.execInContainer("su", "-c", "cat ca.crt").getStdout().trim();
|
||||
|
||||
container.execInContainer("su", "-c", "openssl ecparam -name prime256v1 -genkey -noout -out client.key");
|
||||
container.execInContainer("su", "-c", "openssl req -new -sha256 -key client.key -out client.csr -subj \"/CN=postgres\"");
|
||||
container.execInContainer("su", "-c",
|
||||
"openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256");
|
||||
container.execInContainer("su", "-c", "cp client.crt ~/.postgresql/postgresql.crt");
|
||||
container.execInContainer("su", "-c", "cp client.key ~/.postgresql/postgresql.key");
|
||||
container.execInContainer("su", "-c", "chmod 0600 ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.key");
|
||||
container.execInContainer("su", "-c", "cp ca.crt root/.postgresql/ca.crt");
|
||||
container.execInContainer("su", "-c", "chown postgres:postgres ~/.postgresql/ca.crt");
|
||||
|
||||
container.execInContainer("su", "-c", "psql -U test -c \"SELECT pg_reload_conf();\"");
|
||||
|
||||
var clientKey = container.execInContainer("su", "-c", "cat client.key").getStdout().trim();
|
||||
var clientCert = container.execInContainer("su", "-c", "cat client.crt").getStdout().trim();
|
||||
return new Certificate(caCert, clientCert, clientKey);
|
||||
}
|
||||
|
||||
public static class Certificate {
|
||||
|
||||
private final String caCertificate;
|
||||
private final String clientCertificate;
|
||||
private final String clientKey;
|
||||
|
||||
public Certificate(final String caCertificate, final String clientCertificate, final String clientKey) {
|
||||
this.caCertificate = caCertificate;
|
||||
this.clientCertificate = clientCertificate;
|
||||
this.clientKey = clientKey;
|
||||
}
|
||||
|
||||
public String getCaCertificate() {
|
||||
return caCertificate;
|
||||
}
|
||||
|
||||
public String getClientCertificate() {
|
||||
return clientCertificate;
|
||||
}
|
||||
|
||||
public String getClientKey() {
|
||||
return clientKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
|
||||
*/
|
||||
|
||||
package io.airbyte.integrations.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PostgresSslConnectionUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PostgresSslConnectionUtils.class);
|
||||
private static final String KEY_STORE_PASS = RandomStringUtils.randomAlphanumeric(10);
|
||||
private static final String CA_CERTIFICATE = "ca.crt";
|
||||
private static final String CLIENT_CERTIFICATE = "client.crt";
|
||||
private static final String CLIENT_KEY = "client.key";
|
||||
private static final String CLIENT_ENCRYPTED_KEY = "client.pk8";
|
||||
|
||||
public static final String PARAM_MODE = "mode";
|
||||
public static final String PARAM_SSL = "ssl";
|
||||
public static final String PARAM_SSL_MODE = "ssl_mode";
|
||||
public static final String PARAM_SSLMODE = "sslmode";
|
||||
public static final String PARAM_CLIENT_KEY_PASSWORD = "client_key_password";
|
||||
public static final String PARAM_CA_CERTIFICATE = "ca_certificate";
|
||||
public static final String PARAM_CLIENT_CERTIFICATE = "client_certificate";
|
||||
public static final String PARAM_CLIENT_KEY = "client_key";
|
||||
|
||||
public static final String VERIFY_CA = "verify-ca";
|
||||
public static final String VERIFY_FULL = "verify-full";
|
||||
public static final String DISABLE = "disable";
|
||||
public static final String TRUE_STRING_VALUE = "true";
|
||||
public static final String FACTORY_VALUE = "org.postgresql.ssl.DefaultJavaSSLFactory";
|
||||
|
||||
public static Map<String, String> obtainConnectionOptions(final JsonNode encryption) {
|
||||
final Map<String, String> additionalParameters = new HashMap<>();
|
||||
if (!encryption.isNull()) {
|
||||
final var method = encryption.get(PARAM_MODE).asText();
|
||||
String sslPassword = encryption.has(PARAM_CLIENT_KEY_PASSWORD) ? encryption.get(PARAM_CLIENT_KEY_PASSWORD).asText() : "";
|
||||
var keyStorePassword = KEY_STORE_PASS;
|
||||
if (!sslPassword.isEmpty()) {
|
||||
keyStorePassword = sslPassword;
|
||||
}
|
||||
switch (method) {
|
||||
case VERIFY_CA -> {
|
||||
additionalParameters.putAll(obtainConnectionCaOptions(encryption, method, keyStorePassword));
|
||||
}
|
||||
case VERIFY_FULL -> {
|
||||
additionalParameters.putAll(obtainConnectionFullOptions(encryption, method, keyStorePassword));
|
||||
}
|
||||
default -> {
|
||||
additionalParameters.put(PARAM_SSL, TRUE_STRING_VALUE);
|
||||
additionalParameters.put(PARAM_SSLMODE, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
return additionalParameters;
|
||||
}
|
||||
|
||||
private static Map<String, String> obtainConnectionFullOptions(final JsonNode encryption,
|
||||
final String method,
|
||||
final String clientKeyPassword) {
|
||||
final Map<String, String> additionalParameters = new HashMap<>();
|
||||
try {
|
||||
convertAndImportFullCertificate(encryption.get(PARAM_CA_CERTIFICATE).asText(),
|
||||
encryption.get(PARAM_CLIENT_CERTIFICATE).asText(), encryption.get(PARAM_CLIENT_KEY).asText(), clientKeyPassword);
|
||||
} catch (final IOException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to import certificate into Java Keystore");
|
||||
}
|
||||
additionalParameters.put("ssl", TRUE_STRING_VALUE);
|
||||
additionalParameters.put("sslmode", method);
|
||||
additionalParameters.put("sslrootcert", CA_CERTIFICATE);
|
||||
additionalParameters.put("sslcert", CLIENT_CERTIFICATE);
|
||||
additionalParameters.put("sslkey", CLIENT_ENCRYPTED_KEY);
|
||||
additionalParameters.put("sslfactory", FACTORY_VALUE);
|
||||
return additionalParameters;
|
||||
}
|
||||
|
||||
private static Map<String, String> obtainConnectionCaOptions(final JsonNode encryption,
|
||||
final String method,
|
||||
final String clientKeyPassword) {
|
||||
final Map<String, String> additionalParameters = new HashMap<>();
|
||||
try {
|
||||
convertAndImportCaCertificate(encryption.get(PARAM_CA_CERTIFICATE).asText(), clientKeyPassword);
|
||||
} catch (final IOException | InterruptedException e) {
|
||||
throw new RuntimeException("Failed to import certificate into Java Keystore");
|
||||
}
|
||||
additionalParameters.put("ssl", TRUE_STRING_VALUE);
|
||||
additionalParameters.put("sslmode", method);
|
||||
additionalParameters.put("sslrootcert", CA_CERTIFICATE);
|
||||
additionalParameters.put("sslfactory", FACTORY_VALUE);
|
||||
return additionalParameters;
|
||||
}
|
||||
|
||||
private static void convertAndImportFullCertificate(final String caCertificate,
|
||||
final String clientCertificate,
|
||||
final String clientKey,
|
||||
final String clientKeyPassword)
|
||||
throws IOException, InterruptedException {
|
||||
final Runtime run = Runtime.getRuntime();
|
||||
createCaCertificate(caCertificate, clientKeyPassword, run);
|
||||
createCertificateFile(CLIENT_CERTIFICATE, clientCertificate);
|
||||
createCertificateFile(CLIENT_KEY, clientKey);
|
||||
// add client certificate to the custom keystore
|
||||
runProcess("keytool -alias client-certificate -keystore customkeystore"
|
||||
+ " -import -file " + CLIENT_CERTIFICATE + " -storepass " + clientKeyPassword + " -noprompt", run);
|
||||
// convert client.key to client.pk8 based on the documentation
|
||||
runProcess("openssl pkcs8 -topk8 -inform PEM -in " + CLIENT_KEY + " -outform DER -out "
|
||||
+ CLIENT_ENCRYPTED_KEY + " -nocrypt", run);
|
||||
runProcess("rm " + CLIENT_KEY, run);
|
||||
|
||||
updateTrustStoreSystemProperty(clientKeyPassword);
|
||||
}
|
||||
|
||||
private static void convertAndImportCaCertificate(final String caCertificate,
|
||||
final String clientKeyPassword)
|
||||
throws IOException, InterruptedException {
|
||||
final Runtime run = Runtime.getRuntime();
|
||||
createCaCertificate(caCertificate, clientKeyPassword, run);
|
||||
updateTrustStoreSystemProperty(clientKeyPassword);
|
||||
}
|
||||
|
||||
private static void createCaCertificate(final String caCertificate,
|
||||
final String clientKeyPassword,
|
||||
final Runtime run)
|
||||
throws IOException, InterruptedException {
|
||||
createCertificateFile(CA_CERTIFICATE, caCertificate);
|
||||
// add CA certificate to the custom keystore
|
||||
runProcess("keytool -import -alias rds-root -keystore customkeystore"
|
||||
+ " -file " + CA_CERTIFICATE + " -storepass " + clientKeyPassword + " -noprompt", run);
|
||||
}
|
||||
|
||||
private static void updateTrustStoreSystemProperty(final String clientKeyPassword) {
|
||||
String result = System.getProperty("user.dir") + "/customkeystore";
|
||||
System.setProperty("javax.net.ssl.trustStore", result);
|
||||
System.setProperty("javax.net.ssl.trustStorePassword", clientKeyPassword);
|
||||
}
|
||||
|
||||
private static void createCertificateFile(String fileName, String fileValue) throws IOException {
|
||||
try (final PrintWriter out = new PrintWriter(fileName, StandardCharsets.UTF_8)) {
|
||||
out.print(fileValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void runProcess(final String cmd, final Runtime run) throws IOException, InterruptedException {
|
||||
final Process pr = run.exec(cmd);
|
||||
if (!pr.waitFor(30, TimeUnit.SECONDS)) {
|
||||
pr.destroy();
|
||||
throw new RuntimeException("Timeout while executing: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,5 +16,5 @@ ENV APPLICATION source-postgres-strict-encrypt
|
||||
|
||||
COPY --from=build /airbyte /airbyte
|
||||
|
||||
LABEL io.airbyte.version=0.4.32
|
||||
LABEL io.airbyte.version=0.4.34
|
||||
LABEL io.airbyte.name=airbyte/source-postgres-strict-encrypt
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package io.airbyte.integrations.source.postgres;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import io.airbyte.commons.json.Jsons;
|
||||
import io.airbyte.integrations.base.IntegrationRunner;
|
||||
@@ -29,6 +30,11 @@ public class PostgresSourceStrictEncrypt extends SpecModifyingSource implements
|
||||
public ConnectorSpecification modifySpec(final ConnectorSpecification originalSpec) {
|
||||
final ConnectorSpecification spec = Jsons.clone(originalSpec);
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties")).remove("ssl");
|
||||
ArrayNode modifiedSslModes = spec.getConnectionSpecification().get("properties").get("ssl_mode").get("oneOf").deepCopy();
|
||||
// Assume that the first item is the "disable" option; remove it
|
||||
modifiedSslModes.remove(0);
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties").get("ssl_mode")).remove("oneOf");
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties").get("ssl_mode")).put("oneOf", modifiedSslModes);
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,5 +16,5 @@ ENV APPLICATION source-postgres
|
||||
|
||||
COPY --from=build /airbyte /airbyte
|
||||
|
||||
LABEL io.airbyte.version=0.4.33
|
||||
LABEL io.airbyte.version=0.4.34
|
||||
LABEL io.airbyte.name=airbyte/source-postgres
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
package io.airbyte.integrations.source.postgres;
|
||||
|
||||
import static io.airbyte.integrations.debezium.AirbyteDebeziumHandler.shouldUseCDC;
|
||||
import static io.airbyte.integrations.debezium.internals.DebeziumEventUtils.CDC_DELETED_AT;
|
||||
import static io.airbyte.integrations.debezium.internals.DebeziumEventUtils.CDC_UPDATED_AT;
|
||||
import static io.airbyte.integrations.util.PostgresSslConnectionUtils.DISABLE;
|
||||
import static io.airbyte.integrations.util.PostgresSslConnectionUtils.PARAM_MODE;
|
||||
import static io.airbyte.integrations.util.PostgresSslConnectionUtils.PARAM_SSL;
|
||||
import static io.airbyte.integrations.util.PostgresSslConnectionUtils.PARAM_SSL_MODE;
|
||||
import static io.airbyte.integrations.util.PostgresSslConnectionUtils.obtainConnectionOptions;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
@@ -66,6 +73,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class PostgresSource extends AbstractJdbcSource<JDBCType> implements Source {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PostgresSource.class);
|
||||
|
||||
public static final String CDC_LSN = "_ab_cdc_lsn";
|
||||
public static final String DATABASE_KEY = "database";
|
||||
public static final String HOST_KEY = "host";
|
||||
@@ -114,9 +122,22 @@ public class PostgresSource extends AbstractJdbcSource<JDBCType> implements Sour
|
||||
}
|
||||
|
||||
// assume ssl if not explicitly mentioned.
|
||||
if (!config.has(JdbcUtils.SSL_KEY) || config.get(JdbcUtils.SSL_KEY).asBoolean()) {
|
||||
additionalParameters.add("ssl=true");
|
||||
additionalParameters.add("sslmode=require");
|
||||
if (!config.has(PARAM_SSL) || config.get(PARAM_SSL).asBoolean()) {
|
||||
if (config.has(PARAM_SSL_MODE)) {
|
||||
if (DISABLE.equals(config.get(PARAM_SSL_MODE).get(PARAM_MODE).asText())) {
|
||||
additionalParameters.add("sslmode=disable");
|
||||
} else {
|
||||
var parametersList = obtainConnectionOptions(config.get(PARAM_SSL_MODE))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.toList();
|
||||
additionalParameters.addAll(parametersList);
|
||||
}
|
||||
} else {
|
||||
additionalParameters.add("ssl=true");
|
||||
additionalParameters.add("sslmode=require");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.has(SCHEMAS_KEY) && config.get(SCHEMAS_KEY).isArray()) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package io.airbyte.integrations.source.postgres;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import io.airbyte.commons.json.Jsons;
|
||||
import io.airbyte.integrations.base.IntegrationRunner;
|
||||
@@ -29,6 +30,11 @@ public class PostgresSourceStrictEncrypt extends SpecModifyingSource implements
|
||||
public ConnectorSpecification modifySpec(final ConnectorSpecification originalSpec) {
|
||||
final ConnectorSpecification spec = Jsons.clone(originalSpec);
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties")).remove("ssl");
|
||||
ArrayNode modifiedSslModes = spec.getConnectionSpecification().get("properties").get("ssl_mode").get("oneOf").deepCopy();
|
||||
// Assume that the first item is the "disable" option; remove it
|
||||
modifiedSslModes.remove(0);
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties").get("ssl_mode")).remove("oneOf");
|
||||
((ObjectNode) spec.getConnectionSpecification().get("properties").get("ssl_mode")).put("oneOf", modifiedSslModes);
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +62,160 @@
|
||||
},
|
||||
"ssl": {
|
||||
"title": "Connect using SSL",
|
||||
"description": "Encrypt client/server communications for increased security.",
|
||||
"description": "Encrypt data using SSL. When activating SSL, please select one of the connection modes.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"order": 7
|
||||
},
|
||||
"ssl_mode": {
|
||||
"title": "SSL modes",
|
||||
"description": "SSL connection modes. \n <b>disable</b> - Chose this mode to disable encryption of communication between Airbyte and source database\n <b>allow</b> - Chose this mode to enable encryption only when required by the source database\n <b>prefer</b> - Chose this mode to allow unencrypted connection only if the source database does not support encryption\n <b>require</b> - Chose this mode to always require encryption. If the source database server does not support encryption, connection will fail\n <b>verify-ca</b> - Chose this mode to always require encryption and to verify that the source database server has a valid SSL certificate\n <b>verify-full</b> - This is the most secure mode. Chose this mode to always require encryption and to verify the identity of the source database server\n See more information - <a href=\"https://jdbc.postgresql.org/documentation/head/ssl-client.html\"> in the docs</a>.",
|
||||
"type": "object",
|
||||
"order": 7,
|
||||
"oneOf": [
|
||||
{
|
||||
"title": "disable",
|
||||
"additionalProperties": false,
|
||||
"description": "Disable SSL.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "disable",
|
||||
"enum": ["disable"],
|
||||
"default": "disable",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "allow",
|
||||
"additionalProperties": false,
|
||||
"description": "Allow SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "allow",
|
||||
"enum": ["allow"],
|
||||
"default": "allow",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "prefer",
|
||||
"additionalProperties": false,
|
||||
"description": "Prefer SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "prefer",
|
||||
"enum": ["prefer"],
|
||||
"default": "prefer",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "require",
|
||||
"additionalProperties": false,
|
||||
"description": "Require SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "require",
|
||||
"enum": ["require"],
|
||||
"default": "require",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "verify-ca",
|
||||
"additionalProperties": false,
|
||||
"description": "Verify-ca SSL mode.",
|
||||
"required": ["mode", "ca_certificate"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "verify-ca",
|
||||
"enum": ["verify-ca"],
|
||||
"default": "verify-ca",
|
||||
"order": 0
|
||||
},
|
||||
"ca_certificate": {
|
||||
"type": "string",
|
||||
"title": "CA certificate",
|
||||
"description": "CA certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 1
|
||||
},
|
||||
"client_key_password": {
|
||||
"type": "string",
|
||||
"title": "Client key password (Optional)",
|
||||
"description": "Password for keystorage. This field is optional. If you do not add it - the password will be generated automatically.",
|
||||
"airbyte_secret": true,
|
||||
"order": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "verify-full",
|
||||
"additionalProperties": false,
|
||||
"description": "Verify-full SSL mode.",
|
||||
"required": [
|
||||
"mode",
|
||||
"ca_certificate",
|
||||
"client_certificate",
|
||||
"client_key"
|
||||
],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "verify-full",
|
||||
"enum": ["verify-full"],
|
||||
"default": "verify-full",
|
||||
"order": 0
|
||||
},
|
||||
"ca_certificate": {
|
||||
"type": "string",
|
||||
"title": "CA certificate",
|
||||
"description": "CA certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 1
|
||||
},
|
||||
"client_certificate": {
|
||||
"type": "string",
|
||||
"title": "Client certificate",
|
||||
"description": "Client certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 2
|
||||
},
|
||||
"client_key": {
|
||||
"type": "string",
|
||||
"title": "Client key",
|
||||
"description": "Client key",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 3
|
||||
},
|
||||
"client_key_password": {
|
||||
"type": "string",
|
||||
"title": "Client key password (Optional)",
|
||||
"description": "Password for keystorage. This field is optional. If you do not add it - the password will be generated automatically.",
|
||||
"airbyte_secret": true,
|
||||
"order": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"replication_method": {
|
||||
"type": "object",
|
||||
"title": "Replication Method",
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
|
||||
*/
|
||||
|
||||
package io.airbyte.integrations.io.airbyte.integration_tests.sources;
|
||||
|
||||
import static io.airbyte.db.PostgresUtils.getCertificate;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.airbyte.commons.json.Jsons;
|
||||
import io.airbyte.db.Database;
|
||||
import io.airbyte.db.PostgresUtils;
|
||||
import io.airbyte.db.factory.DSLContextFactory;
|
||||
import io.airbyte.db.factory.DatabaseDriver;
|
||||
import io.airbyte.integrations.base.ssh.SshHelpers;
|
||||
import io.airbyte.integrations.standardtest.source.SourceAcceptanceTest;
|
||||
import io.airbyte.integrations.standardtest.source.TestDestinationEnv;
|
||||
import io.airbyte.protocol.models.CatalogHelpers;
|
||||
import io.airbyte.protocol.models.ConfiguredAirbyteCatalog;
|
||||
import io.airbyte.protocol.models.ConfiguredAirbyteStream;
|
||||
import io.airbyte.protocol.models.ConnectorSpecification;
|
||||
import io.airbyte.protocol.models.DestinationSyncMode;
|
||||
import io.airbyte.protocol.models.Field;
|
||||
import io.airbyte.protocol.models.JsonSchemaType;
|
||||
import io.airbyte.protocol.models.SyncMode;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
public abstract class AbstractPostgresSourceSSLCertificateAcceptanceTest extends SourceAcceptanceTest {
|
||||
|
||||
private static final String STREAM_NAME = "public.id_and_name";
|
||||
private static final String STREAM_NAME2 = "public.starships";
|
||||
private static final String STREAM_NAME_MATERIALIZED_VIEW = "public.testview";
|
||||
|
||||
private PostgreSQLContainer<?> container;
|
||||
private JsonNode config;
|
||||
protected static final String PASSWORD = "Passw0rd";
|
||||
protected static PostgresUtils.Certificate certs;
|
||||
|
||||
@Override
|
||||
protected void setupEnvironment(final TestDestinationEnv environment) throws Exception {
|
||||
container = new PostgreSQLContainer<>(DockerImageName.parse("postgres:bullseye")
|
||||
.asCompatibleSubstituteFor("postgres"));
|
||||
container.start();
|
||||
certs = getCertificate(container);
|
||||
final JsonNode replicationMethod = Jsons.jsonNode(ImmutableMap.builder()
|
||||
.put("method", "Standard")
|
||||
.build());
|
||||
config = Jsons.jsonNode(ImmutableMap.builder()
|
||||
.put("host", container.getHost())
|
||||
.put("port", container.getFirstMappedPort())
|
||||
.put("database", container.getDatabaseName())
|
||||
.put("schemas", Jsons.jsonNode(List.of("public")))
|
||||
.put("username", container.getUsername())
|
||||
.put("password", container.getPassword())
|
||||
.put("ssl", true)
|
||||
.put("replication_method", replicationMethod)
|
||||
.put("ssl_mode", getCertificateConfiguration())
|
||||
.build());
|
||||
|
||||
try (final DSLContext dslContext = DSLContextFactory.create(
|
||||
config.get("username").asText(),
|
||||
config.get("password").asText(),
|
||||
DatabaseDriver.POSTGRESQL.getDriverClassName(),
|
||||
String.format(DatabaseDriver.POSTGRESQL.getUrlFormatString(),
|
||||
config.get("host").asText(),
|
||||
config.get("port").asInt(),
|
||||
config.get("database").asText()),
|
||||
SQLDialect.POSTGRES)) {
|
||||
final Database database = new Database(dslContext);
|
||||
|
||||
database.query(ctx -> {
|
||||
ctx.fetch("CREATE TABLE id_and_name(id INTEGER, name VARCHAR(200));");
|
||||
ctx.fetch("INSERT INTO id_and_name (id, name) VALUES (1,'picard'), (2, 'crusher'), (3, 'vash');");
|
||||
ctx.fetch("CREATE TABLE starships(id INTEGER, name VARCHAR(200));");
|
||||
ctx.fetch("INSERT INTO starships (id, name) VALUES (1,'enterprise-d'), (2, 'defiant'), (3, 'yamato');");
|
||||
ctx.fetch("CREATE MATERIALIZED VIEW testview AS select * from id_and_name where id = '2';");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public abstract ImmutableMap getCertificateConfiguration();
|
||||
|
||||
@Override
|
||||
protected void tearDown(final TestDestinationEnv testEnv) {
|
||||
container.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getImageName() {
|
||||
return "airbyte/source-postgres:dev";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectorSpecification getSpec() throws Exception {
|
||||
return SshHelpers.getSpecAndInjectSsh();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonNode getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConfiguredAirbyteCatalog getConfiguredCatalog() {
|
||||
return new ConfiguredAirbyteCatalog().withStreams(Lists.newArrayList(
|
||||
new ConfiguredAirbyteStream()
|
||||
.withSyncMode(SyncMode.INCREMENTAL)
|
||||
.withCursorField(Lists.newArrayList("id"))
|
||||
.withDestinationSyncMode(DestinationSyncMode.APPEND)
|
||||
.withStream(CatalogHelpers.createAirbyteStream(
|
||||
STREAM_NAME,
|
||||
Field.of("id", JsonSchemaType.NUMBER),
|
||||
Field.of("name", JsonSchemaType.STRING))
|
||||
.withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL))),
|
||||
new ConfiguredAirbyteStream()
|
||||
.withSyncMode(SyncMode.INCREMENTAL)
|
||||
.withCursorField(Lists.newArrayList("id"))
|
||||
.withDestinationSyncMode(DestinationSyncMode.APPEND)
|
||||
.withStream(CatalogHelpers.createAirbyteStream(
|
||||
STREAM_NAME2,
|
||||
Field.of("id", JsonSchemaType.NUMBER),
|
||||
Field.of("name", JsonSchemaType.STRING))
|
||||
.withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL))),
|
||||
new ConfiguredAirbyteStream()
|
||||
.withSyncMode(SyncMode.INCREMENTAL)
|
||||
.withCursorField(Lists.newArrayList("id"))
|
||||
.withDestinationSyncMode(DestinationSyncMode.APPEND)
|
||||
.withStream(CatalogHelpers.createAirbyteStream(
|
||||
STREAM_NAME_MATERIALIZED_VIEW,
|
||||
Field.of("id", JsonSchemaType.NUMBER),
|
||||
Field.of("name", JsonSchemaType.STRING))
|
||||
.withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH, SyncMode.INCREMENTAL)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonNode getState() {
|
||||
return Jsons.jsonNode(new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsPerStream() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
|
||||
*/
|
||||
|
||||
package io.airbyte.integrations.io.airbyte.integration_tests.sources;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public class PostgresSourceSSLCaCertificateAcceptanceTest extends AbstractPostgresSourceSSLCertificateAcceptanceTest {
|
||||
|
||||
@Override
|
||||
public ImmutableMap getCertificateConfiguration() {
|
||||
return ImmutableMap.builder()
|
||||
.put("mode", "verify-ca")
|
||||
.put("ca_certificate", certs.getCaCertificate())
|
||||
.put("client_key_password", PASSWORD)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
|
||||
*/
|
||||
|
||||
package io.airbyte.integrations.io.airbyte.integration_tests.sources;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public class PostgresSourceSSLFullCertificateAcceptanceTest extends AbstractPostgresSourceSSLCertificateAcceptanceTest {
|
||||
|
||||
@Override
|
||||
public ImmutableMap getCertificateConfiguration() {
|
||||
return ImmutableMap.builder()
|
||||
.put("mode", "verify-full")
|
||||
.put("ca_certificate", certs.getCaCertificate())
|
||||
.put("client_certificate", certs.getClientCertificate())
|
||||
.put("client_key", certs.getClientKey())
|
||||
.put("client_key_password", PASSWORD)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,12 +4,15 @@
|
||||
|
||||
package io.airbyte.integrations.io.airbyte.integration_tests.sources;
|
||||
|
||||
import static io.airbyte.db.PostgresUtils.getCertificate;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.airbyte.commons.json.Jsons;
|
||||
import io.airbyte.commons.resources.MoreResources;
|
||||
import io.airbyte.db.Database;
|
||||
import io.airbyte.db.PostgresUtils;
|
||||
import io.airbyte.db.factory.DSLContextFactory;
|
||||
import io.airbyte.db.factory.DatabaseDriver;
|
||||
import io.airbyte.integrations.base.ssh.SshHelpers;
|
||||
@@ -44,11 +47,15 @@ public class PostgresSourceStrictEncryptAcceptanceTest extends SourceAcceptanceT
|
||||
private PostgreSQLContainer<?> container;
|
||||
private JsonNode config;
|
||||
|
||||
protected static final String PASSWORD = "Passw0rd";
|
||||
protected static PostgresUtils.Certificate certs;
|
||||
|
||||
@Override
|
||||
protected void setupEnvironment(final TestDestinationEnv environment) throws Exception {
|
||||
container = new PostgreSQLContainer<>(DockerImageName.parse("marcosmarxm/postgres-ssl:dev").asCompatibleSubstituteFor("postgres"))
|
||||
.withCommand("postgres -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key");
|
||||
container = new PostgreSQLContainer<>(DockerImageName.parse("postgres:bullseye")
|
||||
.asCompatibleSubstituteFor("postgres"));
|
||||
container.start();
|
||||
certs = getCertificate(container);
|
||||
final JsonNode replicationMethod = Jsons.jsonNode(ImmutableMap.builder()
|
||||
.put("method", "Standard")
|
||||
.build());
|
||||
@@ -59,6 +66,13 @@ public class PostgresSourceStrictEncryptAcceptanceTest extends SourceAcceptanceT
|
||||
.put("username", container.getUsername())
|
||||
.put("password", container.getPassword())
|
||||
.put("replication_method", replicationMethod)
|
||||
.put("ssl_mode", ImmutableMap.builder()
|
||||
.put("mode", "verify-full")
|
||||
.put("ca_certificate", certs.getCaCertificate())
|
||||
.put("client_certificate", certs.getClientCertificate())
|
||||
.put("client_key", certs.getClientKey())
|
||||
.put("client_key_password", PASSWORD)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
try (final DSLContext dslContext = DSLContextFactory.create(
|
||||
|
||||
@@ -147,6 +147,7 @@ class PostgresSourceSSLTest {
|
||||
.put("username", psqlDb.getUsername())
|
||||
.put("password", psqlDb.getPassword())
|
||||
.put("ssl", true)
|
||||
.put("ssl_mode", ImmutableMap.builder().put("mode", "require").build())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,140 @@
|
||||
"type": "string",
|
||||
"order": 6
|
||||
},
|
||||
"ssl_mode": {
|
||||
"title": "SSL modes",
|
||||
"description": "SSL connection modes. \n <b>disable</b> - Chose this mode to disable encryption of communication between Airbyte and source database\n <b>allow</b> - Chose this mode to enable encryption only when required by the source database\n <b>prefer</b> - Chose this mode to allow unencrypted connection only if the source database does not support encryption\n <b>require</b> - Chose this mode to always require encryption. If the source database server does not support encryption, connection will fail\n <b>verify-ca</b> - Chose this mode to always require encryption and to verify that the source database server has a valid SSL certificate\n <b>verify-full</b> - This is the most secure mode. Chose this mode to always require encryption and to verify the identity of the source database server\n See more information - <a href=\"https://jdbc.postgresql.org/documentation/head/ssl-client.html\"> in the docs</a>.",
|
||||
"type": "object",
|
||||
"order": 7,
|
||||
"oneOf": [
|
||||
{
|
||||
"title": "allow",
|
||||
"additionalProperties": false,
|
||||
"description": "Allow SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "allow",
|
||||
"enum": ["allow"],
|
||||
"default": "allow",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "prefer",
|
||||
"additionalProperties": false,
|
||||
"description": "Prefer SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "prefer",
|
||||
"enum": ["prefer"],
|
||||
"default": "prefer",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "require",
|
||||
"additionalProperties": false,
|
||||
"description": "Require SSL mode.",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "require",
|
||||
"enum": ["require"],
|
||||
"default": "require",
|
||||
"order": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "verify-ca",
|
||||
"additionalProperties": false,
|
||||
"description": "Verify-ca SSL mode.",
|
||||
"required": ["mode", "ca_certificate"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "verify-ca",
|
||||
"enum": ["verify-ca"],
|
||||
"default": "verify-ca",
|
||||
"order": 0
|
||||
},
|
||||
"ca_certificate": {
|
||||
"type": "string",
|
||||
"title": "CA certificate",
|
||||
"description": "CA certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 1
|
||||
},
|
||||
"client_key_password": {
|
||||
"type": "string",
|
||||
"title": "Client key password (Optional)",
|
||||
"description": "Password for keystorage. This field is optional. If you do not add it - the password will be generated automatically.",
|
||||
"airbyte_secret": true,
|
||||
"order": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "verify-full",
|
||||
"additionalProperties": false,
|
||||
"description": "Verify-full SSL mode.",
|
||||
"required": [
|
||||
"mode",
|
||||
"ca_certificate",
|
||||
"client_certificate",
|
||||
"client_key"
|
||||
],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"const": "verify-full",
|
||||
"enum": ["verify-full"],
|
||||
"default": "verify-full",
|
||||
"order": 0
|
||||
},
|
||||
"ca_certificate": {
|
||||
"type": "string",
|
||||
"title": "CA certificate",
|
||||
"description": "CA certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 1
|
||||
},
|
||||
"client_certificate": {
|
||||
"type": "string",
|
||||
"title": "Client certificate",
|
||||
"description": "Client certificate",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 2
|
||||
},
|
||||
"client_key": {
|
||||
"type": "string",
|
||||
"title": "Client key",
|
||||
"description": "Client key",
|
||||
"airbyte_secret": true,
|
||||
"multiline": true,
|
||||
"order": 3
|
||||
},
|
||||
"client_key_password": {
|
||||
"type": "string",
|
||||
"title": "Client key password (Optional)",
|
||||
"description": "Password for keystorage. This field is optional. If you do not add it - the password will be generated automatically.",
|
||||
"airbyte_secret": true,
|
||||
"order": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"replication_method": {
|
||||
"type": "object",
|
||||
"title": "Replication Method",
|
||||
|
||||
@@ -325,70 +325,71 @@ One optimization on the Airbyte side is to break one large and long sync into mu
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Date | Pull Request | Subject |
|
||||
|:--------|:-----------|:---------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0.4.33 | 2022-07-14 | [14586](https://github.com/airbytehq/airbyte/pull/14586) | Validate source JDBC url parameters |
|
||||
| 0.4.32 | 2022-07-07 | [14694](https://github.com/airbytehq/airbyte/pull/14694) | Force to produce LEGACY state if the use stream capable feature flag is set to false |
|
||||
| 0.4.31 | 2022-07-07 | [14447](https://github.com/airbytehq/airbyte/pull/14447) | Under CDC mode, retrieve only those tables included in the publications |
|
||||
| 0.4.30 | 2022-06-30 | [14251](https://github.com/airbytehq/airbyte/pull/14251) | Use more simple and comprehensive query to get selectable tables |
|
||||
| 0.4.29 | 2022-06-29 | [14265](https://github.com/airbytehq/airbyte/pull/14265) | Upgrade postgresql JDBC version to 42.3.5 |
|
||||
| 0.4.28 | 2022-06-23 | [14077](https://github.com/airbytehq/airbyte/pull/14077) | Use the new state management |
|
||||
| 0.4.26 | 2022-06-17 | [13864](https://github.com/airbytehq/airbyte/pull/13864) | Updated stacktrace format for any trace message errors |
|
||||
| 0.4.25 | 2022-06-15 | [13823](https://github.com/airbytehq/airbyte/pull/13823) | Publish adaptive postgres source that enforces ssl on cloud + Debezium version upgrade to 1.9.2 from 1.4.2 |
|
||||
| 0.4.24 | 2022-06-14 | [13549](https://github.com/airbytehq/airbyte/pull/13549) | Fixed truncated precision if the value of microseconds or seconds is 0 |
|
||||
| 0.4.23 | 2022-06-13 | [13655](https://github.com/airbytehq/airbyte/pull/13745) | Fixed handling datetime cursors when upgrading from older versions of the connector |
|
||||
| 0.4.22 | 2022-06-09 | [13655](https://github.com/airbytehq/airbyte/pull/13655) | Fixed bug with unsupported date-time datatypes during incremental sync |
|
||||
| 0.4.21 | 2022-06-06 | [13435](https://github.com/airbytehq/airbyte/pull/13435) | Adjust JDBC fetch size based on max memory and max row size |
|
||||
| 0.4.20 | 2022-06-02 | [13367](https://github.com/airbytehq/airbyte/pull/13367) | Added convertion hstore to json format |
|
||||
| 0.4.19 | 2022-05-25 | [13166](https://github.com/airbytehq/airbyte/pull/13166) | Added timezone awareness and handle BC dates |
|
||||
| 0.4.18 | 2022-05-25 | [13083](https://github.com/airbytehq/airbyte/pull/13083) | Add support for tsquey type |
|
||||
| 0.4.17 | 2022-05-19 | [13016](https://github.com/airbytehq/airbyte/pull/13016) | CDC modify schema to allow null values |
|
||||
| 0.4.16 | 2022-05-14 | [12840](https://github.com/airbytehq/airbyte/pull/12840) | Added custom JDBC parameters field |
|
||||
| 0.4.15 | 2022-05-13 | [12834](https://github.com/airbytehq/airbyte/pull/12834) | Fix the bug that the connector returns empty catalog for Azure Postgres database |
|
||||
| 0.4.14 | 2022-05-08 | [12689](https://github.com/airbytehq/airbyte/pull/12689) | Add table retrieval according to role-based `SELECT` privilege |
|
||||
| 0.4.13 | 2022-05-05 | [10230](https://github.com/airbytehq/airbyte/pull/10230) | Explicitly set null value for field in json |
|
||||
| 0.4.12 | 2022-04-29 | [12480](https://github.com/airbytehq/airbyte/pull/12480) | Query tables with adaptive fetch size to optimize JDBC memory consumption |
|
||||
| 0.4.11 | 2022-04-11 | [11729](https://github.com/airbytehq/airbyte/pull/11729) | Bump mina-sshd from 2.7.0 to 2.8.0 |
|
||||
| 0.4.10 | 2022-04-08 | [11798](https://github.com/airbytehq/airbyte/pull/11798) | Fixed roles for fetching materialized view processing |
|
||||
| 0.4.8 | 2022-02-21 | [10242](https://github.com/airbytehq/airbyte/pull/10242) | Fixed cursor for old connectors that use non-microsecond format. Now connectors work with both formats |
|
||||
| 0.4.7 | 2022-02-18 | [10242](https://github.com/airbytehq/airbyte/pull/10242) | Updated timestamp transformation with microseconds |
|
||||
| 0.4.6 | 2022-02-14 | [10256](https://github.com/airbytehq/airbyte/pull/10256) | (unpublished) Add `-XX:+ExitOnOutOfMemoryError` JVM option |
|
||||
| 0.4.5 | 2022-02-08 | [10173](https://github.com/airbytehq/airbyte/pull/10173) | Improved discovering tables in case if user does not have permissions to any table |
|
||||
| 0.4.4 | 2022-01-26 | [9807](https://github.com/airbytehq/airbyte/pull/9807) | Update connector fields title/description |
|
||||
| 0.4.3 | 2022-01-24 | [9554](https://github.com/airbytehq/airbyte/pull/9554) | Allow handling of java sql date in CDC |
|
||||
| 0.4.2 | 2022-01-13 | [9360](https://github.com/airbytehq/airbyte/pull/9360) | Added schema selection |
|
||||
| 0.4.1 | 2022-01-05 | [9116](https://github.com/airbytehq/airbyte/pull/9116) | Added materialized views processing |
|
||||
| 0.4.0 | 2021-12-13 | [8726](https://github.com/airbytehq/airbyte/pull/8726) | Support all Postgres types |
|
||||
| 0.3.17 | 2021-12-01 | [8371](https://github.com/airbytehq/airbyte/pull/8371) | Fixed incorrect handling "\n" in ssh key |
|
||||
| 0.3.16 | 2021-11-28 | [7995](https://github.com/airbytehq/airbyte/pull/7995) | Fixed money type with amount > 1000 |
|
||||
| 0.3.15 | 2021-11-26 | [8066](https://github.com/airbytehq/airbyte/pull/8266) | Fixed the case, when Views are not listed during schema discovery |
|
||||
| 0.3.14 | 2021-11-17 | [8010](https://github.com/airbytehq/airbyte/pull/8010) | Added checking of privileges before table internal discovery |
|
||||
| 0.3.13 | 2021-10-26 | [7339](https://github.com/airbytehq/airbyte/pull/7339) | Support or improve support for Interval, Money, Date, various geometric data types, inventory_items, and others |
|
||||
| 0.3.12 | 2021-09-30 | [6585](https://github.com/airbytehq/airbyte/pull/6585) | Improved SSH Tunnel key generation steps |
|
||||
| 0.3.11 | 2021-09-02 | [5742](https://github.com/airbytehq/airbyte/pull/5742) | Add SSH Tunnel support |
|
||||
| 0.3.9 | 2021-08-17 | [5304](https://github.com/airbytehq/airbyte/pull/5304) | Fix CDC OOM issue |
|
||||
| 0.3.8 | 2021-08-13 | [4699](https://github.com/airbytehq/airbyte/pull/4699) | Added json config validator |
|
||||
| 0.3.4 | 2021-06-09 | [3973](https://github.com/airbytehq/airbyte/pull/3973) | Add `AIRBYTE_ENTRYPOINT` for Kubernetes support |
|
||||
| 0.3.3 | 2021-06-08 | [3960](https://github.com/airbytehq/airbyte/pull/3960) | Add method field in specification parameters |
|
||||
| 0.3.2 | 2021-05-26 | [3179](https://github.com/airbytehq/airbyte/pull/3179) | Remove `isCDC` logging |
|
||||
| 0.3.1 | 2021-04-21 | [2878](https://github.com/airbytehq/airbyte/pull/2878) | Set defined cursor for CDC |
|
||||
| 0.3.0 | 2021-04-21 | [2990](https://github.com/airbytehq/airbyte/pull/2990) | Support namespaces |
|
||||
| 0.2.7 | 2021-04-16 | [2923](https://github.com/airbytehq/airbyte/pull/2923) | SSL spec as optional |
|
||||
| 0.2.6 | 2021-04-16 | [2757](https://github.com/airbytehq/airbyte/pull/2757) | Support SSL connection |
|
||||
| 0.2.5 | 2021-04-12 | [2859](https://github.com/airbytehq/airbyte/pull/2859) | CDC bugfix |
|
||||
| 0.2.4 | 2021-04-09 | [2548](https://github.com/airbytehq/airbyte/pull/2548) | Support CDC |
|
||||
| 0.2.3 | 2021-03-28 | [2600](https://github.com/airbytehq/airbyte/pull/2600) | Add NCHAR and NVCHAR support to DB and cursor type casting |
|
||||
| 0.2.2 | 2021-03-26 | [2460](https://github.com/airbytehq/airbyte/pull/2460) | Destination supports destination sync mode |
|
||||
| 0.2.1 | 2021-03-18 | [2488](https://github.com/airbytehq/airbyte/pull/2488) | Sources support primary keys |
|
||||
| 0.2.0 | 2021-03-09 | [2238](https://github.com/airbytehq/airbyte/pull/2238) | Protocol allows future/unknown properties |
|
||||
| 0.1.13 | 2021-02-02 | [1887](https://github.com/airbytehq/airbyte/pull/1887) | Migrate AbstractJdbcSource to use iterators |
|
||||
| 0.1.12 | 2021-01-25 | [1746](https://github.com/airbytehq/airbyte/pull/1746) | Fix NPE in State Decorator |
|
||||
| 0.1.11 | 2021-01-25 | [1765](https://github.com/airbytehq/airbyte/pull/1765) | Add field titles to specification |
|
||||
| 0.1.10 | 2021-01-19 | [1724](https://github.com/airbytehq/airbyte/pull/1724) | Fix JdbcSource handling of tables with same names in different schemas |
|
||||
| 0.1.9 | 2021-01-14 | [1655](https://github.com/airbytehq/airbyte/pull/1655) | Fix JdbcSource OOM |
|
||||
| 0.1.8 | 2021-01-13 | [1588](https://github.com/airbytehq/airbyte/pull/1588) | Handle invalid numeric values in JDBC source |
|
||||
| 0.1.7 | 2021-01-08 | [1307](https://github.com/airbytehq/airbyte/pull/1307) | Migrate Postgres and MySql to use new JdbcSource |
|
||||
| 0.1.6 | 2020-12-09 | [1172](https://github.com/airbytehq/airbyte/pull/1172) | Support incremental sync |
|
||||
| 0.1.5 | 2020-11-30 | [1038](https://github.com/airbytehq/airbyte/pull/1038) | Change JDBC sources to discover more than standard schemas |
|
||||
| 0.1.4 | 2020-11-30 | [1046](https://github.com/airbytehq/airbyte/pull/1046) | Add connectors using an index YAML file |
|
||||
| Version | Date | Pull Request | Subject |
|
||||
|:--------|:-----------|:---------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------|
|
||||
| 0.4.34 | 2022-07-17 | [13840](https://github.com/airbytehq/airbyte/pull/13840) | Added the ability to connect using different SSL modes and SSL certificates. |
|
||||
| 0.4.33 | 2022-07-14 | [14586](https://github.com/airbytehq/airbyte/pull/14586) | Validate source JDBC url parameters |
|
||||
| 0.4.32 | 2022-07-07 | [14694](https://github.com/airbytehq/airbyte/pull/14694) | Force to produce LEGACY state if the use stream capable feature flag is set to false |
|
||||
| 0.4.31 | 2022-07-07 | [14447](https://github.com/airbytehq/airbyte/pull/14447) | Under CDC mode, retrieve only those tables included in the publications |
|
||||
| 0.4.30 | 2022-06-30 | [14251](https://github.com/airbytehq/airbyte/pull/14251) | Use more simple and comprehensive query to get selectable tables |
|
||||
| 0.4.29 | 2022-06-29 | [14265](https://github.com/airbytehq/airbyte/pull/14265) | Upgrade postgresql JDBC version to 42.3.5 |
|
||||
| 0.4.28 | 2022-06-23 | [14077](https://github.com/airbytehq/airbyte/pull/14077) | Use the new state management |
|
||||
| 0.4.26 | 2022-06-17 | [13864](https://github.com/airbytehq/airbyte/pull/13864) | Updated stacktrace format for any trace message errors |
|
||||
| 0.4.25 | 2022-06-15 | [13823](https://github.com/airbytehq/airbyte/pull/13823) | Publish adaptive postgres source that enforces ssl on cloud + Debezium version upgrade to 1.9.2 from 1.4.2 |
|
||||
| 0.4.24 | 2022-06-14 | [13549](https://github.com/airbytehq/airbyte/pull/13549) | Fixed truncated precision if the value of microseconds or seconds is 0 |
|
||||
| 0.4.23 | 2022-06-13 | [13655](https://github.com/airbytehq/airbyte/pull/13745) | Fixed handling datetime cursors when upgrading from older versions of the connector |
|
||||
| 0.4.22 | 2022-06-09 | [13655](https://github.com/airbytehq/airbyte/pull/13655) | Fixed bug with unsupported date-time datatypes during incremental sync |
|
||||
| 0.4.21 | 2022-06-06 | [13435](https://github.com/airbytehq/airbyte/pull/13435) | Adjust JDBC fetch size based on max memory and max row size |
|
||||
| 0.4.20 | 2022-06-02 | [13367](https://github.com/airbytehq/airbyte/pull/13367) | Added convertion hstore to json format |
|
||||
| 0.4.19 | 2022-05-25 | [13166](https://github.com/airbytehq/airbyte/pull/13166) | Added timezone awareness and handle BC dates |
|
||||
| 0.4.18 | 2022-05-25 | [13083](https://github.com/airbytehq/airbyte/pull/13083) | Add support for tsquey type |
|
||||
| 0.4.17 | 2022-05-19 | [13016](https://github.com/airbytehq/airbyte/pull/13016) | CDC modify schema to allow null values |
|
||||
| 0.4.16 | 2022-05-14 | [12840](https://github.com/airbytehq/airbyte/pull/12840) | Added custom JDBC parameters field |
|
||||
| 0.4.15 | 2022-05-13 | [12834](https://github.com/airbytehq/airbyte/pull/12834) | Fix the bug that the connector returns empty catalog for Azure Postgres database |
|
||||
| 0.4.14 | 2022-05-08 | [12689](https://github.com/airbytehq/airbyte/pull/12689) | Add table retrieval according to role-based `SELECT` privilege |
|
||||
| 0.4.13 | 2022-05-05 | [10230](https://github.com/airbytehq/airbyte/pull/10230) | Explicitly set null value for field in json |
|
||||
| 0.4.12 | 2022-04-29 | [12480](https://github.com/airbytehq/airbyte/pull/12480) | Query tables with adaptive fetch size to optimize JDBC memory consumption |
|
||||
| 0.4.11 | 2022-04-11 | [11729](https://github.com/airbytehq/airbyte/pull/11729) | Bump mina-sshd from 2.7.0 to 2.8.0 |
|
||||
| 0.4.10 | 2022-04-08 | [11798](https://github.com/airbytehq/airbyte/pull/11798) | Fixed roles for fetching materialized view processing |
|
||||
| 0.4.8 | 2022-02-21 | [10242](https://github.com/airbytehq/airbyte/pull/10242) | Fixed cursor for old connectors that use non-microsecond format. Now connectors work with both formats |
|
||||
| 0.4.7 | 2022-02-18 | [10242](https://github.com/airbytehq/airbyte/pull/10242) | Updated timestamp transformation with microseconds |
|
||||
| 0.4.6 | 2022-02-14 | [10256](https://github.com/airbytehq/airbyte/pull/10256) | (unpublished) Add `-XX:+ExitOnOutOfMemoryError` JVM option |
|
||||
| 0.4.5 | 2022-02-08 | [10173](https://github.com/airbytehq/airbyte/pull/10173) | Improved discovering tables in case if user does not have permissions to any table |
|
||||
| 0.4.4 | 2022-01-26 | [9807](https://github.com/airbytehq/airbyte/pull/9807) | Update connector fields title/description |
|
||||
| 0.4.3 | 2022-01-24 | [9554](https://github.com/airbytehq/airbyte/pull/9554) | Allow handling of java sql date in CDC |
|
||||
| 0.4.2 | 2022-01-13 | [9360](https://github.com/airbytehq/airbyte/pull/9360) | Added schema selection |
|
||||
| 0.4.1 | 2022-01-05 | [9116](https://github.com/airbytehq/airbyte/pull/9116) | Added materialized views processing |
|
||||
| 0.4.0 | 2021-12-13 | [8726](https://github.com/airbytehq/airbyte/pull/8726) | Support all Postgres types |
|
||||
| 0.3.17 | 2021-12-01 | [8371](https://github.com/airbytehq/airbyte/pull/8371) | Fixed incorrect handling "\n" in ssh key |
|
||||
| 0.3.16 | 2021-11-28 | [7995](https://github.com/airbytehq/airbyte/pull/7995) | Fixed money type with amount > 1000 |
|
||||
| 0.3.15 | 2021-11-26 | [8066](https://github.com/airbytehq/airbyte/pull/8266) | Fixed the case, when Views are not listed during schema discovery |
|
||||
| 0.3.14 | 2021-11-17 | [8010](https://github.com/airbytehq/airbyte/pull/8010) | Added checking of privileges before table internal discovery |
|
||||
| 0.3.13 | 2021-10-26 | [7339](https://github.com/airbytehq/airbyte/pull/7339) | Support or improve support for Interval, Money, Date, various geometric data types, inventory_items, and others |
|
||||
| 0.3.12 | 2021-09-30 | [6585](https://github.com/airbytehq/airbyte/pull/6585) | Improved SSH Tunnel key generation steps |
|
||||
| 0.3.11 | 2021-09-02 | [5742](https://github.com/airbytehq/airbyte/pull/5742) | Add SSH Tunnel support |
|
||||
| 0.3.9 | 2021-08-17 | [5304](https://github.com/airbytehq/airbyte/pull/5304) | Fix CDC OOM issue |
|
||||
| 0.3.8 | 2021-08-13 | [4699](https://github.com/airbytehq/airbyte/pull/4699) | Added json config validator |
|
||||
| 0.3.4 | 2021-06-09 | [3973](https://github.com/airbytehq/airbyte/pull/3973) | Add `AIRBYTE_ENTRYPOINT` for Kubernetes support |
|
||||
| 0.3.3 | 2021-06-08 | [3960](https://github.com/airbytehq/airbyte/pull/3960) | Add method field in specification parameters |
|
||||
| 0.3.2 | 2021-05-26 | [3179](https://github.com/airbytehq/airbyte/pull/3179) | Remove `isCDC` logging |
|
||||
| 0.3.1 | 2021-04-21 | [2878](https://github.com/airbytehq/airbyte/pull/2878) | Set defined cursor for CDC |
|
||||
| 0.3.0 | 2021-04-21 | [2990](https://github.com/airbytehq/airbyte/pull/2990) | Support namespaces |
|
||||
| 0.2.7 | 2021-04-16 | [2923](https://github.com/airbytehq/airbyte/pull/2923) | SSL spec as optional |
|
||||
| 0.2.6 | 2021-04-16 | [2757](https://github.com/airbytehq/airbyte/pull/2757) | Support SSL connection |
|
||||
| 0.2.5 | 2021-04-12 | [2859](https://github.com/airbytehq/airbyte/pull/2859) | CDC bugfix |
|
||||
| 0.2.4 | 2021-04-09 | [2548](https://github.com/airbytehq/airbyte/pull/2548) | Support CDC |
|
||||
| 0.2.3 | 2021-03-28 | [2600](https://github.com/airbytehq/airbyte/pull/2600) | Add NCHAR and NVCHAR support to DB and cursor type casting |
|
||||
| 0.2.2 | 2021-03-26 | [2460](https://github.com/airbytehq/airbyte/pull/2460) | Destination supports destination sync mode |
|
||||
| 0.2.1 | 2021-03-18 | [2488](https://github.com/airbytehq/airbyte/pull/2488) | Sources support primary keys |
|
||||
| 0.2.0 | 2021-03-09 | [2238](https://github.com/airbytehq/airbyte/pull/2238) | Protocol allows future/unknown properties |
|
||||
| 0.1.13 | 2021-02-02 | [1887](https://github.com/airbytehq/airbyte/pull/1887) | Migrate AbstractJdbcSource to use iterators |
|
||||
| 0.1.12 | 2021-01-25 | [1746](https://github.com/airbytehq/airbyte/pull/1746) | Fix NPE in State Decorator |
|
||||
| 0.1.11 | 2021-01-25 | [1765](https://github.com/airbytehq/airbyte/pull/1765) | Add field titles to specification |
|
||||
| 0.1.10 | 2021-01-19 | [1724](https://github.com/airbytehq/airbyte/pull/1724) | Fix JdbcSource handling of tables with same names in different schemas |
|
||||
| 0.1.9 | 2021-01-14 | [1655](https://github.com/airbytehq/airbyte/pull/1655) | Fix JdbcSource OOM |
|
||||
| 0.1.8 | 2021-01-13 | [1588](https://github.com/airbytehq/airbyte/pull/1588) | Handle invalid numeric values in JDBC source |
|
||||
| 0.1.7 | 2021-01-08 | [1307](https://github.com/airbytehq/airbyte/pull/1307) | Migrate Postgres and MySql to use new JdbcSource |
|
||||
| 0.1.6 | 2020-12-09 | [1172](https://github.com/airbytehq/airbyte/pull/1172) | Support incremental sync |
|
||||
| 0.1.5 | 2020-11-30 | [1038](https://github.com/airbytehq/airbyte/pull/1038) | Change JDBC sources to discover more than standard schemas |
|
||||
| 0.1.4 | 2020-11-30 | [1046](https://github.com/airbytehq/airbyte/pull/1046) | Add connectors using an index YAML file |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user