Skip to content

Commit 0e467dc

Browse files
rkpattnaik780wtrocki
authored andcommitted
feat(kafka acl): add base and list command (#1173)
1 parent f909943 commit 0e467dc

File tree

7 files changed

+376
-0
lines changed

7 files changed

+376
-0
lines changed

docs/commands/rhoas_kafka.adoc

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/commands/rhoas_kafka_acl.adoc

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/commands/rhoas_kafka_acl_list.adoc

Lines changed: 52 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cmd/kafka/acl/acl.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package acl
2+
3+
import (
4+
"github.com/redhat-developer/app-services-cli/pkg/cmd/factory"
5+
"github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl/list"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// NewAclCommand creates a new command sub-group for Kafka ACL operations
10+
func NewAclCommand(f *factory.Factory) *cobra.Command {
11+
cmd := &cobra.Command{
12+
Use: "acl",
13+
Short: f.Localizer.MustLocalize("kafka.acl.cmd.shortDescription"),
14+
Long: f.Localizer.MustLocalize("kafka.acl.cmd.longDescription"),
15+
Example: f.Localizer.MustLocalize("kafka.acl.cmd.example"),
16+
Args: cobra.ExactArgs(1),
17+
}
18+
19+
cmd.AddCommand(
20+
list.NewListACLCommand(f),
21+
)
22+
23+
return cmd
24+
}

pkg/cmd/kafka/acl/list/list.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package list
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
9+
"github.com/redhat-developer/app-services-cli/internal/build"
10+
"github.com/redhat-developer/app-services-cli/internal/config"
11+
"github.com/redhat-developer/app-services-cli/pkg/cmd/factory"
12+
"github.com/redhat-developer/app-services-cli/pkg/cmdutil"
13+
"github.com/redhat-developer/app-services-cli/pkg/connection"
14+
"github.com/redhat-developer/app-services-cli/pkg/dump"
15+
"github.com/redhat-developer/app-services-cli/pkg/iostreams"
16+
"github.com/redhat-developer/app-services-cli/pkg/localize"
17+
"github.com/redhat-developer/app-services-cli/pkg/logging"
18+
"github.com/spf13/cobra"
19+
20+
kafkainstanceclient "github.com/redhat-developer/app-services-sdk-go/kafkainstance/apiv1internal/client"
21+
)
22+
23+
type options struct {
24+
Config config.IConfig
25+
Connection factory.ConnectionFunc
26+
Logger logging.Logger
27+
IO *iostreams.IOStreams
28+
localizer localize.Localizer
29+
Context context.Context
30+
31+
page int32
32+
size int32
33+
kafkaID string
34+
output string
35+
}
36+
37+
type permissionsRow struct {
38+
Principal string `json:"principal,omitempty" header:"Principal"`
39+
Permission string `json:"permission,omitempty" header:"permission"`
40+
Description string `json:"description,omitempty" header:"description"`
41+
}
42+
43+
// NewListACLCommand creates a new command to list Kafka ACL rules
44+
func NewListACLCommand(f *factory.Factory) *cobra.Command {
45+
46+
opts := &options{
47+
Config: f.Config,
48+
Connection: f.Connection,
49+
Logger: f.Logger,
50+
IO: f.IOStreams,
51+
localizer: f.Localizer,
52+
Context: f.Context,
53+
}
54+
55+
cmd := &cobra.Command{
56+
Use: "list",
57+
Short: f.Localizer.MustLocalize("kafka.acl.list.cmd.shortDescription"),
58+
Long: f.Localizer.MustLocalize("kafka.acl.list.cmd.longDescription"),
59+
Example: f.Localizer.MustLocalize("kafka.acl.list.cmd.example"),
60+
Args: cobra.NoArgs,
61+
RunE: func(cmd *cobra.Command, _ []string) error {
62+
63+
cfg, err := opts.Config.Load()
64+
if err != nil {
65+
return err
66+
}
67+
68+
if !cfg.HasKafka() {
69+
return opts.localizer.MustLocalizeError("kafka.acl.common.error.noKafkaSelected")
70+
}
71+
72+
opts.kafkaID = cfg.Services.Kafka.ClusterID
73+
74+
return runList(opts)
75+
},
76+
}
77+
78+
cmd.Flags().Int32VarP(&opts.page, "page", "", cmdutil.ConvertPageValueToInt32(build.DefaultPageNumber), opts.localizer.MustLocalize("kafka.acl.list.flag.page.description"))
79+
cmd.Flags().Int32VarP(&opts.size, "size", "", cmdutil.ConvertSizeValueToInt32(build.DefaultPageSize), opts.localizer.MustLocalize("kafka.acl.list.flag.size.description"))
80+
cmd.Flags().StringVarP(&opts.output, "output", "o", "", opts.localizer.MustLocalize("kafka.acl.list.flag.output.description"))
81+
82+
return cmd
83+
}
84+
85+
func runList(opts *options) (err error) {
86+
conn, err := opts.Connection(connection.DefaultConfigRequireMasAuth)
87+
if err != nil {
88+
return err
89+
}
90+
91+
api, kafkaInstance, err := conn.API().KafkaAdmin(opts.kafkaID)
92+
if err != nil {
93+
return err
94+
}
95+
96+
req := api.AclsApi.GetAcls(opts.Context)
97+
98+
req = req.Page(float32(opts.page))
99+
100+
req = req.Size(float32(opts.size))
101+
102+
permissionsData, httpRes, err := req.Execute()
103+
if httpRes != nil {
104+
defer httpRes.Body.Close()
105+
}
106+
107+
if err != nil {
108+
if httpRes == nil {
109+
return err
110+
}
111+
112+
operationTmplPair := localize.NewEntry("Operation", "list")
113+
114+
switch httpRes.StatusCode {
115+
case http.StatusUnauthorized:
116+
return opts.localizer.MustLocalizeError("kafka.acl.common.error.unauthorized", operationTmplPair)
117+
case http.StatusForbidden:
118+
return opts.localizer.MustLocalizeError("kafka.acl.common.error.forbidden", operationTmplPair)
119+
case http.StatusInternalServerError:
120+
return opts.localizer.MustLocalizeError("kafka.acl.common.error.internalServerError")
121+
case http.StatusServiceUnavailable:
122+
return opts.localizer.MustLocalizeError("kafka.acl.common.error.unableToConnectToKafka", localize.NewEntry("Name", kafkaInstance.GetName()))
123+
default:
124+
return err
125+
}
126+
}
127+
128+
switch opts.output {
129+
case dump.EmptyFormat:
130+
opts.Logger.Info("")
131+
permissions := permissionsData.GetItems()
132+
rows := mapPermissionListResultsToTableFormat(permissions, opts.localizer)
133+
dump.Table(opts.IO.Out, rows)
134+
default:
135+
return dump.Formatted(opts.IO.Out, opts.output, permissionsData)
136+
}
137+
138+
return nil
139+
}
140+
141+
func mapPermissionListResultsToTableFormat(permissions []kafkainstanceclient.AclBinding, localizer localize.Localizer) []permissionsRow {
142+
143+
rows := make([]permissionsRow, len(permissions))
144+
145+
for i, p := range permissions {
146+
147+
description := buildDescription(p.PatternType, localizer)
148+
row := permissionsRow{
149+
Principal: formatPrincipal(p.GetPrincipal(), localizer),
150+
Permission: fmt.Sprintf("%s | %s", p.GetPermission(), p.GetOperation()),
151+
Description: fmt.Sprintf("%s %s \"%s\"", p.GetResourceType(), description, p.GetResourceName()),
152+
}
153+
rows[i] = row
154+
}
155+
return rows
156+
}
157+
158+
func formatPrincipal(principal string, localizer localize.Localizer) string {
159+
s := strings.Split(principal, ":")[1]
160+
161+
if s == "*" {
162+
return localizer.MustLocalize("kafka.acl.list.allAccounts")
163+
}
164+
165+
return s
166+
}
167+
168+
func buildDescription(patternType kafkainstanceclient.AclPatternType, localizer localize.Localizer) string {
169+
if patternType == kafkainstanceclient.ACLPATTERNTYPE_LITERAL {
170+
return localizer.MustLocalize("kafka.acl.list.is")
171+
}
172+
173+
return localizer.MustLocalize("kafka.acl.list.startsWith")
174+
}

pkg/cmd/kafka/kafka.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/spf13/cobra"
99

1010
"github.com/redhat-developer/app-services-cli/pkg/cmd/factory"
11+
"github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/acl"
1112
"github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/create"
1213
"github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/delete"
1314
"github.com/redhat-developer/app-services-cli/pkg/cmd/kafka/describe"
@@ -35,6 +36,7 @@ func NewKafkaCommand(f *factory.Factory) *cobra.Command {
3536
topic.NewTopicCommand(f),
3637
consumergroup.NewConsumerGroupCommand(f),
3738
update.NewUpdateCommand(f),
39+
acl.NewAclCommand(f),
3840
)
3941

4042
return cmd

0 commit comments

Comments
 (0)