-
Notifications
You must be signed in to change notification settings - Fork 211
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
added default mapper for mapping logstash config models to data prepper plugin model #559
Changes from all commits
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,18 @@ | ||
package org.opensearch.dataprepper.logstash.exception; | ||
|
||
/** | ||
* Exception thrown when attempting to map between Logstash configuration model and Data Prepper model | ||
* | ||
* @since 1.2 | ||
*/ | ||
public class LogstashMappingException extends LogstashConfigurationException{ | ||
|
||
public LogstashMappingException(String errorMessage) { | ||
super(errorMessage); | ||
} | ||
|
||
public LogstashMappingException(String errorMessage, Exception inner) { | ||
super(errorMessage, inner); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package org.opensearch.dataprepper.logstash.mapping; | ||
|
||
import com.amazon.dataprepper.model.configuration.PluginModel; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; | ||
import org.opensearch.dataprepper.logstash.exception.LogstashMappingException; | ||
import org.opensearch.dataprepper.logstash.model.LogstashPlugin; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Converts Logstash plugin model to Data Prepper plugin model using mapping file | ||
* | ||
* @since 1.2 | ||
*/ | ||
public class DefaultPluginMapper implements LogstashPluginMapper { | ||
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. This class should have unit tests as well. |
||
private static final Logger LOG = LoggerFactory.getLogger(DefaultPluginMapper.class); | ||
private final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); | ||
|
||
@Override | ||
public PluginModel mapPlugin(LogstashPlugin logstashPlugin) { | ||
|
||
String mappingResourceName = logstashPlugin.getPluginName() + ".mapping.yaml"; | ||
|
||
final InputStream inputStream = this.getClass().getResourceAsStream(mappingResourceName); | ||
if (inputStream == null) { | ||
throw new LogstashMappingException("Unable to find mapping resource " + mappingResourceName); | ||
} | ||
|
||
LogstashMappingModel logstashMappingModel; | ||
try { | ||
logstashMappingModel = objectMapper.readValue(inputStream, LogstashMappingModel.class); | ||
} | ||
catch(IOException ex) { | ||
throw new LogstashMappingException("Unable to parse mapping file " + mappingResourceName, ex); | ||
} | ||
|
||
if (logstashMappingModel.getPluginName() == null) { | ||
throw new LogstashMappingException("The mapping file " + mappingResourceName + " has a null value for 'pluginName'."); | ||
} | ||
Map<String, Object> pluginSettings = new LinkedHashMap<>(logstashMappingModel.getAdditionalAttributes()); | ||
|
||
logstashPlugin.getAttributes().forEach(logstashAttribute -> { | ||
if (logstashMappingModel.getMappedAttributeNames().containsKey(logstashAttribute.getAttributeName())) { | ||
pluginSettings.put( | ||
logstashMappingModel.getMappedAttributeNames().get(logstashAttribute.getAttributeName()), | ||
logstashAttribute.getAttributeValue().getValue() | ||
); | ||
} | ||
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 we may wish to log a warning for unmapped Logstash attributes, in an |
||
else { | ||
LOG.warn("Attribute name {} is not found in mapping file.", logstashAttribute.getAttributeName()); | ||
} | ||
}); | ||
|
||
return new PluginModel(logstashMappingModel.getPluginName(), pluginSettings); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package org.opensearch.dataprepper.logstash.mapping; | ||
|
||
import com.amazon.dataprepper.model.configuration.PluginModel; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.opensearch.dataprepper.logstash.exception.LogstashMappingException; | ||
import org.opensearch.dataprepper.logstash.model.LogstashPlugin; | ||
|
||
import static org.hamcrest.CoreMatchers.equalTo; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.Assert.assertThrows; | ||
|
||
class DefaultPluginMapperTest { | ||
|
||
private DefaultPluginMapper defaultPluginMapper; | ||
|
||
@BeforeEach | ||
void createObjectUnderTest() { | ||
defaultPluginMapper = new DefaultPluginMapper(); | ||
} | ||
|
||
@Test | ||
void mapPlugin_without_mapping_file_throws_logstash_mapping_exception_Test() { | ||
LogstashPlugin logstashPlugin = TestDataProvider.invalidMappingResourceNameData(); | ||
String mappingResourceName = logstashPlugin.getPluginName() + ".mapping.yaml"; | ||
|
||
Exception exception = assertThrows(LogstashMappingException.class, () -> | ||
defaultPluginMapper.mapPlugin(logstashPlugin)); | ||
|
||
String expectedMessage = "Unable to find mapping resource " + mappingResourceName; | ||
String actualMessage = exception.getMessage(); | ||
|
||
assertThat(expectedMessage, equalTo(actualMessage)); | ||
} | ||
|
||
@Test | ||
void mapPlugin_with_incorrect_mapping_file_throws_logstash_mapping_exception_Test() { | ||
LogstashPlugin logstashPlugin = TestDataProvider.invalidMappingResourceData(); | ||
String mappingResourceName = logstashPlugin.getPluginName() + ".mapping.yaml"; | ||
|
||
Exception exception = assertThrows(LogstashMappingException.class, () -> | ||
defaultPluginMapper.mapPlugin(logstashPlugin)); | ||
|
||
String expectedMessage = "Unable to parse mapping file " + mappingResourceName; | ||
String actualMessage = exception.getMessage(); | ||
|
||
assertThat(expectedMessage, equalTo(actualMessage)); | ||
} | ||
|
||
@Test | ||
void mapPlugin_without_plugin_name_in_mapping_file_throws_logstash_mapping_exception_Test() { | ||
LogstashPlugin logstashPlugin = TestDataProvider.noPluginNameMappingResourceData(); | ||
String mappingResourceName = logstashPlugin.getPluginName() + ".mapping.yaml"; | ||
|
||
Exception exception = assertThrows(LogstashMappingException.class, () -> | ||
defaultPluginMapper.mapPlugin(logstashPlugin)); | ||
|
||
String expectedMessage = "The mapping file " + mappingResourceName + " has a null value for 'pluginName'."; | ||
String actualMessage = exception.getMessage(); | ||
|
||
assertThat(expectedMessage, equalTo(actualMessage)); | ||
} | ||
|
||
@Test | ||
void mapPlugin_returns_plugin_model_Test() { | ||
LogstashPlugin logstashPlugin = TestDataProvider.pluginData(); | ||
|
||
PluginModel actualPluginModel = defaultPluginMapper.mapPlugin(logstashPlugin); | ||
PluginModel expectedPluginModel = TestDataProvider.getSamplePluginModel(); | ||
|
||
assertThat(expectedPluginModel.getPluginName(), equalTo(actualPluginModel.getPluginName())); | ||
assertThat(expectedPluginModel.getPluginSettings(), equalTo(actualPluginModel.getPluginSettings())); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package org.opensearch.dataprepper.logstash.mapping; | ||
|
||
import com.amazon.dataprepper.model.configuration.PluginModel; | ||
import org.opensearch.dataprepper.logstash.model.LogstashAttribute; | ||
import org.opensearch.dataprepper.logstash.model.LogstashAttributeValue; | ||
import org.opensearch.dataprepper.logstash.model.LogstashPlugin; | ||
import org.opensearch.dataprepper.logstash.model.LogstashValueType; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
public class TestDataProvider { | ||
|
||
public static LogstashPlugin invalidMappingResourceNameData() { | ||
return LogstashPlugin.builder() | ||
.pluginName("amazon_elasticsearch") | ||
.attributes(Collections.singletonList(getArrayTypeAttribute())).build(); | ||
} | ||
|
||
public static LogstashPlugin invalidMappingResourceData() { | ||
return LogstashPlugin.builder() | ||
.pluginName("invalid") | ||
.attributes(Collections.singletonList(getArrayTypeAttribute())).build(); | ||
} | ||
|
||
public static LogstashPlugin noPluginNameMappingResourceData() { | ||
return LogstashPlugin.builder() | ||
.pluginName("no_plugin_name") | ||
.attributes(Collections.singletonList(getArrayTypeAttribute())).build(); | ||
} | ||
|
||
public static LogstashPlugin pluginData() { | ||
return LogstashPlugin.builder() | ||
.pluginName("amazon_es") | ||
.attributes(Arrays.asList(getArrayTypeAttribute(), getStringTypeAttribute())).build(); | ||
} | ||
|
||
public static PluginModel getSamplePluginModel() { | ||
Map<String, Object> attributes = new LinkedHashMap<>(); | ||
attributes.put("aws_sigv4", true); | ||
attributes.put("insecure", false); | ||
attributes.put("aws_region", "us-west-2"); | ||
attributes.put("hosts", Collections.singletonList("https://localhost:9200")); | ||
return new PluginModel("opensearch", attributes); | ||
} | ||
|
||
private static LogstashAttribute getArrayTypeAttribute() { | ||
LogstashAttributeValue logstashAttributeValue = LogstashAttributeValue.builder() | ||
.attributeValueType(LogstashValueType.ARRAY) | ||
.value(Collections.singletonList("https://localhost:9200")) | ||
.build(); | ||
return LogstashAttribute.builder() | ||
.attributeName("hosts") | ||
.attributeValue(logstashAttributeValue) | ||
.build(); | ||
} | ||
|
||
private static LogstashAttribute getStringTypeAttribute() { | ||
LogstashAttributeValue logstashAttributeValue = LogstashAttributeValue.builder() | ||
.attributeValueType(LogstashValueType.STRING) | ||
.value("us-west-2") | ||
.build(); | ||
return LogstashAttribute.builder() | ||
.attributeName("region") | ||
.attributeValue(logstashAttributeValue) | ||
.build(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pluginName: opensearch | ||
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. Minor: Would it be clearer if the file name is something like: logstash_to_dataprepper_config.mapping.yaml It's unit test. I am OK with you adding more tests later. I will approve the pull request now. 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. Thanks, I'll will add more tests later |
||
mappedAttributeNames: | ||
hosts: hosts | ||
index: index | ||
region: aws_region | ||
additionalAttributes: | ||
aws_sigv4: true | ||
insecure: false |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pluginName: | ||
mappedAttributeNames: | ||
hosts: hosts | ||
cacert: cert | ||
user: username | ||
password: password | ||
index: index | ||
proxy: proxy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mappedAttributeNames: | ||
hosts: hosts | ||
index: index | ||
region: aws_region | ||
additionalAttributes: | ||
aws_sigv4: true | ||
insecure: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my comment on wrapping
IOException
, you will need another constructor with(String message, Exception inner)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll update LogstashMappingException