Skip to content

Commit

Permalink
Transformation improvements.
Browse files Browse the repository at this point in the history
I've added all of the transformer jars to the runtime closure of the replayer since it's going to be a challenge for users using a cloud-deployment shrink-wrap solution to add addition jarfiles.
Change the syntax/rules for Transformer configs.
* If no argument was specified for the transformer config, no transformer used, regardless of what's in the classpath.
* To use multiple transformers, you’ll need to specify the transformer-config as a json array (of json transformer configs)
* To use one transformer with default settings, you can JUST put the name of the transformer in the arg.  e.g. --transformer-config JsonTransformerForOpenSearch23PlusTargetTransformerProvider.

I've also updated the key name to only use the short, simple name of a class rather than the fully qualified one with the namespace.
Add a NoopTransformer, which makes unit and sanity testing a lot simpler.

Signed-off-by: Greg Schohn <greg.schohn@gmail.com>
  • Loading branch information
gregschohn committed Nov 14, 2023
1 parent bce4aed commit c66da0e
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private static Map<String,Object> parseAsMap(String contents) throws Exception {
@Test
public void testAddGzip() throws Exception {
final var addGzip =
"[{\"org.opensearch.migrations.transform.JsonJoltTransformerProvider\": { \"canned\": \"ADD_GZIP\" }}]";
"[{\"JsonJoltTransformerProvider\": { \"canned\": \"ADD_GZIP\" }}]";
var toNewHostTransformer = new TransformationLoader().getTransformerFactoryLoader("testhostname",
addGzip);
var origDocStr = SampleContents.loadSampleJsonRequestAsString();
Expand All @@ -37,8 +37,8 @@ public void testAddGzip() throws Exception {
@Test
public void testAddGzipAndCustom() throws Exception {
final var addGzip = "[" +
"{\"org.opensearch.migrations.transform.JsonJoltTransformerProvider\": { \"canned\": \"ADD_GZIP\" }}," +
"{ \"org.opensearch.migrations.transform.JsonJoltTransformerProvider\":" +
"{\"JsonJoltTransformerProvider\": { \"canned\": \"ADD_GZIP\" }}," +
"{ \"JsonJoltTransformerProvider\":" +
" {\"script\": \n" +
" { \"operation\": \"modify-overwrite-beta\", \"spec\": " +
" { \"headers\": {\"newHeader\": \"newValue\"}}}}}" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.opensearch.migrations.transform;

import java.util.Map;

public class NoopTransformerProvider implements IJsonTransformerProvider {
private static class NoopTransformer implements IJsonTransformer {
@Override
public Map<String, Object> transformJson(Map<String, Object> incomingJson) {
return incomingJson;
}
}

@Override
public IJsonTransformer createTransformer(Object jsonConfig) {
return new NoopTransformer();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.opensearch.migrations.transform.NoopTransformerProvider
7 changes: 6 additions & 1 deletion TrafficCapture/trafficReplayer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ dependencies {
implementation project(':captureProtobufs')
implementation project(':coreUtilities')
implementation project(':replayerPlugins:jsonMessageTransformers:jsonMessageTransformerInterface')
implementation project(':replayerPlugins:jsonMessageTransformers:openSearch23PlusTargetTransformerProvider')
runtimeOnly project(':replayerPlugins:jsonMessageTransformers:jsonJMESPathMessageTransformerProvider')
runtimeOnly project(':replayerPlugins:jsonMessageTransformers:jsonJoltMessageTransformerProvider')
runtimeOnly project(':replayerPlugins:jsonMessageTransformers:openSearch23PlusTargetTransformerProvider')

implementation group: 'com.beust', name: 'jcommander', version: '1.82'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.15.0'
Expand Down Expand Up @@ -73,6 +75,9 @@ dependencies {
testImplementation project(':captureOffloader')
testImplementation testFixtures(project(path: ':captureOffloader'))
testImplementation testFixtures(project(path: ':testUtilities'))
testImplementation project(':replayerPlugins:jsonMessageTransformers:jsonJMESPathMessageTransformerProvider')
testImplementation project(':replayerPlugins:jsonMessageTransformers:jsonJoltMessageTransformerProvider')
testImplementation project(':replayerPlugins:jsonMessageTransformers:openSearch23PlusTargetTransformerProvider')

testImplementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.2.1'
testImplementation group: 'org.junit.jupiter', name:'junit-jupiter-api', version:'5.x.x'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
public class TransformationLoader {
public static final String WRONG_JSON_STRUCTURE_MESSAGE = "Must specify the top-level configuration list with a sequence of " +
"maps that have only one key each, where the key is the name of the transformer to be configured.";
public static final Pattern CLASS_NAME_PATTERN = Pattern.compile("^[a-zA-Z_$][a-zA-Z\\d_$]*$");
private final List<IJsonTransformerProvider> providers;
ObjectMapper objMapper = new ObjectMapper();

Expand All @@ -40,23 +42,22 @@ public TransformationLoader() {
}

List<Map<String, Object>> parseFullConfig(String fullConfig) throws JsonProcessingException {
return objMapper.readValue(fullConfig, new TypeReference<>() {});
if (CLASS_NAME_PATTERN.matcher(fullConfig).matches()) {
return List.of(Collections.singletonMap(fullConfig, null));
} else {
return objMapper.readValue(fullConfig, new TypeReference<>() {
});
}
}

protected Stream<IJsonTransformer> getTransformerFactoryFromServiceLoader(String fullConfig)
throws JsonProcessingException {
var configList = fullConfig == null ? List.of() : parseFullConfig(fullConfig);
if (providers.size() > 1 && configList.isEmpty()) {
throw new IllegalArgumentException("Must provide a configuration when multiple IJsonTransformerProvider " +
"are loaded (" + providers.stream().map(p -> p.getClass().toString())
.collect(Collectors.joining(",")) + ")");
} else if (providers.isEmpty()) {
if (configList.isEmpty() || providers.isEmpty()) {
log.warn("No transformer configuration specified. No custom transformations will be performed");
return Stream.of();
} else if (!configList.isEmpty()) {
}else {
return configList.stream().map(c -> configureTransformerFromConfig((Map<String, Object>) c));
} else {
// send in Optional.empty because we would have hit the other case in the previous branch
return Stream.of(providers.get(0).createTransformer(Optional.empty()));
}
}

Expand All @@ -69,7 +70,7 @@ private IJsonTransformer configureTransformerFromConfig(Map<String, Object> c) {
var key = keys.stream().findFirst()
.orElseThrow(()->new IllegalArgumentException(WRONG_JSON_STRUCTURE_MESSAGE));
for (var p : providers) {
var className = p.getClass().getName();
var className = p.getClass().getSimpleName();
if (className.equals(key)) {
var configuration = c.get(key);
log.atInfo().setMessage(()->"Creating a transformer with configuration="+configuration).log();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void testMalformedPayload_andTypeMappingUri_IsPassedThrough() throws Exce

var transformingHandler = new HttpJsonTransformingConsumer(
new TransformationLoader().getTransformerFactoryLoader(SILLY_TARGET_CLUSTER_NAME,
"[{\"org.opensearch.migrations.transform.JsonTransformerForOpenSearch23PlusTargetTransformerProvider\":\"\"}]"),
"[{\"JsonTransformerForOpenSearch23PlusTargetTransformerProvider\":\"\"}]"),
null, testPacketCapture, "TEST", TestRequestKey.getTestConnectionRequestId(0));

Random r = new Random(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,13 @@ public void testTransformationLoader() throws Exception {
Assertions.assertNotEquals(origDocStr, docWithNewHostnameStr);
}

@Test
public void testThatSimpleNoopTransformerLoads() throws Exception {
var noopTransformer = new TransformationLoader()
.getTransformerFactoryLoader("localhost", "NoopTransformerProvider");
var origDoc = parseAsMap(SampleContents.loadSampleJsonRequestAsString());
var output = noopTransformer.transformJson(origDoc);
Assertions.assertEquals(mapper.writeValueAsString(origDoc), mapper.writeValueAsString(output));

}
}

0 comments on commit c66da0e

Please sign in to comment.