[feat](connector) give each connector plugin its own conf file - #66347
Merged
Conversation
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
Contributor
Author
|
run buildall |
Contributor
TPC-H: Total hot run time: 28507 ms |
Adding a deployment-level setting for one connector meant editing two files in the engine: an @ConfField in fe-common's Config, and a line in fe-core's DefaultConnectorContext.buildEnvironment that forwards it. A plugin cannot read Config itself -- it loads child-first, so its own bundled copy shadows the engine's and every field reads back as a code default -- so the engine had to carry each key by name, and fe-core ended up knowing the key names of connectors it is otherwise entirely agnostic about. Give a connector a configuration file of its own instead. The engine reads <pluginDir>/<name>.conf, where <name> is the plugin's ConnectorProvider.name(), and serves the parsed map back through ConnectorContext.getConnectorConfig(). The file is parsed generically, so no key name of any connector reaches fe-core, and a new connector needs no engine change at all. ConnectorConf.get layers that map over getEnvironment(): plugin conf first, then the fe.conf key the setting used to live under, then a default. That is what lets the settings that already ship move to the new channel without their @ConfFields going away, so an existing deployment keeps working after an upgrade with nothing to edit. A setting introduced from now on passes null for the legacy key and has no fe.conf half. Blank is "not set" at every step. An operator who writes 'key=' means they have not configured it, and reading it as a set empty string would let one stray line mask the fe.conf value actually in effect -- with nothing in either file to show which won. ConnectorConfFile still keeps blank-valued keys in the map it returns, so the map reflects the file as written and the decision stays in one place. The engine side of the split is deliberate: the file is located, parsed and defaulted once here rather than once per plugin, and getConnectorConfig() is a narrower thing to hand a plugin than the plugin directory path would be. This adds a method to ConnectorContext, so the recorded plugin API surface baseline is refreshed in the same commit. connector.plugin.api.version stays at 1.0: the method is a default, nothing outside fe-connector-spi implements ConnectorContext, and the only decorators of it extend the parent-first ForwardingConnectorContext -- which is loaded from the FE's own classpath, so they inherit the new forward without being rebuilt. A connector plugin built before this change therefore loads and behaves exactly as it did; it simply never reads the new map. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
The SPI half of this landed with getConnectorConfig() answering an empty map for everyone. This is the engine half: after a plugin directory is admitted, read <pluginDir>/<name>.conf and hand it to that plugin's connectors. The map is keyed by provider instance in an IdentityHashMap, so a lookup never calls equals/hashCode on plugin code -- the same rule DirectoryPluginRuntimeManager follows by snapshotting name() once at load and never re-entering the plugin on a query path. Attaching it has to happen in createConnector rather than in the context itself: fe-core builds a ConnectorContext for a catalog before it knows which plugin will claim the type, so the conf can only be layered on once the provider is picked. Keeping it out of DefaultConnectorContext is also what keeps the engine's context free of any connector's key names -- which is the point of the whole change. A sibling connector comes back through this same method, so it is handed its own plugin's conf rather than inheriting the gateway's: DefaultConnectorContext.createSiblingConnector passes the unwrapped engine context, which is then wrapped with the sibling provider's own map. The conf belongs to the plugin, not to the catalog. A conf file that cannot be read is logged and skipped, and the plugin is still registered. Refusing it would make the catalog type vanish, and the only thing a user would see is CREATE CATALOG answering "no provider supports type" -- which points nowhere near a bad file. Every setting reachable this way has a default or a fe.conf fallback, so proceeding is a real degradation path rather than a guess. The tests drive loadPlugins + createConnector on real plugin directories, because the two things worth proving -- that the file is found beside the jars, and that each provider gets its own -- exist only on that path. The probe plugins live outside org.apache.doris.connector. so their API version is read from the jar that defines them; they report back through a sink class that IS in that (parent-first) package, which is what makes the result readable across the classloader split. One test deploys a plugin into a directory NOT named after it, so nothing can pass by reading a file named after the directory instead of after the provider. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Seeds <name>.conf from the <name>.conf.template the plugin zip carries, with cp -n, right after the zip is unpacked. The live .conf is deliberately NOT in the zip. That is what makes the ordinary upgrade -- unzip a newer plugin build over the deployed directory -- refresh the jars and the template while leaving whatever the administrator configured untouched. Shipping the .conf itself would silently revert their settings on every upgrade. The loop globs *.conf.template and names no connector, so a new connector that ships a template needs no change here. It sits inside the deploy loop because conn_plugin_target is unset once the loop ends. cp -n exits 0 when it skips an existing file, so it is safe under this script's set -eo pipefail; the [ -e ] guard covers a plugin that ships no template, where the glob stays literal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Moves trino_connector_plugin_dir onto the connector's own settings file. plugin_dir in trino-connector.conf now wins; fe.conf's key stays as the fallback, so a deployment that changes nothing keeps resolving exactly as before and its @ConfField keeps working. resolvePluginDir takes the resolved directory rather than the engine environment map. Which file a deployment-level setting comes from is the connector's business, not this helper's, and threading the map through meant the fe.conf key name was baked into a function that has no other reason to know it. Note the conf file is trino-connector.conf, not trino.conf: the engine names it after ConnectorProvider.name(), which is this connector's type, while the plugin directory it sits in is plugins/connector/trino. The two are allowed to differ -- the directory name is the deployer's choice and cannot be what the engine keys on. A test asserts the shipped template's name still tracks name(), so renaming getType() cannot silently deploy a file nothing opens. The fail-loud on a missing value is kept, and its message now names both places the setting can come from, since after this either one could be the missing half. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Moves hive_default_file_format and enable_create_hive_bucket_table onto the connector's own settings file, as default_file_format and enable_create_bucket_table in hms.conf. The plugin conf wins; fe.conf stays as the fallback, so a deployment that changes nothing behaves exactly as before and both @ConfFields keep working. The keys lose their hive_ prefix because the file name already namespaces them -- hms.conf can only be read by this connector. Note the file is hms.conf, not hive.conf: the engine names it after ConnectorProvider.name(), which for this connector is "hms", while the plugin directory it sits in is plugins/connector/hive. The two are allowed to differ, and a test asserts the shipped template's name still tracks name() so renaming getType() cannot silently deploy a file nothing opens. doris_version stays in the engine environment. It is a build stamp rather than something an administrator configures, so it does not belong in a settings file at all. One behavior difference worth naming: a blank value now counts as unset. Before, a blank hive_default_file_format reached the metastore create as an empty format string; now it falls through to orc. That is the intent of a blank line in a conf file, and an empty file format was never a working configuration. The bucket-gate rejection message now names both the conf key and the fe.conf key, since after this either one could be the one that is off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Moves jdbc_drivers_dir and force_sqlserver_jdbc_encrypt_false onto the connector's own settings file, as drivers_dir and force_sqlserver_encrypt_false in jdbc.conf. The plugin conf wins; fe.conf stays as the fallback, so a deployment that changes nothing behaves exactly as before and both @ConfFields keep working. The keys lose their jdbc_ prefix because the file name already namespaces them. JdbcUrlNormalizer.normalize now takes the resolved boolean rather than the engine environment map. It had no reason to know an fe.conf key name, and after this change the value can come from either of two files -- deciding which is the connector's job, not the URL normalizer's. doris_home stays in the engine environment: it is the FE install root, not this connector's setting, and the drivers-directory default is still built from it exactly as before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
… conf Moves jdbc_drivers_dir and hive_metastore_client_timeout_second onto these two connectors' own settings files, as drivers_dir and metastore_client_timeout_second in iceberg.conf and paimon.conf. Each plugin conf wins; fe.conf stays as the fallback, so a deployment that changes nothing behaves exactly as before and both @ConfFields keep working. Both settings are shared at the fe.conf end -- one jdbc_drivers_dir and one hive_metastore_client_timeout_second serve jdbc, iceberg and paimon. A per-plugin file cannot express that, so a deployment moving to these files sets the value in each plugin's conf. That is the accepted cost of the per-plugin model and is called out in both templates; leaving them commented out keeps the single shared fe.conf value, which is what every existing deployment gets. JdbcDriverSupport.resolveDriverUrl now takes the drivers directory and DORIS_HOME rather than the engine environment map. It lives in a module shared by connectors whose conf files differ, so which file a value comes from cannot be its decision -- the same shape AbstractHmsMetaStoreProperties already has, taking its timeout default as a parameter instead of reading the environment. The resolution itself is unchanged, including the <doris_home>/plugins/jdbc_drivers fallback. Paimon resolves the drivers directory through one accessor shared by both its call sites (FE driver registration and the BE-bound scan options), for the same reason both already delegate to JdbcDriverSupport: the two must resolve a given driver_url identically or FE and BE load different jars. PaimonConnectorProperties' javadoc claim of being a pure constant holder is amended -- HiveConnectorProperties and JdbcConnectorProperties have carried static accessors for a while. This has to be one commit: the signature change and its three call sites span two plugin modules, so splitting it leaves an intermediate commit that does not compile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
…nvironment No connector reads it. The JDBC driver allow-list is enforced in fe-core by JdbcResource, which reads Config.jdbc_driver_secure_path directly, so this env entry was only ever written -- a dead key that reads like a connector setting and invites someone to build on it. Config.jdbc_driver_secure_path itself stays: JdbcResource is a legitimate in-engine user of it, and the fe.conf key is unchanged for operators. The comment added to buildEnvironment says what the map is now for, so the next person adding a deployment-level setting reaches for the plugin's own conf instead of adding a tenth key here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Rule 7 listed three knob channels and named the fe.conf one "the one knob shape that requires an engine change per key". That is no longer the shape a new connector should reach for, and leaving the rule as written would keep pointing people at Config.java. It now lists four: the plugin's own <name>.conf is the deployment-level channel, and the fe.conf/getEnvironment one is marked closed to new keys and explained as the fallback that keeps existing deployments working. The connector README gains the corresponding step in "Adding a New Connector", including the two things that are not guessable: the keys take no connector prefix (the file name namespaces them), and <name> is ConnectorProvider.name() rather than the plugin directory name -- plugins/connector/hive/ holds hms.conf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
… check build.sh seeds each connector's live <name>.conf from its template verbatim, so the template's content is the file an administrator edits in plugins/connector/<dir>/. Listed by name rather than through a **/*.conf.template glob, so a new template is a deliberate entry here rather than something a wildcard silently absorbs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W8r8ffK711cExL5p6SB1fr
Contributor
TPC-DS: Total hot run time: 169631 ms |
Contributor
ClickBench: Total hot run time: 23.95 s |
morningman
force-pushed
the
connector-plugin-conf
branch
from
August 1, 2026 08:34
e9e5b4d to
6dc8847
Compare
Contributor
Author
|
run buildall |
…he class ObsFileSystemProperties picks between fs.obs.impl=OBSFileSystem and the S3AFileSystem fallback with a static probe for org.apache.hadoop.fs.obs.OBSFileSystem. It probed with Class.forName, which answers a strictly harder question than the one being asked: loading the class also links its superclass org.apache.hadoop.fs.FileSystem, and hadoop-common is deliberately not part of this plugin -- hadoop-huaweicloud declares it provided and plugin-zip.xml packs only the runtime closure, so lib/ holds the OBS connector with no hadoop-common behind it. That has one consequence already visible and one waiting: - Wherever hadoop-common is absent, Class.forName throws NoClassDefFoundError. It is a LinkageError, not a ClassNotFoundException, so the catch did not hold it and it aborted the class's static initializer instead; every later touch of ObsFileSystemProperties then failed with "Could not initialize class", not only the hadoop map. This module's own test classpath is exactly that shape, so 25 of its 28 tests fail today. - Merely widening the catch would trade the crash for a lie. The probe would report OBS absent and silently downgrade fs.obs.impl to S3AFileSystem as soon as fe-core stops carrying hadoop -- which apache#66324 leaves open as the next step -- even though the connector is right there in lib/, and the consumers that actually instantiate it (fe-connector-paimon, be-java-extensions/hadoop-deps) bring their own hadoop. Resolving the class file as a resource asks the intended question, against the same classloader and the same delegation, without linking anything. It is also what this dependency's comment in pom.xml already claims the probe does: "the jar has to sit in this plugin for the probe to tell the truth". The new test pins the native impl and asserts the classpath premise it rests on, so adding hadoop-common later fails loudly instead of quietly turning the test into a tautology. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YeHiB85SmvZyKCq7FzuJD
The FE UT job parses results with the report pattern fe/*/target/surefire-reports/*.xml. That single wildcard only reaches the 17 modules sitting directly under fe/; the other 56 -- everything under fe-filesystem/, fe-connector/, fe-authentication/ and be-java-extensions/ -- is invisible to it. The coverage run also passes -Dmaven.test.failure.ignore=true, which it needs in order to finish every module and still emit a jacoco report, so maven exits 0 and the reactor prints SUCCESS for a module whose tests failed. Together those two make a nested module's failures unobservable: the job goes green reporting "failed: 0". Build 1012189 is the worked example -- 25 of fe-filesystem-obs' 28 tests failed there and nothing anywhere said so. So gate on the reports the parser cannot see, and leave the ones it can reach to the job itself: it owns those results, and its per-test mutes have to keep working. Two things that are easy to get wrong here: - The obvious way to express "skip the ones the parser already sees" is a [[ ]] glob against the parser's own pattern, and it is wrong: inside [[ ]] a * matches / as well, so fe/*/target/... also swallows every nested module this is meant to catch, and the check silently passes everything. Comparing the shape of the module path is exact. - The totals are read from the root <testsuite> element only, since a stack trace quoted inside a later <testcase> can otherwise be mistaken for it. Scoped to the full run: --run leaves every other module's reports from an earlier invocation untouched, and those are not that run's results. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YeHiB85SmvZyKCq7FzuJD
morningman
force-pushed
the
connector-plugin-conf
branch
from
August 1, 2026 08:51
6dc8847 to
09e138c
Compare
Contributor
Author
|
run buildall |
Contributor
TPC-H: Total hot run time: 28255 ms |
Contributor
TPC-DS: Total hot run time: 168296 ms |
Contributor
ClickBench: Total hot run time: 24 s |
The bucket gate moved onto the plugin conf channel, so it can now be off in either hms.conf (enable_create_bucket_table) or fe.conf (enable_create_hive_bucket_table), and the rejection message was reworded to name both. test_hive_ddl still pinned the old single-key wording and failed. Updating the assertion rather than the message: with the plugin conf winning, a message that names only the fe.conf key sends an administrator whose hms.conf holds the toggle false to edit a file that cannot turn it back on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
run buildall |
Contributor
TPC-H: Total hot run time: 28427 ms |
Contributor
TPC-DS: Total hot run time: 169547 ms |
Contributor
ClickBench: Total hot run time: 23.86 s |
Contributor
FE Regression Coverage ReportIncrement line coverage |
CalvinKirs
approved these changes
Aug 2, 2026
Contributor
|
PR approved by at least one committer and no changes requested. |
Contributor
|
PR approved by anyone and no changes requested. |
gavinchou
approved these changes
Aug 2, 2026
morningman
added a commit
to morningman/doris
that referenced
this pull request
Aug 2, 2026
Both of this connector's deployment-level settings move off fe.conf and into the plugin's own adbc.conf -- the channel apache#66347 introduced -- as drivers_dir and driver_secure_path, read through ConnectorConf.get. Neither has an fe.conf half. The two @ConfFields they used to be (adbc_drivers_dir, adbc_driver_secure_path) and the two DefaultConnectorContext env entries that forwarded them are removed rather than kept as a fallback: this connector has never shipped, so no deployment configured them anywhere else, and a key in fe-core is an engine change per connector setting -- which is what that channel exists to stop. The default drivers directory is computed in the connector from the doris_home the engine already publishes, so it stays <DORIS_HOME>/plugins/adbc_drivers. build.sh needs no change: it seeds a live <name>.conf from any *.conf.template found in a plugin zip. AdbcConnectorConfTest pins the template's name against ConnectorProvider.name() -- a template under any other name deploys a file the engine never opens, with every setting in it silently ignored -- and pins that an environment still carrying the old fe.conf keys does not resurrect a channel fe-core no longer feeds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RgJjuW5w4jEKF9HorENTur
morningman
added a commit
to morningman/doris
that referenced
this pull request
Aug 2, 2026
Both of this connector's deployment-level settings move off fe.conf and into the plugin's own adbc.conf -- the channel apache#66347 introduced -- as drivers_dir and driver_secure_path, read through ConnectorConf.get. Neither has an fe.conf half. The two @ConfFields they used to be (adbc_drivers_dir, adbc_driver_secure_path) and the two DefaultConnectorContext env entries that forwarded them are removed rather than kept as a fallback: this connector has never shipped, so no deployment configured them anywhere else, and a key in fe-core is an engine change per connector setting -- which is what that channel exists to stop. The default drivers directory is computed in the connector from the doris_home the engine already publishes, so it stays <DORIS_HOME>/plugins/adbc_drivers. build.sh needs no change: it seeds a live <name>.conf from any *.conf.template found in a plugin zip. AdbcConnectorConfTest pins the template's name against ConnectorProvider.name() -- a template under any other name deploys a file the engine never opens, with every setting in it silently ignored -- and pins that an environment still carrying the old fe.conf keys does not resurrect a channel fe-core no longer feeds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RgJjuW5w4jEKF9HorENTur
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this PR solve?
Issue Number: N/A
Related PR: N/A
Problem Summary:
Giving one connector a new deployment-level setting currently costs two edits in
the engine: an
@ConfFieldin fe-common'sConfig, and a line in fe-core'sDefaultConnectorContext.buildEnvironment()that forwards it. A connector plugincannot read
Configitself — it loads child-first, so its own bundled copyshadows the engine's and every field reads back as a code default — so the engine
has to carry each key by name. The result is that
fe-coreknows the config keynames of connectors it is otherwise entirely agnostic about, and that list only
grows.
This PR gives a connector plugin a configuration file of its own. The engine
reads
<pluginDir>/<name>.conf(where<name>isConnectorProvider.name()),parses it generically, and serves it back through the new
ConnectorContext.getConnectorConfig(). No key name of any connector reachesfe-core, and a new connector needs no engine change at all to add adeployment-level setting.
Connectors read a setting through one entry point:
Resolution is plugin conf → fe.conf → default, with blank treated as "not
set" at each step (an operator who writes
key=has not configured it, andreading it as a set empty string would let one stray line mask the fe.conf value
actually in effect).
Six settings across five connectors are moved onto the new channel. Every
@ConfFieldis kept and stays the fallback, so an existing deployment upgradeswith nothing to edit and behaves exactly as before:
name())trino-connectortrino-connector.confplugin_dirtrino_connector_plugin_dirhms(hive)hms.confdefault_file_formathive_default_file_formathms(hive)hms.confenable_create_bucket_tableenable_create_hive_bucket_tablejdbcjdbc.confdrivers_dirjdbc_drivers_dirjdbcjdbc.confforce_sqlserver_encrypt_falseforce_sqlserver_jdbc_encrypt_falseiceberg/paimoniceberg.conf/paimon.confdrivers_dirjdbc_drivers_diriceberg/paimoniceberg.conf/paimon.confmetastore_client_timeout_secondhive_metastore_client_timeout_secondTwo of these are shared by several connectors at the fe.conf end (one
jdbc_drivers_dirserves jdbc, iceberg and paimon). A per-plugin file cannotexpress that, so a deployment that moves them sets the value in each plugin's
conf; leaving them commented out keeps the single shared fe.conf value, which is
what every existing deployment gets. Both templates say so.
doris_homeanddoris_versionstay ingetEnvironment()— they are notconnector settings.
jdbc_driver_secure_pathis dropped from it: no connectorever read it (the JDBC allow-list is enforced in fe-core by
JdbcResource, whichreads
Configdirectly), so it was a dead key that read like a connectorsetting. The
Configfield itself is unchanged.Packaging. A plugin ships
src/main/resources/<name>.conf.template;build.shseeds the live
<name>.conffrom it withcp -n, globbing*.conf.templatewithno connector named, so a new connector needs no
build.shchange either. The live.confis deliberately not in the plugin zip, so the ordinary upgrade —unzipping a newer plugin build over the deployed directory — refreshes the jars
and the template but never the administrator's file.
Note the conf file is named after
ConnectorProvider.name(), not after theplugin directory:
plugins/connector/hive/holdshms.confandplugins/connector/trino/holdstrino-connector.conf. The directory name is thedeployer's choice and cannot be what the engine keys on. Each connector carries a
test asserting its shipped template name still tracks
name().connector.plugin.api.versionstays at 1.0. The addedConnectorContext.getConnectorConfig()is adefaultmethod, nothing outsidefe-connector-spi implements
ConnectorContext, and the only decorators of itextend the parent-first
ForwardingConnectorContext— loaded from the FE's ownclasspath, so they inherit the new forward without being rebuilt. A connector
plugin built before this change loads and behaves exactly as it did; it simply
never reads the new map.
Release note
Connector plugins can now carry their own deployment-level configuration file,
<DORIS_HOME>/plugins/connector/<dir>/<name>.conf, seeded from a template shippedwith each plugin. Settings there take precedence over the corresponding
fe.confkeys, which keep working unchanged — no action is required when upgrading. The
file must be maintained on every FE node and takes effect after an FE restart.
Check List (For Author)
Unit tests — new:
ConnectorConfFileTest,ConnectorConfTest(spi),ConnectorPluginConfTest(fe-core, drivesloadPlugins+createConnectoron realplugin directories),
IcebergConnectorConfTest,PaimonConnectorConfTest, plusper-connector cases and a template-name guard in
TrinoBootstrapTest,HiveConnectorMetadataDdlTest,JdbcUrlNormalizerTest. ExistingForwardingConnectorContextTestcovers the new forward by reflection.Each was mutation-checked (precedence reversed, forward removed, surface baseline
reverted, conf not keyed per provider, conf never attached, template renamed) and
confirmed to fail.
Manual test —
sh build.sh --fe, then verified inoutput/fe/plugins/connector/:hive/hms.conf,trino/trino-connector.conf,iceberg/iceberg.conf,jdbc/jdbc.conf,paimon/paimon.confare created and byte-identical to theirtemplates;
es/,hudi/,maxcompute/ship no template and get no file, withno error.
Every seeded file has 0 active settings (all commented out), so a fresh
deployment behaves exactly as before.
Upgrade safety: hand-edited
hms.conf, replayed the deploy step (unzip -o+the
cp -nloop) from the real plugin zip — the edit survives and only thetemplate is refreshed.
Behavior changed:
Two, both narrow:
<name>.confbeforefe.conf. For a deployment that does not edit the seeded (all-commented) file,nothing changes.
hive_default_file_formatin fe.conf now falls through toorcinsteadof reaching the metastore create as an empty format string. An empty file format
was never a working configuration.
Each shipped
.conf.templatedocuments its own keys inline, andfe/fe-connector/README.mdplusfe-connector-api/package-info.java(Rule 7) areupdated for connector authors. A doris-website page for operators is still to be
written.