Skip to content

Commit

Permalink
feat(apps): support config file
Browse files Browse the repository at this point in the history
- added support for app config files
- removed AppPrivateConfig from the OpenMetadata server configuration
  • Loading branch information
sushi30 committed Sep 17, 2024
1 parent eb7b1d5 commit e2597bf
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.openmetadata.schema.api.configuration.apps.AppsPrivateConfiguration;
import org.openmetadata.schema.api.configuration.dataQuality.DataQualityConfiguration;
import org.openmetadata.schema.api.configuration.events.EventHandlerConfiguration;
import org.openmetadata.schema.api.configuration.pipelineServiceClient.PipelineServiceClientConfiguration;
Expand Down Expand Up @@ -114,9 +113,6 @@ public PipelineServiceClientConfiguration getPipelineServiceClientConfiguration(
@JsonProperty("dataQualityConfiguration")
private DataQualityConfiguration dataQualityConfiguration;

@JsonProperty("applications")
private AppsPrivateConfiguration appsPrivateConfiguration;

@JsonProperty("limits")
private LimitsConfiguration limitsConfiguration;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package org.openmetadata.service.apps;

import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty;
import static org.openmetadata.service.apps.scheduler.AppScheduler.APPS_JOB_GROUP;
import static org.openmetadata.service.apps.scheduler.AppScheduler.APP_INFO_KEY;
import static org.openmetadata.service.apps.scheduler.AppScheduler.APP_NAME;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.configuration.apps.AppPrivateConfig;
import org.openmetadata.schema.api.configuration.apps.AppsPrivateConfiguration;
import org.openmetadata.schema.entity.app.App;
import org.openmetadata.service.OpenMetadataApplicationConfig;
import org.openmetadata.service.apps.scheduler.AppScheduler;
Expand All @@ -33,12 +32,11 @@ public class ApplicationHandler {

@Getter private static ApplicationHandler instance;
private final OpenMetadataApplicationConfig config;
private final AppsPrivateConfiguration privateConfiguration;
private final AppRepository appRepository;
private final ConfigurationReader configReader = new ConfigurationReader();

private ApplicationHandler(OpenMetadataApplicationConfig config) {
this.config = config;
this.privateConfiguration = config.getAppsPrivateConfiguration();
this.appRepository = new AppRepository();
}

Expand All @@ -55,28 +53,23 @@ public static void initialize(OpenMetadataApplicationConfig config) {
public void setAppRuntimeProperties(App app) {
app.setOpenMetadataServerConnection(
new OpenMetadataConnectionBuilder(config, app.getBot().getName()).build());

if (privateConfiguration != null
&& !nullOrEmpty(privateConfiguration.getAppsPrivateConfiguration())) {
for (AppPrivateConfig appPrivateConfig : privateConfiguration.getAppsPrivateConfiguration()) {
if (app.getName().equals(appPrivateConfig.getName())) {
app.setPreview(appPrivateConfig.getPreview());
app.setPrivateConfiguration(appPrivateConfig.getParameters());
}
}
try {
AppPrivateConfig appPrivateConfig = configReader.readConfigFromResource(app.getName());
app.setPreview(appPrivateConfig.getPreview());
app.setPrivateConfiguration(appPrivateConfig.getParameters());
} catch (IOException e) {
LOG.debug("Config file for app {} not found: ", app.getName(), e);
}
}

public Boolean isPreview(String appName) {
if (privateConfiguration != null
&& !nullOrEmpty(privateConfiguration.getAppsPrivateConfiguration())) {
for (AppPrivateConfig appPrivateConfig : privateConfiguration.getAppsPrivateConfiguration()) {
if (appName.equals(appPrivateConfig.getName())) {
return appPrivateConfig.getPreview();
}
}
try {
AppPrivateConfig appPrivateConfig = configReader.readConfigFromResource(appName);
return appPrivateConfig.getPreview();
} catch (IOException e) {
LOG.debug("Config file for app {} not found: ", appName, e);
return false;
}
return false;
}

public void triggerApplicationOnDemand(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.openmetadata.service.apps;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import joptsimple.internal.Strings;
import org.apache.commons.text.StringSubstitutor;
import org.openmetadata.schema.api.configuration.apps.AppPrivateConfig;
import org.openmetadata.service.util.JsonUtils;

public class ConfigurationReader {

private final Map<String, String> envMap;

public ConfigurationReader(Map<String, String> envMap) {
this.envMap = envMap;
}

public ConfigurationReader() {
this.envMap = System.getenv();
}

public AppPrivateConfig readConfigFromResource(String appName) throws IOException {
String configFilePath = "applications/" + appName + "/config.yaml";
try (InputStream inputStream =
ConfigurationReader.class.getClassLoader().getResourceAsStream(configFilePath)) {
if (inputStream == null) {
throw new IOException("Configuration file not found: " + configFilePath);
}
return JsonUtils.convertValue(readConfigFile(inputStream), AppPrivateConfig.class);
}
}

public Map<String, Object> readConfigFile(InputStream configStream) throws IOException {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Map<String, Object> config = mapper.readValue(configStream, Map.class);
resolveEnvVariablesInMap(config);
return mapper.convertValue(config, Map.class);
}

private void resolveEnvVariablesInMap(Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof String) {
map.put(entry.getKey(), resolveEnvVariables((String) entry.getValue(), envMap));
} else if (entry.getValue() instanceof Map) {
resolveEnvVariablesInMap((Map<String, Object>) entry.getValue());
} else if (entry.getValue() instanceof List) {
resolveEnvVariablesInList((List<Object>) entry.getValue());
}
}
}

private void resolveEnvVariablesInList(List<Object> list) {
for (int i = 0; i < list.size(); i++) {
Object element = list.get(i);
if (element instanceof String) {
list.set(i, resolveEnvVariables((String) element, envMap));
} else if (element instanceof Map) {
resolveEnvVariablesInMap((Map<String, Object>) element);
} else if (element instanceof List) {
resolveEnvVariablesInList((List<Object>) element);
}
}
}

public static String resolveEnvVariables(String value, Map<String, String> envMap) {
StringSubstitutor substitutor = new StringSubstitutor(envMap);
String resolved = substitutor.replace(value);
return resolved.equals("\"\"") ? Strings.EMPTY : resolved;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.openmetadata.service.resources.apps;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.openmetadata.schema.api.configuration.apps.AppPrivateConfig;
import org.openmetadata.service.apps.ConfigurationReader;

public class ConfigurationReaderTest {

@Test
public void testReadConfigFile() throws IOException {
ConfigurationReader reader =
new ConfigurationReader(
Map.of(
"ENV_VAR",
"resolvedValue",
"NESTED_ENV_VAR",
"nestedValue",
"LIST_ENV_VAR",
"value1"));
AppPrivateConfig appConfig = reader.readConfigFromResource("TestApplication");
assertNotNull(appConfig);
assertEquals("value1", appConfig.getParameters().getAdditionalProperties().get("key1"));
assertEquals("resolvedValue", appConfig.getParameters().getAdditionalProperties().get("key2"));
assertEquals("", appConfig.getParameters().getAdditionalProperties().get("emptyKey"));
assertEquals("default", appConfig.getParameters().getAdditionalProperties().get("defaultKey"));
Map<String, String> nested =
(Map<String, String>) appConfig.getParameters().getAdditionalProperties().get("nested");
assertEquals("nestedValue", nested.get("nestedKey"));
List<String> list =
(List<String>) appConfig.getParameters().getAdditionalProperties().get("list");
assertEquals("value1", list.get(1));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
parameters:
key1: value1
key2: ${ENV_VAR}
emptyKey: ${UNDEFINED_ENV_VAR:-""}
defaultKey: ${UNDEFINED_ENV_VAR:-default}
nested:
nestedKey: ${NESTED_ENV_VAR}
list:
- elem1
- ${LIST_ENV_VAR}

0 comments on commit e2597bf

Please sign in to comment.