Skip to content

Commit 74a65a0

Browse files
committed
GeoIP interfaces for the Logstash bridge where elastic_integration plugin utilizes.
1 parent d047add commit 74a65a0

File tree

8 files changed

+300
-2
lines changed

8 files changed

+300
-2
lines changed

libs/logstash-bridge/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ dependencies {
2424
compileOnly project(':x-pack:plugin:redact')
2525
compileOnly project(':x-pack:plugin:spatial')
2626
compileOnly project(':x-pack:plugin:wildcard')
27+
28+
compileOnly('com.maxmind.db:maxmind-db:3.1.1')
2729
}
2830

2931
tasks.named('forbiddenApisMain').configure {

libs/logstash-bridge/src/main/java/module-info.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
requires org.elasticsearch.redact;
2424
requires org.elasticsearch.spatial;
2525
requires org.elasticsearch.wildcard;
26+
requires org.elasticsearch.ingest.geoip;
27+
requires com.maxmind.db;
2628

2729
exports org.elasticsearch.logstashbridge;
2830
exports org.elasticsearch.logstashbridge.common;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
package org.elasticsearch.logstashbridge.geoip;
10+
11+
import org.elasticsearch.ingest.geoip.GeoIpProcessor;
12+
import org.elasticsearch.ingest.geoip.IpDatabaseProvider;
13+
import org.elasticsearch.logstashbridge.StableBridgeAPI;
14+
15+
/**
16+
* An external bridge for {@link GeoIpProcessor}
17+
*/
18+
public interface GeoIpProcessorBridge {
19+
20+
class Factory extends StableBridgeAPI.ProxyInternal<GeoIpProcessor.Factory> {
21+
22+
public Factory(String type, IpDatabaseProvider ipDatabaseProvider) {
23+
super(new GeoIpProcessor.Factory(type, ipDatabaseProvider));
24+
}
25+
}
26+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
package org.elasticsearch.logstashbridge.geoip;
10+
11+
import com.maxmind.db.Reader;
12+
13+
import org.elasticsearch.ExceptionsHelper;
14+
import org.elasticsearch.common.CheckedBiFunction;
15+
import org.elasticsearch.core.Nullable;
16+
import org.elasticsearch.ingest.geoip.IpDatabase;
17+
import org.elasticsearch.logstashbridge.StableBridgeAPI;
18+
19+
import java.io.IOException;
20+
21+
/**
22+
* An external bridge for {@link IpDatabase}
23+
*/
24+
public interface IpDatabaseBridge extends StableBridgeAPI<IpDatabase> {
25+
26+
String getDatabaseType() throws IOException;
27+
28+
MaxMindDbBridge.Reader getDatabaseReader() throws IOException;
29+
30+
@Nullable
31+
default <RESPONSE> RESPONSE getResponse(String ipAddress, CheckedBiFunction<Reader, String, RESPONSE, Exception> responseProvider) {
32+
try {
33+
return responseProvider.apply(this.getDatabaseReader().toInternal(), ipAddress);
34+
} catch (Exception e) {
35+
throw ExceptionsHelper.convertToRuntime(e);
36+
}
37+
}
38+
39+
void close() throws IOException;
40+
41+
static IpDatabaseBridge fromInternal(final IpDatabase internalDatabase) {
42+
if (internalDatabase instanceof AbstractExternal.ProxyExternal externalProxy) {
43+
return externalProxy.getIpDatabaseBridge();
44+
}
45+
return new ProxyInternal(internalDatabase);
46+
}
47+
48+
/**
49+
* The {@code IpDatabaseBridge.AbstractExternal} is an abstract base class for implementing
50+
* the {@link IpDatabaseBridge} externally to the Elasticsearch code-base. It takes care of
51+
* the details of maintaining a singular internal-form implementation of {@link IpDatabase}
52+
* that proxies calls through the external implementation.
53+
*/
54+
abstract class AbstractExternal implements IpDatabaseBridge {
55+
private ProxyExternal internalDatabase;
56+
57+
@Override
58+
public IpDatabase toInternal() {
59+
if (internalDatabase == null) {
60+
internalDatabase = new ProxyExternal();
61+
}
62+
return internalDatabase;
63+
}
64+
65+
private class ProxyExternal implements IpDatabase {
66+
67+
private AbstractExternal getIpDatabaseBridge() {
68+
return AbstractExternal.this;
69+
}
70+
71+
@Override
72+
public String getDatabaseType() throws IOException {
73+
return AbstractExternal.this.getDatabaseType();
74+
}
75+
76+
@Override
77+
public <RESPONSE> RESPONSE getResponse(
78+
String ipAddress,
79+
CheckedBiFunction<Reader, String, RESPONSE, Exception> responseProvider
80+
) {
81+
return AbstractExternal.this.getResponse(ipAddress, responseProvider);
82+
}
83+
84+
@Override
85+
public void close() throws IOException {
86+
AbstractExternal.this.close();
87+
}
88+
}
89+
}
90+
91+
/**
92+
* An implementation of {@link IpDatabaseBridge} that proxies to an internal {@link IpDatabase}
93+
*/
94+
class ProxyInternal extends StableBridgeAPI.ProxyInternal<IpDatabase> implements IpDatabaseBridge {
95+
96+
public ProxyInternal(final IpDatabase delegate) {
97+
super(delegate);
98+
}
99+
100+
@Override
101+
public String getDatabaseType() throws IOException {
102+
return toInternal().getDatabaseType();
103+
}
104+
105+
@Override
106+
public MaxMindDbBridge.Reader getDatabaseReader() throws IOException {
107+
return null;
108+
}
109+
110+
@Override
111+
public <RESPONSE> RESPONSE getResponse(String ipAddress, CheckedBiFunction<Reader, String, RESPONSE, Exception> responseProvider) {
112+
return toInternal().getResponse(ipAddress, responseProvider);
113+
}
114+
115+
@Override
116+
public void close() throws IOException {
117+
toInternal().close();
118+
}
119+
}
120+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
package org.elasticsearch.logstashbridge.geoip;
10+
11+
import org.elasticsearch.cluster.metadata.ProjectId;
12+
import org.elasticsearch.ingest.Processor;
13+
import org.elasticsearch.ingest.geoip.IpDatabase;
14+
import org.elasticsearch.ingest.geoip.IpDatabaseProvider;
15+
import org.elasticsearch.logstashbridge.StableBridgeAPI;
16+
17+
import java.util.Objects;
18+
19+
/**
20+
* An external bridge for {@link Processor}
21+
*/
22+
public interface IpDatabaseProviderBridge extends StableBridgeAPI<IpDatabaseProvider> {
23+
24+
Boolean isValid(String name);
25+
26+
IpDatabaseBridge getDatabase(String name);
27+
28+
static IpDatabaseProviderBridge fromInternal(final IpDatabaseProvider internalProvider) {
29+
if (internalProvider instanceof IpDatabaseProviderBridge.AbstractExternal.ProxyExternal externalProxy) {
30+
return externalProxy.getIpDatabaseProviderBridge();
31+
}
32+
return new IpDatabaseProviderBridge.ProxyInternal(internalProvider);
33+
}
34+
35+
/**
36+
* The {@code IpDatabaseProviderBridge.AbstractExternal} is an abstract base class for implementing
37+
* the {@link IpDatabaseProviderBridge} externally to the Elasticsearch code-base. It takes care of
38+
* the details of maintaining a singular internal-form implementation of {@link IpDatabaseProvider}
39+
* that proxies calls through the external implementation.
40+
*/
41+
abstract class AbstractExternal implements IpDatabaseProviderBridge {
42+
private AbstractExternal.ProxyExternal internalProcessor;
43+
44+
public IpDatabaseProvider toInternal() {
45+
if (internalProcessor == null) {
46+
internalProcessor = new AbstractExternal.ProxyExternal();
47+
}
48+
return internalProcessor;
49+
}
50+
51+
private class ProxyExternal implements IpDatabaseProvider {
52+
53+
private AbstractExternal getIpDatabaseProviderBridge() {
54+
return AbstractExternal.this;
55+
}
56+
57+
@Override
58+
public Boolean isValid(ProjectId projectId, String name) {
59+
return IpDatabaseProviderBridge.AbstractExternal.this.isValid(name);
60+
}
61+
62+
@Override
63+
public IpDatabase getDatabase(ProjectId projectId, String name) {
64+
IpDatabaseBridge bridge = IpDatabaseProviderBridge.AbstractExternal.this.getDatabase(name);
65+
return Objects.isNull(bridge) ? null : bridge.toInternal();
66+
}
67+
}
68+
}
69+
70+
/**
71+
* An implementation of {@link IpDatabaseProviderBridge} that proxies to an internal {@link IpDatabaseProvider}
72+
*/
73+
class ProxyInternal extends StableBridgeAPI.ProxyInternal<IpDatabaseProvider> implements IpDatabaseProviderBridge {
74+
public ProxyInternal(final IpDatabaseProvider delegate) {
75+
super(delegate);
76+
}
77+
78+
@Override
79+
public Boolean isValid(String name) {
80+
return toInternal().isValid(ProjectId.DEFAULT, name);
81+
}
82+
83+
@Override
84+
public IpDatabaseBridge getDatabase(String name) {
85+
IpDatabase ipDatabase = toInternal().getDatabase(ProjectId.DEFAULT, name);
86+
return new IpDatabaseBridge.ProxyInternal(ipDatabase);
87+
}
88+
}
89+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
package org.elasticsearch.logstashbridge.geoip;
10+
11+
import org.elasticsearch.core.SuppressForbidden;
12+
import org.elasticsearch.logstashbridge.StableBridgeAPI;
13+
14+
import java.io.File;
15+
import java.io.IOException;
16+
17+
public interface MaxMindDbBridge {
18+
19+
class Reader extends StableBridgeAPI.ProxyInternal<com.maxmind.db.Reader> {
20+
21+
@SuppressForbidden(reason = "Maxmind Reader constructor requires java.io.File")
22+
public Reader(final File databasePath, final NodeCache nodeCache) throws IOException {
23+
super(new com.maxmind.db.Reader(databasePath, nodeCache.toInternal()));
24+
}
25+
26+
protected Reader(final com.maxmind.db.Reader internalDelegate) {
27+
super(internalDelegate);
28+
}
29+
30+
@Override
31+
public com.maxmind.db.Reader toInternal() {
32+
return internalDelegate;
33+
}
34+
35+
public String getDatabaseType() {
36+
return toInternal().getMetadata().getDatabaseType();
37+
}
38+
39+
public void close() throws IOException {
40+
toInternal().close();
41+
}
42+
}
43+
44+
class NodeCache extends StableBridgeAPI.ProxyInternal<com.maxmind.db.NodeCache> {
45+
46+
protected NodeCache(final com.maxmind.db.NodeCache internalDelegate) {
47+
super(internalDelegate);
48+
}
49+
50+
public static NodeCache get(final int capacity) {
51+
return new NodeCache(new com.maxmind.db.CHMCache(capacity));
52+
}
53+
54+
public static NodeCache getInstance() {
55+
return new NodeCache(com.maxmind.db.NoCache.getInstance());
56+
}
57+
}
58+
59+
}

libs/logstash-bridge/src/main/java/org/elasticsearch/logstashbridge/script/ScriptServiceBridge.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public void close() throws IOException {
117117
@FixForMultiProject
118118
// Logstash resolves and runs ingest pipelines based on the datastream.
119119
// How should ProjectIdResolverBridge behave in this case?
120-
// In other words, it looks we need to find a way to figure out which ingest pipeline belongs to which project.
120+
// In other words, it looks we need to find a way to figure out which ingest pipeline belongs to which project.
121121
static class ProjectIdResolverBridge implements ProjectResolver {
122122

123123
public static final ProjectIdResolverBridge INSTANCE = new ProjectIdResolverBridge();

modules/ingest-geoip/src/main/java/module-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
exports org.elasticsearch.ingest.geoip.direct to org.elasticsearch.server;
2020
exports org.elasticsearch.ingest.geoip.stats to org.elasticsearch.server;
2121

22-
exports org.elasticsearch.ingest.geoip to com.maxmind.db;
22+
exports org.elasticsearch.ingest.geoip to com.maxmind.db, org.elasticsearch.logstashbridge;
2323
}

0 commit comments

Comments
 (0)