Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ACL LOG #2536

Merged
merged 25 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3366245
feat: Add ACL LOG
SoulPancake Apr 4, 2023
11c363b
feat: test for reset
SoulPancake Apr 4, 2023
7297686
fix: attempt test
SoulPancake Apr 4, 2023
0faf622
fix: test fix
SoulPancake Apr 4, 2023
aa5283a
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 5, 2023
a383f55
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 6, 2023
760e05a
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 12, 2023
7fc9f21
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 18, 2023
0106d06
Merge branch 'master' into support-for-ACLLOG
ktsivkov Apr 20, 2023
eb0aecf
Fixed acl command, arg spreading
ktsivkov Apr 21, 2023
5e209dc
Merge pull request #1 from ktsivkov/acl-log-fix
SoulPancake Apr 21, 2023
1b76504
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 24, 2023
3a22a12
feat: migrating to client info struct
SoulPancake Apr 24, 2023
7a709a9
fix: using ptr for ClientInfo
SoulPancake Apr 24, 2023
c7100b6
fix: suppress lint check for the line
SoulPancake Apr 24, 2023
93dcc3b
fix: suppress both linter warnings:
SoulPancake Apr 24, 2023
e668ea9
fix: re-running pipelines
SoulPancake Apr 24, 2023
3d4004d
fix: acc to comments
SoulPancake Apr 25, 2023
965eeae
Merge branch 'master' into support-for-ACLLOG
SoulPancake Apr 25, 2023
0a4841a
Merge branch 'master' into support-for-ACLLOG
SoulPancake May 2, 2023
64001d7
fix: read resp response len
SoulPancake May 6, 2023
7876ac5
fix: adding mandatory count
SoulPancake May 6, 2023
dba1eaf
fix: adding mandatory count
SoulPancake May 6, 2023
b1be11b
Expanding test and fixing reading of response for AclLog
elena-kolevska May 7, 2023
0a0a107
correct acl-log count param
monkey92t May 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5057,3 +5057,112 @@ func parseClientInfo(txt string) (info *ClientInfo, err error) {

return info, nil
}

// -------------------------------------------

type ACLLogEntry struct {
Count int64
Reason string
Context string
Object string
Username string
AgeSeconds float64
ClientInfo *ClientInfo
EntryID int64
TimestampCreated int64
TimestampLastUpdated int64
}

type ACLLogCmd struct {
baseCmd

val []*ACLLogEntry
}

var _ Cmder = (*ACLLogCmd)(nil)

func NewACLLogCmd(ctx context.Context, args ...interface{}) *ACLLogCmd {
return &ACLLogCmd{
baseCmd: baseCmd{
ctx: ctx,
args: args,
},
}
}

func (cmd *ACLLogCmd) SetVal(val []*ACLLogEntry) {
cmd.val = val
}

func (cmd *ACLLogCmd) Val() []*ACLLogEntry {
return cmd.val
}

func (cmd *ACLLogCmd) Result() ([]*ACLLogEntry, error) {
return cmd.Val(), cmd.Err()
}

func (cmd *ACLLogCmd) String() string {
return cmdString(cmd, cmd.val)
}

func (cmd *ACLLogCmd) readReply(rd *proto.Reader) error {
n, err := rd.ReadArrayLen()
if err != nil {
return err
}

cmd.val = make([]*ACLLogEntry, n)
for i := 0; i < n; i++ {
cmd.val[i] = &ACLLogEntry{}
entry := cmd.val[i]
respLen, err := rd.ReadMapLen()
if err != nil {
return err
}
for j := 0; j < respLen; j++ {
key, err := rd.ReadString()
if err != nil {
return err
}

switch key {
case "count":
entry.Count, err = rd.ReadInt()
case "reason":
entry.Reason, err = rd.ReadString()
case "context":
entry.Context, err = rd.ReadString()
case "object":
entry.Object, err = rd.ReadString()
case "username":
entry.Username, err = rd.ReadString()
case "age-seconds":
entry.AgeSeconds, err = rd.ReadFloat()
case "client-info":
txt, err := rd.ReadString()
if err != nil {
return err
}
entry.ClientInfo, err = parseClientInfo(strings.TrimSpace(txt))
if err != nil {
return err
}
case "entry-id":
entry.EntryID, err = rd.ReadInt()
case "timestamp-created":
entry.TimestampCreated, err = rd.ReadInt()
case "timestamp-last-updated":
entry.TimestampLastUpdated, err = rd.ReadInt()
default:
return fmt.Errorf("redis: unexpected key %q in ACL LOG reply", key)
}

if err != nil {
return err
}
}
}

return nil
}
19 changes: 19 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ type Cmdable interface {
GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd

ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd
ACLLog(ctx context.Context, count int64) *ACLLogCmd
ACLLogReset(ctx context.Context) *StatusCmd

ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd
}
Expand Down Expand Up @@ -3946,3 +3948,20 @@ func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *St
_ = c(ctx, cmd)
return cmd
}

func (c cmdable) ACLLog(ctx context.Context, count int64) *ACLLogCmd {
args := make([]interface{}, 0, 3)
args = append(args, "acl", "log")
if count > 0 {
args = append(args, count)
}
cmd := NewACLLogCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}

func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd {
cmd := NewStatusCmd(ctx, "acl", "log", "reset")
_ = c(ctx, cmd)
return cmd
}
49 changes: 49 additions & 0 deletions commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1985,6 +1985,55 @@ var _ = Describe("Commands", func() {

Expect(args).To(Equal(expectedArgs))
})

It("should ACL LOG", func() {

err := client.Do(ctx, "acl", "setuser", "test", ">test", "on", "allkeys", "+get").Err()
Expect(err).NotTo(HaveOccurred())

clientAcl := redis.NewClient(redisOptions())
clientAcl.Options().Username = "test"
clientAcl.Options().Password = "test"
clientAcl.Options().DB = 0
_ = clientAcl.Set(ctx, "mystring", "foo", 0).Err()
_ = clientAcl.HSet(ctx, "myhash", "foo", "bar").Err()
_ = clientAcl.SAdd(ctx, "myset", "foo", "bar").Err()

logEntries, err := client.ACLLog(ctx, 10).Result()
Expect(err).NotTo(HaveOccurred())
Expect(len(logEntries)).To(Equal(3))

for _, entry := range logEntries {
Expect(entry.Count).To(BeNumerically("==", 1))
Expect(entry.Reason).To(Equal("command"))
Expect(entry.Context).To(Equal("toplevel"))
Expect(entry.Object).NotTo(BeEmpty())
Expect(entry.Username).To(Equal("test"))
Expect(entry.AgeSeconds).To(BeNumerically(">=", 0))
Expect(entry.ClientInfo).NotTo(BeNil())
Expect(entry.EntryID).To(BeNumerically(">=", 0))
Expect(entry.TimestampCreated).To(BeNumerically(">=", 0))
Expect(entry.TimestampLastUpdated).To(BeNumerically(">=", 0))
}

limitedLogEntries, err := client.ACLLog(ctx, 2).Result()
Expect(err).NotTo(HaveOccurred())
Expect(len(limitedLogEntries)).To(Equal(2))

})

It("should ACL LOG RESET", func() {
// Call ACL LOG RESET
resetCmd := client.ACLLogReset(ctx)
Expect(resetCmd.Err()).NotTo(HaveOccurred())
Expect(resetCmd.Val()).To(Equal("OK"))

// Verify that the log is empty after the reset
logEntries, err := client.ACLLog(ctx, 10).Result()
Expect(err).NotTo(HaveOccurred())
Expect(len(logEntries)).To(Equal(0))
})

})

Describe("hashes", func() {
Expand Down