From aa10ab5ddf82f14db8afb32db97c20547ed294cf Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Tue, 24 Oct 2023 11:54:04 -0400 Subject: [PATCH 1/7] Add methods for marshalling/unmarshalling ACLOperationType and ACLPermissionType --- createacls.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++ createacls_test.go | 34 +++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/createacls.go b/createacls.go index 672f6fdce..c1b2e44d3 100644 --- a/createacls.go +++ b/createacls.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "strings" "time" "github.com/segmentio/kafka-go/protocol/createacls" @@ -42,6 +43,42 @@ const ( ACLPermissionTypeAllow ACLPermissionType = 3 ) +func (apt ACLPermissionType) String() string { + mapping := map[ACLPermissionType]string{ + ACLPermissionTypeUnknown: "Unknown", + ACLPermissionTypeAny: "Any", + ACLPermissionTypeDeny: "Deny", + ACLPermissionTypeAllow: "Allow", + } + s, ok := mapping[apt] + if !ok { + s = mapping[ACLPermissionTypeUnknown] + } + return s +} + +// UnmarshalText takes a string representation of the resource type and converts it to an ACLPermissionType. +func (apt *ACLPermissionType) UnmarshalText(text []byte) error { + normalized := strings.ToLower(string(text)) + mapping := map[string]ACLPermissionType{ + "unknown": ACLPermissionTypeUnknown, + "any": ACLPermissionTypeAny, + "deny": ACLPermissionTypeDeny, + "allow": ACLPermissionTypeAllow, + } + parsed, ok := mapping[normalized] + if !ok { + return fmt.Errorf("cannot parse %s as an ACLPermissionType", normalized) + } + *apt = parsed + return nil +} + +// MarshalText transforms an ACLPermissionType into its string representation. +func (apt ACLPermissionType) MarshalText() ([]byte, error) { + return []byte(apt.String()), nil +} + type ACLOperationType int8 const ( @@ -60,6 +97,61 @@ const ( ACLOperationTypeIdempotentWrite ACLOperationType = 12 ) +func (aot ACLOperationType) String() string { + mapping := map[ACLOperationType]string{ + ACLOperationTypeUnknown: "Unknown", + ACLOperationTypeAny: "Any", + ACLOperationTypeAll: "All", + ACLOperationTypeRead: "Read", + ACLOperationTypeWrite: "Write", + ACLOperationTypeCreate: "Create", + ACLOperationTypeDelete: "Delete", + ACLOperationTypeAlter: "Alter", + ACLOperationTypeDescribe: "Describe", + ACLOperationTypeClusterAction: "ClusterAction", + ACLOperationTypeDescribeConfigs: "DescribeConfigs", + ACLOperationTypeAlterConfigs: "AlterConfigs", + ACLOperationTypeIdempotentWrite: "IdempotentWrite", + } + s, ok := mapping[aot] + if !ok { + s = mapping[ACLOperationTypeUnknown] + } + return s +} + +// UnmarshalText takes a string representation of the resource type and converts it to an ACLPermissionType. +func (aot *ACLOperationType) UnmarshalText(text []byte) error { + normalized := strings.ToLower(string(text)) + mapping := map[string]ACLOperationType{ + "unknown": ACLOperationTypeUnknown, + "any": ACLOperationTypeAny, + "all": ACLOperationTypeAll, + "read": ACLOperationTypeRead, + "write": ACLOperationTypeWrite, + "create": ACLOperationTypeCreate, + "delete": ACLOperationTypeDelete, + "alter": ACLOperationTypeAlter, + "describe": ACLOperationTypeDescribe, + "clusteraction": ACLOperationTypeClusterAction, + "describeconfigs": ACLOperationTypeDescribeConfigs, + "alterconfigs": ACLOperationTypeAlterConfigs, + "idempotentwrite": ACLOperationTypeIdempotentWrite, + } + parsed, ok := mapping[normalized] + if !ok { + return fmt.Errorf("cannot parse %s as an ACLOperationType", normalized) + } + *aot = parsed + return nil + +} + +// MarshalText transforms an ACLOperationType into its string representation. +func (aot ACLOperationType) MarshalText() ([]byte, error) { + return []byte(aot.String()), nil +} + type ACLEntry struct { ResourceType ResourceType ResourceName string diff --git a/createacls_test.go b/createacls_test.go index ee04779ea..314427a57 100644 --- a/createacls_test.go +++ b/createacls_test.go @@ -50,3 +50,37 @@ func TestClientCreateACLs(t *testing.T) { } } } + +func TestACLPermissionTypeMarshal(t *testing.T) { + for i := ACLPermissionTypeUnknown; i <= ACLPermissionTypeAllow; i++ { + text, err := i.MarshalText() + if err != nil { + t.Errorf("couldn't marshal %d to text: %s", i, err) + } + var got ACLPermissionType + err = got.UnmarshalText(text) + if err != nil { + t.Errorf("couldn't unmarshal %s to ACLPermissionType: %s", text, err) + } + if got != i { + t.Errorf("got %d, want %d", got, i) + } + } +} + +func TestACLOperationTypeMarshal(t *testing.T) { + for i := ACLOperationTypeUnknown; i <= ACLOperationTypeIdempotentWrite; i++ { + text, err := i.MarshalText() + if err != nil { + t.Errorf("couldn't marshal %d to text: %s", i, err) + } + var got ACLOperationType + err = got.UnmarshalText(text) + if err != nil { + t.Errorf("couldn't unmarshal %s to ACLOperationType: %s", text, err) + } + if got != i { + t.Errorf("got %d, want %d", got, i) + } + } +} From 485d15b0f22fab081806b5cdfb0a5d40765a6d92 Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Tue, 24 Oct 2023 13:17:44 -0400 Subject: [PATCH 2/7] Fix unknown types --- createacls.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/createacls.go b/createacls.go index c1b2e44d3..88d3fa71d 100644 --- a/createacls.go +++ b/createacls.go @@ -68,6 +68,7 @@ func (apt *ACLPermissionType) UnmarshalText(text []byte) error { } parsed, ok := mapping[normalized] if !ok { + *apt = ACLPermissionTypeUnknown return fmt.Errorf("cannot parse %s as an ACLPermissionType", normalized) } *apt = parsed @@ -140,6 +141,7 @@ func (aot *ACLOperationType) UnmarshalText(text []byte) error { } parsed, ok := mapping[normalized] if !ok { + *aot = ACLOperationTypeUnknown return fmt.Errorf("cannot parse %s as an ACLOperationType", normalized) } *aot = parsed From 2cb79da136d86a815c20257945171985475fb7d3 Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Tue, 24 Oct 2023 13:17:55 -0400 Subject: [PATCH 3/7] Implement ResourceType --- resource.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/resource.go b/resource.go index f5c2e73a5..dd2b0a43b 100644 --- a/resource.go +++ b/resource.go @@ -1,5 +1,10 @@ package kafka +import ( + "fmt" + "strings" +) + // https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/ResourceType.java type ResourceType int8 @@ -15,6 +20,44 @@ const ( ResourceTypeDelegationToken ResourceType = 6 ) +func (rt ResourceType) String() string { + mapping := map[ResourceType]string{ + ResourceTypeUnknown: "unknown", + ResourceTypeAny: "any", + ResourceTypeTopic: "topic", + ResourceTypeGroup: "group", + ResourceTypeCluster: "cluster", + ResourceTypeTransactionalID: "transactionalid", + ResourceTypeDelegationToken: "delegationtoken", + } + s, ok := mapping[rt] + if !ok { + s = mapping[ResourceTypeUnknown] + } + return s +} + +func (rt *ResourceType) UnmarshalText(text []byte) error { + normalized := strings.ToLower(string(text)) + mapping := map[string]ResourceType{ + "unknown": ResourceTypeUnknown, + "any": ResourceTypeAny, + "topic": ResourceTypeTopic, + "group": ResourceTypeGroup, + "broker": ResourceTypeBroker, + "cluster": ResourceTypeCluster, + "transactionalid": ResourceTypeTransactionalID, + "delegationtoken": ResourceTypeDelegationToken, + } + parsed, ok := mapping[normalized] + if !ok { + *rt = ResourceTypeUnknown + return fmt.Errorf("cannot parse %s as a ResourceType", normalized) + } + *rt = parsed + return nil +} + // https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/resource/PatternType.java type PatternType int8 From c1906e357e32accac2bcb70d4543fb430834ce82 Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Mon, 30 Oct 2023 10:48:36 -0400 Subject: [PATCH 4/7] make function ordering more consistent --- createacls.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/createacls.go b/createacls.go index 88d3fa71d..601974171 100644 --- a/createacls.go +++ b/createacls.go @@ -57,6 +57,11 @@ func (apt ACLPermissionType) String() string { return s } +// MarshalText transforms an ACLPermissionType into its string representation. +func (apt ACLPermissionType) MarshalText() ([]byte, error) { + return []byte(apt.String()), nil +} + // UnmarshalText takes a string representation of the resource type and converts it to an ACLPermissionType. func (apt *ACLPermissionType) UnmarshalText(text []byte) error { normalized := strings.ToLower(string(text)) @@ -75,11 +80,6 @@ func (apt *ACLPermissionType) UnmarshalText(text []byte) error { return nil } -// MarshalText transforms an ACLPermissionType into its string representation. -func (apt ACLPermissionType) MarshalText() ([]byte, error) { - return []byte(apt.String()), nil -} - type ACLOperationType int8 const ( @@ -121,6 +121,11 @@ func (aot ACLOperationType) String() string { return s } +// MarshalText transforms an ACLOperationType into its string representation. +func (aot ACLOperationType) MarshalText() ([]byte, error) { + return []byte(aot.String()), nil +} + // UnmarshalText takes a string representation of the resource type and converts it to an ACLPermissionType. func (aot *ACLOperationType) UnmarshalText(text []byte) error { normalized := strings.ToLower(string(text)) @@ -149,11 +154,6 @@ func (aot *ACLOperationType) UnmarshalText(text []byte) error { } -// MarshalText transforms an ACLOperationType into its string representation. -func (aot ACLOperationType) MarshalText() ([]byte, error) { - return []byte(aot.String()), nil -} - type ACLEntry struct { ResourceType ResourceType ResourceName string From 53484d55bdcb4fc625aa790459d85fa5efccfe9c Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Mon, 30 Oct 2023 10:53:54 -0400 Subject: [PATCH 5/7] add patterntype and resourcetype --- resource.go | 41 +++++++++++++++++++++++++++++++++++++++++ resource_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 resource_test.go diff --git a/resource.go b/resource.go index dd2b0a43b..fb6293dd9 100644 --- a/resource.go +++ b/resource.go @@ -37,6 +37,10 @@ func (rt ResourceType) String() string { return s } +func (rt ResourceType) MarshalText() ([]byte, error) { + return []byte(rt.String()), nil +} + func (rt *ResourceType) UnmarshalText(text []byte) error { normalized := strings.ToLower(string(text)) mapping := map[string]ResourceType{ @@ -78,3 +82,40 @@ const ( // that start with 'foo'. PatternTypePrefixed PatternType = 4 ) + +func (pt PatternType) String() string { + mapping := map[PatternType]string{ + PatternTypeUnknown: "unknown", + PatternTypeAny: "any", + PatternTypeMatch: "match", + PatternTypeLiteral: "literal", + PatternTypePrefixed: "prefixed", + } + s, ok := mapping[pt] + if !ok { + s = mapping[PatternTypeUnknown] + } + return s +} + +func (pt PatternType) MarshalText() ([]byte, error) { + return []byte(pt.String()), nil +} + +func (pt *PatternType) UnmarshalText(text []byte) error { + normalized := strings.ToLower(string(text)) + mapping := map[string]PatternType{ + "unknown": PatternTypeUnknown, + "any": PatternTypeAny, + "match": PatternTypeMatch, + "literal": PatternTypeLiteral, + "prefixed": PatternTypePrefixed, + } + parsed, ok := mapping[normalized] + if !ok { + *pt = PatternTypeUnknown + return fmt.Errorf("cannot parse %s as a PatternType", normalized) + } + *pt = parsed + return nil +} diff --git a/resource_test.go b/resource_test.go new file mode 100644 index 000000000..8be454c2c --- /dev/null +++ b/resource_test.go @@ -0,0 +1,37 @@ +package kafka + +import "testing" + +func TestResourceTypeMarshal(t *testing.T) { + for i := ResourceTypeUnknown; i <= ResourceTypeDelegationToken; i++ { + text, err := i.MarshalText() + if err != nil { + t.Errorf("couldn't marshal %d to text: %s", i, err) + } + var got ResourceType + err = got.UnmarshalText(text) + if err != nil { + t.Errorf("couldn't unmarshal %s to ResourceType: %s", text, err) + } + if got != i { + t.Errorf("got %d, want %d", got, i) + } + } +} + +func TestPatternTypeMarshal(t *testing.T) { + for i := PatternTypeUnknown; i <= PatternTypePrefixed; i++ { + text, err := i.MarshalText() + if err != nil { + t.Errorf("couldn't marshal %d to text: %s", i, err) + } + var got PatternType + err = got.UnmarshalText(text) + if err != nil { + t.Errorf("couldn't unmarshal %s to PatternType: %s", text, err) + } + if got != i { + t.Errorf("got %d, want %d", got, i) + } + } +} From fe3531c569083c9bf1ee2cbd08ca0a2137788248 Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Mon, 30 Oct 2023 10:59:25 -0400 Subject: [PATCH 6/7] make capitalization consistent --- resource.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/resource.go b/resource.go index fb6293dd9..6d09da462 100644 --- a/resource.go +++ b/resource.go @@ -22,13 +22,13 @@ const ( func (rt ResourceType) String() string { mapping := map[ResourceType]string{ - ResourceTypeUnknown: "unknown", - ResourceTypeAny: "any", - ResourceTypeTopic: "topic", - ResourceTypeGroup: "group", - ResourceTypeCluster: "cluster", - ResourceTypeTransactionalID: "transactionalid", - ResourceTypeDelegationToken: "delegationtoken", + ResourceTypeUnknown: "Unknown", + ResourceTypeAny: "Any", + ResourceTypeTopic: "Topic", + ResourceTypeGroup: "Group", + ResourceTypeCluster: "Cluster", + ResourceTypeTransactionalID: "Transactionalid", + ResourceTypeDelegationToken: "Delegationtoken", } s, ok := mapping[rt] if !ok { @@ -85,11 +85,11 @@ const ( func (pt PatternType) String() string { mapping := map[PatternType]string{ - PatternTypeUnknown: "unknown", - PatternTypeAny: "any", - PatternTypeMatch: "match", - PatternTypeLiteral: "literal", - PatternTypePrefixed: "prefixed", + PatternTypeUnknown: "Unknown", + PatternTypeAny: "Any", + PatternTypeMatch: "Match", + PatternTypeLiteral: "Literal", + PatternTypePrefixed: "Prefixed", } s, ok := mapping[pt] if !ok { From 617146f85e1880bfb88099c75ad18198d52d016b Mon Sep 17 00:00:00 2001 From: Peter Dannemann Date: Mon, 30 Oct 2023 13:13:03 -0400 Subject: [PATCH 7/7] add comment and test around ResourceTypeBroker and ResourceTypeCluster having same value --- resource.go | 10 ++++++---- resource_test.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/resource.go b/resource.go index 6d09da462..b9be107c2 100644 --- a/resource.go +++ b/resource.go @@ -22,10 +22,12 @@ const ( func (rt ResourceType) String() string { mapping := map[ResourceType]string{ - ResourceTypeUnknown: "Unknown", - ResourceTypeAny: "Any", - ResourceTypeTopic: "Topic", - ResourceTypeGroup: "Group", + ResourceTypeUnknown: "Unknown", + ResourceTypeAny: "Any", + ResourceTypeTopic: "Topic", + ResourceTypeGroup: "Group", + // Note that ResourceTypeBroker and ResourceTypeCluster have the same value. + // A map cannot have duplicate values so we just use the same value for both. ResourceTypeCluster: "Cluster", ResourceTypeTransactionalID: "Transactionalid", ResourceTypeDelegationToken: "Delegationtoken", diff --git a/resource_test.go b/resource_test.go index 8be454c2c..b0175d2a3 100644 --- a/resource_test.go +++ b/resource_test.go @@ -19,6 +19,27 @@ func TestResourceTypeMarshal(t *testing.T) { } } +// Verify that the text version of ResourceTypeBroker is "Cluster". +// This is added since ResourceTypeBroker and ResourceTypeCluster +// have the same value. +func TestResourceTypeBroker(t *testing.T) { + text, err := ResourceTypeBroker.MarshalText() + if err != nil { + t.Errorf("couldn't marshal %d to text: %s", ResourceTypeBroker, err) + } + if string(text) != "Cluster" { + t.Errorf("got %s, want %s", string(text), "Cluster") + } + var got ResourceType + err = got.UnmarshalText(text) + if err != nil { + t.Errorf("couldn't unmarshal %s to ResourceType: %s", text, err) + } + if got != ResourceTypeBroker { + t.Errorf("got %d, want %d", got, ResourceTypeBroker) + } +} + func TestPatternTypeMarshal(t *testing.T) { for i := PatternTypeUnknown; i <= PatternTypePrefixed; i++ { text, err := i.MarshalText()