-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-15031: Add plugin.discovery to Connect worker configuration (KIP-898) #14055
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
Changes from 5 commits
9b26287
2a0f702
c92cb3d
266c39f
28e0f50
da71b8d
346e23c
436f595
22cbcd0
e0ccb0c
228ea45
fd2f693
7d65156
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.storage.StringConverter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.storage.SimpleHeaderConverter | ||
| org.apache.kafka.connect.storage.StringConverter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.sink.SinkConnectorTest$TestSinkConnector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.source.SourceConnectorTest$TestSourceConnector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.file.FileStreamSinkConnector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.file.FileStreamSourceConnector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.json.JsonConverter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.json.JsonConverter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.mirror.MirrorCheckpointConnector | ||
| org.apache.kafka.connect.mirror.MirrorHeartbeatConnector | ||
| org.apache.kafka.connect.mirror.MirrorSourceConnector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
| package org.apache.kafka.connect.runtime.isolation; | ||
|
|
||
| /** | ||
| * Method to use to discover plugins usable on a Connect worker. | ||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||
| */ | ||
| public enum PluginDiscoveryMode { | ||
|
|
||
| /** | ||
| * Scan for plugins reflectively. This corresponds to the legacy behavior of Connect prior to KIP-898. | ||
| * <p>Note: the following plugins are still loaded using {@link java.util.ServiceLoader} in this mode: | ||
| * <ul> | ||
| * <li>{@link org.apache.kafka.common.config.provider.ConfigProvider}</li> | ||
| * <li>{@link org.apache.kafka.connect.rest.ConnectRestExtension}</li> | ||
| * <li>{@link org.apache.kafka.connect.connector.policy.ConnectorClientConfigOverridePolicy}</li> | ||
| * </ul> | ||
| */ | ||
| ONLY_SCAN, | ||
| /** | ||
| * Scan for plugins reflectively and via {@link java.util.ServiceLoader}. | ||
| * Emit warnings if one or more plugins is not available via {@link java.util.ServiceLoader} | ||
| */ | ||
| HYBRID_WARN, | ||
| /** | ||
| * Scan for plugins reflectively and via {@link java.util.ServiceLoader}. | ||
| * Fail worker during startup if one or more plugins is not available via {@link java.util.ServiceLoader} | ||
| */ | ||
| HYBRID_FAIL, | ||
| /** | ||
| * Discover plugins via {@link java.util.ServiceLoader} only. | ||
| * Plugins will not be present in the REST API if it is not available via {@link java.util.ServiceLoader} | ||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||
| */ | ||
| SERVICE_LOAD; | ||
|
|
||
| public static boolean reflectivelyScan(PluginDiscoveryMode pluginDiscoveryMode) { | ||
| return pluginDiscoveryMode != SERVICE_LOAD; | ||
| } | ||
|
|
||
| public static boolean serviceLoad(PluginDiscoveryMode pluginDiscoveryMode) { | ||
| return pluginDiscoveryMode != ONLY_SCAN; | ||
| } | ||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -39,11 +39,15 @@ | |||||
|
|
||||||
| import java.nio.file.Path; | ||||||
| import java.util.ArrayList; | ||||||
| import java.util.Arrays; | ||||||
| import java.util.Collection; | ||||||
| import java.util.Collections; | ||||||
| import java.util.List; | ||||||
| import java.util.Map; | ||||||
| import java.util.Set; | ||||||
| import java.util.SortedSet; | ||||||
| import java.util.TreeSet; | ||||||
| import java.util.stream.Collectors; | ||||||
|
|
||||||
| public class Plugins { | ||||||
|
|
||||||
|
|
@@ -63,16 +67,72 @@ public Plugins(Map<String, String> props) { | |||||
| // VisibleForTesting | ||||||
| Plugins(Map<String, String> props, ClassLoader parent, ClassLoaderFactory factory) { | ||||||
| String pluginPath = WorkerConfig.pluginPath(props); | ||||||
| PluginDiscoveryMode discoveryMode = WorkerConfig.pluginDiscovery(props); | ||||||
| List<Path> pluginLocations = PluginUtils.pluginLocations(pluginPath); | ||||||
| delegatingLoader = factory.newDelegatingClassLoader(parent); | ||||||
| Set<PluginSource> pluginSources = PluginUtils.pluginSources(pluginLocations, delegatingLoader, factory); | ||||||
| scanResult = initLoaders(pluginSources); | ||||||
| scanResult = initLoaders(pluginSources, discoveryMode); | ||||||
| } | ||||||
|
|
||||||
| private PluginScanResult initLoaders(Set<PluginSource> pluginSources) { | ||||||
| PluginScanResult reflectiveScanResult = new ReflectionScanner().discoverPlugins(pluginSources); | ||||||
| delegatingLoader.installDiscoveredPlugins(reflectiveScanResult); | ||||||
| return reflectiveScanResult; | ||||||
| public PluginScanResult initLoaders(Set<PluginSource> pluginSources, PluginDiscoveryMode discoveryMode) { | ||||||
| PluginScanResult empty = new PluginScanResult(Collections.emptyList()); | ||||||
| PluginScanResult serviceLoadingScanResult; | ||||||
| try { | ||||||
| serviceLoadingScanResult = PluginDiscoveryMode.serviceLoad(discoveryMode) ? | ||||||
| new ServiceLoaderScanner().discoverPlugins(pluginSources) : empty; | ||||||
| } catch (Throwable t) { | ||||||
| log.error("Unable to perform ServiceLoader scanning as requested by {}={}, this error may be avoided by reconfiguring {}={}", | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| WorkerConfig.PLUGIN_DISCOVERY_CONFIG, discoveryMode, | ||||||
| WorkerConfig.PLUGIN_DISCOVERY_CONFIG, PluginDiscoveryMode.ONLY_SCAN, t); | ||||||
| throw t; | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| } | ||||||
| PluginScanResult reflectiveScanResult = PluginDiscoveryMode.reflectivelyScan(discoveryMode) ? | ||||||
| new ReflectionScanner().discoverPlugins(pluginSources) : empty; | ||||||
| PluginScanResult scanResult = new PluginScanResult(Arrays.asList(reflectiveScanResult, serviceLoadingScanResult)); | ||||||
| maybeReportHybridDiscoveryIssue(discoveryMode, serviceLoadingScanResult, scanResult); | ||||||
| delegatingLoader.installDiscoveredPlugins(scanResult); | ||||||
| return scanResult; | ||||||
| } | ||||||
|
|
||||||
| private static void maybeReportHybridDiscoveryIssue(PluginDiscoveryMode discoveryMode, PluginScanResult serviceLoadingScanResult, PluginScanResult mergedResult) { | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| SortedSet<PluginDesc<?>> missingPlugins = new TreeSet<>(); | ||||||
| mergedResult.forEach(missingPlugins::add); | ||||||
| serviceLoadingScanResult.forEach(missingPlugins::remove); | ||||||
| if (missingPlugins.isEmpty()) { | ||||||
| switch (discoveryMode) { | ||||||
| case ONLY_SCAN: | ||||||
| log.debug("Service loading of plugins disabled, consider reconfiguring {}={}", | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| WorkerConfig.PLUGIN_DISCOVERY_CONFIG, PluginDiscoveryMode.HYBRID_WARN); | ||||||
| break; | ||||||
| case HYBRID_WARN: | ||||||
| case HYBRID_FAIL: | ||||||
| log.warn("All plugins have ServiceLoader manifests, consider reconfiguring {}={}", | ||||||
| WorkerConfig.PLUGIN_DISCOVERY_CONFIG, PluginDiscoveryMode.SERVICE_LOAD); | ||||||
| break; | ||||||
| case SERVICE_LOAD: | ||||||
| log.debug("Reflective loading of plugins disabled, plugins without manifests will not be visible"); | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| break; | ||||||
| default: | ||||||
| throw new IllegalArgumentException("Unknown discovery mode"); | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| } | ||||||
| } else { | ||||||
| String message = String.format( | ||||||
| "Plugins are missing ServiceLoader manifests, these plugins will not be visible with %s=%s: %s", | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: language
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, should we include instructions on what users should do in this case? For many of them, this is going to be the first time hearing about new discovery logic; we should make this message as informative as possible if we want them to start to make use of it. Some options include:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also also, if the point about classpath-installed plugins being unaffected by the plugin discovery mode is correct, should we either filter these plugins out from I suppose "visible" is accurate in the sense that these plugins won't be listed by the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think to explaining everything in one warning/error message is unreasonable, and linking out to external documentation is the better strategy. The error message is already lengthy enough with each plugin listing.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linked documentation is added in #14068
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks great--one more thing: can we make the same tweak to the language here that we did in |
||||||
| WorkerConfig.PLUGIN_DISCOVERY_CONFIG, | ||||||
| PluginDiscoveryMode.SERVICE_LOAD, | ||||||
| missingPlugins.stream() | ||||||
| .map(pluginDesc -> pluginDesc.location() + "\t" + pluginDesc.className() + "\t" + pluginDesc.version()) | ||||||
| .collect(Collectors.joining("\n", "[\n", "\n]"))); | ||||||
| switch (discoveryMode) { | ||||||
| case HYBRID_WARN: | ||||||
| log.warn(message); | ||||||
| break; | ||||||
| case HYBRID_FAIL: | ||||||
| throw new ConnectException(message); | ||||||
| default: | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| throw new IllegalArgumentException("Unknown discovery mode"); | ||||||
|
gharris1727 marked this conversation as resolved.
Outdated
|
||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private static <T> String pluginNames(Collection<PluginDesc<T>> plugins) { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # 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. | ||
|
|
||
| org.apache.kafka.connect.tools.MockSinkConnector | ||
| org.apache.kafka.connect.tools.VerifiableSinkConnector |
Uh oh!
There was an error while loading. Please reload this page.