1
0
mirror of synced 2025-12-25 02:09:19 -05:00

add check connection and discover without having to create source and destination (#1358)

This commit is contained in:
Charles
2020-12-17 18:53:14 -08:00
committed by GitHub
parent 06e98150a5
commit 49e746d23a
9 changed files with 758 additions and 50 deletions

View File

@@ -768,6 +768,69 @@ paths:
description: Connection not found
"422":
$ref: "#/components/responses/InvalidInput"
/v1/scheduler/sources/check_connection:
post:
tags:
- scheduler
summary: Run check connection for a given source configuration
operationId: executeSourceCheckConnection
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SourceCoreConfig"
required: true
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/CheckConnectionRead"
"422":
$ref: "#/components/responses/InvalidInput"
/v1/scheduler/sources/discover_schema:
post:
tags:
- scheduler
summary: Run discover schema for a given source a source configuration
operationId: executeSourceDiscoverSchema
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SourceCoreConfig"
required: true
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/SourceDiscoverSchemaRead"
"422":
$ref: "#/components/responses/InvalidInput"
/v1/scheduler/destinations/check_connection:
post:
tags:
- scheduler
summary: Run check connection for a given destination configuration
operationId: executeDestinationCheckConnection
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/DestinationCoreConfig"
required: true
responses:
"200":
description: Successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/CheckConnectionRead"
"422":
$ref: "#/components/responses/InvalidInput"
/v1/web_backend/connections/list:
post:
tags:
@@ -1148,22 +1211,28 @@ components:
SourceConfiguration:
description: The values required to configure the source. The schema for this must match the schema return by source_definition_specifications/get for the source.
example: { user: "charles" }
SourceCreate:
SourceCoreConfig:
type: object
required:
- workspaceId
- sourceDefinitionId
- connectionConfiguration
- name
properties:
workspaceId:
$ref: "#/components/schemas/WorkspaceId"
sourceDefinitionId:
$ref: "#/components/schemas/SourceDefinitionId"
connectionConfiguration:
$ref: "#/components/schemas/SourceConfiguration"
name:
type: string
SourceCreate:
allOf:
- $ref: "#/components/schemas/SourceCoreConfig"
- type: object
required:
- workspaceId
- name
properties:
workspaceId:
$ref: "#/components/schemas/WorkspaceId"
name:
type: string
SourceRecreate:
type: object
required:
@@ -1231,9 +1300,12 @@ components:
type: object
required:
- schema
- job_info
properties:
schema:
$ref: "#/components/schemas/SourceSchema"
job_info:
$ref: "#/components/schemas/JobInfoRead"
# DESTINATION DEFINITION
DestinationDefinitionId:
type: string
@@ -1331,21 +1403,29 @@ components:
DestinationConfiguration:
description: The values required to configure the destination. The schema for this must match the schema return by destination_definition_specifications/get for the destinationDefinition.
example: { user: "charles" }
DestinationCreate:
DestinationCoreConfig:
type: object
required:
- workspaceId
- destinationDefinitionId
- connectionConfiguration
properties:
workspaceId:
$ref: "#/components/schemas/WorkspaceId"
destinationDefinitionId:
$ref: "#/components/schemas/DestinationDefinitionId"
connectionConfiguration:
$ref: "#/components/schemas/DestinationConfiguration"
name:
type: string
DestinationCreate:
allOf:
- $ref: "#/components/schemas/DestinationCoreConfig"
- type: object
required:
- workspaceId
- name
properties:
workspaceId:
$ref: "#/components/schemas/WorkspaceId"
name:
type: string
DestinationRecreate:
type: object
required:
@@ -1758,6 +1838,7 @@ components:
type: object
required:
- status
- jobInfo
properties:
status:
type: string
@@ -1766,6 +1847,8 @@ components:
- failed
message:
type: string
job_info:
$ref: "#/components/schemas/JobInfoRead"
# Web Backend
WbConnectionRead:
type: object

View File

@@ -31,6 +31,7 @@ import io.airbyte.api.model.ConnectionRead;
import io.airbyte.api.model.ConnectionReadList;
import io.airbyte.api.model.ConnectionUpdate;
import io.airbyte.api.model.DebugRead;
import io.airbyte.api.model.DestinationCoreConfig;
import io.airbyte.api.model.DestinationCreate;
import io.airbyte.api.model.DestinationDefinitionCreate;
import io.airbyte.api.model.DestinationDefinitionIdRequestBody;
@@ -49,6 +50,7 @@ import io.airbyte.api.model.JobInfoRead;
import io.airbyte.api.model.JobListRequestBody;
import io.airbyte.api.model.JobReadList;
import io.airbyte.api.model.SlugRequestBody;
import io.airbyte.api.model.SourceCoreConfig;
import io.airbyte.api.model.SourceCreate;
import io.airbyte.api.model.SourceDefinitionCreate;
import io.airbyte.api.model.SourceDefinitionIdRequestBody;
@@ -217,13 +219,14 @@ public class ConfigurationApi implements io.airbyte.api.V1Api {
@Override
public CheckConnectionRead checkConnectionToSource(@Valid SourceIdRequestBody sourceIdRequestBody) {
return execute(() -> schedulerHandler.checkSourceConnection(sourceIdRequestBody));
return execute(() -> schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody));
}
@Override
public SourceDiscoverSchemaRead discoverSchemaForSource(@Valid SourceIdRequestBody sourceIdRequestBody) {
return execute(() -> schedulerHandler.discoverSchemaForSource(sourceIdRequestBody));
return execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceId(sourceIdRequestBody));
}
// DESTINATION
@Override
@@ -285,7 +288,7 @@ public class ConfigurationApi implements io.airbyte.api.V1Api {
@Override
public CheckConnectionRead checkConnectionToDestination(@Valid DestinationIdRequestBody destinationIdRequestBody) {
return execute(() -> schedulerHandler.checkDestinationConnection(destinationIdRequestBody));
return execute(() -> schedulerHandler.checkDestinationConnectionFromDestinationId(destinationIdRequestBody));
}
// CONNECTION
@@ -329,6 +332,22 @@ public class ConfigurationApi implements io.airbyte.api.V1Api {
return execute(() -> schedulerHandler.resetConnection(connectionIdRequestBody));
}
// SCHEDULER
@Override
public CheckConnectionRead executeSourceCheckConnection(@Valid SourceCoreConfig sourceCreate) {
return execute(() -> schedulerHandler.checkSourceConnectionFromSourceCreate(sourceCreate));
}
@Override
public CheckConnectionRead executeDestinationCheckConnection(@Valid DestinationCoreConfig destinationCreate) {
return execute(() -> schedulerHandler.checkDestinationConnectionFromDestinationCreate(destinationCreate));
}
@Override
public SourceDiscoverSchemaRead executeSourceDiscoverSchema(@Valid SourceCoreConfig sourceCreate) {
return execute(() -> schedulerHandler.discoverSchemaForSourceFromSourceCreate(sourceCreate));
}
// JOB HISTORY
@Override

View File

@@ -24,12 +24,15 @@
package io.airbyte.server.handlers;
import com.google.common.annotations.VisibleForTesting;
import io.airbyte.api.model.CheckConnectionRead;
import io.airbyte.api.model.ConnectionIdRequestBody;
import io.airbyte.api.model.DestinationCoreConfig;
import io.airbyte.api.model.DestinationDefinitionIdRequestBody;
import io.airbyte.api.model.DestinationDefinitionSpecificationRead;
import io.airbyte.api.model.DestinationIdRequestBody;
import io.airbyte.api.model.JobInfoRead;
import io.airbyte.api.model.SourceCoreConfig;
import io.airbyte.api.model.SourceDefinitionIdRequestBody;
import io.airbyte.api.model.SourceDefinitionSpecificationRead;
import io.airbyte.api.model.SourceDiscoverSchemaRead;
@@ -58,18 +61,26 @@ import io.airbyte.server.converters.SchemaConverter;
import io.airbyte.validation.json.JsonValidationException;
import java.io.IOException;
import java.util.UUID;
import java.util.function.Supplier;
public class SchedulerHandler {
private final ConfigRepository configRepository;
private final SchedulerJobClient schedulerJobClient;
private final Supplier<UUID> uuidSupplier;
public SchedulerHandler(final ConfigRepository configRepository, SchedulerJobClient schedulerJobClient) {
@VisibleForTesting
SchedulerHandler(final ConfigRepository configRepository, SchedulerJobClient schedulerJobClient, Supplier<UUID> uuidSupplier) {
this.configRepository = configRepository;
this.schedulerJobClient = schedulerJobClient;
this.uuidSupplier = uuidSupplier;
}
public CheckConnectionRead checkSourceConnection(SourceIdRequestBody sourceIdRequestBody)
public SchedulerHandler(final ConfigRepository configRepository, SchedulerJobClient schedulerJobClient) {
this(configRepository, schedulerJobClient, UUID::randomUUID);
}
public CheckConnectionRead checkSourceConnectionFromSourceId(SourceIdRequestBody sourceIdRequestBody)
throws ConfigNotFoundException, IOException, JsonValidationException {
final SourceConnection source = configRepository.getSourceConnection(sourceIdRequestBody.getSourceId());
final StandardSourceDefinition sourceDef = configRepository.getStandardSourceDefinition(source.getSourceDefinitionId());
@@ -78,27 +89,82 @@ public class SchedulerHandler {
return reportConnectionStatus(schedulerJobClient.createSourceCheckConnectionJob(source, imageName));
}
public CheckConnectionRead checkDestinationConnection(DestinationIdRequestBody destinationIdRequestBody)
public CheckConnectionRead checkSourceConnectionFromSourceCreate(SourceCoreConfig sourceCreate)
throws ConfigNotFoundException, IOException, JsonValidationException {
final StandardSourceDefinition sourceDef = configRepository.getStandardSourceDefinition(sourceCreate.getSourceDefinitionId());
final String imageName = DockerUtils.getTaggedImageName(sourceDef.getDockerRepository(), sourceDef.getDockerImageTag());
final UUID sourceUuid = uuidSupplier.get();
final SourceConnection source = new SourceConnection()
.withName("source:" + sourceUuid) // todo (cgardens) - narrow the struct passed to the client.
.withSourceDefinitionId(sourceCreate.getSourceDefinitionId())
.withWorkspaceId(sourceUuid) // todo (cgardens) - narrow the struct passed to the client.
.withTombstone(false)
// todo (cgardens) - used to create the scope so we want a random value.
.withSourceId(sourceUuid)
.withConfiguration(sourceCreate.getConnectionConfiguration());
return reportConnectionStatus(schedulerJobClient.createSourceCheckConnectionJob(source, imageName));
}
public CheckConnectionRead checkDestinationConnectionFromDestinationId(DestinationIdRequestBody destinationIdRequestBody)
throws ConfigNotFoundException, IOException, JsonValidationException {
final DestinationConnection destination = configRepository.getDestinationConnection(destinationIdRequestBody.getDestinationId());
final StandardDestinationDefinition destinationDef = configRepository.getStandardDestinationDefinition(destination.getDestinationDefinitionId());
final String imageName = DockerUtils.getTaggedImageName(destinationDef.getDockerRepository(), destinationDef.getDockerImageTag());
return reportConnectionStatus(schedulerJobClient.createDestinationCheckConnectionJob(destination, imageName));
}
public SourceDiscoverSchemaRead discoverSchemaForSource(SourceIdRequestBody sourceIdRequestBody)
public CheckConnectionRead checkDestinationConnectionFromDestinationCreate(DestinationCoreConfig destinationCreate)
throws ConfigNotFoundException, IOException, JsonValidationException {
final StandardDestinationDefinition destDef = configRepository.getStandardDestinationDefinition(destinationCreate.getDestinationDefinitionId());
final String imageName = DockerUtils.getTaggedImageName(destDef.getDockerRepository(), destDef.getDockerImageTag());
final UUID destinationUuid = uuidSupplier.get();
final DestinationConnection destination = new DestinationConnection()
.withName("destination:" + destinationUuid) // todo (cgardens) - narrow the struct passed to the client.
.withDestinationDefinitionId(destinationCreate.getDestinationDefinitionId())
.withWorkspaceId(destinationUuid) // todo (cgardens) - narrow the struct passed to the client.
.withTombstone(false)
// todo (cgardens) - used to create the scope so we want a random value.
.withDestinationId(destinationUuid)
.withConfiguration(destinationCreate.getConnectionConfiguration());
return reportConnectionStatus(schedulerJobClient.createDestinationCheckConnectionJob(destination, imageName));
}
public SourceDiscoverSchemaRead discoverSchemaForSourceFromSourceId(SourceIdRequestBody sourceIdRequestBody)
throws ConfigNotFoundException, IOException, JsonValidationException {
final SourceConnection source = configRepository.getSourceConnection(sourceIdRequestBody.getSourceId());
final StandardSourceDefinition sourceDef = configRepository.getStandardSourceDefinition(source.getSourceDefinitionId());
final String imageName = DockerUtils.getTaggedImageName(sourceDef.getDockerRepository(), sourceDef.getDockerImageTag());
final StandardDiscoverCatalogOutput discoverOutput = schedulerJobClient.createDiscoverSchemaJob(source, imageName)
.getSuccessOutput()
final Job job = schedulerJobClient.createDiscoverSchemaJob(source, imageName);
return discoverJobToOutput(job);
}
public SourceDiscoverSchemaRead discoverSchemaForSourceFromSourceCreate(SourceCoreConfig sourceCreate)
throws ConfigNotFoundException, IOException, JsonValidationException {
final StandardSourceDefinition sourceDef = configRepository.getStandardSourceDefinition(sourceCreate.getSourceDefinitionId());
final String imageName = DockerUtils.getTaggedImageName(sourceDef.getDockerRepository(), sourceDef.getDockerImageTag());
final UUID sourceUuid = uuidSupplier.get();
final SourceConnection source = new SourceConnection()
.withName("source:" + sourceUuid) // todo (cgardens) - narrow the struct passed to the client.
.withSourceDefinitionId(sourceCreate.getSourceDefinitionId())
.withWorkspaceId(sourceUuid) // todo (cgardens) - narrow the struct passed to the client.
.withTombstone(false)
// todo (cgardens) - used to create the scope so we want a random value.
.withSourceId(sourceUuid)
.withConfiguration(sourceCreate.getConnectionConfiguration());
final Job job = schedulerJobClient.createDiscoverSchemaJob(source, imageName);
return discoverJobToOutput(job);
}
private static SourceDiscoverSchemaRead discoverJobToOutput(Job job) {
StandardDiscoverCatalogOutput discoverOutput = job.getSuccessOutput()
.map(JobOutput::getDiscoverCatalog)
.orElseThrow(() -> new IllegalStateException("no discover output found"));
final Schema schema = AirbyteProtocolConverters.toSchema(discoverOutput.getCatalog());
return new SourceDiscoverSchemaRead().schema(SchemaConverter.toApiSchema(schema));
return new SourceDiscoverSchemaRead()
.schema(SchemaConverter.toApiSchema(schema))
.jobInfo(JobConverter.getJobInfoRead(job));
}
public SourceDefinitionSpecificationRead getSourceDefinitionSpecification(SourceDefinitionIdRequestBody sourceDefinitionIdRequestBody)
@@ -179,7 +245,8 @@ public class SchedulerHandler {
return new CheckConnectionRead()
.status(Enums.convertTo(checkConnectionOutput.getStatus(), CheckConnectionRead.StatusEnum.class))
.message(checkConnectionOutput.getMessage());
.message(checkConnectionOutput.getMessage())
.jobInfo(JobConverter.getJobInfoRead(job));
}
}

View File

@@ -59,7 +59,7 @@ public class WebBackendDestinationHandler {
.destinationId(destination.getDestinationId());
try {
final CheckConnectionRead checkConnectionRead = schedulerHandler.checkDestinationConnection(destinationIdRequestBody);
final CheckConnectionRead checkConnectionRead = schedulerHandler.checkDestinationConnectionFromDestinationId(destinationIdRequestBody);
if (checkConnectionRead.getStatus() == SUCCEEDED) {
return destination;
}
@@ -86,7 +86,7 @@ public class WebBackendDestinationHandler {
try {
final CheckConnectionRead checkConnectionRead = schedulerHandler
.checkDestinationConnection(destinationIdRequestBody);
.checkDestinationConnectionFromDestinationId(destinationIdRequestBody);
if (checkConnectionRead.getStatus() == SUCCEEDED) {
final DestinationIdRequestBody destinationIdRequestBody1 = new DestinationIdRequestBody()
.destinationId(destinationRecreate.getDestinationId());

View File

@@ -60,7 +60,7 @@ public class WebBackendSourceHandler {
.sourceId(source.getSourceId());
try {
final CheckConnectionRead checkConnectionRead = schedulerHandler.checkSourceConnection(sourceIdRequestBody);
final CheckConnectionRead checkConnectionRead = schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody);
if (checkConnectionRead.getStatus() == CheckConnectionRead.StatusEnum.SUCCEEDED) {
return source;
}
@@ -86,7 +86,7 @@ public class WebBackendSourceHandler {
try {
final CheckConnectionRead checkConnectionRead = schedulerHandler
.checkSourceConnection(sourceIdRequestBody);
.checkSourceConnectionFromSourceId(sourceIdRequestBody);
if (checkConnectionRead.getStatus() == SUCCEEDED) {
final SourceIdRequestBody sourceIdRequestBody1 = new SourceIdRequestBody().sourceId(sourceRecreate.getSourceId());
sourceHandler.deleteSource(sourceIdRequestBody1);

View File

@@ -26,6 +26,7 @@ package io.airbyte.server.handlers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -33,9 +34,11 @@ import static org.mockito.Mockito.when;
import io.airbyte.api.model.CheckConnectionRead;
import io.airbyte.api.model.ConnectionIdRequestBody;
import io.airbyte.api.model.DestinationCoreConfig;
import io.airbyte.api.model.DestinationDefinitionIdRequestBody;
import io.airbyte.api.model.DestinationIdRequestBody;
import io.airbyte.api.model.JobInfoRead;
import io.airbyte.api.model.SourceCoreConfig;
import io.airbyte.api.model.SourceDefinitionIdRequestBody;
import io.airbyte.api.model.SourceIdRequestBody;
import io.airbyte.commons.docker.DockerUtils;
@@ -54,6 +57,7 @@ import io.airbyte.config.StandardSourceDefinition;
import io.airbyte.config.StandardSync;
import io.airbyte.config.persistence.ConfigNotFoundException;
import io.airbyte.config.persistence.ConfigRepository;
import io.airbyte.protocol.models.AirbyteCatalog;
import io.airbyte.protocol.models.CatalogHelpers;
import io.airbyte.protocol.models.ConnectorSpecification;
import io.airbyte.protocol.models.Field;
@@ -71,6 +75,7 @@ import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Supplier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -84,23 +89,45 @@ class SchedulerHandlerTest {
private static final String DESTINATION_DOCKER_TAG = "tag";
private static final String DESTINATION_DOCKER_IMAGE = DockerUtils.getTaggedImageName(DESTINATION_DOCKER_REPO, DESTINATION_DOCKER_TAG);
private static final SourceConnection SOURCE = new SourceConnection()
.withName("my postgres db")
.withWorkspaceId(UUID.randomUUID())
.withSourceDefinitionId(UUID.randomUUID())
.withSourceId(UUID.randomUUID())
.withConfiguration(Jsons.emptyObject())
.withTombstone(false);
private static final DestinationConnection DESTINATION = new DestinationConnection()
.withName("my db2 instance")
.withWorkspaceId(UUID.randomUUID())
.withDestinationDefinitionId(UUID.randomUUID())
.withDestinationId(UUID.randomUUID())
.withConfiguration(Jsons.emptyObject())
.withTombstone(false);
private SchedulerHandler schedulerHandler;
private ConfigRepository configRepository;
private Job completedJob;
private SchedulerJobClient schedulerJobClient;
private Supplier<UUID> uuidSupplier;
@SuppressWarnings("unchecked")
@BeforeEach
void setup() {
completedJob = mock(Job.class);
completedJob = mock(Job.class, RETURNS_DEEP_STUBS);
when(completedJob.getStatus()).thenReturn(JobStatus.SUCCEEDED);
schedulerJobClient = spy(SchedulerJobClient.class);
when(completedJob.getConfig().getConfigType()).thenReturn(ConfigType.SYNC);
when(completedJob.getScope()).thenReturn("sync:123");
uuidSupplier = mock(Supplier.class);
schedulerJobClient = spy(SchedulerJobClient.class);
configRepository = mock(ConfigRepository.class);
schedulerHandler = new SchedulerHandler(configRepository, schedulerJobClient);
schedulerHandler = new SchedulerHandler(configRepository, schedulerJobClient, uuidSupplier);
}
@Test
void testCheckSourceConnection() throws JsonValidationException, IOException, ConfigNotFoundException {
void testCheckSourceConnectionFromSourceId() throws JsonValidationException, IOException, ConfigNotFoundException {
final SourceConnection source = SourceHelpers.generateSource(UUID.randomUUID());
final SourceIdRequestBody request = new SourceIdRequestBody().sourceId(source.getSourceId());
@@ -112,12 +139,36 @@ class SchedulerHandlerTest {
when(configRepository.getSourceConnection(source.getSourceId())).thenReturn(source);
when(schedulerJobClient.createSourceCheckConnectionJob(source, SOURCE_DOCKER_IMAGE)).thenReturn(completedJob);
schedulerHandler.checkSourceConnection(request);
schedulerHandler.checkSourceConnectionFromSourceId(request);
verify(configRepository).getSourceConnection(source.getSourceId());
verify(schedulerJobClient).createSourceCheckConnectionJob(source, SOURCE_DOCKER_IMAGE);
}
@Test
void testCheckSourceConnectionFromSourceCreate() throws JsonValidationException, IOException, ConfigNotFoundException {
final SourceConnection source = Jsons.clone(SOURCE);
source.setName("source:" + source.getSourceId());
source.setWorkspaceId(source.getSourceId());
when(uuidSupplier.get()).thenReturn(source.getSourceId());
final SourceCoreConfig sourceCoreConfig = new SourceCoreConfig()
.sourceDefinitionId(source.getSourceDefinitionId())
.connectionConfiguration(source.getConfiguration());
when(configRepository.getStandardSourceDefinition(source.getSourceDefinitionId()))
.thenReturn(new StandardSourceDefinition()
.withDockerRepository(SOURCE_DOCKER_REPO)
.withDockerImageTag(SOURCE_DOCKER_TAG)
.withSourceDefinitionId(source.getSourceDefinitionId()));
when(schedulerJobClient.createSourceCheckConnectionJob(source, SOURCE_DOCKER_IMAGE)).thenReturn(completedJob);
schedulerHandler.checkSourceConnectionFromSourceCreate(sourceCoreConfig);
verify(schedulerJobClient).createSourceCheckConnectionJob(source, SOURCE_DOCKER_IMAGE);
}
@Test
void testGetSourceSpec() throws JsonValidationException, IOException, ConfigNotFoundException, URISyntaxException {
final SourceDefinitionIdRequestBody sourceDefinitionIdRequestBody = new SourceDefinitionIdRequestBody().sourceDefinitionId(UUID.randomUUID());
@@ -191,7 +242,7 @@ class SchedulerHandlerTest {
}
@Test
void testCheckDestinationConnection() throws IOException, JsonValidationException, ConfigNotFoundException {
void testCheckDestinationConnectionFromDestinationId() throws IOException, JsonValidationException, ConfigNotFoundException {
final DestinationConnection destination = DestinationHelpers.generateDestination(UUID.randomUUID());
final DestinationIdRequestBody request = new DestinationIdRequestBody().destinationId(destination.getDestinationId());
@@ -203,14 +254,38 @@ class SchedulerHandlerTest {
when(configRepository.getDestinationConnection(destination.getDestinationId())).thenReturn(destination);
when(schedulerJobClient.createDestinationCheckConnectionJob(destination, DESTINATION_DOCKER_IMAGE)).thenReturn(completedJob);
schedulerHandler.checkDestinationConnection(request);
schedulerHandler.checkDestinationConnectionFromDestinationId(request);
verify(configRepository).getDestinationConnection(destination.getDestinationId());
verify(schedulerJobClient).createDestinationCheckConnectionJob(destination, DESTINATION_DOCKER_IMAGE);
}
@Test
void testDiscoverSchemaForSource() throws IOException, JsonValidationException, ConfigNotFoundException {
void testCheckSourceConnectionFromDestinationCreate() throws JsonValidationException, IOException, ConfigNotFoundException {
final DestinationConnection destination = Jsons.clone(DESTINATION);
destination.setName("destination:" + destination.getDestinationId());
destination.setWorkspaceId(destination.getDestinationId());
when(uuidSupplier.get()).thenReturn(destination.getDestinationId());
final DestinationCoreConfig destinationCoreConfig = new DestinationCoreConfig()
.destinationDefinitionId(destination.getDestinationDefinitionId())
.connectionConfiguration(destination.getConfiguration());
when(configRepository.getStandardDestinationDefinition(destination.getDestinationDefinitionId()))
.thenReturn(new StandardDestinationDefinition()
.withDockerRepository(DESTINATION_DOCKER_REPO)
.withDockerImageTag(DESTINATION_DOCKER_TAG)
.withDestinationDefinitionId(destination.getDestinationDefinitionId()));
when(schedulerJobClient.createDestinationCheckConnectionJob(destination, DESTINATION_DOCKER_IMAGE)).thenReturn(completedJob);
schedulerHandler.checkDestinationConnectionFromDestinationCreate(destinationCoreConfig);
verify(schedulerJobClient).createDestinationCheckConnectionJob(destination, DESTINATION_DOCKER_IMAGE);
}
@Test
void testDiscoverSchemaForSourceFromSourceId() throws IOException, JsonValidationException, ConfigNotFoundException {
final SourceConnection source = SourceHelpers.generateSource(UUID.randomUUID());
final SourceIdRequestBody request = new SourceIdRequestBody().sourceId(source.getSourceId());
@@ -226,12 +301,39 @@ class SchedulerHandlerTest {
.withCatalog(CatalogHelpers.createAirbyteCatalog("shoes", Field.of("sku", JsonSchemaPrimitive.STRING))));
when(completedJob.getSuccessOutput()).thenReturn(Optional.of(jobOutput));
schedulerHandler.discoverSchemaForSource(request);
schedulerHandler.discoverSchemaForSourceFromSourceId(request);
verify(configRepository).getSourceConnection(source.getSourceId());
verify(schedulerJobClient).createDiscoverSchemaJob(source, SOURCE_DOCKER_IMAGE);
}
@Test
void testDiscoverSchemaForSourceFromSourceCreate() throws JsonValidationException, IOException, ConfigNotFoundException {
final SourceConnection source = Jsons.clone(SOURCE);
source.setName("source:" + source.getSourceId());
source.setWorkspaceId(source.getSourceId());
when(uuidSupplier.get()).thenReturn(source.getSourceId());
final JobOutput jobOutput = mock(JobOutput.class);
when(completedJob.getSuccessOutput()).thenReturn(Optional.of(jobOutput));
when(jobOutput.getDiscoverCatalog()).thenReturn(new StandardDiscoverCatalogOutput().withCatalog(new AirbyteCatalog()));
final SourceCoreConfig sourceCoreConfig = new SourceCoreConfig()
.sourceDefinitionId(source.getSourceDefinitionId())
.connectionConfiguration(source.getConfiguration());
when(configRepository.getStandardSourceDefinition(source.getSourceDefinitionId()))
.thenReturn(new StandardSourceDefinition()
.withDockerRepository(SOURCE_DOCKER_REPO)
.withDockerImageTag(SOURCE_DOCKER_TAG)
.withSourceDefinitionId(source.getSourceDefinitionId()));
when(schedulerJobClient.createDiscoverSchemaJob(source, SOURCE_DOCKER_IMAGE)).thenReturn(completedJob);
schedulerHandler.discoverSchemaForSourceFromSourceCreate(sourceCoreConfig);
verify(schedulerJobClient).createDiscoverSchemaJob(source, SOURCE_DOCKER_IMAGE);
}
@Test
void testSyncConnection() throws JsonValidationException, IOException, ConfigNotFoundException {
final StandardSync standardSync = ConnectionHelpers.generateSyncWithSourceId(UUID.randomUUID());

View File

@@ -88,7 +88,7 @@ public class WebBackendDestinationHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.SUCCEEDED);
when(schedulerHandler.checkDestinationConnection(destinationIdRequestBody)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkDestinationConnectionFromDestinationId(destinationIdRequestBody)).thenReturn(checkConnectionRead);
DestinationRead returnedDestination =
wbDestinationHandler.webBackendCreateDestinationAndCheck(destinationCreate);
@@ -113,7 +113,7 @@ public class WebBackendDestinationHandlerTest {
DestinationIdRequestBody destinationIdRequestBody = new DestinationIdRequestBody();
destinationIdRequestBody.setDestinationId(destinationRead.getDestinationId());
when(schedulerHandler.checkDestinationConnection(destinationIdRequestBody)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkDestinationConnectionFromDestinationId(destinationIdRequestBody)).thenReturn(checkConnectionRead);
Assertions.assertThrows(KnownException.class,
() -> wbDestinationHandler.webBackendCreateDestinationAndCheck(destinationCreate));
@@ -141,7 +141,7 @@ public class WebBackendDestinationHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.SUCCEEDED);
when(schedulerHandler.checkDestinationConnection(newDestinationId)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkDestinationConnectionFromDestinationId(newDestinationId)).thenReturn(checkConnectionRead);
DestinationRecreate destinationRecreate = new DestinationRecreate();
destinationRecreate.setName(destinationRead.getName());
@@ -179,7 +179,7 @@ public class WebBackendDestinationHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.FAILED);
when(schedulerHandler.checkDestinationConnection(newDestinationId)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkDestinationConnectionFromDestinationId(newDestinationId)).thenReturn(checkConnectionRead);
DestinationRecreate destinationRecreate = new DestinationRecreate();
destinationRecreate.setName(destinationRead.getName());

View File

@@ -86,7 +86,7 @@ public class WebBackendSourceHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.SUCCEEDED);
when(schedulerHandler.checkSourceConnection(sourceIdRequestBody)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody)).thenReturn(checkConnectionRead);
SourceRead returnedSource = wbSourceHandler.webBackendCreateSourceAndCheck(sourceCreate);
@@ -107,7 +107,7 @@ public class WebBackendSourceHandlerTest {
SourceIdRequestBody sourceIdRequestBody = new SourceIdRequestBody();
sourceIdRequestBody.setSourceId(sourceRead.getSourceId());
when(schedulerHandler.checkSourceConnection(sourceIdRequestBody)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkSourceConnectionFromSourceId(sourceIdRequestBody)).thenReturn(checkConnectionRead);
Assertions.assertThrows(KnownException.class,
() -> wbSourceHandler.webBackendCreateSourceAndCheck(sourceCreate));
@@ -134,7 +134,7 @@ public class WebBackendSourceHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.SUCCEEDED);
when(schedulerHandler.checkSourceConnection(newSourceId)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkSourceConnectionFromSourceId(newSourceId)).thenReturn(checkConnectionRead);
SourceRecreate sourceRecreate = new SourceRecreate();
sourceRecreate.setName(sourceRead.getName());
@@ -172,7 +172,7 @@ public class WebBackendSourceHandlerTest {
CheckConnectionRead checkConnectionRead = new CheckConnectionRead();
checkConnectionRead.setStatus(StatusEnum.FAILED);
when(schedulerHandler.checkSourceConnection(newSourceId)).thenReturn(checkConnectionRead);
when(schedulerHandler.checkSourceConnectionFromSourceId(newSourceId)).thenReturn(checkConnectionRead);
SourceRecreate sourceRecreate = new SourceRecreate();
sourceRecreate.setName(sourceRead.getName());

View File

@@ -261,6 +261,12 @@ font-style: italic;
<li><a href="#getJobInfo"><code><span class="http-method">post</span> /v1/jobs/get</code></a></li>
<li><a href="#listJobsFor"><code><span class="http-method">post</span> /v1/jobs/list</code></a></li>
</ul>
<h4><a href="#Scheduler">Scheduler</a></h4>
<ul>
<li><a href="#executeDestinationCheckConnection"><code><span class="http-method">post</span> /v1/scheduler/destinations/check_connection</code></a></li>
<li><a href="#executeSourceCheckConnection"><code><span class="http-method">post</span> /v1/scheduler/sources/check_connection</code></a></li>
<li><a href="#executeSourceDiscoverSchema"><code><span class="http-method">post</span> /v1/scheduler/sources/discover_schema</code></a></li>
</ul>
<h4><a href="#Source">Source</a></h4>
<ul>
<li><a href="#checkConnectionToSource"><code><span class="http-method">post</span> /v1/sources/check_connection</code></a></li>
@@ -1048,6 +1054,39 @@ font-style: italic;
<h3 class="field-label">Example data</h3>
<div class="example-data-content-type">Content-Type: application/json</div>
<pre class="example"><code>{
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
},
"message" : "message",
"status" : "succeeded"
}</code></pre>
@@ -1914,6 +1953,309 @@ font-style: italic;
<a href="#"></a>
</div> <!-- method -->
<hr/>
<h1><a name="Scheduler">Scheduler</a></h1>
<div class="method"><a name="executeDestinationCheckConnection"/>
<div class="method-path">
<a class="up" href="#__Methods">Up</a>
<pre class="post"><code class="huge"><span class="http-method">post</span> /v1/scheduler/destinations/check_connection</code></pre></div>
<div class="method-summary">Run check connection for a given destination configuration (<span class="nickname">executeDestinationCheckConnection</span>)</div>
<div class="method-notes"></div>
<h3 class="field-label">Consumes</h3>
This API call consumes the following media types via the <span class="header">Content-Type</span> request header:
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Request body</h3>
<div class="field-items">
<div class="param">DestinationCoreConfig <a href="#DestinationCoreConfig">DestinationCoreConfig</a> (required)</div>
<div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; </div>
</div> <!-- field-items -->
<h3 class="field-label">Return type</h3>
<div class="return-type">
<a href="#CheckConnectionRead">CheckConnectionRead</a>
</div>
<!--Todo: process Response Object and its headers, schema, examples -->
<h3 class="field-label">Example data</h3>
<div class="example-data-content-type">Content-Type: application/json</div>
<pre class="example"><code>{
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
},
"message" : "message",
"status" : "succeeded"
}</code></pre>
<h3 class="field-label">Produces</h3>
This API call produces the following media types according to the <span class="header">Accept</span> request header;
the media type will be conveyed by the <span class="header">Content-Type</span> response header.
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Responses</h3>
<h4 class="field-label">200</h4>
Successful operation
<a href="#CheckConnectionRead">CheckConnectionRead</a>
<h4 class="field-label">422</h4>
Invalid Input
<a href="#"></a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="executeSourceCheckConnection"/>
<div class="method-path">
<a class="up" href="#__Methods">Up</a>
<pre class="post"><code class="huge"><span class="http-method">post</span> /v1/scheduler/sources/check_connection</code></pre></div>
<div class="method-summary">Run check connection for a given source configuration (<span class="nickname">executeSourceCheckConnection</span>)</div>
<div class="method-notes"></div>
<h3 class="field-label">Consumes</h3>
This API call consumes the following media types via the <span class="header">Content-Type</span> request header:
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Request body</h3>
<div class="field-items">
<div class="param">SourceCoreConfig <a href="#SourceCoreConfig">SourceCoreConfig</a> (required)</div>
<div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; </div>
</div> <!-- field-items -->
<h3 class="field-label">Return type</h3>
<div class="return-type">
<a href="#CheckConnectionRead">CheckConnectionRead</a>
</div>
<!--Todo: process Response Object and its headers, schema, examples -->
<h3 class="field-label">Example data</h3>
<div class="example-data-content-type">Content-Type: application/json</div>
<pre class="example"><code>{
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
},
"message" : "message",
"status" : "succeeded"
}</code></pre>
<h3 class="field-label">Produces</h3>
This API call produces the following media types according to the <span class="header">Accept</span> request header;
the media type will be conveyed by the <span class="header">Content-Type</span> response header.
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Responses</h3>
<h4 class="field-label">200</h4>
Successful operation
<a href="#CheckConnectionRead">CheckConnectionRead</a>
<h4 class="field-label">422</h4>
Invalid Input
<a href="#"></a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="executeSourceDiscoverSchema"/>
<div class="method-path">
<a class="up" href="#__Methods">Up</a>
<pre class="post"><code class="huge"><span class="http-method">post</span> /v1/scheduler/sources/discover_schema</code></pre></div>
<div class="method-summary">Run discover schema for a given source a source configuration (<span class="nickname">executeSourceDiscoverSchema</span>)</div>
<div class="method-notes"></div>
<h3 class="field-label">Consumes</h3>
This API call consumes the following media types via the <span class="header">Content-Type</span> request header:
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Request body</h3>
<div class="field-items">
<div class="param">SourceCoreConfig <a href="#SourceCoreConfig">SourceCoreConfig</a> (required)</div>
<div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; </div>
</div> <!-- field-items -->
<h3 class="field-label">Return type</h3>
<div class="return-type">
<a href="#SourceDiscoverSchemaRead">SourceDiscoverSchemaRead</a>
</div>
<!--Todo: process Response Object and its headers, schema, examples -->
<h3 class="field-label">Example data</h3>
<div class="example-data-content-type">Content-Type: application/json</div>
<pre class="example"><code>{
"schema" : {
"streams" : [ {
"supportedSyncModes" : [ null, null ],
"sourceDefinedCursor" : true,
"name" : "name",
"cleanedName" : "cleanedName",
"defaultCursorField" : [ "defaultCursorField", "defaultCursorField" ],
"fields" : [ {
"name" : "name",
"cleanedName" : "cleanedName",
"selected" : true
}, {
"name" : "name",
"cleanedName" : "cleanedName",
"selected" : true
} ],
"selected" : true,
"cursorField" : [ "cursorField", "cursorField" ]
}, {
"supportedSyncModes" : [ null, null ],
"sourceDefinedCursor" : true,
"name" : "name",
"cleanedName" : "cleanedName",
"defaultCursorField" : [ "defaultCursorField", "defaultCursorField" ],
"fields" : [ {
"name" : "name",
"cleanedName" : "cleanedName",
"selected" : true
}, {
"name" : "name",
"cleanedName" : "cleanedName",
"selected" : true
} ],
"selected" : true,
"cursorField" : [ "cursorField", "cursorField" ]
} ]
},
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
}
}</code></pre>
<h3 class="field-label">Produces</h3>
This API call produces the following media types according to the <span class="header">Accept</span> request header;
the media type will be conveyed by the <span class="header">Content-Type</span> response header.
<ul>
<li><code>application/json</code></li>
</ul>
<h3 class="field-label">Responses</h3>
<h4 class="field-label">200</h4>
Successful operation
<a href="#SourceDiscoverSchemaRead">SourceDiscoverSchemaRead</a>
<h4 class="field-label">422</h4>
Invalid Input
<a href="#"></a>
</div> <!-- method -->
<hr/>
<h1><a name="Source">Source</a></h1>
<div class="method"><a name="checkConnectionToSource"/>
<div class="method-path">
@@ -1951,6 +2293,39 @@ font-style: italic;
<h3 class="field-label">Example data</h3>
<div class="example-data-content-type">Content-Type: application/json</div>
<pre class="example"><code>{
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
},
"message" : "message",
"status" : "succeeded"
}</code></pre>
@@ -2150,6 +2525,39 @@ font-style: italic;
"selected" : true,
"cursorField" : [ "cursorField", "cursorField" ]
} ]
},
"job_info" : {
"job" : {
"createdAt" : 6,
"configId" : "configId",
"id" : 0,
"updatedAt" : 1
},
"attempts" : [ {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
}, {
"attempt" : {
"createdAt" : 5,
"bytesSynced" : 9,
"endedAt" : 7,
"id" : 5,
"recordsSynced" : 3,
"updatedAt" : 2
},
"logs" : {
"logLines" : [ "logLines", "logLines" ]
}
} ]
}
}</code></pre>
@@ -3455,6 +3863,7 @@ font-style: italic;
<li><a href="#ConnectionUpdate"><code>ConnectionUpdate</code> - </a></li>
<li><a href="#DataType"><code>DataType</code> - </a></li>
<li><a href="#DebugRead"><code>DebugRead</code> - </a></li>
<li><a href="#DestinationCoreConfig"><code>DestinationCoreConfig</code> - </a></li>
<li><a href="#DestinationCreate"><code>DestinationCreate</code> - </a></li>
<li><a href="#DestinationDefinitionCreate"><code>DestinationDefinitionCreate</code> - </a></li>
<li><a href="#DestinationDefinitionIdRequestBody"><code>DestinationDefinitionIdRequestBody</code> - </a></li>
@@ -3478,7 +3887,9 @@ font-style: italic;
<li><a href="#JobWithAttemptsRead"><code>JobWithAttemptsRead</code> - </a></li>
<li><a href="#LogRead"><code>LogRead</code> - </a></li>
<li><a href="#SlugRequestBody"><code>SlugRequestBody</code> - </a></li>
<li><a href="#SourceCoreConfig"><code>SourceCoreConfig</code> - </a></li>
<li><a href="#SourceCreate"><code>SourceCreate</code> - </a></li>
<li><a href="#SourceCreate_allOf"><code>SourceCreate_allOf</code> - </a></li>
<li><a href="#SourceDefinitionCreate"><code>SourceDefinitionCreate</code> - </a></li>
<li><a href="#SourceDefinitionIdRequestBody"><code>SourceDefinitionIdRequestBody</code> - </a></li>
<li><a href="#SourceDefinitionRead"><code>SourceDefinitionRead</code> - </a></li>
@@ -3537,6 +3948,7 @@ font-style: italic;
<div class="param-enum-header">Enum:</div>
<div class="param-enum">succeeded</div><div class="param-enum">failed</div>
<div class="param">message (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">job_info (optional)</div><div class="param-desc"><span class="param-type"><a href="#JobInfoRead">JobInfoRead</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
@@ -3619,14 +4031,22 @@ font-style: italic;
<div class="param">info </div><div class="param-desc"><span class="param-type"><a href="#">Object</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="DestinationCoreConfig"><code>DestinationCoreConfig</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">destinationDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">connectionConfiguration </div><div class="param-desc"><span class="param-type"><a href="#DestinationConfiguration">DestinationConfiguration</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="DestinationCreate"><code>DestinationCreate</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">destinationDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">destinationDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">connectionConfiguration </div><div class="param-desc"><span class="param-type"><a href="#DestinationConfiguration">DestinationConfiguration</a></span> </div>
<div class="param">name (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
@@ -3810,13 +4230,29 @@ font-style: italic;
<div class="param">slug </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="SourceCoreConfig"><code>SourceCoreConfig</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">sourceDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">connectionConfiguration </div><div class="param-desc"><span class="param-type"><a href="#SourceConfiguration">SourceConfiguration</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="SourceCreate"><code>SourceCreate</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">sourceDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">sourceDefinitionId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">connectionConfiguration </div><div class="param-desc"><span class="param-type"><a href="#SourceConfiguration">SourceConfiguration</a></span> </div>
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="SourceCreate_allOf"><code>SourceCreate_allOf</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">workspaceId </div><div class="param-desc"><span class="param-type"><a href="#UUID">UUID</a></span> format: uuid</div>
<div class="param">name </div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
</div> <!-- field-items -->
</div>
@@ -3877,6 +4313,7 @@ font-style: italic;
<div class='model-description'></div>
<div class="field-items">
<div class="param">schema </div><div class="param-desc"><span class="param-type"><a href="#SourceSchema">SourceSchema</a></span> </div>
<div class="param">job_info </div><div class="param-desc"><span class="param-type"><a href="#JobInfoRead">JobInfoRead</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">