close
Skip to content

[Feature][Engine]Metalake support for data source information storage and management#9688

Merged
Hisoka-X merged 41 commits into
apache:devfrom
wtybxqm:support_metalake_development
Sep 24, 2025
Merged

[Feature][Engine]Metalake support for data source information storage and management#9688
Hisoka-X merged 41 commits into
apache:devfrom
wtybxqm:support_metalake_development

Conversation

@wtybxqm

@wtybxqm wtybxqm commented Aug 10, 2025

Copy link
Copy Markdown
Contributor

Purpose of this pull request

To address the problem: sensitive information such as data source usernames and passwords is directly written into task scripts
close #9687

Does this PR introduce any user-facing change?

yes
To enable Metalake, users need to configure three critical settings in seatunnel.sh: first set 'metalake_enable=true', then specify their 'metalake_url' and 'metalake_type'. Once activated, users can simply add a 'sourceId' field in their task script's source/sink configurations and replace sensitive credentials with secure placeholders like '${password}'.

How was this patch tested?

Integration testing has passed.

Check list

wtybxqm added 4 commits July 20, 2025 18:57
…nel-env.cmd files; modify EnvCommonOptions class to include metalake configuration option
…ntroduce factory for type-based MetalakeClient creation; Fetch Metalake data by sourceId and replace Config placeholders
@Hisoka-X

Copy link
Copy Markdown
Member

cc @liugddx

@liugddx

liugddx commented Aug 11, 2025

Copy link
Copy Markdown
Member

Please add test cases and add documentation.

@github-actions github-actions Bot added the e2e label Aug 25, 2025
Comment thread seatunnel-api/pom.xml Outdated
Comment on lines +45 to +47
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to send http request to get metainfo from gravitino, so a http tool is necessary

}

sink {
Console {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the Assert connector.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the Assert connector instead of console

Comment on lines +184 to +191
boolean metalakeEnabled =
Boolean.parseBoolean(System.getenv().getOrDefault("METALAKE_ENABLED", "false"));
if (metalakeEnabled) {
this.seaTunnelJobConfig =
getMetalakeConfig(ConfigBuilder.of(Paths.get(jobDefineFilePath), variables));
} else {
this.seaTunnelJobConfig = ConfigBuilder.of(Paths.get(jobDefineFilePath), variables);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to ensure that Flink/Spark/Zeta all support this feature simultaneously.

Therefore, it needs to be adapted in both the FlinkTaskExecuteCommandand SparkTaskExecuteCommand classes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this feature in spark and flink engine and the test has passed

</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E2e test case need to support flink/spark/zeta, so they should be placed in the seatunnel-connector-v2-e2e.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the metalakeIT to seatunnel-connector-v2-e2e

@Hisoka-X Hisoka-X left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @wtybxqm for update! It's looks great!

if (entity == null) {
throw new RuntimeException("No response entity");
}
ObjectMapper mapper = new ObjectMapper();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reuse JsonUtils

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a readTree method in JsonUtils and reuse it here

Comment on lines +46 to +47
String metalakeType = System.getenv("METALAKE_TYPE");
String metalakeUrl = System.getenv("METALAKE_URL");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe user can overwrite it on job config env part is better. cc @liugddx

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe user can overwrite it on job config env part is better. cc @liugddx

Yes, user can retrieve variables from the environment (env), and if they are not present in the environment, they can obtain them from the System. Config envConfig = config.getConfig("env");

Comment on lines +65 to +69
if (value.valueType() == ConfigValueType.STRING) {
String strValue = (String) value.unwrapped();
Matcher matcher = pattern.matcher(strValue);
if (matcher.find()) {
String placeholder = matcher.group(1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about move this part into PlaceholderUtils with new method?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved this into PlaceholderUtils

Comment on lines +98 to +113
if (sinkObj.containsKey("sourceId")) {
ConfigObject tmp = sinkObj;
String sourceId = sinkObj.toConfig().getString("sourceId");
JsonNode metalakeJson = metalakeClient.getMetaInfo(sourceId);
for (Map.Entry<String, ConfigValue> entry : sinkObj.entrySet()) {
String subKey = entry.getKey();
ConfigValue value = entry.getValue();

if (value.valueType() == ConfigValueType.STRING) {
String strValue = (String) value.unwrapped();
Matcher matcher = pattern.matcher(strValue);
if (matcher.find()) {
String placeholder = matcher.group(1);

if (metalakeJson.has(placeholder)) {
String replaced = metalakeJson.get(placeholder).asText();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse source and sink has same code. Let's refactor it again!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have refactored these same code

Comment on lines +12 to +14
httpcore-4.4.13.jar
httpcore-4.4.16.jar
httpcore-4.4.4.jar

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weired we introduce new two version of httpcore. Can you analyze the dependencies and use only httpcore-4.4.16.jar?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually wired. I just introduce httpclient-4.5.13 which is already in the other part of the project, but the Dependency License test remind me to add other two version of httpcore

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should find the core reason before merge it. cc @liugddx

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

httpcore has been introduced in multiple versions. Can we unify the version?
image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we unify the version?

Sure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have unified the version of httpcore to 4.4.16 and removed the extra version in known-dependency.txt

@github-actions github-actions Bot removed the dependencies Pull requests that update a dependency file label Sep 17, 2025
@Slf4j
public class MetalakeConfigUtils {

public static Config getMetalakeConfig(Config jobConfigTmp) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should support transform too. For example, OpenAI key in LLM/Embedding etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have supported transform here.

Comment on lines +176 to +189
Config envConfig =
ConfigBuilder.of(Paths.get(jobDefineFilePath), variables).getConfig("env");
boolean metalakeEnabled =
envConfig.hasPath("metalake_enabled")
? envConfig.getBoolean("metalake_enabled")
: Boolean.parseBoolean(
System.getenv().getOrDefault("METALAKE_ENABLED", "false"));
if (metalakeEnabled) {
this.seaTunnelJobConfig =
MetalakeConfigUtils.getMetalakeConfig(
ConfigBuilder.of(Paths.get(jobDefineFilePath), variables));
} else {
this.seaTunnelJobConfig = ConfigBuilder.of(Paths.get(jobDefineFilePath), variables);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The part can be refactor too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have refactored this part

@Hisoka-X Hisoka-X left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @wtybxqm . We almost fininsh this.

return result.toString();
}

public static String replacePlaceholders(String input, JsonNode json) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static String replacePlaceholders(String input, JsonNode json) {
public static String replacePlaceholders(String input, JsonNode supportedValues) {

Comment on lines +49 to +81
Config update = jobConfigTmp;
try {
ConfigList sourceList = jobConfigTmp.getList("source");
update =
update.withValue(
"source",
ConfigValueFactory.fromIterable(
replaceConfigList(sourceList, envConfig)));
} catch (IOException e) {
log.error("Fail to get MetaInfo", e);
}

try {
ConfigList sinkList = jobConfigTmp.getList("sink");
update =
update.withValue(
"sink",
ConfigValueFactory.fromIterable(
replaceConfigList(sinkList, envConfig)));
} catch (IOException e) {
log.error("Fail to get MetaInfo", e);
}

try {
ConfigList sinkList = jobConfigTmp.getList("transform");
update =
update.withValue(
"transform",
ConfigValueFactory.fromIterable(
replaceConfigList(sinkList, envConfig)));
} catch (IOException e) {
log.error("Fail to get MetaInfo", e);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this part can be refactor too.

Comment on lines +57 to +66
Config envConfig = updateConfig.getConfig("env");
String metalakeType =
envConfig.hasPath("metalake_type")
? envConfig.getString("metalake_type")
: System.getenv("METALAKE_TYPE");
String metalakeUrl =
envConfig.hasPath("metalake_url")
? envConfig.getString("metalake_url")
: System.getenv("METALAKE_URL");
MetalakeClient metalakeClient = MetalakeClientFactory.create(metalakeType, metalakeUrl);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should move this part outer replaceConfigList. The metalakeClient should only created once.

@Hisoka-X Hisoka-X left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hisoka-X Hisoka-X left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if ci passes. Thanks @wtybxqm !

@liugddx liugddx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM @wtybxqm Thank you for your contribution.

@Hisoka-X

Copy link
Copy Markdown
Member

waiting test case passes.

@Hisoka-X Hisoka-X merged commit 6416a17 into apache:dev Sep 24, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature][Engine] Metalake support for data source information storage and management

3 participants