Skip to content

Commit 2b0d0bd

Browse files
VitaliiMaltsevvmaltsev
andauthored
Source MongoDB fetch authorized collections only (#9238)
* fix for jdk 17 * Source MongoDB show authorized collections * add javadoc * fixed checkstyle * add CHANGELOG * fix checkstyle * refactoring * bump version anf fix checkstyle Co-authored-by: vmaltsev <[email protected]>
1 parent ecfc9e1 commit 2b0d0bd

File tree

9 files changed

+47
-25
lines changed

9 files changed

+47
-25
lines changed

airbyte-config/init/src/main/resources/config/STANDARD_SOURCE_DEFINITION/b2e713cd-cc36-4c0a-b5bd-b47cb8a0561e.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"sourceDefinitionId": "b2e713cd-cc36-4c0a-b5bd-b47cb8a0561e",
33
"name": "MongoDb",
44
"dockerRepository": "airbyte/source-mongodb-v2",
5-
"dockerImageTag": "0.1.10",
5+
"dockerImageTag": "0.1.11",
66
"documentationUrl": "https://docs.airbyte.io/integrations/sources/mongodb-v2",
77
"icon": "mongodb.svg"
88
}

airbyte-config/init/src/main/resources/seed/source_definitions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@
426426
- name: MongoDb
427427
sourceDefinitionId: b2e713cd-cc36-4c0a-b5bd-b47cb8a0561e
428428
dockerRepository: airbyte/source-mongodb-v2
429-
dockerImageTag: 0.1.10
429+
dockerImageTag: 0.1.11
430430
documentationUrl: https://docs.airbyte.io/integrations/sources/mongodb-v2
431431
icon: mongodb.svg
432432
sourceType: database

airbyte-integrations/connectors/destination-snowflake/src/main/java/io/airbyte/integrations/destination/snowflake/SnowflakeInternalStagingConsumerFactory.java

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import io.airbyte.protocol.models.ConfiguredAirbyteCatalog;
2323
import io.airbyte.protocol.models.ConfiguredAirbyteStream;
2424
import io.airbyte.protocol.models.DestinationSyncMode;
25-
26-
import java.sql.SQLException;
2725
import java.util.ArrayList;
2826
import java.util.List;
2927
import java.util.Map;
@@ -51,11 +49,11 @@ public class SnowflakeInternalStagingConsumerFactory {
5149
private final String CURRENT_SYNC_PATH = UUID.randomUUID().toString();
5250

5351
public AirbyteMessageConsumer create(final Consumer<AirbyteMessage> outputRecordCollector,
54-
final JdbcDatabase database,
55-
final SnowflakeStagingSqlOperations sqlOperations,
56-
final SnowflakeSQLNameTransformer namingResolver,
57-
final JsonNode config,
58-
final ConfiguredAirbyteCatalog catalog) {
52+
final JdbcDatabase database,
53+
final SnowflakeStagingSqlOperations sqlOperations,
54+
final SnowflakeSQLNameTransformer namingResolver,
55+
final JsonNode config,
56+
final ConfiguredAirbyteCatalog catalog) {
5957
final List<WriteConfig> writeConfigs = createWriteConfigs(namingResolver, config, catalog);
6058

6159
return new BufferedStreamConsumer(
@@ -135,10 +133,10 @@ private static AirbyteStreamNameNamespacePair toNameNamespacePair(final WriteCon
135133
}
136134

137135
private RecordWriter recordWriterFunction(final JdbcDatabase database,
138-
final SqlOperations snowflakeSqlOperations,
139-
final List<WriteConfig> writeConfigs,
140-
final ConfiguredAirbyteCatalog catalog,
141-
final SnowflakeSQLNameTransformer namingResolver) {
136+
final SqlOperations snowflakeSqlOperations,
137+
final List<WriteConfig> writeConfigs,
138+
final ConfiguredAirbyteCatalog catalog,
139+
final SnowflakeSQLNameTransformer namingResolver) {
142140
final Map<AirbyteStreamNameNamespacePair, WriteConfig> pairToWriteConfig =
143141
writeConfigs.stream()
144142
.collect(Collectors.toUnmodifiableMap(
@@ -160,9 +158,9 @@ private RecordWriter recordWriterFunction(final JdbcDatabase database,
160158
}
161159

162160
private OnCloseFunction onCloseFunction(final JdbcDatabase database,
163-
final SnowflakeStagingSqlOperations sqlOperations,
164-
final List<WriteConfig> writeConfigs,
165-
final SnowflakeSQLNameTransformer namingResolver) {
161+
final SnowflakeStagingSqlOperations sqlOperations,
162+
final List<WriteConfig> writeConfigs,
163+
final SnowflakeSQLNameTransformer namingResolver) {
166164
return (hasFailed) -> {
167165
if (!hasFailed) {
168166
final List<String> queryList = new ArrayList<>();
@@ -176,14 +174,14 @@ private OnCloseFunction onCloseFunction(final JdbcDatabase database,
176174

177175
final String path = namingResolver.getStagingPath(schemaName, dstTableName, CURRENT_SYNC_PATH);
178176
LOGGER.info("Uploading data from stage: stream {}. schema {}, tmp table {}, stage path {}", writeConfig.getStreamName(), schemaName,
179-
srcTableName,
180-
path);
177+
srcTableName,
178+
path);
181179
try {
182180
sqlOperations.copyIntoTmpTableFromStage(database, path, srcTableName, schemaName);
183-
} catch (SQLException e){
181+
} catch (Exception e) {
184182
sqlOperations.cleanUpStage(database, path);
185183
LOGGER.info("Cleaning stage path {}", path);
186-
throw new RuntimeException("Failed to upload data from stage "+ path, e);
184+
throw new RuntimeException("Failed to upload data from stage " + path, e);
187185
}
188186

189187
sqlOperations.createTableIfNotExists(database, schemaName, dstTableName);

airbyte-integrations/connectors/destination-snowflake/src/main/java/io/airbyte/integrations/destination/snowflake/SnowflakeSQLNameTransformer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public String getStageName(String schemaName, String outputTableName) {
1818
}
1919

2020
public String getStagingPath(String schemaName, String tableName, String currentSyncPath) {
21-
return (getStageName(schemaName,tableName)+"/staged/"+currentSyncPath).toUpperCase();
21+
return (getStageName(schemaName, tableName) + "/staged/" + currentSyncPath).toUpperCase();
2222
}
23+
2324
}

airbyte-integrations/connectors/destination-snowflake/src/main/java/io/airbyte/integrations/destination/snowflake/SnowflakeStagingSqlOperations.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,5 @@ public void cleanUpStage(JdbcDatabase database, String path) throws SQLException
8585
public boolean isSchemaExists(JdbcDatabase database, String outputSchema) throws Exception {
8686
return database.query(SHOW_SCHEMAS).map(schemas -> schemas.get(NAME).asText()).anyMatch(outputSchema::equalsIgnoreCase);
8787
}
88+
8889
}

airbyte-integrations/connectors/source-mongodb-v2/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ ENV APPLICATION source-mongodb-v2
1616

1717
COPY --from=build /airbyte /airbyte
1818

19-
LABEL io.airbyte.version=0.1.10
19+
LABEL io.airbyte.version=0.1.11
2020
LABEL io.airbyte.name=airbyte/source-mongodb-v2

airbyte-integrations/connectors/source-mongodb-v2/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies {
1616
implementation files(project(':airbyte-integrations:bases:base-java').airbyteDocker.outputs)
1717
implementation project(':airbyte-integrations:connectors:source-relational-db')
1818

19-
implementation 'org.mongodb:mongodb-driver-sync:4.3.0'
19+
implementation 'org.mongodb:mongodb-driver-sync:4.4.0'
2020

2121
testImplementation 'org.testcontainers:mongodb:1.15.3'
2222

airbyte-integrations/connectors/source-mongodb-v2/src/main/java/io.airbyte.integrations.source.mongodb/MongoDbSource.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public List<CheckedConsumer<MongoDatabase, Exception>> getCheckOperations(final
9090
throws Exception {
9191
final List<CheckedConsumer<MongoDatabase, Exception>> checkList = new ArrayList<>();
9292
checkList.add(database -> {
93-
if (database.getCollectionNames().isEmpty()) {
93+
if (getAuthorizedCollections(database).isEmpty()) {
9494
throw new Exception("Unable to execute any operation on the source!");
9595
} else {
9696
LOGGER.info("The source passed the basic operation test!");
@@ -114,7 +114,7 @@ protected List<TableInfo<CommonField<BsonType>>> discoverInternal(final MongoDat
114114
throws Exception {
115115
final List<TableInfo<CommonField<BsonType>>> tableInfos = new ArrayList<>();
116116

117-
for (final String collectionName : database.getCollectionNames()) {
117+
for (final String collectionName : getAuthorizedCollections(database)) {
118118
final MongoCollection<Document> collection = database.getCollection(collectionName);
119119
final Map<String, BsonType> uniqueFields = MongoUtils.getUniqueFields(collection);
120120

@@ -135,6 +135,27 @@ protected List<TableInfo<CommonField<BsonType>>> discoverInternal(final MongoDat
135135
return tableInfos;
136136
}
137137

138+
private Set<String> getAuthorizedCollections(MongoDatabase database) {
139+
/*
140+
* db.runCommand ({listCollections: 1.0, authorizedCollections: true, nameOnly: true }) the command
141+
* returns only those collections for which the user has privileges. For example, if a user has find
142+
* action on specific collections, the command returns only those collections; or, if a user has
143+
* find or any other action, on the database resource, the command lists all collections in the
144+
* database.
145+
*/
146+
Document document = database.getDatabase().runCommand(new Document("listCollections", 1)
147+
.append("authorizedCollections", true)
148+
.append("nameOnly", true))
149+
.append("filter", "{ 'type': 'collection' }");
150+
return document.toBsonDocument()
151+
.get("cursor").asDocument()
152+
.getArray("firstBatch")
153+
.stream()
154+
.map(bsonValue -> bsonValue.asDocument().getString("name").getValue())
155+
.collect(Collectors.toSet());
156+
157+
}
158+
138159
@Override
139160
protected List<TableInfo<CommonField<BsonType>>> discoverInternal(final MongoDatabase database, final String schema) throws Exception {
140161
// MondoDb doesn't support schemas

docs/integrations/sources/mongodb-v2.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ For more information regarding configuration parameters, please see [MongoDb Doc
102102

103103
| Version | Date | Pull Request | Subject |
104104
| :--- | :--- | :--- | :--- |
105+
| 0.1.11 | 2022-01-10 | [9238](https://github.com/airbytehq/airbyte/pull/9238) | Return only those collections for which the user has privileges |
105106
| 0.1.10 | 2021-12-30 | [9202](https://github.com/airbytehq/airbyte/pull/9202) | Update connector fields title/description |
106107
| 0.1.9 | 2021-12-07 | [8491](https://github.com/airbytehq/airbyte/pull/8491) | Configure 10000 limit doc reading during Discovery step |
107108
| 0.1.8 | 2021-11-29 | [8306](https://github.com/airbytehq/airbyte/pull/8306) | Added milliseconds for date format for cursor |

0 commit comments

Comments
 (0)