Skip to content

[Ingest][convert-processor] Added MAC type in convert processor #96183

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

5 changes: 5 additions & 0 deletions docs/changelog/96183.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 96183
summary: Add MAC type in the convert processor.
area: Ingest
type: enhancement
issues: []
4 changes: 3 additions & 1 deletion docs/reference/ingest/processors/convert.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
Converts a field in the currently ingested document to a different type, such as converting a string to an integer.
If the field value is an array, all members will be converted.

The supported types include: `integer`, `long`, `float`, `double`, `string`, `boolean`, `ip`, and `auto`.
The supported types include: `integer`, `long`, `float`, `double`, `string`, `boolean`, `ip`, `mac`, and `auto`.

Specifying `boolean` will set the field to true if its string value is equal to `true` (ignore case), to
false if its string value is equal to `false` (ignore case), or it will throw an exception otherwise.

Specifying `ip` will set the target field to the value of `field` if it contains a valid IPv4 or IPv6 address
that can be indexed into an <<ip,IP field type>>.

Specifying `mac` will set the target field to the value of `field` if t contains a valid 48-bit/64-bit MAC Address. Moreover, it would convert the MAC Address in RFC 7042 format.

Specifying `auto` will attempt to convert the string-valued `field` into the closest non-string, non-IP type.
For example, a field whose value is `"true"` will be converted to its respective boolean type: `true`. Do note
that float takes precedence of double in `auto`. A value of `"242.15"` will "automatically" be converted to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ public Object convert(Object value) {
return value;
}
},
MAC {
@Override
public Object convert(Object value) {
StringBuilder stringBuilder = new StringBuilder();
String stringValue = value.toString().toUpperCase().replaceAll("[^a-fA-F0-9]", "");

// throw error if invalid 48-bit/64-bit MAC Address.
if ((stringValue.length() == 12 || stringValue.length() == 16) == false) throw new IllegalArgumentException(
"[" + value + "] is not a valid MAC Address"
);

for (int i = 0; i < stringValue.length(); i++) {
if (i != 0 && i % 2 == 0) {
stringBuilder.append('-');
}
stringBuilder.append(stringValue.charAt(i));
}

return stringBuilder.toString();
}
},
STRING {
@Override
public Object convert(Object value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,48 @@ public void testConvertIpList() throws Exception {
assertThat(ingestDocument.getFieldValue(fieldName, List.class), equalTo(expectedList));
}

public void testValidMACConvert() throws Exception {
List<String> fieldValue = new ArrayList<>();
List<String> expectedList = new ArrayList<>();
Map<String, String> testValueMap = new HashMap<>();
testValueMap.put("10:AC:AF:BC:16:22", "10-AC-AF-BC-16-22");
testValueMap.put("10-AC-AF-BC-16-22", "10-AC-AF-BC-16-22");
testValueMap.put("10A.CAF.BC1.622", "10-AC-AF-BC-16-22");
testValueMap.put("10:ac:af:bc:16:22", "10-AC-AF-BC-16-22");
testValueMap.put("00:01:10:ac:af:bc:16:22", "00-01-10-AC-AF-BC-16-22");
testValueMap.put("00-01-10-AC-AF-BC-16-22", "00-01-10-AC-AF-BC-16-22");

testValueMap.forEach((key, value) -> {
fieldValue.add(key);
expectedList.add(value);
});

IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, fieldValue);
Processor processor = new ConvertProcessor(randomAlphaOfLength(10), null, fieldName, fieldName, Type.MAC, false);
processor.execute(ingestDocument);
assertThat(ingestDocument.getFieldValue(fieldName, List.class), equalTo(expectedList));
}

public void testInvalidMACConvert() throws Exception {
List<String> fieldValue = new ArrayList<>();
fieldValue.add("XX:xx:AF:BC:16:22");
fieldValue.add("XX:01:10:ac:af:bc:16:22");
fieldValue.add("::01:10:ac:af:bc:16:22");
fieldValue.add("00:00:01:10:ac:af:bc:16:22");
fieldValue.add("01-10-ac-af-bc-16-22");
fieldValue.add("10:AC:AF:BC:16:2");

String value = fieldValue.get(randomIntBetween(0, fieldValue.size() - 1));

IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
String fieldName = RandomDocumentPicks.addRandomField(random(), ingestDocument, value);
Processor processor = new ConvertProcessor(randomAlphaOfLength(10), null, fieldName, fieldName, Type.MAC, false);

IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> processor.execute(ingestDocument));
assertThat(e.getMessage(), containsString("[" + value + "] is not a valid MAC Address"));
}

public void testConvertString() throws Exception {
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random());
Object fieldValue;
Expand Down