capistrant commented on code in PR #18923:
URL: https://github.com/apache/druid/pull/18923#discussion_r2722407933
##########
embedded-tests/src/test/java/org/apache/druid/testing/embedded/auth/EmbeddedBasicAuthResource.java:
##########
@@ -65,19 +75,100 @@ public void stop()
{
// Do nothing
}
-
+
private String authenticatorProp(String name)
{
return StringUtils.format("druid.auth.authenticator.%s.%s",
AUTHENTICATOR_NAME, name);
}
-
+
private String authorizerProp(String name)
{
return StringUtils.format("druid.auth.authorizer.%s.%s", AUTHORIZER_NAME,
name);
}
-
+
private String escalatorProp(String name)
{
return StringUtils.format("druid.escalator.%s", name);
}
+
+ /**
+ * Creates a user with specified permissions using the basic auth security
API.
+ *
+ * @param adminClient HTTP client authenticated as admin
+ * @param coordinator the coordinator server to make API calls against
+ * @param username the username to create
+ * @param password the password for the user
+ * @param roleName the role name to create and assign
+ * @param permissions the permissions to grant to the role
+ */
+ public static void createUserWithPermissions(
Review Comment:
nice
##########
sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java:
##########
@@ -1184,4 +1217,136 @@
}
return projectedRow;
}
+
+ /**
+ * This table contains currently running and recently completed queries from
all SQL engines.
+ * Enabled based on {@link PlannerConfig#isEnableSysQueriesTable()}.
+ */
+ static class QueriesTable extends AbstractTable implements
ProjectableFilterableTable
+ {
+ private final Provider<SqlEngineRegistry> sqlEngineRegistryProvider;
+ private final ObjectMapper jsonMapper;
+ private final AuthorizerMapper authorizerMapper;
+
+ public QueriesTable(
+ final Provider<SqlEngineRegistry> sqlEngineRegistryProvider,
+ final ObjectMapper jsonMapper,
+ final AuthorizerMapper authorizerMapper
+ )
+ {
+ this.sqlEngineRegistryProvider = sqlEngineRegistryProvider;
+ this.jsonMapper = jsonMapper;
+ this.authorizerMapper = authorizerMapper;
+ }
+
+ @Override
+ public RelDataType getRowType(final RelDataTypeFactory typeFactory)
+ {
+ return RowSignatures.toRelDataType(QUERIES_SIGNATURE, typeFactory);
+ }
+
+ @Override
+ public TableType getJdbcTableType()
+ {
+ return TableType.SYSTEM_TABLE;
+ }
+
+ @Override
+ public Enumerable<Object[]> scan(
+ final DataContext root,
+ final List<RexNode> filters,
+ @Nullable final int[] projects
+ )
+ {
+ final AuthenticationResult authenticationResult = (AuthenticationResult)
Preconditions.checkNotNull(
+ root.get(PlannerContext.DATA_CTX_AUTHENTICATION_RESULT),
+ "authenticationResult in dataContext"
+ );
+
+ // Check STATE READ authorization
+ final AuthorizationResult stateReadAuthorization =
AuthorizationUtils.authorizeAllResourceActions(
+ authenticationResult,
+ Collections.singletonList(new
ResourceAction(Resource.STATE_RESOURCE, Action.READ)),
+ authorizerMapper
+ );
+
+ // Get queries from all engines
+ final List<QueryInfo> allQueries = new ArrayList<>();
+ for (final SqlEngine sqlEngine :
sqlEngineRegistryProvider.get().getAllEngines()) {
+ final GetQueriesResponse response = sqlEngine.getRunningQueries(
+ false, // selfOnly false to get queries from all servers
+ true, // includeComplete true to include all queries
+ authenticationResult,
+ stateReadAuthorization
+ );
+ allQueries.addAll(response.getQueries());
+ }
+
+ // Determine if we need to serialize the info field (based on projection
pushdown)
+ final int[] nonNullProjects = projects == null ? QUERIES_PROJECT_ALL :
projects;
+ final boolean includeInfo = containsIndex(nonNullProjects,
QUERIES_INFO_INDEX);
+
+ // Build rows
+ final FluentIterable<Object[]> results = FluentIterable
+ .from(allQueries)
+ .transform(queryInfo -> buildQueryRow(queryInfo, includeInfo,
jsonMapper))
+ .transform(row -> projectQueriesRow(row, nonNullProjects));
+
+ return Linq4j.asEnumerable(results);
+ }
+
+ /**
+ * Build a full row for a query.
+ */
+ private static Object[] buildQueryRow(
+ final QueryInfo queryInfo,
+ final boolean includeInfo,
+ final ObjectMapper jsonMapper
+ )
+ {
+ final Object[] row = new Object[QUERIES_SIGNATURE.size()];
+ row[0] = queryInfo.executionId();
+ row[1] = queryInfo.engine();
+ row[2] = queryInfo.state().toString();
Review Comment:
+1 to the bot
##########
sql/src/test/java/org/apache/druid/sql/calcite/schema/SystemSchemaTest.java:
##########
@@ -1587,6 +1595,76 @@ public void testPropertiesTable()
}
+ @Test
+ public void testQueriesTable()
+ {
+ // Create mock SqlEngine that returns test queries
+ final SqlEngine mockEngine = EasyMock.createMock(SqlEngine.class);
+ EasyMock.expect(mockEngine.name()).andReturn("native").anyTimes();
Review Comment:
just showing the native engine some love by using it in the mocks so it
isn't feeling left out by not being in the real thing?
##########
docs/querying/sql-metadata-tables.md:
##########
@@ -335,4 +335,37 @@ For example, to retrieve properties for a specific server,
use the query
```sql
SELECT * FROM sys.server_properties WHERE server='192.168.1.1:8081'
-```
\ No newline at end of file
+```
+
+### QUERIES table
Review Comment:
With this being off by default, I guess it would make me think as an
operator that there is either a cost or a risk to turning it on. I don't think
risk, but cost, maybe? Or is this just how we have operated with new sys tables
in past, feature flag them, and once non-experimental remove the flag?
If there is a consideration an operator should take beyond "this is off by
default cuz it is experimental" then I think we should add such a disclaimer
here
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]