diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java index 7ea77b085a856d..000f1fb0386438 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java @@ -26,10 +26,7 @@ import org.apache.doris.cloud.qe.ComputeGroupException; import org.apache.doris.cloud.system.CloudSystemInfoService; import org.apache.doris.cluster.ClusterNamespace; -import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; -import org.apache.doris.common.ErrorCode; -import org.apache.doris.common.ErrorReport; import org.apache.doris.mysql.privilege.Auth; import org.apache.doris.mysql.privilege.PrivBitSet; import org.apache.doris.mysql.privilege.PrivPredicate; @@ -50,7 +47,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.TreeMap; import java.util.stream.Collectors; /** @@ -65,6 +64,11 @@ public class ShowClustersCommand extends ShowCommand { public static final ImmutableList COMPUTE_GROUP_TITLE_NAMES = new ImmutableList.Builder() .add("Name").add("IsCurrent").add("Users").add("BackendNum") .add("SubComputeGroups").add("Policy").add("Properties").build(); + // non cloud mode, a resource group(backend location tag) is the counterpart of a cloud compute group + public static final ImmutableList CLUSTER_TITLE_NAMES_NON_CLOUD = new ImmutableList.Builder() + .add("cluster").add("backend_num").build(); + public static final ImmutableList COMPUTE_GROUP_TITLE_NAMES_NON_CLOUD = new ImmutableList.Builder() + .add("Name").add("BackendNum").build(); private static final Logger LOG = LogManager.getLogger(ShowClustersCommand.class); private final boolean isComputeGroup; @@ -74,22 +78,23 @@ public ShowClustersCommand(boolean isComputeGroup) { this.isComputeGroup = isComputeGroup; } - private void validate(ConnectContext ctx) throws AnalysisException { - if (Config.isNotCloudMode()) { - // just user admin - if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get().getCurrentUserIdentity(), - PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV, Privilege.NODE_PRIV), Operator.OR))) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "ADMIN"); - } - } - } - @Override public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { - validate(ctx); final List> rows = Lists.newArrayList(); - if (!Config.isCloudMode()) { - ErrorReport.reportAnalysisException(ErrorCode.ERR_NOT_CLOUD_MODE); + if (Config.isNotCloudMode()) { + // resource group is the compute group of non cloud mode, a user only sees the resource groups + // it is allowed to use, same as the cloud mode which filters clusters by usage priv. + org.apache.doris.resource.computegroup.ComputeGroup userComputeGroup = ctx.getComputeGroup(); + if (org.apache.doris.resource.computegroup.ComputeGroup.INVALID_COMPUTE_GROUP == userComputeGroup) { + return new ShowResultSet(getMetaData(), rows); + } + Map backendNumByGroup = Env.getCurrentSystemInfo().getAllClusterBackends(false).stream() + .map(be -> be.getLocationTag().value) + .filter(userComputeGroup::containsBackend) + .collect(Collectors.groupingBy(name -> name, TreeMap::new, Collectors.counting())); + for (Map.Entry entry : backendNumByGroup.entrySet()) { + rows.add(Lists.newArrayList(entry.getKey(), String.valueOf(entry.getValue()))); + } return new ShowResultSet(getMetaData(), rows); } @@ -182,9 +187,9 @@ public ShowResultSetMetaData getMetaData() { ImmutableList titleNames = null; if (isComputeGroup) { - titleNames = COMPUTE_GROUP_TITLE_NAMES; + titleNames = Config.isNotCloudMode() ? COMPUTE_GROUP_TITLE_NAMES_NON_CLOUD : COMPUTE_GROUP_TITLE_NAMES; } else { - titleNames = CLUSTER_TITLE_NAMES; + titleNames = Config.isNotCloudMode() ? CLUSTER_TITLE_NAMES_NON_CLOUD : CLUSTER_TITLE_NAMES; } for (String title : titleNames) { @@ -193,4 +198,3 @@ public ShowResultSetMetaData getMetaData() { return builder.build(); } } - diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowComputeGroupTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowComputeGroupTest.java index 06588301872693..cab5353856c5a4 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowComputeGroupTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowComputeGroupTest.java @@ -18,11 +18,14 @@ package org.apache.doris.nereids.trees.plans.commands; import org.apache.doris.catalog.Column; -import org.apache.doris.common.AnalysisException; +import org.apache.doris.catalog.Env; import org.apache.doris.common.Config; import org.apache.doris.qe.ShowResultSetMetaData; +import org.apache.doris.resource.Tag; +import org.apache.doris.system.Backend; import org.apache.doris.utframe.TestWithFeService; +import com.google.common.collect.Lists; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -38,6 +41,7 @@ protected void runBeforeAll() throws Exception { @Test public void testShowComputeGroupsInCloudMode() throws Exception { Config.deploy_mode = "cloud"; + Config.cloud_unique_id = "cloud_unique_id"; ShowClustersCommand command = new ShowClustersCommand(true); ShowResultSetMetaData metaData = command.getMetaData(); Assertions.assertNotNull(metaData); @@ -56,15 +60,47 @@ public void testShowComputeGroupsInCloudMode() throws Exception { @Test public void testShowComputeGroupsInNonCloudMode() throws Exception { - Config.deploy_mode = "not-cloud"; + Config.deploy_mode = ""; + Config.cloud_unique_id = ""; + Tag groupA = Tag.create(Tag.TYPE_LOCATION, "group_a"); + Backend groupABackend1 = addNewBackend(); + Backend groupABackend2 = addNewBackend(); + Backend groupBBackend = addNewBackend(); + groupABackend1.setTagMap(groupA.toMap()); + groupABackend2.setTagMap(groupA.toMap()); + groupBBackend.setTagMap(Tag.create(Tag.TYPE_LOCATION, "group_b").toMap()); + ShowClustersCommand command = new ShowClustersCommand(true); - Assertions.assertThrows(AnalysisException.class, () -> { - command.doRun(connectContext, null); - }); + List columnNames = command.getMetaData().getColumns().stream() + .map(Column::getName).collect(Collectors.toList()); + Assertions.assertEquals(Lists.newArrayList("Name", "BackendNum"), columnNames); + List> rows = command.doRun(connectContext, null).getResultRows(); + List> expectedRows = Lists.newArrayList( + Lists.newArrayList(Tag.VALUE_DEFAULT_TAG, "1"), + Lists.newArrayList("group_a", "2"), + Lists.newArrayList("group_b", "1")); + Assertions.assertEquals(expectedRows, rows); + + // a user restricted by resource_tags.location only sees the resource groups it can use, + // this is the compute group bound to the session when the user logs in. + executeSql("CREATE USER show_cg_user IDENTIFIED BY '12345'"); + try { + executeSql("SET PROPERTY FOR 'show_cg_user' 'resource_tags.location' = 'group_a'"); + connectContext.setComputeGroup(Env.getCurrentEnv().getAuth().getComputeGroup("show_cg_user")); + Assertions.assertEquals(expectedRows.subList(1, 2), command.doRun(connectContext, null).getResultRows()); + + executeSql("SET PROPERTY FOR 'show_cg_user' 'resource_tags.location' = 'no_such_resource_group'"); + connectContext.setComputeGroup(Env.getCurrentEnv().getAuth().getComputeGroup("show_cg_user")); + Assertions.assertTrue(command.doRun(connectContext, null).getResultRows().isEmpty()); + } finally { + connectContext.setComputeGroup(null); + } } @Test public void testShowClustersInCloudMode() throws Exception { + Config.deploy_mode = "cloud"; + Config.cloud_unique_id = "cloud_unique_id"; ShowClustersCommand command = new ShowClustersCommand(false); ShowResultSetMetaData metaData = command.getMetaData(); Assertions.assertNotNull(metaData); @@ -82,10 +118,11 @@ public void testShowClustersInCloudMode() throws Exception { @Test public void testShowClustersInNonCloudMode() throws Exception { - Config.deploy_mode = "not-cloud"; + Config.deploy_mode = ""; + Config.cloud_unique_id = ""; ShowClustersCommand command = new ShowClustersCommand(false); - Assertions.assertThrows(AnalysisException.class, () -> { - command.doRun(connectContext, null); - }); + List columnNames = command.getMetaData().getColumns().stream() + .map(Column::getName).collect(Collectors.toList()); + Assertions.assertEquals(Lists.newArrayList("cluster", "backend_num"), columnNames); } }