diff --git a/src/go/rpk/pkg/cli/cluster/quotas/alter.go b/src/go/rpk/pkg/cli/cluster/quotas/alter.go index 79cbee25c02e5..0f1c99922621c 100644 --- a/src/go/rpk/pkg/cli/cluster/quotas/alter.go +++ b/src/go/rpk/pkg/cli/cluster/quotas/alter.go @@ -11,6 +11,8 @@ package quotas import ( "fmt" + "maps" + "slices" "strconv" "strings" @@ -49,8 +51,8 @@ This command allows you to add or delete a client quota. A client quota consists of an entity (to whom the quota is applied) and a quota type (what is being applied). -There are two entity types supported by Redpanda: client ID and client ID -prefix. +There are three entity types supported by Redpanda: user, client ID, and +client ID prefix. Assigning quotas to default entity types is possible using the '--default' flag. @@ -95,8 +97,8 @@ Remove quota (producer_byte_rate) from client ID 'foo': } k, v := split[0], split[1] k = strings.ToLower(k) - if !anyValidTypes[k] { - out.Die("name type %q is invalid (allowed: client-id, client-id-prefix)", split[0]) + if _, ok := anyValidTypes[k]; !ok { + out.Die("name type %q is invalid (allowed: %v)", k, strings.Join(slices.Collect(maps.Keys(anyValidTypes)), ", ")) } nameMap[k] = true entity = append(entity, kadm.ClientQuotaEntityComponent{ @@ -105,8 +107,8 @@ Remove quota (producer_byte_rate) from client ID 'foo': }) } for _, def := range defaults { - if !defaultValidTypes[def] { - out.Die("default type %q is invalid (allowed: client-id)", def) + if _, ok := defaultValidTypes[def]; !ok { + out.Die("default type %q is invalid (allowed: %v)", def, strings.Join(slices.Collect(maps.Keys(defaultValidTypes)), ", ")) } if nameMap[def] { out.Die("default type %q was previously defined in --name, you can only set it once", def) diff --git a/src/go/rpk/pkg/cli/cluster/quotas/describe.go b/src/go/rpk/pkg/cli/cluster/quotas/describe.go index b4466aee2a341..07a66ecf20183 100644 --- a/src/go/rpk/pkg/cli/cluster/quotas/describe.go +++ b/src/go/rpk/pkg/cli/cluster/quotas/describe.go @@ -11,6 +11,8 @@ package quotas import ( "fmt" + "maps" + "slices" "strconv" "strings" @@ -88,8 +90,8 @@ Describe client quotas for a given client ID prefix 'bar.': } k, v := split[0], split[1] k = strings.ToLower(k) - if !anyValidTypes[k] { - out.Die("name type %q is invalid (allowed: client-id, client-id-prefix)", split[0]) + if _, ok := anyValidTypes[k]; !ok { + out.Die("name type %q is invalid (allowed: %v)", k, strings.Join(slices.Collect(maps.Keys(anyValidTypes)), ", ")) } reqQuotas = append(reqQuotas, kadm.DescribeClientQuotaComponent{ Type: k, @@ -99,8 +101,8 @@ Describe client quotas for a given client ID prefix 'bar.': } for _, def := range defaults { k := strings.ToLower(def) - if !defaultValidTypes[k] { - out.Die("default type %q is invalid (allowed: client-id)", def) + if _, ok := defaultValidTypes[k]; !ok { + out.Die("default type %q is invalid (allowed: %v)", def, strings.Join(slices.Collect(maps.Keys(defaultValidTypes)), ", ")) } reqQuotas = append(reqQuotas, kadm.DescribeClientQuotaComponent{ Type: k, @@ -109,8 +111,8 @@ Describe client quotas for a given client ID prefix 'bar.': } for _, a := range anyFlag { k := strings.ToLower(a) - if !anyValidTypes[k] { - out.Die("'any' type %q is invalid (allowed: client-id, client-id-prefix)", a) + if _, ok := anyValidTypes[k]; !ok { + out.Die("'any' type %q is invalid (allowed: %v)", a, strings.Join(slices.Collect(maps.Keys(anyValidTypes)), ", ")) } reqQuotas = append(reqQuotas, kadm.DescribeClientQuotaComponent{ Type: k, diff --git a/src/go/rpk/pkg/cli/cluster/quotas/quotas.go b/src/go/rpk/pkg/cli/cluster/quotas/quotas.go index 2af28f369c5ca..b5ae0ece23feb 100644 --- a/src/go/rpk/pkg/cli/cluster/quotas/quotas.go +++ b/src/go/rpk/pkg/cli/cluster/quotas/quotas.go @@ -38,22 +38,18 @@ func NewCommand(fs afero.Fs, p *config.Params) *cobra.Command { } // anyValidTypes are the types allowed in --name and --any flags. -var anyValidTypes = map[string]bool{ - // Supported by Redpanda. - "client-id": true, - "client-id-prefix": true, - // Not supported by Redpanda yet. - "user": true, - "ip": true, +var anyValidTypes = map[string]struct{}{ + "client-id": {}, + "client-id-prefix": {}, + "user": {}, + // IP is not supported by Redpanda yet. } // defaultValidTypes are the types allowed in --default flag. -var defaultValidTypes = map[string]bool{ - // Supported by Redpanda. - "client-id": true, - // Not supported by Redpanda yet. - "user": true, - "ip": true, +var defaultValidTypes = map[string]struct{}{ + "client-id": {}, + "user": {}, + // IP is not supported by Redpanda yet. } type entityData struct { diff --git a/tests/rptest/tests/rpk_cluster_quota_test.py b/tests/rptest/tests/rpk_cluster_quota_test.py index d40447970b515..38f99b02068b8 100644 --- a/tests/rptest/tests/rpk_cluster_quota_test.py +++ b/tests/rptest/tests/rpk_cluster_quota_test.py @@ -36,9 +36,12 @@ def test_import_describe_quotas(self): self._rpk.alter_cluster_quotas( name=["client-id-prefix=foo-"], add=["consumer_byte_rate=2222"] ) + self._rpk.alter_cluster_quotas( + name=["user=bar"], add=["controller_mutation_rate=512"] + ) q2 = self._rpk.describe_cluster_quotas() - assert len(q2["quotas"]) == 2 # Quick check, just that we have something. + assert len(q2["quotas"]) == 3 # Quick check, just that we have something. # Same values, NoOp: import1 = """ @@ -71,14 +74,28 @@ def test_import_describe_quotas(self): "value":"11111" } ] - } + }, + { + "entity":[ + { + "name":"bar", + "type":"user" + } + ], + "values":[ + { + "key":"controller_mutation_rate", + "value":"512" + } + ] + }, ] } """ out = self._rpk.import_cluster_quota(import1, output_format="text") assert "No changes detected from import" in out - # Remove 1 (default client-id), Add 1 (producer byte rate). + # Remove 2 (default client-id and user), Add 1 (producer byte rate). import2 = """ { "quotas":[ @@ -121,6 +138,9 @@ def assertChanges(quotas, entity, quotaType, old, new): assertChanges( out, "client-id=", "producer_byte_rate", old="11111", new="-" ) # New Value as '-' means it was deleted + assertChanges( + out, "user=bar", "controller_mutation_rate", old="512", new="-" + ) assertChanges( out, "client-id-prefix=foo-", "producer_byte_rate", old="-", new="3333" )