Skip to content

Commit 56e33c5

Browse files
Chaho12mosabua
authored andcommitted
Add external routing group selector
1 parent b701662 commit 56e33c5

13 files changed

+798
-25
lines changed

docs/routing-rules.md

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,82 @@ By default, Trino Gateway reads the `X-Trino-Routing-Group` request header to
66
route requests. If this header is not specified, requests are sent to default
77
routing group (adhoc).
88

9-
The routing rules engine feature enables you to write custom logic to route
9+
The routing rules engine feature enables you to either write custom logic to route
1010
requests based on the request info such as any of the [request
11-
headers](https://trino.io/docs/current/develop/client-protocol.html#client-request-headers).
11+
headers](https://trino.io/docs/current/develop/client-protocol.html#client-request-headers),
12+
or set a URL address to make an HTTP POST request and route based on the returned result.
13+
1214
Routing rules are separated from Trino Gateway application code to a
13-
configuration file, allowing for dynamic rule changes.
15+
configuration file or a separate service. This separate service is specified as a URL
16+
and can implement any dynamic rule changes or other behavior.
17+
18+
### Enabling the routing rules engine
19+
20+
To enable the routing rules engine, find the following lines in `gateway-ha-config.yml`.
1421

15-
### Defining your routing rules
22+
* Set `rulesEngineEnabled` to `true`, then `rulesType` as `FILE` or `EXTERNAL`.
23+
* Then either add `rulesConfigPath` to the path to your rules config file or set `rulesExternalConfiguration`
24+
to the URL of an external service for routing rules processing.
25+
*`rulesType` is by default `FILE` unless specified.
26+
27+
```yaml
28+
routingRules:
29+
rulesEngineEnabled: true
30+
rulesType: FILE
31+
rulesConfigPath: "app/config/routing_rules.yml" # replace with actual path to your rules config file
32+
rulesExternalConfiguration:
33+
urlPath: https://router.example.com/gateway-rules # replace with your own API path
34+
blacklistHeaders:
35+
- 'Authorization'
36+
```
37+
38+
* Redirect URLs are not supported
39+
* Optionally add headers to the `BlacklistHeaders` list to exclude requests with corresponding header values
40+
from being sent in the POST request.
41+
42+
If there is error parsing the routing rules configuration file, an error is logged,
43+
and requests are routed using the routing group header `X-Trino-Routing-Group` as default.
44+
45+
### Use an external service for routing rules
46+
47+
You can use an external service for processing your routing by setting the
48+
`rulesType` to `EXTERNAL` and configuring the `rulesExternalConfiguration`.
49+
50+
Trino Gateway then sends all headers as a map in the body of a POST request to the external service.
51+
Headers specified in `blacklistHeaders` are excluded. If `requestAnalyzerConfig.isAnalyzeRequest` is set to `true`,
52+
`TrinoRequestUser` and `TrinoQueryProperties` are also included.
53+
54+
Additionally, the following HTTP information is included:
55+
56+
- `remoteUser`
57+
- `method`
58+
- `requestURI`
59+
- `queryString`
60+
- `session`
61+
- `remoteAddr`
62+
- `remoteHost`
63+
- `parameterMap`
64+
65+
The external service can process the information in any way desired
66+
and must return a result with the following criteria:
67+
68+
* Response status code of OK (200)
69+
* Message in JSON format
70+
* Only one group can be returned
71+
* If errors is not null, then query would route to default routing group adhoc
72+
73+
```json
74+
{
75+
"routingGroup": "test-group",
76+
"errors": [
77+
"Error1",
78+
"Error2",
79+
"Error3"
80+
]
81+
}
82+
```
83+
84+
### Configure routing rules with a file
1685

1786
To express and fire routing rules, we use the
1887
[easy-rules](https://github.com/j-easy/easy-rules) engine. These rules should be
@@ -354,18 +423,3 @@ actions:
354423
result.put(\"routingGroup\", \"etl\")
355424
}"
356425
```
357-
358-
### Enabling routing rules engine
359-
360-
To enable routing rules engine, find the following lines in
361-
`gateway-ha-config.yml`. Set `rulesEngineEnabled` to True and `rulesConfigPath`
362-
to the path to your rules config file.
363-
364-
```
365-
routingRules:
366-
rulesEngineEnabled: true
367-
rulesConfigPath: "src/test/resources/rules/routing_rules.yml" # replace with path to your rules config file
368-
```
369-
370-
If there is error opening routing rules configuration file, then request is routed
371-
using routing group header `X-Trino-Routing-Group` as default.

gateway-ha/src/main/java/io/trino/gateway/ha/config/RoutingRulesConfiguration.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
public class RoutingRulesConfiguration
1717
{
1818
private boolean rulesEngineEnabled;
19+
private RulesType rulesType = RulesType.FILE;
1920
private String rulesConfigPath;
21+
private RulesExternalConfiguration rulesExternalConfiguration;
2022

2123
public RoutingRulesConfiguration() {}
2224

@@ -30,6 +32,16 @@ public void setRulesEngineEnabled(boolean rulesEngineEnabled)
3032
this.rulesEngineEnabled = rulesEngineEnabled;
3133
}
3234

35+
public RulesType getRulesType()
36+
{
37+
return rulesType;
38+
}
39+
40+
public void setRulesType(RulesType rulesType)
41+
{
42+
this.rulesType = rulesType;
43+
}
44+
3345
public String getRulesConfigPath()
3446
{
3547
return this.rulesConfigPath;
@@ -39,4 +51,14 @@ public void setRulesConfigPath(String rulesConfigPath)
3951
{
4052
this.rulesConfigPath = rulesConfigPath;
4153
}
54+
55+
public RulesExternalConfiguration getRulesExternalConfiguration()
56+
{
57+
return this.rulesExternalConfiguration;
58+
}
59+
60+
public void setRulesExternalConfiguration(RulesExternalConfiguration rulesExternalConfiguration)
61+
{
62+
this.rulesExternalConfiguration = rulesExternalConfiguration;
63+
}
4264
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.gateway.ha.config;
15+
16+
import java.util.List;
17+
18+
public class RulesExternalConfiguration
19+
{
20+
private String urlPath;
21+
private List<String> blackListHeaders;
22+
23+
public String getUrlPath()
24+
{
25+
return urlPath;
26+
}
27+
28+
public void setUrlPath(String urlPath)
29+
{
30+
this.urlPath = urlPath;
31+
}
32+
33+
public List<String> getBlackListHeaders()
34+
{
35+
return this.blackListHeaders;
36+
}
37+
38+
public void setBlackListHeaders(List<String> blackListHeaders)
39+
{
40+
this.blackListHeaders = blackListHeaders;
41+
}
42+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.gateway.ha.config;
15+
16+
/**
17+
* Specifies the sources of routing rules in the Trino Gateway's routing rules engine.
18+
*
19+
* <p>By default, requests are routed based on the `X-Trino-Routing-Group` header,
20+
* or to the default routing group (adhoc) if the header is absent.</p>
21+
*
22+
* <p>Routing rules can be defined in two ways:</p>
23+
* <ul>
24+
* <li><strong>FILE:</strong> Rules are specified in a configuration file.</li>
25+
* <li><strong>EXTERNAL:</strong> Rules are fetched from an external service via an HTTP POST request.</li>
26+
* </ul>
27+
*/
28+
public enum RulesType
29+
{
30+
/**
31+
* Routing rules defined in a configuration file.
32+
*/
33+
FILE,
34+
35+
/**
36+
* Routing rules obtained from an external service.
37+
* The service URL can implement dynamic rule changes.
38+
*/
39+
EXTERNAL,
40+
}

gateway-ha/src/main/java/io/trino/gateway/ha/module/HaGatewayProviderModule.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.trino.gateway.ha.config.HaGatewayConfiguration;
2424
import io.trino.gateway.ha.config.OAuth2GatewayCookieConfigurationPropertiesProvider;
2525
import io.trino.gateway.ha.config.RoutingRulesConfiguration;
26+
import io.trino.gateway.ha.config.RulesExternalConfiguration;
2627
import io.trino.gateway.ha.config.UserConfiguration;
2728
import io.trino.gateway.ha.handler.RoutingTargetHandler;
2829
import io.trino.gateway.ha.router.BackendStateManager;
@@ -181,8 +182,21 @@ public RoutingGroupSelector getRoutingGroupSelector()
181182
{
182183
RoutingRulesConfiguration routingRulesConfig = configuration.getRoutingRules();
183184
if (routingRulesConfig.isRulesEngineEnabled()) {
184-
String rulesConfigPath = routingRulesConfig.getRulesConfigPath();
185-
return RoutingGroupSelector.byRoutingRulesEngine(rulesConfigPath, configuration.getRequestAnalyzerConfig());
185+
try {
186+
return switch (routingRulesConfig.getRulesType()) {
187+
case FILE -> {
188+
String rulesConfigPath = routingRulesConfig.getRulesConfigPath();
189+
yield RoutingGroupSelector.byRoutingRulesEngine(rulesConfigPath, configuration.getRequestAnalyzerConfig());
190+
}
191+
case EXTERNAL -> {
192+
RulesExternalConfiguration rulesExternalConfiguration = routingRulesConfig.getRulesExternalConfiguration();
193+
yield RoutingGroupSelector.byRoutingExternal(rulesExternalConfiguration, configuration.getRequestAnalyzerConfig());
194+
}
195+
};
196+
}
197+
catch (Exception e) {
198+
return RoutingGroupSelector.byRoutingGroupHeader();
199+
}
186200
}
187201
return RoutingGroupSelector.byRoutingGroupHeader();
188202
}

0 commit comments

Comments
 (0)