Skip to content

Commit 1ab131f

Browse files
xkrogenwendigo
authored andcommitted
Add originalUser and authenticatedUser as selectors available for resource group selection
1 parent 8c0cc3a commit 1ab131f

26 files changed

+630
-86
lines changed

core/trino-main/src/main/java/io/trino/dispatcher/DispatchManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import io.trino.spi.TrinoException;
4545
import io.trino.spi.resourcegroups.SelectionContext;
4646
import io.trino.spi.resourcegroups.SelectionCriteria;
47+
import io.trino.spi.security.Identity;
4748
import jakarta.annotation.PostConstruct;
4849
import jakarta.annotation.PreDestroy;
4950
import org.weakref.jmx.Flatten;
@@ -229,6 +230,8 @@ private <C> void createQueryInternal(QueryId queryId, Span querySpan, Slug slug,
229230
sessionContext.getIdentity().getPrincipal().isPresent(),
230231
sessionContext.getIdentity().getUser(),
231232
sessionContext.getIdentity().getGroups(),
233+
sessionContext.getOriginalIdentity().getUser(),
234+
sessionContext.getAuthenticatedIdentity().map(Identity::getUser),
232235
sessionContext.getSource(),
233236
sessionContext.getClientTags(),
234237
sessionContext.getResourceEstimates(),

core/trino-spi/src/main/java/io/trino/spi/resourcegroups/SelectionCriteria.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public final class SelectionCriteria
2626
private final boolean authenticated;
2727
private final String user;
2828
private final Set<String> userGroups;
29+
private final String originalUser;
30+
private final Optional<String> authenticatedUser;
2931
private final Optional<String> source;
3032
private final Set<String> clientTags;
3133
private final ResourceEstimates resourceEstimates;
@@ -35,6 +37,8 @@ public SelectionCriteria(
3537
boolean authenticated,
3638
String user,
3739
Set<String> userGroups,
40+
String originalUser,
41+
Optional<String> authenticatedUser,
3842
Optional<String> source,
3943
Set<String> clientTags,
4044
ResourceEstimates resourceEstimates,
@@ -43,12 +47,39 @@ public SelectionCriteria(
4347
this.authenticated = authenticated;
4448
this.user = requireNonNull(user, "user is null");
4549
this.userGroups = requireNonNull(userGroups, "userGroups is null");
50+
this.originalUser = requireNonNull(originalUser, "originalUser is null");
51+
this.authenticatedUser = requireNonNull(authenticatedUser, "authenticatedUser is null");
4652
this.source = requireNonNull(source, "source is null");
4753
this.clientTags = Set.copyOf(requireNonNull(clientTags, "clientTags is null"));
4854
this.resourceEstimates = requireNonNull(resourceEstimates, "resourceEstimates is null");
4955
this.queryType = requireNonNull(queryType, "queryType is null");
5056
}
5157

58+
/**
59+
* @deprecated Use {@link #SelectionCriteria(boolean, String, Set, String, Optional, Optional, Set, ResourceEstimates, Optional)} instead.
60+
*/
61+
@Deprecated(since = "474", forRemoval = true)
62+
public SelectionCriteria(
63+
boolean authenticated,
64+
String user,
65+
Set<String> userGroups,
66+
Optional<String> source,
67+
Set<String> clientTags,
68+
ResourceEstimates resourceEstimates,
69+
Optional<String> queryType)
70+
{
71+
this(
72+
authenticated,
73+
user,
74+
userGroups,
75+
user,
76+
Optional.empty(),
77+
source,
78+
clientTags,
79+
resourceEstimates,
80+
queryType);
81+
}
82+
5283
public boolean isAuthenticated()
5384
{
5485
return authenticated;
@@ -64,6 +95,16 @@ public Set<String> getUserGroups()
6495
return userGroups;
6596
}
6697

98+
public String getOriginalUser()
99+
{
100+
return originalUser;
101+
}
102+
103+
public Optional<String> getAuthenticatedUser()
104+
{
105+
return authenticatedUser;
106+
}
107+
67108
public Optional<String> getSource()
68109
{
69110
return source;
@@ -91,6 +132,8 @@ public String toString()
91132
.add("authenticated=" + authenticated)
92133
.add("user='" + user + "'")
93134
.add("userGroups=" + userGroups)
135+
.add("originalUser=" + originalUser)
136+
.add("authenticatedUser=" + authenticatedUser)
94137
.add("source=" + source)
95138
.add("clientTags=" + clientTags)
96139
.add("resourceEstimates=" + resourceEstimates)

docs/src/main/sphinx/admin/resource-groups-example.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@
8888
"user": "bob",
8989
"group": "admin"
9090
},
91+
{
92+
"originalUser": "bob",
93+
"group": "admin"
94+
},
95+
{
96+
"authenticatedUser": "bob",
97+
"group": "admin"
98+
},
9199
{
92100
"userGroup": "admin",
93101
"group": "admin"

docs/src/main/sphinx/admin/resource-groups.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ documentation](https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java
166166

167167
- `user` (optional): Java regex to match against user name.
168168

169+
- `originalUser` (optional): Java regex to match against the _original_ user name,
170+
i.e. before any changes to the session user. For example, if user "foo" runs
171+
`SET SESSION AUTHORIZATION 'bar'`, `originalUser` is "foo", while `user` is "bar".
172+
173+
- `authenticatedUser` (optional): Java regex to match against the _authenticated_ user name,
174+
which will always refer to the user that authenticated with the system, regardless of any
175+
changes made to the session user.
176+
169177
- `userGroup` (optional): Java regex to match against every user group the user belongs to.
170178

171179
- `source` (optional): Java regex to match against source string.
@@ -234,18 +242,23 @@ In the example configuration below, there are several resource groups, some of w
234242
Templates allow administrators to construct resource group trees dynamically. For example, in
235243
the `pipeline_${USER}` group, `${USER}` is expanded to the name of the user that submitted
236244
the query. `${SOURCE}` is also supported, which is expanded to the source that submitted the
237-
query. You may also use custom named variables in the `source` and `user` regular expressions.
245+
query. You may also use custom named variables in the regular expressions for `user`, `source`,
246+
`originalUser`, and `authenticatedUser`.
238247

239-
There are four selectors, that define which queries run in which resource group:
248+
There are six selectors, that define which queries run in which resource group:
240249

241250
- The first selector matches queries from `bob` and places them in the admin group.
242-
- The second selector matches queries from `admin` user group and places them in the admin group.
243-
- The third selector matches all data definition (DDL) queries from a source name that includes `pipeline`
251+
- The next selector matches queries with an _original_ user of `bob`
252+
and places them in the admin group.
253+
- The next selector matches queries with an _authenticated_ user of `bob`
254+
and places them in the admin group.
255+
- The next selector matches queries from `admin` user group and places them in the admin group.
256+
- The next selector matches all data definition (DDL) queries from a source name that includes `pipeline`
244257
and places them in the `global.data_definition` group. This could help reduce queue times for this
245258
class of queries, since they are expected to be fast.
246-
- The fourth selector matches queries from a source name that includes `pipeline`, and places them in a
259+
- The next selector matches queries from a source name that includes `pipeline`, and places them in a
247260
dynamically-created per-user pipeline group under the `global.pipeline` group.
248-
- The fifth selector matches queries that come from BI tools which have a source matching the regular
261+
- The next selector matches queries that come from BI tools which have a source matching the regular
249262
expression `jdbc#(?<toolname>.*)` and have client provided tags that are a superset of `hipri`.
250263
These are placed in a dynamically-created sub-group under the `global.adhoc` group.
251264
The dynamic sub-groups are created based on the values of named variables `toolname` and `user`.
@@ -257,9 +270,10 @@ There are four selectors, that define which queries run in which resource group:
257270

258271
Together, these selectors implement the following policy:
259272

260-
- The user `bob` and any user belonging to user group `admin`
261-
is an admin and can run up to 50 concurrent queries.
262-
Queries will be run based on user-provided priority.
273+
- The user `bob` and any user belonging to user group `admin` is an admin and can run up to
274+
50 concurrent queries. `bob` will be treated as an admin even if they have changed their session
275+
user to a different user (i.e. via a `SET SESSION AUTHORIZATION` statement or the
276+
`X-Trino-User` request header). Queries will be run based on user-provided priority.
263277

264278
For the remaining users:
265279

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/AbstractResourceConfigurationManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ protected List<ResourceGroupSelector> buildSelectors(ManagerSpec managerSpec)
9696
selectors.add(new StaticSelector(
9797
spec.getUserRegex(),
9898
spec.getUserGroupRegex(),
99+
spec.getOriginalUserRegex(),
100+
spec.getAuthenticatedUserRegex(),
99101
spec.getSourceRegex(),
100102
spec.getClientTags(),
101103
spec.getResourceEstimate(),

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/SelectorSpec.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class SelectorSpec
2828
{
2929
private final Optional<Pattern> userRegex;
3030
private final Optional<Pattern> userGroupRegex;
31+
private final Optional<Pattern> originalUserRegex;
32+
private final Optional<Pattern> authenticatedUserRegex;
3133
private final Optional<Pattern> sourceRegex;
3234
private final Optional<String> queryType;
3335
private final Optional<List<String>> clientTags;
@@ -38,6 +40,8 @@ public class SelectorSpec
3840
public SelectorSpec(
3941
@JsonProperty("user") Optional<Pattern> userRegex,
4042
@JsonProperty("userGroup") Optional<Pattern> userGroupRegex,
43+
@JsonProperty("originalUser") Optional<Pattern> originalUserRegex,
44+
@JsonProperty("authenticatedUser") Optional<Pattern> authenticatedUserRegex,
4145
@JsonProperty("source") Optional<Pattern> sourceRegex,
4246
@JsonProperty("queryType") Optional<String> queryType,
4347
@JsonProperty("clientTags") Optional<List<String>> clientTags,
@@ -46,6 +50,8 @@ public SelectorSpec(
4650
{
4751
this.userRegex = requireNonNull(userRegex, "userRegex is null");
4852
this.userGroupRegex = requireNonNull(userGroupRegex, "userGroupRegex is null");
53+
this.originalUserRegex = requireNonNull(originalUserRegex, "originalUserRegex is null");
54+
this.authenticatedUserRegex = requireNonNull(authenticatedUserRegex, "authenticatedUserRegex is null");
4955
this.sourceRegex = requireNonNull(sourceRegex, "sourceRegex is null");
5056
this.queryType = requireNonNull(queryType, "queryType is null");
5157
this.clientTags = requireNonNull(clientTags, "clientTags is null");
@@ -63,6 +69,16 @@ public Optional<Pattern> getUserGroupRegex()
6369
return userGroupRegex;
6470
}
6571

72+
public Optional<Pattern> getOriginalUserRegex()
73+
{
74+
return originalUserRegex;
75+
}
76+
77+
public Optional<Pattern> getAuthenticatedUserRegex()
78+
{
79+
return authenticatedUserRegex;
80+
}
81+
6682
public Optional<Pattern> getSourceRegex()
6783
{
6884
return sourceRegex;
@@ -103,6 +119,10 @@ public boolean equals(Object other)
103119
userRegex.map(Pattern::flags).equals(that.userRegex.map(Pattern::flags)) &&
104120
userGroupRegex.map(Pattern::pattern).equals(that.userGroupRegex.map(Pattern::pattern)) &&
105121
userGroupRegex.map(Pattern::flags).equals(that.userGroupRegex.map(Pattern::flags)) &&
122+
originalUserRegex.map(Pattern::pattern).equals(that.originalUserRegex.map(Pattern::pattern)) &&
123+
originalUserRegex.map(Pattern::flags).equals(that.originalUserRegex.map(Pattern::flags)) &&
124+
authenticatedUserRegex.map(Pattern::pattern).equals(that.authenticatedUserRegex.map(Pattern::pattern)) &&
125+
authenticatedUserRegex.map(Pattern::flags).equals(that.authenticatedUserRegex.map(Pattern::flags)) &&
106126
sourceRegex.map(Pattern::pattern).equals(that.sourceRegex.map(Pattern::pattern))) &&
107127
sourceRegex.map(Pattern::flags).equals(that.sourceRegex.map(Pattern::flags)) &&
108128
queryType.equals(that.queryType) &&
@@ -118,6 +138,10 @@ public int hashCode()
118138
userRegex.map(Pattern::flags),
119139
userGroupRegex.map(Pattern::pattern),
120140
userGroupRegex.map(Pattern::flags),
141+
originalUserRegex.map(Pattern::pattern),
142+
originalUserRegex.map(Pattern::flags),
143+
authenticatedUserRegex.map(Pattern::pattern),
144+
authenticatedUserRegex.map(Pattern::flags),
121145
sourceRegex.map(Pattern::pattern),
122146
sourceRegex.map(Pattern::flags),
123147
queryType,
@@ -133,6 +157,10 @@ public String toString()
133157
.add("userFlags", userRegex.map(Pattern::flags))
134158
.add("userGroupRegex", userGroupRegex)
135159
.add("userGroupFlags", userGroupRegex.map(Pattern::flags))
160+
.add("originalUserRegex", originalUserRegex)
161+
.add("originalUserFlags", originalUserRegex.map(Pattern::flags))
162+
.add("authenticatedUserRegex", authenticatedUserRegex)
163+
.add("authenticatedUserFlags", authenticatedUserRegex.map(Pattern::flags))
136164
.add("sourceRegex", sourceRegex)
137165
.add("sourceFlags", sourceRegex.map(Pattern::flags))
138166
.add("queryType", queryType)

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/StaticSelector.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public class StaticSelector
4848
public StaticSelector(
4949
Optional<Pattern> userRegex,
5050
Optional<Pattern> userGroupRegex,
51+
Optional<Pattern> originalUserRegex,
52+
Optional<Pattern> authenticatedUserRegex,
5153
Optional<Pattern> sourceRegex,
5254
Optional<List<String>> clientTags,
5355
Optional<SelectorResourceEstimate> selectorResourceEstimate,
@@ -56,6 +58,8 @@ public StaticSelector(
5658
{
5759
this.userRegex = requireNonNull(userRegex, "userRegex is null");
5860
requireNonNull(userGroupRegex, "userGroupRegex is null");
61+
requireNonNull(originalUserRegex, "originalUserRegex is null");
62+
requireNonNull(authenticatedUserRegex, "authenticatedUserRegex is null");
5963
requireNonNull(sourceRegex, "sourceRegex is null");
6064
requireNonNull(clientTags, "clientTags is null");
6165
requireNonNull(selectorResourceEstimate, "selectorResourceEstimate is null");
@@ -68,6 +72,14 @@ public StaticSelector(
6872
addNamedGroups(userRegexValue, variableNames);
6973
return new PatternMatcher(variableNames, userRegexValue, SelectionCriteria::getUser);
7074
}))
75+
.add(originalUserRegex.map(originalUserRegexValue -> {
76+
addNamedGroups(originalUserRegexValue, variableNames);
77+
return new PatternMatcher(variableNames, originalUserRegexValue, SelectionCriteria::getOriginalUser);
78+
}))
79+
.add(authenticatedUserRegex.map(authenticatedUserRegexValue -> {
80+
addNamedGroups(authenticatedUserRegexValue, variableNames);
81+
return new PatternMatcher(variableNames, authenticatedUserRegexValue, criteria -> criteria.getAuthenticatedUser().orElse(""));
82+
}))
7183
.add(sourceRegex.map(sourceRegexValue -> {
7284
addNamedGroups(sourceRegexValue, variableNames);
7385
return new PatternMatcher(variableNames, sourceRegexValue, criteria -> criteria.getSource().orElse(""));

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/DbResourceGroupConfigurationManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,8 @@ private synchronized Map.Entry<ManagerSpec, Map<ResourceGroupIdTemplate, Resourc
379379
new SelectorSpec(
380380
selectorRecord.getUserRegex(),
381381
selectorRecord.getUserGroupRegex(),
382+
selectorRecord.getOriginalUserRegex(),
383+
selectorRecord.getAuthenticatedUserRegex(),
382384
selectorRecord.getSourceRegex(),
383385
selectorRecord.getQueryType(),
384386
selectorRecord.getClientTags(),

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/ResourceGroupsDao.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public interface ResourceGroupsDao
6060
@UseRowMapper(ResourceGroupSpecBuilder.Mapper.class)
6161
List<ResourceGroupSpecBuilder> getResourceGroups(@Bind("environment") String environment);
6262

63-
@SqlQuery("SELECT S.resource_group_id, S.priority, S.user_regex, S.source_regex, S.query_type, S.client_tags, S.selector_resource_estimate, S.user_group_regex\n" +
63+
@SqlQuery("SELECT S.resource_group_id, S.priority, S.user_regex, S.source_regex, S.original_user_regex, S.authenticated_user_regex, S.query_type, S.client_tags, S.selector_resource_estimate, S.user_group_regex\n" +
6464
"FROM selectors S\n" +
6565
"JOIN resource_groups R ON (S.resource_group_id = R.resource_group_id)\n" +
6666
"WHERE R.environment = :environment\n" +
@@ -73,6 +73,8 @@ public interface ResourceGroupsDao
7373
" priority BIGINT NOT NULL,\n" +
7474
" user_regex VARCHAR(512),\n" +
7575
" user_group_regex VARCHAR(512),\n" +
76+
" original_user_regex VARCHAR(512),\n" +
77+
" authenticated_user_regex VARCHAR(512),\n" +
7678
" source_regex VARCHAR(512),\n" +
7779
" query_type VARCHAR(512),\n" +
7880
" client_tags VARCHAR(512),\n" +

plugin/trino-resource-group-managers/src/main/java/io/trino/plugin/resourcegroups/db/SelectorRecord.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public class SelectorRecord
3535
private final long priority;
3636
private final Optional<Pattern> userRegex;
3737
private final Optional<Pattern> userGroupRegex;
38+
private final Optional<Pattern> originalUserRegex;
39+
private final Optional<Pattern> authenticatedUserRegex;
3840
private final Optional<Pattern> sourceRegex;
3941
private final Optional<String> queryType;
4042
private final Optional<List<String>> clientTags;
@@ -45,6 +47,8 @@ public SelectorRecord(
4547
long priority,
4648
Optional<Pattern> userRegex,
4749
Optional<Pattern> userGroupRegex,
50+
Optional<Pattern> originalUserRegex,
51+
Optional<Pattern> authenticatedUserRegex,
4852
Optional<Pattern> sourceRegex,
4953
Optional<String> queryType,
5054
Optional<List<String>> clientTags,
@@ -54,6 +58,8 @@ public SelectorRecord(
5458
this.priority = priority;
5559
this.userRegex = requireNonNull(userRegex, "userRegex is null");
5660
this.userGroupRegex = requireNonNull(userGroupRegex, "userGroupRegex is null");
61+
this.originalUserRegex = requireNonNull(originalUserRegex, "originalUserRegex is null");
62+
this.authenticatedUserRegex = requireNonNull(authenticatedUserRegex, "authenticatedUserRegex is null");
5763
this.sourceRegex = requireNonNull(sourceRegex, "sourceRegex is null");
5864
this.queryType = requireNonNull(queryType, "queryType is null");
5965
this.clientTags = clientTags.map(ImmutableList::copyOf);
@@ -80,6 +86,16 @@ public Optional<Pattern> getUserGroupRegex()
8086
return userGroupRegex;
8187
}
8288

89+
public Optional<Pattern> getOriginalUserRegex()
90+
{
91+
return originalUserRegex;
92+
}
93+
94+
public Optional<Pattern> getAuthenticatedUserRegex()
95+
{
96+
return authenticatedUserRegex;
97+
}
98+
8399
public Optional<Pattern> getSourceRegex()
84100
{
85101
return sourceRegex;
@@ -115,6 +131,8 @@ public SelectorRecord map(ResultSet resultSet, StatementContext context)
115131
resultSet.getLong("priority"),
116132
Optional.ofNullable(resultSet.getString("user_regex")).map(Pattern::compile),
117133
Optional.ofNullable(resultSet.getString("user_group_regex")).map(Pattern::compile),
134+
Optional.ofNullable(resultSet.getString("original_user_regex")).map(Pattern::compile),
135+
Optional.ofNullable(resultSet.getString("authenticated_user_regex")).map(Pattern::compile),
118136
Optional.ofNullable(resultSet.getString("source_regex")).map(Pattern::compile),
119137
Optional.ofNullable(resultSet.getString("query_type")),
120138
Optional.ofNullable(resultSet.getString("client_tags")).map(LIST_STRING_CODEC::fromJson),

0 commit comments

Comments
 (0)