-
Notifications
You must be signed in to change notification settings - Fork 80
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
Show and modify routing rules from the UI #433
base: main
Are you sure you want to change the base?
Conversation
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
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.
This looks like a nice improvement, thank you! I reviewed the Java half, and will try to find someone for the typescript.
My biggest concern here is not with the code, but with allowing users to supply input that will be written to disk on the server, then executed by the jeasy
rules engine. We should take a close look at jeasy
and mvel
to understand what security vulnerabilities we might be introducing. At minimum we should log all of the updates so that they can be audited. @wendigo and @ebyhr wdyt?
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Show resolved
Hide resolved
for (int i = 0; i < routingRulesList.size(); i++) { | ||
if (routingRulesList.get(i).name().equals(routingRules.name())) { | ||
routingRulesList.set(i, routingRules); | ||
break; | ||
} | ||
} |
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.
as the name of this method suggests, this updates an existing rule. It does not appear that this change adds support for deleting an existing rule or adding a new one. I guess this may be due to the UI changes required, but would it be difficult to add this functionality?
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.
I don't think it would be difficult. I thought of initially going with only updates and in a separate PR i will put Add and Delete functionality. Will that be ok? Or should I add it in this PR itself?
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.
that plan sounds fine to me, thanks!
This functionality will be accessible only for users with ADMIN privileges. Regular users will have this as Read-Only. I also have a functionality implemented in our internal repo where we are auditing changes being made to the Clusters from the UI. I can raise a PR for that as well and will add functionality to audit routing rules as well. I was thinking of getting this reviewed first and then from comments and suggestions I will raise the Audit logs PR. |
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
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.
this is looking good, we're almost there. @mosabua and I discussed the need to support this for clustered deployments. We should also provide a way to disable this feature in case someone doesn't want to bother setting up a shared filesystem
@prakhar10 please squash these commits |
So this means provide an option or a config to show/disable the Routing Rules option in the left panel of the UI right? |
I think for now we can just say in the docs that you must provide shared storage for that feature to work and in terms of disabling it could be just a config option option .. I think over time we will need various config options for the UI anyway |
Remove console logs and renamed api Add api documentation and changes related to PR comments
85287b9
to
d3c7855
Compare
@mosabua @willmostly can you please review? |
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Show resolved
Hide resolved
I assume that @prakhar10 and @willmostly are collaborating on this currently .. ping me if review or anything else is needed. |
I need to make changes according to @ebyhr 's comments. So i will get that done by this weekend. |
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/config/HaGatewayConfiguration.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
@ebyhr can you review now please? |
@mosabua can you please review? |
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/resource/GatewayWebAppResource.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/config/UIConfiguration.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/config/UIConfiguration.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/domain/RoutingRules.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
@ebyhr can you take a look now? |
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/main/java/io/trino/gateway/ha/router/RoutingRulesManager.java
Outdated
Show resolved
Hide resolved
gateway-ha/src/test/java/io/trino/gateway/ha/router/TestRoutingRulesManager.java
Outdated
Show resolved
Hide resolved
@willmostly @ebyhr can you review now please? |
For this feature to work with multiple replicas of the Trino Gateway, you will need to provide a shared storage for the routing rules file. If multiple replicas are used with local storage, then rules will get out of sync when updated. | ||
|
||
```shell | ||
curl -X POST http://localhost:8080/webapp/updateRoutingRules \ |
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.
The method definition includes
@Consumes(MediaType.APPLICATION_JSON)
Does this curl command work without
-H 'Content-Type: application/json'
?
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.
Let me check
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.
It does not work without it, I will add it to the documentation.
@RolesAllowed("USER") | ||
@Produces(MediaType.APPLICATION_JSON) | ||
@Path("/getRoutingRules") | ||
public Response getRoutingRules() |
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.
Should these methods return the bare type instead of wrapping them in a Response
, similar to the Trino UI? E.g. https://github.com/trinodb/trino/blob/bb80ff8be6073bc970501825e2e7f304b3b9d643/core/trino-main/src/main/java/io/trino/server/ui/ClusterResource.java#L51
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.
I tried to keep it similar to other methods and also here -
trino-gateway/webapp/src/api/base.ts
Line 6 in 64dcbd5
async get(url: string, params: Record<string, any> = {}): Promise<any> { |
we are checking the response status and then extracting the json body, so to not make any changes to this code I kept it as is.
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.
Ok in that case
This API can be used to programmatically update the Routing Rules. | ||
Rule will be updated based on the rule name. | ||
|
||
For this feature to work with multiple replicas of the Trino Gateway, you will need to provide a shared storage for the routing rules file. If multiple replicas are used with local storage, then rules will get out of sync when updated. |
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.
For this feature to work with multiple replicas of the Trino Gateway, you will need to provide a shared storage for the routing rules file. If multiple replicas are used with local storage, then rules will get out of sync when updated. | |
For this feature to work with multiple replicas of the Trino Gateway, you will need to provide a shared storage that supports file locking for the routing rules file. If multiple replicas are used with local storage, then rules will get out of sync when updated. |
throws IOException | ||
{ | ||
ImmutableList.Builder<RoutingRule> updatedRoutingRulesBuilder = ImmutableList.builder(); | ||
List<RoutingRule> currentRoutingRulesList = new ArrayList<>(); |
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.
List<RoutingRule> currentRoutingRulesList = new ArrayList<>(); | |
List<RoutingRule> currentRoutingRulesList = getRoutingRules(); |
also remove the the logic below to read rules
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.
I was doing this earlier but changed it due to this review comment - #433 (comment)
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.
You could use an immutable currentRoutingRulesList
in this method if you move your replacement logic to the write phase. For example, delete
for (int i = 0; i < currentRoutingRulesList.size(); i++) {
if (currentRoutingRulesList.get(i).name().equals(routingRule.name())) {
currentRoutingRulesList.set(i, routingRule);
break;
}
}
then modify the loop where you build yamlWriter
and updatedRoutingRulesBuilder
to
for (RoutingRule rule : currentRoutingRulesList) {
if (rule.name().equals(routingRule.name())) {
yamlContent.append(yamlWriter.writeValueAsString(routingRule));
updatedRoutingRulesBuilder.add(routingRule);
} else {
yamlContent.append(yamlWriter.writeValueAsString(rule));
updatedRoutingRulesBuilder.add(rule);
}
}
Please double check the code - I wrote it in the GH text box :). If this change causes some issue then please disregard the suggestion, we can clean up the code in a follow up.
yamlContent.append(yamlWriter.writeValueAsString(rule)); | ||
updatedRoutingRulesBuilder.add(rule); | ||
} | ||
try (FileChannel fileChannel = FileChannel.open(Paths.get(rulesConfigPath), StandardOpenOption.WRITE, StandardOpenOption.READ); |
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.
Lock the file before it is read. Otherwise you allow a sequence like
- Gateway 1 reads rules
- Gateway 2 reads rules
- Gateway 1 locks rules, writes rules, releases lock.
- Gateway 2 locks rules, writes rules, releases lock.
Which results in the changes by Gateway 1 being lost.
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
final class TestRoutingRulesManager |
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.
Please add tests that use the REST API
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.
@willmostly sorry I didn't understand this, can you provide an examples or please help me understand?
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.
Discussed with Will, working on this.
public record RoutingRule( | ||
String name, | ||
@Nullable String description, | ||
@Nullable Integer priority, |
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.
priority should not be nullable. It may be defaulted to 0
.
requireNonNull(name, "name is null"); | ||
actions = ImmutableList.copyOf(actions); | ||
requireNonNull(condition, "condition is null"); | ||
} |
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.
Set description to ""
if it is null
Description
Additional context and related issues
Release notes
( ) This is not user-visible or is docs only, and no release notes are required.
(X) Release notes are required. Please propose a release note for me.
( ) Release notes are required, with the following suggested text:
*