Skip to content

Commit 47db44b

Browse files
committed
Expose security-sensitive properties for Hudi connector
1 parent c98dc03 commit 47db44b

File tree

3 files changed

+84
-26
lines changed

3 files changed

+84
-26
lines changed

Diff for: plugin/trino-hudi/src/main/java/io/trino/plugin/hudi/HudiConnectorFactory.java

+58-23
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@
1313
*/
1414
package io.trino.plugin.hudi;
1515

16+
import com.google.common.annotations.VisibleForTesting;
1617
import com.google.common.collect.ImmutableSet;
1718
import com.google.inject.Injector;
1819
import com.google.inject.Key;
1920
import com.google.inject.Module;
2021
import io.airlift.bootstrap.Bootstrap;
2122
import io.airlift.bootstrap.LifeCycleManager;
23+
import io.airlift.configuration.ConfigPropertyMetadata;
2224
import io.airlift.json.JsonModule;
2325
import io.opentelemetry.api.OpenTelemetry;
2426
import io.opentelemetry.api.trace.Tracer;
2527
import io.trino.filesystem.manager.FileSystemModule;
2628
import io.trino.plugin.base.classloader.ClassLoaderSafeConnectorPageSourceProvider;
2729
import io.trino.plugin.base.classloader.ClassLoaderSafeConnectorSplitManager;
2830
import io.trino.plugin.base.classloader.ClassLoaderSafeNodePartitioningProvider;
31+
import io.trino.plugin.base.config.ConfigUtils;
2932
import io.trino.plugin.base.jmx.MBeanServerModule;
3033
import io.trino.plugin.base.session.SessionPropertiesProvider;
3134
import io.trino.plugin.hive.NodeVersion;
@@ -52,6 +55,8 @@
5255
public class HudiConnectorFactory
5356
implements ConnectorFactory
5457
{
58+
private static final Module DEFAULT_ADDITIONAL_MODULE = EMPTY_MODULE;
59+
5560
@Override
5661
public String getName()
5762
{
@@ -62,38 +67,34 @@ public String getName()
6267
public Connector create(String catalogName, Map<String, String> config, ConnectorContext context)
6368
{
6469
checkStrictSpiVersionMatch(context, this);
65-
return createConnector(catalogName, config, context, Optional.empty());
70+
return createConnector(catalogName, config, context, DEFAULT_ADDITIONAL_MODULE);
71+
}
72+
73+
@Override
74+
public Set<String> getSecuritySensitivePropertyNames(String catalogName, Map<String, String> config, ConnectorContext context)
75+
{
76+
ClassLoader classLoader = HudiConnectorFactory.class.getClassLoader();
77+
try (ThreadContextClassLoader _ = new ThreadContextClassLoader(classLoader)) {
78+
Bootstrap app = createBootstrap(catalogName, config, context, DEFAULT_ADDITIONAL_MODULE, true);
79+
80+
Set<ConfigPropertyMetadata> usedProperties = app.configureAndGetUsedProperties();
81+
82+
return ConfigUtils.getSecuritySensitivePropertyNames(config, usedProperties);
83+
}
6684
}
6785

86+
@VisibleForTesting
6887
public static Connector createConnector(
6988
String catalogName,
7089
Map<String, String> config,
7190
ConnectorContext context,
72-
Optional<Module> module)
91+
Module module)
7392
{
7493
ClassLoader classLoader = HudiConnectorFactory.class.getClassLoader();
7594
try (ThreadContextClassLoader _ = new ThreadContextClassLoader(classLoader)) {
76-
Bootstrap app = new Bootstrap(
77-
new MBeanModule(),
78-
new JsonModule(),
79-
new HudiModule(),
80-
new HiveMetastoreModule(Optional.empty()),
81-
new FileSystemModule(catalogName, context.getNodeManager(), context.getOpenTelemetry(), false, false),
82-
new MBeanServerModule(),
83-
module.orElse(EMPTY_MODULE),
84-
binder -> {
85-
binder.bind(OpenTelemetry.class).toInstance(context.getOpenTelemetry());
86-
binder.bind(Tracer.class).toInstance(context.getTracer());
87-
binder.bind(NodeVersion.class).toInstance(new NodeVersion(context.getNodeManager().getCurrentNode().getVersion()));
88-
binder.bind(NodeManager.class).toInstance(context.getNodeManager());
89-
binder.bind(TypeManager.class).toInstance(context.getTypeManager());
90-
binder.bind(CatalogName.class).toInstance(new CatalogName(catalogName));
91-
});
92-
93-
Injector injector = app
94-
.doNotInitializeLogging()
95-
.setRequiredConfigurationProperties(config)
96-
.initialize();
95+
Bootstrap app = createBootstrap(catalogName, config, context, module, false);
96+
97+
Injector injector = app.initialize();
9798

9899
LifeCycleManager lifeCycleManager = injector.getInstance(LifeCycleManager.class);
99100
HudiTransactionManager transactionManager = injector.getInstance(HudiTransactionManager.class);
@@ -115,4 +116,38 @@ public static Connector createConnector(
115116
hudiTableProperties.getTableProperties());
116117
}
117118
}
119+
120+
private static Bootstrap createBootstrap(
121+
String catalogName,
122+
Map<String, String> config,
123+
ConnectorContext context,
124+
Module module,
125+
boolean quietBootstrap)
126+
{
127+
Bootstrap app = new Bootstrap(
128+
new MBeanModule(),
129+
new JsonModule(),
130+
new HudiModule(),
131+
new HiveMetastoreModule(Optional.empty()),
132+
new FileSystemModule(catalogName, context.getNodeManager(), context.getOpenTelemetry(), false, quietBootstrap),
133+
new MBeanServerModule(),
134+
module,
135+
binder -> {
136+
binder.bind(OpenTelemetry.class).toInstance(context.getOpenTelemetry());
137+
binder.bind(Tracer.class).toInstance(context.getTracer());
138+
binder.bind(NodeVersion.class).toInstance(new NodeVersion(context.getNodeManager().getCurrentNode().getVersion()));
139+
binder.bind(NodeManager.class).toInstance(context.getNodeManager());
140+
binder.bind(TypeManager.class).toInstance(context.getTypeManager());
141+
binder.bind(CatalogName.class).toInstance(new CatalogName(catalogName));
142+
});
143+
144+
if (quietBootstrap) {
145+
app.quiet()
146+
.suppressErrorsAndWarnings();
147+
}
148+
149+
return app
150+
.doNotInitializeLogging()
151+
.setRequiredConfigurationProperties(config);
152+
}
118153
}

Diff for: plugin/trino-hudi/src/test/java/io/trino/plugin/hudi/TestHudiPlugin.java

+24
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
import io.trino.testing.TestingConnectorContext;
1919
import org.junit.jupiter.api.Test;
2020

21+
import java.util.Map;
22+
import java.util.Set;
23+
2124
import static com.google.common.collect.Iterables.getOnlyElement;
25+
import static org.assertj.core.api.Assertions.assertThat;
2226

2327
final class TestHudiPlugin
2428
{
@@ -35,4 +39,24 @@ void testCreateConnector()
3539
new TestingConnectorContext())
3640
.shutdown();
3741
}
42+
43+
@Test
44+
void testGetSecuritySensitivePropertyNames()
45+
{
46+
ConnectorFactory factory = getOnlyElement(new HudiPlugin().getConnectorFactories());
47+
Map<String, String> config = ImmutableMap.of(
48+
"non-existent-property", "value",
49+
"fs.hadoop.enabled", "true",
50+
"hive.azure.abfs.oauth.client-id", "test-client-id", // security-sensitive property from trino-hdfs
51+
"hive.azure.adl-proxy-host", "proxy-host:9800", // non-sensitive property from trino-hdfs
52+
"hive.dfs-timeout", "invalidValue", // property from trino-hdfs with invalid value
53+
"hive.metastore.uri", "thrift://foo:1234",
54+
"hive.metastore.thrift.client.ssl.key-password", "password",
55+
"hudi.size-based-split-weights-enabled", "shouldBeBoolean");
56+
57+
Set<String> sensitiveProperties = factory.getSecuritySensitivePropertyNames("catalog", config, new TestingConnectorContext());
58+
59+
assertThat(sensitiveProperties)
60+
.containsExactlyInAnyOrder("non-existent-property", "hive.azure.abfs.oauth.client-id", "hive.metastore.thrift.client.ssl.key-password");
61+
}
3862
}

Diff for: plugin/trino-hudi/src/test/java/io/trino/plugin/hudi/TestingHudiConnectorFactory.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import java.nio.file.Path;
2525
import java.util.Map;
26-
import java.util.Optional;
2726

2827
import static com.google.inject.multibindings.MapBinder.newMapBinder;
2928
import static io.airlift.configuration.ConfigBinder.configBinder;
@@ -55,10 +54,10 @@ public Connector create(String catalogName, Map<String, String> config, Connecto
5554
if (!config.containsKey("hive.metastore")) {
5655
configBuilder.put("hive.metastore", "file");
5756
}
58-
return createConnector(catalogName, configBuilder.buildOrThrow(), context, Optional.of(binder -> {
57+
return createConnector(catalogName, configBuilder.buildOrThrow(), context, binder -> {
5958
newMapBinder(binder, String.class, TrinoFileSystemFactory.class)
6059
.addBinding("local").toInstance(new LocalFileSystemFactory(localFileSystemRootPath));
6160
configBinder(binder).bindConfigDefaults(FileHiveMetastoreConfig.class, metastoreConfig -> metastoreConfig.setCatalogDirectory("local:///managed/"));
62-
}));
61+
});
6362
}
6463
}

0 commit comments

Comments
 (0)