From 4b22b8f6b18fbd224377de3c69415c21208c8a30 Mon Sep 17 00:00:00 2001 From: Evan Wall Date: Fri, 10 Mar 2023 10:13:25 -0500 Subject: [PATCH 1/4] multitenant: multitenant_admin_function_test cleanup Get cluster settings and capabilities directly from testCase instead of passing through testClusterCfg. Release note: None --- pkg/sql/multitenant_admin_function_test.go | 87 +++++++--------------- 1 file changed, 25 insertions(+), 62 deletions(-) diff --git a/pkg/sql/multitenant_admin_function_test.go b/pkg/sql/multitenant_admin_function_test.go index 37337401c21f..91d13f8a86ed 100644 --- a/pkg/sql/multitenant_admin_function_test.go +++ b/pkg/sql/multitenant_admin_function_test.go @@ -54,11 +54,7 @@ var ctx = context.Background() type testClusterCfg struct { base.TestClusterArgs - numNodes int - setupClusterSetting *settings.BoolSetting - queryClusterSetting *settings.BoolSetting - setupCapability tenantcapabilities.CapabilityID - queryCapability tenantcapabilities.CapabilityID + numNodes int } func createTestClusterArgs(numReplicas, numVoters int32) base.TestClusterArgs { @@ -248,11 +244,10 @@ type testCase struct { func (tc testCase) runTest( t *testing.T, - makeTestClusterCfg func() testClusterCfg, + cfg testClusterCfg, execQueries func(serverutils.TestClusterInterface, *gosql.DB, string, tenantExpected), ) { - cfg := makeTestClusterCfg() testingKnobs := &cfg.ServerArgs.Knobs if testingKnobs.Store == nil { testingKnobs.Store = &kvserver.StoreTestingKnobs{} @@ -341,27 +336,27 @@ func (tc testCase) runTest( secondaryDB := createSecondaryDB( tenantID1, true, /* skipSQLSystemTentantCheck */ - cfg.setupClusterSetting, - cfg.queryClusterSetting, + tc.setupClusterSetting, + tc.queryClusterSetting, ) - setCapabilities(tenantID1, cfg.setupCapability, cfg.queryCapability) + setCapabilities(tenantID1, tc.setupCapability, tc.queryCapability) tenantID2 := serverutils.TestTenantID2() secondaryWithoutClusterSettingDB := createSecondaryDB( tenantID2, false, /* skipSQLSystemTentantCheck */ - cfg.setupClusterSetting, + tc.setupClusterSetting, ) - setCapabilities(tenantID2, cfg.setupCapability) + setCapabilities(tenantID2, tc.setupCapability) tenantID3 := serverutils.TestTenantID3() secondaryWithoutCapabilityDB := createSecondaryDB( tenantID3, false, /* skipSQLSystemTentantCheck */ - cfg.setupClusterSetting, - cfg.queryClusterSetting, + tc.setupClusterSetting, + tc.queryClusterSetting, ) - setCapabilities(tenantID3, cfg.setupCapability) + setCapabilities(tenantID3, tc.setupCapability) // Wait for cluster settings to propagate async. for _, fn := range waitForTenantCapabilitiesFns { @@ -598,14 +593,7 @@ func TestMultiTenantAdminFunction(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - setupClusterSetting: tc.setupClusterSetting, - queryClusterSetting: tc.queryClusterSetting, - setupCapability: tc.setupCapability, - queryCapability: tc.queryCapability, - } - }, + testClusterCfg{}, func(testCluster serverutils.TestClusterInterface, db *gosql.DB, tenant string, expected tenantExpected) { setups := tc.setups setup := tc.setup @@ -652,24 +640,11 @@ func TestTruncateTable(t *testing.T) { }, }, setupClusterSetting: sql.SecondaryTenantSplitAtEnabled, + setupCapability: tenantcapabilities.CanAdminSplit, } tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - TestClusterArgs: base.TestClusterArgs{ - ServerArgs: base.TestServerArgs{ - Knobs: base.TestingKnobs{ - TenantCapabilitiesTestingKnobs: &tenantcapabilities.TestingKnobs{ - AuthorizerSkipAdminSplitCapabilityChecks: true, - }, - }, - }, - }, - setupClusterSetting: sql.SecondaryTenantSplitAtEnabled, - setupCapability: tenantcapabilities.CanAdminSplit, - } - }, + testClusterCfg{}, func(_ serverutils.TestClusterInterface, db *gosql.DB, tenant string, expected tenantExpected) { _, err := db.ExecContext(ctx, createTable) message := fmt.Sprintf("tenant=%s", tenant) @@ -729,12 +704,9 @@ func TestRelocateVoters(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - numNodes: numNodes, - TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), - queryClusterSetting: tc.queryClusterSetting, - } + testClusterCfg{ + numNodes: numNodes, + TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), }, func(testCluster serverutils.TestClusterInterface, db *gosql.DB, tenant string, tExp tenantExpected) { _, err := db.ExecContext(ctx, createTable) @@ -802,12 +774,9 @@ func TestExperimentalRelocateVoters(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - numNodes: numNodes, - TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), - queryClusterSetting: tc.queryClusterSetting, - } + testClusterCfg{ + numNodes: numNodes, + TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), }, func(testCluster serverutils.TestClusterInterface, db *gosql.DB, tenant string, expected tenantExpected) { _, err := db.ExecContext(ctx, createTable) @@ -884,12 +853,9 @@ func TestRelocateNonVoters(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - numNodes: numNodes, - TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), - queryClusterSetting: tc.queryClusterSetting, - } + testClusterCfg{ + numNodes: numNodes, + TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), }, func(testCluster serverutils.TestClusterInterface, db *gosql.DB, tenant string, expected tenantExpected) { _, err := db.ExecContext(ctx, createTable) @@ -952,12 +918,9 @@ func TestExperimentalRelocateNonVoters(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tc.runTest( t, - func() testClusterCfg { - return testClusterCfg{ - numNodes: numNodes, - TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), - queryClusterSetting: tc.queryClusterSetting, - } + testClusterCfg{ + numNodes: numNodes, + TestClusterArgs: createTestClusterArgs(expectedNumReplicas, expectedNumVotingReplicas), }, func(testCluster serverutils.TestClusterInterface, db *gosql.DB, tenant string, tExp tenantExpected) { _, err := db.ExecContext(ctx, createTable) From 9996674c57cd3b1b68d3bc26d2296afe7d97f983 Mon Sep 17 00:00:00 2001 From: Evan Wall Date: Fri, 10 Mar 2023 16:10:07 -0500 Subject: [PATCH 2/4] multitenant: reduce capability unrelated test churn Exclude capabilities from `tenant` logic test, `restore-tenants` data driven test. These tests do not set or depend on capabilities and they are tested elsewhere. Release note: None --- .../testdata/backup-restore/restore-tenants | 28 +++++----- pkg/sql/logictest/testdata/logic_test/tenant | 55 ++++++++++--------- 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/pkg/ccl/backupccl/testdata/backup-restore/restore-tenants b/pkg/ccl/backupccl/testdata/backup-restore/restore-tenants index 01bcc8236b7a..2458186bf443 100644 --- a/pkg/ccl/backupccl/testdata/backup-restore/restore-tenants +++ b/pkg/ccl/backupccl/testdata/backup-restore/restore-tenants @@ -27,11 +27,11 @@ CREATE DATABASE db1; ---- query-sql -SELECT id,name,data_state,service_mode,active,crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) FROM system.tenants; +SELECT id,name,data_state,service_mode,active,json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState'),json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') FROM system.tenants; ---- -1 system 1 2 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -5 2 0 false {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "5", "droppedName": "tenant-5", "tenantReplicationJobId": "0"} -6 tenant-6 1 1 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "6", "droppedName": "", "tenantReplicationJobId": "0"} +1 system 1 2 true READY +5 2 0 false DROP tenant-5 +6 tenant-6 1 1 true READY exec-sql BACKUP INTO 'nodelocal://1/cluster_without_tenants' @@ -79,10 +79,10 @@ job paused at pausepoint # Application tenants backed up in an ACTIVE state should be moved to an ADD # state during restore. query-sql -SELECT id,active,crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) FROM system.tenants; +SELECT id,active,json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState'),json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') FROM system.tenants; ---- -1 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -6 false {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "ADD", "deprecatedId": "6", "droppedName": "", "tenantReplicationJobId": "0"} +1 true READY +6 false ADD exec-sql SET CLUSTER SETTING jobs.debug.pausepoints = '' @@ -100,10 +100,10 @@ USE defaultdb; # A dropped tenant should be restored as an inactive tenant. query-sql -SELECT id,name,data_state,service_mode,active,crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) FROM system.tenants; +SELECT id,name,data_state,service_mode,active,json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState'),json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') FROM system.tenants; ---- -1 system 1 2 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -6 tenant-6 1 1 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "6", "droppedName": "", "tenantReplicationJobId": "0"} +1 system 1 2 true READY +6 tenant-6 1 1 true READY exec-sql expect-error-regex=(tenant 6 not in backup) @@ -131,11 +131,11 @@ RESTORE TENANT 6 FROM LATEST IN 'nodelocal://1/tenant6' WITH tenant_name = 'newn ---- query-sql -SELECT id,name,data_state,service_mode,active,crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) FROM system.tenants; +SELECT id,name,data_state,service_mode,active,json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState'),json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') FROM system.tenants; ---- -1 system 1 2 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 newname 1 1 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -6 tenant-6 1 1 true {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "6", "droppedName": "", "tenantReplicationJobId": "0"} +1 system 1 2 true READY +2 newname 1 1 true READY +6 tenant-6 1 1 true READY # Check that another service mode is also preserved. exec-sql diff --git a/pkg/sql/logictest/testdata/logic_test/tenant b/pkg/sql/logictest/testdata/logic_test/tenant index c8fa12b3b603..88fea1d94cc8 100644 --- a/pkg/sql/logictest/testdata/logic_test/tenant +++ b/pkg/sql/logictest/testdata/logic_test/tenant @@ -32,16 +32,16 @@ CREATE TENANT "invalid.name" statement ok CREATE TENANT three -query IBTT colnames -SELECT id, active, name, crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) +query IBT colnames +SELECT id, active, name FROM system.tenants ORDER BY id ---- -id active name crdb_internal.pb_to_json -1 true system {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 true tenant-one {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -3 true two {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "3", "droppedName": "", "tenantReplicationJobId": "0"} -4 true three {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "4", "droppedName": "", "tenantReplicationJobId": "0"} +id active name +1 true system +2 true tenant-one +3 true two +4 true three query ITTT colnames SHOW TENANT system @@ -152,23 +152,23 @@ DROP TENANT IF EXISTS dne statement ok CREATE TENANT four -query IBTT colnames -SELECT id, active, name, crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) +query IBT colnames +SELECT id, active, name FROM system.tenants WHERE name = 'four' ORDER BY id ---- -id active name crdb_internal.pb_to_json -5 true four {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "5", "droppedName": "", "tenantReplicationJobId": "0"} +id active name +5 true four statement ok DROP TENANT four -query IBTT colnames -SELECT id, active, name, crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) +query IBT colnames +SELECT id, active, name FROM system.tenants WHERE name = 'four' ORDER BY id ---- -id active name crdb_internal.pb_to_json +id active name statement error tenant "four" does not exist SHOW TENANT four @@ -226,20 +226,25 @@ DROP TENANT "to-be-reclaimed" statement ok CREATE TENANT "to-be-reclaimed" -query IBTT colnames -SELECT id, active, name, crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true) +query IBTTT colnames +SELECT + id, + active, + name, + json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState') AS deprecated_data_state, + json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') AS dropped_name FROM system.tenants ORDER BY id ---- -id active name crdb_internal.pb_to_json -1 true system {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 true tenant-one {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -3 true two {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "3", "droppedName": "", "tenantReplicationJobId": "0"} -4 true three {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "4", "droppedName": "", "tenantReplicationJobId": "0"} -5 false NULL {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "5", "droppedName": "four", "tenantReplicationJobId": "0"} -6 false NULL {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "6", "droppedName": "five-requiring-quotes", "tenantReplicationJobId": "0"} -7 false NULL {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "7", "droppedName": "to-be-reclaimed", "tenantReplicationJobId": "0"} -8 true to-be-reclaimed {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "8", "droppedName": "", "tenantReplicationJobId": "0"} +id active name deprecated_data_state dropped_name +1 true system READY · +2 true tenant-one READY · +3 true two READY · +4 true three READY · +5 false NULL DROP four +6 false NULL DROP five-requiring-quotes +7 false NULL DROP to-be-reclaimed +8 true to-be-reclaimed READY · # More valid tenant names. statement ok From 3f366fdd0c88b04cd1baa3089fbe8fc4cc4450f7 Mon Sep 17 00:00:00 2001 From: Evan Wall Date: Fri, 10 Mar 2023 16:57:12 -0500 Subject: [PATCH 3/4] multitenant: reduce capability unrelated test churn Filter out static capabilities in `subtest node_tenant_capabilities_cache`. Release note: None --- .../testdata/logic_test/crdb_internal | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal b/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal index 9f9bec3b4be8..b0d538692a62 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal +++ b/pkg/ccl/logictestccl/testdata/logic_test/crdb_internal @@ -191,33 +191,21 @@ SELECT crdb_internal.create_tenant(5) # Use retry because source data is eventually consistent. query ITT colnames,retry -SELECT * FROM crdb_internal.node_tenant_capabilities_cache +SELECT * FROM crdb_internal.node_tenant_capabilities_cache WHERE capability_id = 'can_admin_split' ---- -tenant_id capability_id capability_value -1 can_admin_split false -1 can_admin_unsplit false -1 can_view_node_info false -1 can_view_tsdb_metrics false -5 can_admin_split false -5 can_admin_unsplit false -5 can_view_node_info false -5 can_view_tsdb_metrics false +tenant_id capability_id capability_value +1 can_admin_split false +5 can_admin_split false statement ok ALTER TENANT [5] GRANT CAPABILITY can_admin_split # Use retry because source data is eventually consistent. query ITT colnames,retry -SELECT * FROM crdb_internal.node_tenant_capabilities_cache +SELECT * FROM crdb_internal.node_tenant_capabilities_cache WHERE capability_id = 'can_admin_split' ---- -tenant_id capability_id capability_value -1 can_admin_split false -1 can_admin_unsplit false -1 can_view_node_info false -1 can_view_tsdb_metrics false -5 can_admin_split true -5 can_admin_unsplit false -5 can_view_node_info false -5 can_view_tsdb_metrics false +tenant_id capability_id capability_value +1 can_admin_split false +5 can_admin_split true subtest end From 39a723dc5c8922fece520411a1a5a5d2a04a1bdf Mon Sep 17 00:00:00 2001 From: Evan Wall Date: Thu, 9 Mar 2023 21:14:50 -0500 Subject: [PATCH 4/4] multitenant: add AdminScatterRequest capability Fixes #98394 1) Add a new `tenantcapabilities.CanAdminScatter` capability. 2) Check capability in `Authorizer.HasCapabilityForBatch`. Release note: None --- .../testdata/logic_test/tenant_capability | 7 ++++ .../tenantcapabilities/capabilities.go | 7 ++++ .../tenantcapabilities/capabilityid_string.go | 17 +++++----- .../authorizer.go | 5 +-- .../testdata/basic | 18 +++++++++-- .../tenantcapabilitiespb/capabilities.go | 4 +++ .../tenantcapabilitiespb/capabilities.proto | 4 +++ .../tenantcapabilitieswatcher/testdata/basic | 24 +++++++------- .../testdata/initial_scan | 10 +++--- .../testdata/rangefeed_errors | 32 +++++++++---------- .../testdata/logic_test/tenant_builtins | 22 ++++++------- pkg/sql/multitenant_admin_function_test.go | 29 ++++++++++++----- 12 files changed, 114 insertions(+), 65 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/tenant_capability b/pkg/ccl/logictestccl/testdata/logic_test/tenant_capability index 9be70cb85382..093a37aa0f61 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/tenant_capability +++ b/pkg/ccl/logictestccl/testdata/logic_test/tenant_capability @@ -31,6 +31,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "no-capabilities-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split false can_admin_unsplit false can_view_node_info false @@ -50,6 +51,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "bool-capability-no-value-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split true can_admin_unsplit false can_view_node_info false @@ -62,6 +64,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "bool-capability-no-value-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split false can_admin_unsplit false can_view_node_info false @@ -81,6 +84,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "bool-capability-with-value-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split true can_admin_unsplit false can_view_node_info false @@ -100,6 +104,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "bool-capability-with-expression-value-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split true can_admin_unsplit false can_view_node_info false @@ -119,6 +124,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "multiple-capability-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split true can_admin_unsplit false can_view_node_info true @@ -131,6 +137,7 @@ query TT colnames SELECT capability_id, capability_value FROM [SHOW TENANT "multiple-capability-tenant" WITH CAPABILITIES] ---- capability_id capability_value +can_admin_scatter false can_admin_split false can_admin_unsplit false can_view_node_info false diff --git a/pkg/multitenant/tenantcapabilities/capabilities.go b/pkg/multitenant/tenantcapabilities/capabilities.go index 40661c06b0a1..891782e6e998 100644 --- a/pkg/multitenant/tenantcapabilities/capabilities.go +++ b/pkg/multitenant/tenantcapabilities/capabilities.go @@ -160,6 +160,12 @@ type TenantCapabilities interface { const ( _ CapabilityID = iota + // CanAdminScatter describes the ability of a tenant to perform manual + // KV scatter requests. These operations need a capability + // because excessive KV range scatter can overwhelm the storage + // cluster. + CanAdminScatter // can_admin_scatter + // CanAdminSplit describes the ability of a tenant to perform manual // KV range split requests. These operations need a capability // because excessive KV range splits can overwhelm the storage @@ -222,6 +228,7 @@ const ( func (c CapabilityID) CapabilityType() Type { switch c { case + CanAdminScatter, CanAdminSplit, CanAdminUnsplit, CanViewNodeInfo, diff --git a/pkg/multitenant/tenantcapabilities/capabilityid_string.go b/pkg/multitenant/tenantcapabilities/capabilityid_string.go index dfb87a9988c8..f4dd2d5076b4 100644 --- a/pkg/multitenant/tenantcapabilities/capabilityid_string.go +++ b/pkg/multitenant/tenantcapabilities/capabilityid_string.go @@ -8,17 +8,18 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} - _ = x[CanAdminSplit-1] - _ = x[CanAdminUnsplit-2] - _ = x[CanViewNodeInfo-3] - _ = x[CanViewTSDBMetrics-4] - _ = x[TenantSpanConfigBounds-5] - _ = x[MaxCapabilityID-5] + _ = x[CanAdminScatter-1] + _ = x[CanAdminSplit-2] + _ = x[CanAdminUnsplit-3] + _ = x[CanViewNodeInfo-4] + _ = x[CanViewTSDBMetrics-5] + _ = x[TenantSpanConfigBounds-6] + _ = x[MaxCapabilityID-6] } -const _CapabilityID_name = "can_admin_splitcan_admin_unsplitcan_view_node_infocan_view_tsdb_metricsspan_config_bounds" +const _CapabilityID_name = "can_admin_scattercan_admin_splitcan_admin_unsplitcan_view_node_infocan_view_tsdb_metricsspan_config_bounds" -var _CapabilityID_index = [...]uint8{0, 15, 32, 50, 71, 89} +var _CapabilityID_index = [...]uint8{0, 17, 32, 49, 67, 88, 106} func (i CapabilityID) String() string { i -= 1 diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go index acf7d3fed9fd..312b79b4cd43 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/authorizer.go @@ -71,7 +71,8 @@ func (a *Authorizer) HasCapabilityForBatch( continue } if !hasCap || requiredCap == onlySystemTenant || !found || !cp.GetBool(requiredCap) { - if requiredCap == tenantcapabilities.CanAdminSplit && a.knobs.AuthorizerSkipAdminSplitCapabilityChecks { + if (requiredCap == tenantcapabilities.CanAdminSplit || requiredCap == tenantcapabilities.CanAdminScatter) && + a.knobs.AuthorizerSkipAdminSplitCapabilityChecks { continue } // All allowable request types must be explicitly opted into the @@ -118,6 +119,7 @@ var reqMethodToCap = map[kvpb.Method]tenantcapabilities.CapabilityID{ kvpb.Scan: noCapCheckNeeded, // The following are authorized via specific capabilities. + kvpb.AdminScatter: tenantcapabilities.CanAdminScatter, kvpb.AdminSplit: tenantcapabilities.CanAdminSplit, kvpb.AdminUnsplit: tenantcapabilities.CanAdminUnsplit, @@ -125,7 +127,6 @@ var reqMethodToCap = map[kvpb.Method]tenantcapabilities.CapabilityID{ kvpb.AdminChangeReplicas: noCapCheckNeeded, kvpb.AdminMerge: noCapCheckNeeded, kvpb.AdminRelocateRange: noCapCheckNeeded, - kvpb.AdminScatter: noCapCheckNeeded, kvpb.AdminTransferLease: noCapCheckNeeded, // TODO(knz,arul): Verify with the relevant teams whether secondary diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/testdata/basic b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/testdata/basic index 0537a58abd89..553c6e3110ba 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/testdata/basic +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiesauthorizer/testdata/basic @@ -1,8 +1,12 @@ -upsert ten=10 can_admin_split=true can_admin_unsplit=true can_view_node_info=true can_view_tsdb_metrics=true +upsert ten=10 can_admin_scatter=true can_admin_split=true can_admin_unsplit=true can_view_node_info=true can_view_tsdb_metrics=true ---- ok -upsert ten=11 can_admin_split=false can_admin_unsplit=false can_view_node_info=false can_view_tsdb_metrics=false +upsert ten=11 can_admin_scatter=false can_admin_split=false can_admin_unsplit=false can_view_node_info=false can_view_tsdb_metrics=false +---- +ok + +has-capability-for-batch ten=10 cmds=(AdminScatter, Scan, ConditionalPut) ---- ok @@ -16,6 +20,10 @@ has-capability-for-batch ten=10 cmds=(AdminUnsplit, Scan, ConditionalPut) ---- ok +has-capability-for-batch ten=11 cmds=(AdminScatter, Scan, ConditionalPut) +---- +client tenant does not have capability "can_admin_scatter" (*kvpb.AdminScatterRequest) + # Tenant 11 shouldn't be able to issue splits. has-capability-for-batch ten=11 cmds=(AdminSplit, Scan, ConditionalPut) ---- @@ -43,10 +51,14 @@ ok # Lastly, flip tenant 10's capability for splits; ensure it can no longer issue # splits as a result. -upsert ten=10 can_admin_split=false can_admin_unsplit=false can_view_node_info=true can_view_tsdb_metrics=true +upsert ten=10 can_admin_scatter=false can_admin_split=false can_admin_unsplit=false can_view_node_info=true can_view_tsdb_metrics=true ---- ok +has-capability-for-batch ten=10 cmds=(AdminScatter, Scan, ConditionalPut) +---- +client tenant does not have capability "can_admin_scatter" (*kvpb.AdminScatterRequest) + has-capability-for-batch ten=10 cmds=(AdminSplit, Scan, ConditionalPut) ---- client tenant does not have capability "can_admin_split" (*kvpb.AdminSplitRequest) diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.go b/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.go index c62059aa3c2d..f33e0318ad46 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.go +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.go @@ -52,6 +52,8 @@ func (t *TenantCapabilities) Cap( capabilityID tenantcapabilities.CapabilityID, ) tenantcapabilities.Capability { switch capabilityID { + case tenantcapabilities.CanAdminScatter: + return boolCap{&t.CanAdminScatter} case tenantcapabilities.CanAdminSplit: return boolCap{&t.CanAdminSplit} case tenantcapabilities.CanAdminUnsplit: @@ -69,6 +71,8 @@ func (t *TenantCapabilities) Cap( // GetBool implements the tenantcapabilities.TenantCapabilities interface. It is an optimization. func (t *TenantCapabilities) GetBool(capabilityID tenantcapabilities.CapabilityID) bool { switch capabilityID { + case tenantcapabilities.CanAdminScatter: + return t.CanAdminScatter case tenantcapabilities.CanAdminSplit: return t.CanAdminSplit case tenantcapabilities.CanAdminUnsplit: diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.proto b/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.proto index 096d4112bad4..922e4373ffe9 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.proto +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitiespb/capabilities.proto @@ -61,6 +61,10 @@ message TenantCapabilities { // CanAdminUnsplit if set to true, grants the tenant the ability to // successfully perform `AdminUnsplit` requests. bool can_admin_unsplit = 5; + + // CanAdminScatter if set to true, grants the tenant the ability to + // successfully perform `AdminScatter` requests. + bool can_admin_scatter = 6; }; // SpanConfigBound is used to constrain the possible values a SpanConfig may diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/basic b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/basic index 7c9c956f9ddd..bde38ef1a181 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/basic +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/basic @@ -18,13 +18,13 @@ ok updates ---- Incremental Update -update: ten=10 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=10 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} flush-state ---- -ten=10 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=10 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} upsert ten=11 can_admin_split=true ---- @@ -33,11 +33,11 @@ ok updates ---- Incremental Update -update: ten=11 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=11 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=11 ---- -{can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} delete ten=10 ---- @@ -64,7 +64,7 @@ updates # what we'd expect. flush-state ---- -ten=11 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=11 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} upsert ten=15 can_admin_split=true ---- @@ -73,7 +73,7 @@ ok updates ---- Incremental Update -update: ten=15 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=15 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} # Ensure only the last update is applied, even when there are multiple updates # to a single key. @@ -100,7 +100,7 @@ not-found flush-state ---- -ten=15 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=15 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} # Same thing, but this time instead of deleting the key, leave it behind. delete ten=15 @@ -118,12 +118,12 @@ ok updates ---- Incremental Update -update: ten=15 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=15 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} flush-state ---- -ten=15 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=15 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=15 ---- -{can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/initial_scan b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/initial_scan index ae2fda0f78e3..a93b960655f7 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/initial_scan +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/initial_scan @@ -38,13 +38,13 @@ ok updates ---- Complete Update -update: ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=15 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=15 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} flush-state ---- -ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=15 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=15 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=10 ---- @@ -52,4 +52,4 @@ not-found get-capabilities ten=15 ---- -{can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} diff --git a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/rangefeed_errors b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/rangefeed_errors index 118ea7b65e78..a6202e19299f 100644 --- a/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/rangefeed_errors +++ b/pkg/multitenant/tenantcapabilities/tenantcapabilitieswatcher/testdata/rangefeed_errors @@ -25,9 +25,9 @@ ok updates ---- Incremental Update -update: ten=10 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=12 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=10 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=12 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} inject-error ---- @@ -56,9 +56,9 @@ updates flush-state ---- -ten=10 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=12 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=10 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=12 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=50 ---- @@ -66,11 +66,11 @@ not-found get-capabilities ten=12 ---- -{can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=10 ---- -{can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} # Let the Watcher attempt to restart. restart-after-injected-error @@ -82,23 +82,23 @@ ok updates ---- Complete Update -update: ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=12 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -update: ten=50 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=12 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +update: ten=50 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} flush-state ---- -ten=11 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=12 cap={can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} -ten=50 cap={can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=11 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=12 cap={can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +ten=50 cap={can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=50 ---- -{can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:false can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=12 ---- -{can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} +{can_admin_scatter:false can_admin_split:true can_admin_unsplit:false can_view_node_info:false can_view_tsdb_metrics:false} get-capabilities ten=10 ---- diff --git a/pkg/sql/logictest/testdata/logic_test/tenant_builtins b/pkg/sql/logictest/testdata/logic_test/tenant_builtins index 8818e4e416f2..2cb686aee22a 100644 --- a/pkg/sql/logictest/testdata/logic_test/tenant_builtins +++ b/pkg/sql/logictest/testdata/logic_test/tenant_builtins @@ -47,10 +47,10 @@ FROM system.tenants ORDER BY id ---- id active name data_state service_mode crdb_internal.pb_to_json -1 true system 1 2 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -5 true tenant-5 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "5", "droppedName": "", "tenantReplicationJobId": "0"} -10 true tenant-number-ten 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} +1 true system 1 2 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} +2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} +5 true tenant-5 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "5", "droppedName": "", "tenantReplicationJobId": "0"} +10 true tenant-number-ten 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} # Check we can add a name where none existed before. statement ok @@ -118,10 +118,10 @@ FROM system.tenants ORDER BY id ---- id active name data_state service_mode crdb_internal.pb_to_json -1 true system 1 2 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -5 false NULL 2 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "5", "droppedName": "my-new-tenant-name", "tenantReplicationJobId": "0"} -10 true tenant-number-ten 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} +1 true system 1 2 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} +2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} +5 false NULL 2 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "DROP", "deprecatedId": "5", "droppedName": "my-new-tenant-name", "tenantReplicationJobId": "0"} +10 true tenant-number-ten 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} # Try to recreate an existing tenant. @@ -229,9 +229,9 @@ FROM system.tenants ORDER BY id ---- id active name data_state service_mode crdb_internal.pb_to_json -1 true system 1 2 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} -2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} -10 true tenant-number-ten 1 0 {"capabilities": {"canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} +1 true system 1 2 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "1", "droppedName": "", "tenantReplicationJobId": "0"} +2 true tenant-number-eleven 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "2", "droppedName": "", "tenantReplicationJobId": "0"} +10 true tenant-number-ten 1 0 {"capabilities": {"canAdminScatter": false, "canAdminSplit": false, "canAdminUnsplit": false, "canViewNodeInfo": false, "canViewTsdbMetrics": false, "spanConfigBounds": null}, "deprecatedDataState": "READY", "deprecatedId": "10", "droppedName": "", "tenantReplicationJobId": "0"} query error tenant resource limits require a CCL binary SELECT crdb_internal.update_tenant_resource_limits(10, 1000, 100, 0, now(), 0) diff --git a/pkg/sql/multitenant_admin_function_test.go b/pkg/sql/multitenant_admin_function_test.go index 91d13f8a86ed..68b2b7c49a8c 100644 --- a/pkg/sql/multitenant_admin_function_test.go +++ b/pkg/sql/multitenant_admin_function_test.go @@ -570,7 +570,11 @@ func TestMultiTenantAdminFunction(t *testing.T) { secondaryWithoutClusterSetting: tenantExpected{ errorMessage: "tenant cluster setting sql.scatter.allow_for_secondary_tenant.enabled disabled", }, + secondaryWithoutCapability: tenantExpected{ + errorMessage: `does not have capability "can_admin_scatter"`, + }, queryClusterSetting: sql.SecondaryTenantScatterEnabled, + queryCapability: tenantcapabilities.CanAdminScatter, }, { desc: "ALTER INDEX x SCATTER", @@ -585,7 +589,11 @@ func TestMultiTenantAdminFunction(t *testing.T) { secondaryWithoutClusterSetting: tenantExpected{ errorMessage: "tenant cluster setting sql.scatter.allow_for_secondary_tenant.enabled disabled", }, + secondaryWithoutCapability: tenantExpected{ + errorMessage: `does not have capability "can_admin_scatter"`, + }, queryClusterSetting: sql.SecondaryTenantScatterEnabled, + queryCapability: tenantcapabilities.CanAdminScatter, }, } @@ -634,13 +642,13 @@ func TestTruncateTable(t *testing.T) { }, }, secondaryWithoutCapability: tenantExpected{ - result: [][]string{ - {"", "…/104/2/1"}, - {"…/104/2/1", ""}, - }, + // CanAdminScatter will default to true so this will open happen if it is + // set to false. + errorMessage: `does not have capability "can_admin_scatter"`, }, setupClusterSetting: sql.SecondaryTenantSplitAtEnabled, setupCapability: tenantcapabilities.CanAdminSplit, + queryCapability: tenantcapabilities.CanAdminScatter, } tc.runTest( t, @@ -651,10 +659,15 @@ func TestTruncateTable(t *testing.T) { require.NoErrorf(t, err, message) _, err = db.ExecContext(ctx, "ALTER TABLE t SPLIT AT VALUES (1);") require.NoErrorf(t, err, message) - _, err = db.ExecContext(ctx, "TRUNCATE TABLE t;") - require.NoErrorf(t, err, message) - rows, err := db.QueryContext(ctx, "SELECT start_key, end_key from [SHOW RANGES FROM INDEX t@primary];") - expected.validate(t, rows, err, message) + + // validateErr and validateRows come from separate queries for TRUNCATE. + _, validateErr := db.ExecContext(ctx, "TRUNCATE TABLE t;") + var validateRows *gosql.Rows + if err == nil { + validateRows, err = db.QueryContext(ctx, "SELECT start_key, end_key from [SHOW RANGES FROM INDEX t@primary];") + require.NoErrorf(t, err, message) + } + expected.validate(t, validateRows, validateErr, message) }, ) }