Browse Source

KAFKA-13780: Generate OpenAPI file for Connect REST API (#12067)

New gradle task `connect:runtime:genConnectOpenAPIDocs` that generates `connect_rest.yaml` under `docs/generated`.
This task is executed when `siteDocsTar` runs.
pull/12283/head
Mickael Maison 2 years ago committed by GitHub
parent
commit
4a06458633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      build.gradle
  2. 1
      checkstyle/import-control.xml
  3. 21
      connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResource.java
  4. 43
      connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java
  5. 4
      connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/LoggingResource.java
  6. 2
      connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/RootResource.java
  7. 2
      docs/connect.html
  8. 4
      gradle/dependencies.gradle
  9. 24
      gradle/openapi.template

25
build.gradle

@ -41,6 +41,7 @@ plugins {
id 'org.gradle.test-retry' version '1.3.1' apply false id 'org.gradle.test-retry' version '1.3.1' apply false
id 'org.scoverage' version '7.0.0' apply false id 'org.scoverage' version '7.0.0' apply false
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
id "io.swagger.core.v3.swagger-gradle-plugin" version "2.2.0"
} }
spotless { spotless {
@ -1033,7 +1034,7 @@ project(':core') {
':connect:runtime:genConnectPredicateDocs', ':connect:runtime:genConnectPredicateDocs',
':connect:runtime:genSinkConnectorConfigDocs', ':connect:runtime:genSourceConnectorConfigDocs', ':connect:runtime:genSinkConnectorConfigDocs', ':connect:runtime:genSourceConnectorConfigDocs',
':streams:genStreamsConfigDocs', 'genConsumerMetricsDocs', 'genProducerMetricsDocs', ':streams:genStreamsConfigDocs', 'genConsumerMetricsDocs', 'genProducerMetricsDocs',
':connect:runtime:genConnectMetricsDocs'], type: Tar) { ':connect:runtime:genConnectMetricsDocs', ':connect:runtime:genConnectOpenAPIDocs'], type: Tar) {
archiveClassifier = 'site-docs' archiveClassifier = 'site-docs'
compression = Compression.GZIP compression = Compression.GZIP
from project.file("$rootDir/docs") from project.file("$rootDir/docs")
@ -2518,6 +2519,8 @@ project(':connect:runtime') {
implementation libs.jettyClient implementation libs.jettyClient
implementation libs.reflections implementation libs.reflections
implementation libs.mavenArtifact implementation libs.mavenArtifact
implementation libs.swaggerJaxrs2
implementation libs.swaggerAnnotations
testImplementation project(':clients').sourceSets.test.output testImplementation project(':clients').sourceSets.test.output
testImplementation project(':core') testImplementation project(':core')
@ -2598,6 +2601,26 @@ project(':connect:runtime') {
standardOutput = new File(generatedDocsDir, "connect_metrics.html").newOutputStream() standardOutput = new File(generatedDocsDir, "connect_metrics.html").newOutputStream()
} }
task setVersionInOpenAPISpec(type: Copy) {
from "$rootDir/gradle/openapi.template"
into "$buildDir/resources/docs"
rename ('openapi.template', 'openapi.yaml')
expand(kafkaVersion: "$rootProject.version")
}
task genConnectOpenAPIDocs(type: io.swagger.v3.plugins.gradle.tasks.ResolveTask, dependsOn: setVersionInOpenAPISpec) {
classpath = sourceSets.main.runtimeClasspath
buildClasspath = classpath
outputFileName = 'connect_rest'
outputFormat = 'YAML'
prettyPrint = 'TRUE'
sortOutput = 'TRUE'
openApiFile = file("$buildDir/resources/docs/openapi.yaml")
resourcePackages = ['org.apache.kafka.connect.runtime.rest.resources']
if( !generatedDocsDir.exists() ) { generatedDocsDir.mkdirs() }
outputDir = file(generatedDocsDir)
}
} }
project(':connect:file') { project(':connect:file') {

1
checkstyle/import-control.xml

@ -564,6 +564,7 @@
<allow pkg="org.glassfish.jersey" /> <allow pkg="org.glassfish.jersey" />
<allow pkg="com.fasterxml.jackson" /> <allow pkg="com.fasterxml.jackson" />
<allow pkg="org.apache.http"/> <allow pkg="org.apache.http"/>
<allow pkg="io.swagger.v3.oas.annotations"/>
<subpackage name="resources"> <subpackage name="resources">
<allow pkg="org.apache.log4j" /> <allow pkg="org.apache.log4j" />
</subpackage> </subpackage>

21
connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResource.java

@ -16,6 +16,8 @@
*/ */
package org.apache.kafka.connect.runtime.rest.resources; package org.apache.kafka.connect.runtime.rest.resources;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.ConnectorConfig;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.PredicatedTransformation; import org.apache.kafka.connect.runtime.PredicatedTransformation;
@ -102,17 +104,18 @@ public class ConnectorPluginsResource {
} }
@PUT @PUT
@Path("/{connectorType}/config/validate") @Path("/{pluginName}/config/validate")
@Operation(summary = "Validate the provided configuration against the configuration definition for the specified pluginName")
public ConfigInfos validateConfigs( public ConfigInfos validateConfigs(
final @PathParam("connectorType") String connType, final @PathParam("pluginName") String pluginName,
final Map<String, String> connectorConfig final Map<String, String> connectorConfig
) throws Throwable { ) throws Throwable {
String includedConnType = connectorConfig.get(ConnectorConfig.CONNECTOR_CLASS_CONFIG); String includedConnType = connectorConfig.get(ConnectorConfig.CONNECTOR_CLASS_CONFIG);
if (includedConnType != null if (includedConnType != null
&& !normalizedPluginName(includedConnType).endsWith(normalizedPluginName(connType))) { && !normalizedPluginName(includedConnType).endsWith(normalizedPluginName(pluginName))) {
throw new BadRequestException( throw new BadRequestException(
"Included connector type " + includedConnType + " does not match request type " "Included connector type " + includedConnType + " does not match request type "
+ connType + pluginName
); );
} }
@ -133,7 +136,10 @@ public class ConnectorPluginsResource {
@GET @GET
@Path("/") @Path("/")
public List<PluginInfo> listConnectorPlugins(@DefaultValue("true") @QueryParam("connectorsOnly") boolean connectorsOnly) { @Operation(summary = "List all connector plugins installed")
public List<PluginInfo> listConnectorPlugins(
@DefaultValue("true") @QueryParam("connectorsOnly") @Parameter(description = "Whether to list only connectors instead of all plugins") boolean connectorsOnly
) {
synchronized (this) { synchronized (this) {
if (connectorsOnly) { if (connectorsOnly) {
return Collections.unmodifiableList(connectorPlugins.stream() return Collections.unmodifiableList(connectorPlugins.stream()
@ -146,8 +152,9 @@ public class ConnectorPluginsResource {
} }
@GET @GET
@Path("/{name}/config") @Path("/{pluginName}/config")
public List<ConfigKeyInfo> getConnectorConfigDef(final @PathParam("name") String pluginName) { @Operation(summary = "Get the configuration definition for the specified pluginName")
public List<ConfigKeyInfo> getConnectorConfigDef(final @PathParam("pluginName") String pluginName) {
synchronized (this) { synchronized (this) {
return herder.connectorPluginConfig(pluginName); return herder.connectorPluginConfig(pluginName);
} }

43
connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java

@ -22,6 +22,8 @@ import javax.ws.rs.DefaultValue;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.errors.NotFoundException;
import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.ConnectorConfig;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
@ -113,6 +115,7 @@ public class ConnectorsResource {
@GET @GET
@Path("/") @Path("/")
@Operation(summary = "List all active connectors")
public Response listConnectors( public Response listConnectors(
final @Context UriInfo uriInfo, final @Context UriInfo uriInfo,
final @Context HttpHeaders headers final @Context HttpHeaders headers
@ -150,7 +153,8 @@ public class ConnectorsResource {
@POST @POST
@Path("/") @Path("/")
public Response createConnector(final @QueryParam("forward") Boolean forward, @Operation(summary = "Create a new connector")
public Response createConnector(final @Parameter(hidden = true) @QueryParam("forward") Boolean forward,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final CreateConnectorRequest createRequest) throws Throwable { final CreateConnectorRequest createRequest) throws Throwable {
// Trim leading and trailing whitespaces from the connector name, replace null with empty string // Trim leading and trailing whitespaces from the connector name, replace null with empty string
@ -172,9 +176,10 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}") @Path("/{connector}")
@Operation(summary = "Get the details for the specified connector")
public ConnectorInfo getConnector(final @PathParam("connector") String connector, public ConnectorInfo getConnector(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<ConnectorInfo> cb = new FutureCallback<>(); FutureCallback<ConnectorInfo> cb = new FutureCallback<>();
herder.connectorInfo(connector, cb); herder.connectorInfo(connector, cb);
return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward);
@ -182,9 +187,10 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}/config") @Path("/{connector}/config")
@Operation(summary = "Get the configuration for the specified connector")
public Map<String, String> getConnectorConfig(final @PathParam("connector") String connector, public Map<String, String> getConnectorConfig(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<Map<String, String>> cb = new FutureCallback<>(); FutureCallback<Map<String, String>> cb = new FutureCallback<>();
herder.connectorConfig(connector, cb); herder.connectorConfig(connector, cb);
return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward);
@ -192,10 +198,11 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}/tasks-config") @Path("/{connector}/tasks-config")
@Operation(summary = "Get the configuration of all tasks for the specified connector")
public Map<ConnectorTaskId, Map<String, String>> getTasksConfig( public Map<ConnectorTaskId, Map<String, String>> getTasksConfig(
final @PathParam("connector") String connector, final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<Map<ConnectorTaskId, Map<String, String>>> cb = new FutureCallback<>(); FutureCallback<Map<ConnectorTaskId, Map<String, String>>> cb = new FutureCallback<>();
herder.tasksConfig(connector, cb); herder.tasksConfig(connector, cb);
return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks-config", "GET", headers, null, forward); return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks-config", "GET", headers, null, forward);
@ -203,12 +210,14 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}/status") @Path("/{connector}/status")
@Operation(summary = "Get the status for the specified connector")
public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") String connector) { public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") String connector) {
return herder.connectorStatus(connector); return herder.connectorStatus(connector);
} }
@GET @GET
@Path("/{connector}/topics") @Path("/{connector}/topics")
@Operation(summary = "Get the list of topics actively used by the specified connector")
public Response getConnectorActiveTopics(final @PathParam("connector") String connector) { public Response getConnectorActiveTopics(final @PathParam("connector") String connector) {
if (isTopicTrackingDisabled) { if (isTopicTrackingDisabled) {
throw new ConnectRestException(Response.Status.FORBIDDEN.getStatusCode(), throw new ConnectRestException(Response.Status.FORBIDDEN.getStatusCode(),
@ -220,6 +229,7 @@ public class ConnectorsResource {
@PUT @PUT
@Path("/{connector}/topics/reset") @Path("/{connector}/topics/reset")
@Operation(summary = "Reset the list of topics actively used by the specified connector")
public Response resetConnectorActiveTopics(final @PathParam("connector") String connector, final @Context HttpHeaders headers) { public Response resetConnectorActiveTopics(final @PathParam("connector") String connector, final @Context HttpHeaders headers) {
if (isTopicTrackingDisabled) { if (isTopicTrackingDisabled) {
throw new ConnectRestException(Response.Status.FORBIDDEN.getStatusCode(), throw new ConnectRestException(Response.Status.FORBIDDEN.getStatusCode(),
@ -235,9 +245,10 @@ public class ConnectorsResource {
@PUT @PUT
@Path("/{connector}/config") @Path("/{connector}/config")
@Operation(summary = "Create or reconfigure the specified connector")
public Response putConnectorConfig(final @PathParam("connector") String connector, public Response putConnectorConfig(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward, final @Parameter(hidden = true) @QueryParam("forward") Boolean forward,
final Map<String, String> connectorConfig) throws Throwable { final Map<String, String> connectorConfig) throws Throwable {
FutureCallback<Herder.Created<ConnectorInfo>> cb = new FutureCallback<>(); FutureCallback<Herder.Created<ConnectorInfo>> cb = new FutureCallback<>();
checkAndPutConnectorConfigName(connector, connectorConfig); checkAndPutConnectorConfigName(connector, connectorConfig);
@ -257,11 +268,12 @@ public class ConnectorsResource {
@POST @POST
@Path("/{connector}/restart") @Path("/{connector}/restart")
@Operation(summary = "Restart the specified connector")
public Response restartConnector(final @PathParam("connector") String connector, public Response restartConnector(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @DefaultValue("false") @QueryParam("includeTasks") Boolean includeTasks, final @DefaultValue("false") @QueryParam("includeTasks") @Parameter(description = "Whether to also restart tasks") Boolean includeTasks,
final @DefaultValue("false") @QueryParam("onlyFailed") Boolean onlyFailed, final @DefaultValue("false") @QueryParam("onlyFailed") @Parameter(description = "Whether to only restart failed tasks/connectors")Boolean onlyFailed,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
RestartRequest restartRequest = new RestartRequest(connector, onlyFailed, includeTasks); RestartRequest restartRequest = new RestartRequest(connector, onlyFailed, includeTasks);
String forwardingPath = "/connectors/" + connector + "/restart"; String forwardingPath = "/connectors/" + connector + "/restart";
if (restartRequest.forceRestartConnectorOnly()) { if (restartRequest.forceRestartConnectorOnly()) {
@ -285,6 +297,8 @@ public class ConnectorsResource {
@PUT @PUT
@Path("/{connector}/pause") @Path("/{connector}/pause")
@Operation(summary = "Pause the specified connector",
description = "This operation is idempotent and has no effects if the connector is already paused")
public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) {
herder.pauseConnector(connector); herder.pauseConnector(connector);
return Response.accepted().build(); return Response.accepted().build();
@ -292,6 +306,8 @@ public class ConnectorsResource {
@PUT @PUT
@Path("/{connector}/resume") @Path("/{connector}/resume")
@Operation(summary = "Resume the specified connector",
description = "This operation is idempotent and has no effects if the connector is already running")
public Response resumeConnector(@PathParam("connector") String connector) { public Response resumeConnector(@PathParam("connector") String connector) {
herder.resumeConnector(connector); herder.resumeConnector(connector);
return Response.accepted().build(); return Response.accepted().build();
@ -299,9 +315,10 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}/tasks") @Path("/{connector}/tasks")
@Operation(summary = "List all tasks for the specified connector")
public List<TaskInfo> getTaskConfigs(final @PathParam("connector") String connector, public List<TaskInfo> getTaskConfigs(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<List<TaskInfo>> cb = new FutureCallback<>(); FutureCallback<List<TaskInfo>> cb = new FutureCallback<>();
herder.taskConfigs(connector, cb); herder.taskConfigs(connector, cb);
return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference<List<TaskInfo>>() { return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference<List<TaskInfo>>() {
@ -310,6 +327,7 @@ public class ConnectorsResource {
@POST @POST
@Path("/{connector}/tasks") @Path("/{connector}/tasks")
@Operation(hidden = true, summary = "This operation is only for inter-worker communications")
public void putTaskConfigs(final @PathParam("connector") String connector, public void putTaskConfigs(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward, final @QueryParam("forward") Boolean forward,
@ -322,6 +340,7 @@ public class ConnectorsResource {
@GET @GET
@Path("/{connector}/tasks/{task}/status") @Path("/{connector}/tasks/{task}/status")
@Operation(summary = "Get the state of the specified task for the specified connector")
public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @PathParam("task") Integer task) { final @PathParam("task") Integer task) {
@ -330,10 +349,11 @@ public class ConnectorsResource {
@POST @POST
@Path("/{connector}/tasks/{task}/restart") @Path("/{connector}/tasks/{task}/restart")
@Operation(summary = "Restart the specified task for the specified connector")
public void restartTask(final @PathParam("connector") String connector, public void restartTask(final @PathParam("connector") String connector,
final @PathParam("task") Integer task, final @PathParam("task") Integer task,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<Void> cb = new FutureCallback<>(); FutureCallback<Void> cb = new FutureCallback<>();
ConnectorTaskId taskId = new ConnectorTaskId(connector, task); ConnectorTaskId taskId = new ConnectorTaskId(connector, task);
herder.restartTask(taskId, cb); herder.restartTask(taskId, cb);
@ -342,9 +362,10 @@ public class ConnectorsResource {
@DELETE @DELETE
@Path("/{connector}") @Path("/{connector}")
@Operation(summary = "Delete the specified connector")
public void destroyConnector(final @PathParam("connector") String connector, public void destroyConnector(final @PathParam("connector") String connector,
final @Context HttpHeaders headers, final @Context HttpHeaders headers,
final @QueryParam("forward") Boolean forward) throws Throwable { final @Parameter(hidden = true) @QueryParam("forward") Boolean forward) throws Throwable {
FutureCallback<Herder.Created<ConnectorInfo>> cb = new FutureCallback<>(); FutureCallback<Herder.Created<ConnectorInfo>> cb = new FutureCallback<>();
herder.deleteConnectorConfig(connector, cb); herder.deleteConnectorConfig(connector, cb);
completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward);

4
connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/LoggingResource.java

@ -16,6 +16,7 @@
*/ */
package org.apache.kafka.connect.runtime.rest.resources; package org.apache.kafka.connect.runtime.rest.resources;
import io.swagger.v3.oas.annotations.Operation;
import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.errors.NotFoundException;
import org.apache.kafka.connect.runtime.rest.errors.BadRequestException; import org.apache.kafka.connect.runtime.rest.errors.BadRequestException;
import org.apache.log4j.Level; import org.apache.log4j.Level;
@ -59,6 +60,7 @@ public class LoggingResource {
*/ */
@GET @GET
@Path("/") @Path("/")
@Operation(summary = "List the current loggers that have their levels explicitly set and their log levels")
public Response listLoggers() { public Response listLoggers() {
Map<String, Map<String, String>> loggers = new TreeMap<>(); Map<String, Map<String, String>> loggers = new TreeMap<>();
Enumeration<Logger> enumeration = currentLoggers(); Enumeration<Logger> enumeration = currentLoggers();
@ -83,6 +85,7 @@ public class LoggingResource {
*/ */
@GET @GET
@Path("/{logger}") @Path("/{logger}")
@Operation(summary = "Get the log level for the specified logger")
public Response getLogger(final @PathParam("logger") String namedLogger) { public Response getLogger(final @PathParam("logger") String namedLogger) {
Objects.requireNonNull(namedLogger, "require non-null name"); Objects.requireNonNull(namedLogger, "require non-null name");
@ -120,6 +123,7 @@ public class LoggingResource {
*/ */
@PUT @PUT
@Path("/{logger}") @Path("/{logger}")
@Operation(summary = "Set the level for the specified logger")
public Response setLevel(final @PathParam("logger") String namedLogger, public Response setLevel(final @PathParam("logger") String namedLogger,
final Map<String, String> levelMap) { final Map<String, String> levelMap) {
String desiredLevelStr = levelMap.get("level"); String desiredLevelStr = levelMap.get("level");

2
connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/RootResource.java

@ -16,6 +16,7 @@
*/ */
package org.apache.kafka.connect.runtime.rest.resources; package org.apache.kafka.connect.runtime.rest.resources;
import io.swagger.v3.oas.annotations.Operation;
import org.apache.kafka.connect.runtime.Herder; import org.apache.kafka.connect.runtime.Herder;
import org.apache.kafka.connect.runtime.rest.entities.ServerInfo; import org.apache.kafka.connect.runtime.rest.entities.ServerInfo;
@ -36,6 +37,7 @@ public class RootResource {
@GET @GET
@Path("/") @Path("/")
@Operation(summary = "Get details about this Connect worker and the id of the Kafka cluster it is connected to")
public ServerInfo serverInfo() { public ServerInfo serverInfo() {
return new ServerInfo(herder.kafkaClusterId()); return new ServerInfo(herder.kafkaClusterId());
} }

2
docs/connect.html

@ -327,6 +327,8 @@ listeners=http://localhost:8080,https://localhost:8443</pre>
<li><code>GET /</code>- return basic information about the Kafka Connect cluster such as the version of the Connect worker that serves the REST request (including git commit ID of the source code) and the Kafka cluster ID that is connected to. <li><code>GET /</code>- return basic information about the Kafka Connect cluster such as the version of the Connect worker that serves the REST request (including git commit ID of the source code) and the Kafka cluster ID that is connected to.
</ul> </ul>
<p>For the complete specification of the REST API, see the <a href="generated/connect_rest.yaml">OpenAPI documentation</a></p>
<h4><a id="connect_errorreporting" href="#connect_errorreporting">Error Reporting in Connect</a></h4> <h4><a id="connect_errorreporting" href="#connect_errorreporting">Error Reporting in Connect</a></h4>
<p>Kafka Connect provides error reporting to handle errors encountered along various stages of processing. By default, any error encountered during conversion or within transformations will cause the connector to fail. Each connector configuration can also enable tolerating such errors by skipping them, optionally writing each error and the details of the failed operation and problematic record (with various levels of detail) to the Connect application log. These mechanisms also capture errors when a sink connector is processing the messages consumed from its Kafka topics, and all of the errors can be written to a configurable "dead letter queue" (DLQ) Kafka topic.</p> <p>Kafka Connect provides error reporting to handle errors encountered along various stages of processing. By default, any error encountered during conversion or within transformations will cause the connector to fail. Each connector configuration can also enable tolerating such errors by skipping them, optionally writing each error and the details of the failed operation and problematic record (with various levels of detail) to the Connect application log. These mechanisms also capture errors when a sink connector is processing the messages consumed from its Kafka topics, and all of the errors can be written to a configurable "dead letter queue" (DLQ) Kafka topic.</p>

4
gradle/dependencies.gradle

@ -117,6 +117,8 @@ versions += [
slf4j: "1.7.36", slf4j: "1.7.36",
snappy: "1.1.8.4", snappy: "1.1.8.4",
spotbugs: "4.2.2", spotbugs: "4.2.2",
swaggerAnnotations: "2.2.0",
swaggerJaxrs2: "2.2.0",
zinc: "1.3.5", zinc: "1.3.5",
zookeeper: "3.6.3", zookeeper: "3.6.3",
zstd: "1.5.2-1" zstd: "1.5.2-1"
@ -200,6 +202,8 @@ libs += [
slf4jApi: "org.slf4j:slf4j-api:$versions.slf4j", slf4jApi: "org.slf4j:slf4j-api:$versions.slf4j",
slf4jlog4j: "org.slf4j:slf4j-log4j12:$versions.slf4j", slf4jlog4j: "org.slf4j:slf4j-log4j12:$versions.slf4j",
snappy: "org.xerial.snappy:snappy-java:$versions.snappy", snappy: "org.xerial.snappy:snappy-java:$versions.snappy",
swaggerAnnotations: "io.swagger.core.v3:swagger-annotations:$versions.swaggerAnnotations",
swaggerJaxrs2: "io.swagger.core.v3:swagger-jaxrs2:$versions.swaggerJaxrs2",
zookeeper: "org.apache.zookeeper:zookeeper:$versions.zookeeper", zookeeper: "org.apache.zookeeper:zookeeper:$versions.zookeeper",
jfreechart: "jfreechart:jfreechart:$versions.jfreechart", jfreechart: "jfreechart:jfreechart:$versions.jfreechart",
mavenArtifact: "org.apache.maven:maven-artifact:$versions.mavenArtifact", mavenArtifact: "org.apache.maven:maven-artifact:$versions.mavenArtifact",

24
gradle/openapi.template

@ -0,0 +1,24 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
openapi: 3.0.0
info:
version: $kafkaVersion
title: Kafka Connect REST API
description: "This is the documentation of the [Apache Kafka](https://kafka.apache.org) Connect REST API."
contact:
email: dev@kafka.apache.org
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
Loading…
Cancel
Save