Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Platform): update actor configuration when receiving control messages from connectors during sync #19811

Merged
merged 61 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
736ac57
track latest config message
pedroslopez Nov 26, 2022
715c170
pass new config as part of outputs
pedroslopez Nov 26, 2022
2df5039
persist new config
pedroslopez Nov 26, 2022
59122d7
persist config as the messages come through, dont set output
pedroslopez Nov 28, 2022
7f5a4e7
clean up old implementation
pedroslopez Nov 28, 2022
2637e62
accept control messages for destinations
pedroslopez Nov 28, 2022
289672d
get api client from micronaut
pedroslopez Nov 28, 2022
9c2bded
mask instance-wide oauth params when updating configs
pedroslopez Nov 30, 2022
1ebed55
defaultreplicationworker tests
pedroslopez Nov 30, 2022
6ec3db5
formatting
pedroslopez Nov 30, 2022
1bad8e9
tests for source/destination handlers
pedroslopez Nov 30, 2022
753dafe
rm todo
pedroslopez Nov 30, 2022
ab8e2fc
refactor test a bit to fix pmd
pedroslopez Nov 30, 2022
de0d638
fix pmd
pedroslopez Nov 30, 2022
d159366
fix test
pedroslopez Nov 30, 2022
0f1c122
add PersistConfigHelperTest
pedroslopez Nov 30, 2022
519b920
update message tracker comment
pedroslopez Nov 30, 2022
4ef8b91
fix pmd
pedroslopez Dec 1, 2022
24c2968
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 1, 2022
dda5861
format
pedroslopez Dec 1, 2022
c30e8f6
move ApiClientBeanFactory to commons-worker, use in container-orchest…
pedroslopez Dec 1, 2022
51f1976
pull out config updating to separate methods
pedroslopez Dec 6, 2022
8203432
add jitter
pedroslopez Dec 6, 2022
bff1d44
rename PersistConfigHelper -> UpdateConnectorConfigHelper, docs
pedroslopez Dec 6, 2022
9563ddc
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 6, 2022
44be06d
fix exception type
pedroslopez Dec 6, 2022
5227c73
fmt
pedroslopez Dec 6, 2022
f2ec8dd
move message type check into runnable
pedroslopez Dec 6, 2022
329f641
formatting
pedroslopez Dec 6, 2022
b94a8f8
pass api client env vars to container orchestrator
pedroslopez Dec 8, 2022
6fbbfbe
pass micronaut envs to container orchestrator
pedroslopez Dec 8, 2022
b486f6d
print stacktrace for debugging
pedroslopez Dec 8, 2022
2710f27
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 8, 2022
adabd35
different api host for container orchestrator
pedroslopez Dec 15, 2022
27ebbfb
fix default env var
pedroslopez Dec 16, 2022
2fc87c6
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 16, 2022
d88f12f
format
pedroslopez Dec 16, 2022
ef656dc
fix errors after merge
pedroslopez Dec 16, 2022
a8a0496
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 16, 2022
8a67e13
set source and destination actor id as part of the sync input
pedroslopez Dec 19, 2022
8d3deab
fix: get destination definition
pedroslopez Dec 20, 2022
0f81248
fix null ptr
pedroslopez Dec 20, 2022
8b64f4a
remove "actor" from naming
pedroslopez Dec 20, 2022
e4e3584
fix missing change from rename
pedroslopez Dec 20, 2022
875228e
revert ContainerOrchestratorConfigBeanFactory changes
pedroslopez Dec 20, 2022
4e6ff2e
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 21, 2022
01e3aee
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Dec 21, 2022
6ecac44
inject sourceapi/destinationapi directly rather than airbyteapiclient
pedroslopez Dec 21, 2022
c20f61e
UpdateConnectorConfigHelper -> ConnectorConfigUpdater
pedroslopez Dec 21, 2022
b3a443c
rm log
pedroslopez Dec 21, 2022
079c25d
fix test
pedroslopez Dec 21, 2022
e7f4736
dont fail on config update error
pedroslopez Dec 26, 2022
d6eb05f
pass id, not full config to runnables/accept control message
pedroslopez Jan 3, 2023
860a478
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Jan 3, 2023
87c8fe2
add new config required for api client
pedroslopez Jan 3, 2023
beb9f70
add test file
pedroslopez Jan 3, 2023
e1261d8
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Jan 3, 2023
ad8d6b0
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Jan 6, 2023
6e42699
fix test compatibility
pedroslopez Jan 6, 2023
6554039
Merge branch 'master' into pedroslopez/config-control-msg
pedroslopez Jan 6, 2023
7a86e6e
mount data plane credentials secret to container orchestrator (#20724)
pedroslopez Jan 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions airbyte-commons-worker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies {
implementation libs.bundles.micronaut

implementation 'io.fabric8:kubernetes-client:5.12.2'
implementation 'com.auth0:java-jwt:3.19.2'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious, what is this for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was necessary in order to move the ApiClientBeanFactory into commons-worker (to reuse it in both airbyte-workers and container-orchestrator). It does some token generation that needs this dependency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be an issue, we split up airbyte-commons-worker recently due to some initialization issues of the beans when we added cron.

Copy link
Contributor Author

@pedroslopez pedroslopez Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gosusnp Could you expand a bit on what the issue might be? My change moved the AirbyteAPiClientBeanFactory from airbyte-workers into airbyte-commons-worker. I don't see airbyte-workers nor airbyte-commons-worker being a dependency of airbyte-cron.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking for an issue to link for better context but I cannot find it...
I think the problem we had is that micronaut discovers all singleton upon starts, so by having some services in a shared lib led us to start more services than intended. For example, the cron would pick up some beans from the workers and would effectively behave as an extra worker.

@jdpgrailsdev or @benmoriceau might have better context since they were more closely working on this.

implementation libs.guava
implementation (libs.temporal.sdk) {
exclude module: 'guava'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public static void cancelProcess(final Process process) {
*/
public static WorkerSourceConfig syncToWorkerSourceConfig(final StandardSyncInput sync) {
return new WorkerSourceConfig()
.withSourceId(sync.getSourceId())
.withSourceConnectionConfiguration(sync.getSourceConfiguration())
.withCatalog(sync.getCatalog())
.withState(sync.getState());
Expand All @@ -102,6 +103,7 @@ public static WorkerSourceConfig syncToWorkerSourceConfig(final StandardSyncInpu
*/
public static WorkerDestinationConfig syncToWorkerDestinationConfig(final StandardSyncInput sync) {
return new WorkerDestinationConfig()
.withDestinationId(sync.getDestinationId())
.withDestinationConnectionConfiguration(sync.getDestinationConfiguration())
.withCatalog(sync.getCatalog())
.withState(sync.getState());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.auth0.jwt.algorithms.Algorithm;
import com.google.auth.oauth2.ServiceAccountCredentials;
import io.airbyte.api.client.AirbyteApiClient;
import io.airbyte.api.client.generated.DestinationApi;
import io.airbyte.api.client.generated.SourceApi;
import io.airbyte.api.client.invoker.generated.ApiClient;
import io.airbyte.commons.temporal.config.WorkerMode;
Expand Down Expand Up @@ -58,7 +59,7 @@ public ApiClient apiClient(@Value("${airbyte.internal.api.auth-header.name}") fi
}

@Singleton
public AirbyteApiClient airbyteApiClient(ApiClient apiClient) {
public AirbyteApiClient airbyteApiClient(final ApiClient apiClient) {
return new AirbyteApiClient(apiClient);
}

Expand All @@ -67,6 +68,11 @@ public SourceApi sourceApi(final ApiClient apiClient) {
return new SourceApi(apiClient);
}

@Singleton
public DestinationApi destinationApi(final ApiClient apiClient) {
return new DestinationApi(apiClient);
}
Comment on lines +73 to +76
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added so we have the singleton available for injection directly - followed what was already being done for SourceApi


@Singleton
public HttpClient httpClient() {
return HttpClient.newHttpClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.airbyte.config.WorkerDestinationConfig;
import io.airbyte.config.WorkerSourceConfig;
import io.airbyte.metrics.lib.ApmTraceUtils;
import io.airbyte.protocol.models.AirbyteControlMessage;
import io.airbyte.protocol.models.AirbyteMessage;
import io.airbyte.protocol.models.AirbyteMessage.Type;
import io.airbyte.protocol.models.AirbyteRecordMessage;
Expand All @@ -36,6 +37,7 @@
import io.airbyte.workers.WorkerUtils;
import io.airbyte.workers.exception.RecordSchemaValidationException;
import io.airbyte.workers.exception.WorkerException;
import io.airbyte.workers.helper.ConnectorConfigUpdater;
import io.airbyte.workers.helper.FailureHelper;
import io.airbyte.workers.helper.ThreadedTimeTracker;
import io.airbyte.workers.internal.AirbyteDestination;
Expand Down Expand Up @@ -98,6 +100,7 @@ public class DefaultReplicationWorker implements ReplicationWorker {
private final AtomicBoolean hasFailed;
private final RecordSchemaValidator recordSchemaValidator;
private final WorkerMetricReporter metricReporter;
private final ConnectorConfigUpdater connectorConfigUpdater;
private final boolean fieldSelectionEnabled;

public DefaultReplicationWorker(final String jobId,
Expand All @@ -108,6 +111,7 @@ public DefaultReplicationWorker(final String jobId,
final MessageTracker messageTracker,
final RecordSchemaValidator recordSchemaValidator,
final WorkerMetricReporter metricReporter,
final ConnectorConfigUpdater connectorConfigUpdater,
final boolean fieldSelectionEnabled) {
this.jobId = jobId;
this.attempt = attempt;
Expand All @@ -118,6 +122,7 @@ public DefaultReplicationWorker(final String jobId,
this.executors = Executors.newFixedThreadPool(2);
this.recordSchemaValidator = recordSchemaValidator;
this.metricReporter = metricReporter;
this.connectorConfigUpdater = connectorConfigUpdater;
this.fieldSelectionEnabled = fieldSelectionEnabled;

this.cancelled = new AtomicBoolean(false);
Expand Down Expand Up @@ -191,7 +196,7 @@ private void replicate(final Path jobRoot,
// note: `whenComplete` is used instead of `exceptionally` so that the original exception is still
// thrown
final CompletableFuture<?> readFromDstThread = CompletableFuture.runAsync(
readFromDstRunnable(destination, cancelled, messageTracker, mdc, timeTracker),
readFromDstRunnable(destination, cancelled, messageTracker, connectorConfigUpdater, mdc, timeTracker, destinationConfig),
executors)
.whenComplete((msg, ex) -> {
if (ex != null) {
Expand All @@ -212,10 +217,12 @@ private void replicate(final Path jobRoot,
cancelled,
mapper,
messageTracker,
connectorConfigUpdater,
mdc,
recordSchemaValidator,
metricReporter,
timeTracker,
sourceConfig,
fieldSelectionEnabled),
executors)
.whenComplete((msg, ex) -> {
Expand Down Expand Up @@ -253,8 +260,10 @@ private void replicate(final Path jobRoot,
private static Runnable readFromDstRunnable(final AirbyteDestination destination,
final AtomicBoolean cancelled,
final MessageTracker messageTracker,
final ConnectorConfigUpdater connectorConfigUpdater,
final Map<String, String> mdc,
final ThreadedTimeTracker timeHolder) {
final ThreadedTimeTracker timeHolder,
final WorkerDestinationConfig destinationConfig) {
return () -> {
MDC.setContextMap(mdc);
LOGGER.info("Destination output thread started.");
Expand All @@ -267,8 +276,18 @@ private static Runnable readFromDstRunnable(final AirbyteDestination destination
throw new DestinationException("Destination process read attempt failed", e);
}
if (messageOptional.isPresent()) {
LOGGER.info("State in DefaultReplicationWorker from destination: {}", messageOptional.get());
messageTracker.acceptFromDestination(messageOptional.get());
final AirbyteMessage message = messageOptional.get();
LOGGER.info("State in DefaultReplicationWorker from destination: {}", message);

messageTracker.acceptFromDestination(message);

try {
if (message.getType() == Type.CONTROL) {
acceptDstControlMessage(destinationConfig, message.getControl(), connectorConfigUpdater);
}
} catch (final Exception e) {
LOGGER.error("Error updating destination configuration", e);
}
}
}
timeHolder.trackDestinationWriteEndTime();
Expand Down Expand Up @@ -300,10 +319,12 @@ private static Runnable readFromSrcAndWriteToDstRunnable(final AirbyteSource sou
final AtomicBoolean cancelled,
final AirbyteMapper mapper,
final MessageTracker messageTracker,
final ConnectorConfigUpdater connectorConfigUpdater,
final Map<String, String> mdc,
final RecordSchemaValidator recordSchemaValidator,
final WorkerMetricReporter metricReporter,
final ThreadedTimeTracker timeHolder,
final WorkerSourceConfig sourceConfig,
final boolean fieldSelectionEnabled) {
return () -> {
MDC.setContextMap(mdc);
Expand Down Expand Up @@ -333,6 +354,14 @@ private static Runnable readFromSrcAndWriteToDstRunnable(final AirbyteSource sou

messageTracker.acceptFromSource(message);

try {
if (message.getType() == Type.CONTROL) {
acceptSrcControlMessage(sourceConfig, message.getControl(), connectorConfigUpdater);
}
} catch (final Exception e) {
LOGGER.error("Error updating source configuration", e);
}

try {
if (message.getType() == Type.RECORD || message.getType() == Type.STATE) {
destination.accept(message);
Expand Down Expand Up @@ -391,6 +420,22 @@ private static Runnable readFromSrcAndWriteToDstRunnable(final AirbyteSource sou
};
}

private static void acceptSrcControlMessage(final WorkerSourceConfig sourceConfig,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can simplify this method signature by passing in the id instead of the entire config

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this simplification also extends to the various runnable method interfaces e.g readFromDstRunnable doesn't need the destinationConfig. Improves readability since it's clearer what scope requires what data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻 updated in d6eb05f

final AirbyteControlMessage controlMessage,
final ConnectorConfigUpdater connectorConfigUpdater) {
if (controlMessage.getType() == AirbyteControlMessage.Type.CONNECTOR_CONFIG) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are there other kinds of control messages today?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, this is the only one for now!

connectorConfigUpdater.updateSource(sourceConfig.getSourceId(), controlMessage.getConnectorConfig().getConfig());
}
}

private static void acceptDstControlMessage(final WorkerDestinationConfig destinationConfig,
final AirbyteControlMessage controlMessage,
final ConnectorConfigUpdater connectorConfigUpdater) {
if (controlMessage.getType() == AirbyteControlMessage.Type.CONNECTOR_CONFIG) {
connectorConfigUpdater.updateDestination(destinationConfig.getDestinationId(), controlMessage.getConnectorConfig().getConfig());
}
}

private ReplicationOutput getReplicationOutput(final StandardSyncInput syncInput,
final WorkerDestinationConfig destinationConfig,
final AtomicReference<FailureReason> replicationRunnableFailureRef,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2022 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.workers.helper;

import com.google.common.hash.Hashing;
import io.airbyte.api.client.AirbyteApiClient;
import io.airbyte.api.client.generated.DestinationApi;
import io.airbyte.api.client.generated.SourceApi;
import io.airbyte.api.client.model.generated.DestinationIdRequestBody;
import io.airbyte.api.client.model.generated.DestinationRead;
import io.airbyte.api.client.model.generated.DestinationUpdate;
import io.airbyte.api.client.model.generated.SourceIdRequestBody;
import io.airbyte.api.client.model.generated.SourceRead;
import io.airbyte.api.client.model.generated.SourceUpdate;
import io.airbyte.commons.json.Jsons;
import io.airbyte.protocol.models.Config;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the javadocs!

* Helper class for workers to persist updates to Source/Destination configs emitted from
* AirbyteControlMessages.
*
* This is in order to support connectors updating configs when running commands, which is specially
* useful for migrating configuration to a new version or for enabling connectors that require
* single-use or short-lived OAuth tokens.
*/
public class ConnectorConfigUpdater {

private static final Logger LOGGER = LoggerFactory.getLogger(ConnectorConfigUpdater.class);

private final SourceApi sourceApi;
private final DestinationApi destinationApi;

public ConnectorConfigUpdater(final SourceApi sourceApi, final DestinationApi destinationApi) {
this.sourceApi = sourceApi;
this.destinationApi = destinationApi;
}

/**
* Updates the Source from a sync job ID with the provided Configuration. Secrets and OAuth
* parameters will be masked when saving.
*/
public void updateSource(final UUID sourceId, final Config config) {
final SourceRead source = AirbyteApiClient.retryWithJitter(
() -> sourceApi.getSource(new SourceIdRequestBody().sourceId(sourceId)),
"get source");

final SourceRead updatedSource = AirbyteApiClient.retryWithJitter(
() -> sourceApi
.updateSource(new SourceUpdate()
.sourceId(sourceId)
.name(source.getName())
.connectionConfiguration(Jsons.jsonNode(config.getAdditionalProperties()))),
"update source");

LOGGER.info("Persisted updated configuration for source {}. New config hash: {}.", sourceId,
Hashing.sha256().hashString(updatedSource.getConnectionConfiguration().asText(), StandardCharsets.UTF_8));

}

/**
* Updates the Destination from a sync job ID with the provided Configuration. Secrets and OAuth
* parameters will be masked when saving.
*/
public void updateDestination(final UUID destinationId, final Config config) {
final DestinationRead destination = AirbyteApiClient.retryWithJitter(
() -> destinationApi.getDestination(new DestinationIdRequestBody().destinationId(destinationId)),
"get destination");

final DestinationRead updatedDestination = AirbyteApiClient.retryWithJitter(
() -> destinationApi
.updateDestination(new DestinationUpdate()
.destinationId(destinationId)
.name(destination.getName())
.connectionConfiguration(Jsons.jsonNode(config.getAdditionalProperties()))),
"update destination");

LOGGER.info("Persisted updated configuration for destination {}. New config hash: {}.", destinationId,
Hashing.sha256().hashString(updatedDestination.getConnectionConfiguration().asText(), StandardCharsets.UTF_8));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.OutputStreamWriter;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -81,8 +82,9 @@ public void start(final WorkerDestinationConfig destinationConfig, final Path jo

writer = messageWriterFactory.createWriter(new BufferedWriter(new OutputStreamWriter(destinationProcess.getOutputStream(), Charsets.UTF_8)));

final List<Type> acceptedMessageTypes = List.of(Type.STATE, Type.TRACE, Type.CONTROL);
messageIterator = streamFactory.create(IOs.newBufferedReader(destinationProcess.getInputStream()))
.filter(message -> message.getType() == Type.STATE || message.getType() == Type.TRACE)
.filter(message -> acceptedMessageTypes.contains(message.getType()))
.iterator();
Comment on lines +90 to 93
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enable reading control messages from destinations

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
Expand Down Expand Up @@ -86,9 +87,10 @@ public void start(final WorkerSourceConfig sourceConfig, final Path jobRoot) thr

logInitialStateAsJSON(sourceConfig);

final List<Type> acceptedMessageTypes = List.of(Type.RECORD, Type.STATE, Type.TRACE, Type.CONTROL);
messageIterator = streamFactory.create(IOs.newBufferedReader(sourceProcess.getInputStream()))
.peek(message -> heartbeatMonitor.beat())
.filter(message -> message.getType() == Type.RECORD || message.getType() == Type.STATE || message.getType() == Type.TRACE)
.filter(message -> acceptedMessageTypes.contains(message.getType()))
Comment on lines +95 to +98
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enable reading control messages from sources

.iterator();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,8 @@ private void handleEmittedOrchestratorMessage(final AirbyteControlMessage contro
@SuppressWarnings("PMD") // until method is implemented
private void handleEmittedOrchestratorConnectorConfig(final AirbyteControlConnectorConfigMessage configMessage,
final ConnectorType connectorType) {
// TODO: Update config here
/**
* Pseudocode: for (key in configMessage.getConfig()) { validateIsReallyConfig(key);
* persistConfigChange(connectorType, key, configMessage.getConfig().get(key)); // nuance here for
* secret storage or not. May need to be async over API for replication orchestrator }
*/
// Config updates are being persisted as part of the DefaultReplicationWorker.
// In the future, we could add tracking of these kinds of messages here. Nothing to do for now.
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableMap;
import io.airbyte.commons.json.Jsons;
import io.airbyte.protocol.models.AirbyteControlConnectorConfigMessage;
import io.airbyte.protocol.models.AirbyteControlMessage;
import io.airbyte.protocol.models.AirbyteErrorTraceMessage;
import io.airbyte.protocol.models.AirbyteEstimateTraceMessage;
import io.airbyte.protocol.models.AirbyteGlobalState;
Expand All @@ -18,6 +20,7 @@
import io.airbyte.protocol.models.AirbyteStateMessage.AirbyteStateType;
import io.airbyte.protocol.models.AirbyteStreamState;
import io.airbyte.protocol.models.AirbyteTraceMessage;
import io.airbyte.protocol.models.Config;
import io.airbyte.protocol.models.StreamDescriptor;
import java.time.Instant;
import java.util.ArrayList;
Expand Down Expand Up @@ -159,4 +162,14 @@ public static AirbyteTraceMessage createErrorTraceMessage(final String message,
return msg;
}

public static AirbyteMessage createConfigControlMessage(final Config config, final Double emittedAt) {
return new AirbyteMessage()
.withType(Type.CONTROL)
.withControl(new AirbyteControlMessage()
.withEmittedAt(emittedAt)
.withType(AirbyteControlMessage.Type.CONNECTOR_CONFIG)
.withConnectorConfig(new AirbyteControlConnectorConfigMessage()
.withConfig(config)));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ public static ImmutablePair<StandardSync, StandardSyncInput> createSyncConfig(fi
final StandardSyncInput syncInput = new StandardSyncInput()
.withNamespaceDefinition(standardSync.getNamespaceDefinition())
.withPrefix(standardSync.getPrefix())
.withSourceId(sourceId)
.withDestinationId(destinationId)
.withDestinationConfiguration(destinationConnectionConfig.getConfiguration())
.withCatalog(standardSync.getCatalog())
.withSourceConfiguration(sourceConnectionConfig.getConfiguration())
Expand Down
Loading