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

db: don't set bouncer last_pull until first connection #3020

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 7 additions & 2 deletions cmd/crowdsec-cli/bouncers.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@
valid = "pending"
}

if err := csvwriter.Write([]string{b.Name, b.IPAddress, valid, b.LastPull.Format(time.RFC3339), b.Type, b.Version, b.AuthType}); err != nil {
lastPull := ""
if b.LastPull != nil {
lastPull = b.LastPull.Format(time.RFC3339)
}

Check warning on line 122 in cmd/crowdsec-cli/bouncers.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/bouncers.go#L121-L122

Added lines #L121 - L122 were not covered by tests

if err := csvwriter.Write([]string{b.Name, b.IPAddress, valid, lastPull, b.Type, b.Version, b.AuthType}); err != nil {
return fmt.Errorf("failed to write raw: %w", err)
}
}
Expand Down Expand Up @@ -259,7 +264,7 @@
}
}

bouncers, err := cli.db.QueryBouncersLastPulltimeLT(time.Now().UTC().Add(-duration))
bouncers, err := cli.db.QueryBouncersInactiveSince(time.Now().UTC().Add(-duration))
if err != nil {
return fmt.Errorf("unable to query bouncers: %w", err)
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/crowdsec-cli/bouncers_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
revoked = emoji.Prohibited
}

t.AddRow(b.Name, b.IPAddress, revoked, b.LastPull.Format(time.RFC3339), b.Type, b.Version, b.AuthType)
lastPull := ""
if b.LastPull != nil {
lastPull = b.LastPull.Format(time.RFC3339)
}

Check warning on line 27 in cmd/crowdsec-cli/bouncers_table.go

View check run for this annotation

Codecov / codecov/patch

cmd/crowdsec-cli/bouncers_table.go#L26-L27

Added lines #L26 - L27 were not covered by tests

t.AddRow(b.Name, b.IPAddress, revoked, lastPull, b.Type, b.Version, b.AuthType)
}

t.Render()
Expand Down
11 changes: 8 additions & 3 deletions pkg/apiserver/controllers/v1/decisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
return
}

if time.Now().UTC().Sub(bouncerInfo.LastPull) >= time.Minute {
if bouncerInfo.LastPull == nil || time.Now().UTC().Sub(*bouncerInfo.LastPull) >= time.Minute {
if err := c.DBClient.UpdateBouncerLastPull(time.Now().UTC(), bouncerInfo.ID); err != nil {
log.Errorf("failed to update bouncer last pull: %v", err)
}
Expand Down Expand Up @@ -186,7 +186,7 @@
return nil
}

func writeDeltaDecisions(gctx *gin.Context, filters map[string][]string, lastPull time.Time, dbFunc func(time.Time, map[string][]string) ([]*ent.Decision, error)) error {
func writeDeltaDecisions(gctx *gin.Context, filters map[string][]string, lastPull *time.Time, dbFunc func(*time.Time, map[string][]string) ([]*ent.Decision, error)) error {

Check warning on line 189 in pkg/apiserver/controllers/v1/decisions.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/controllers/v1/decisions.go#L189

Added line #L189 was not covered by tests
//respBuffer := bytes.NewBuffer([]byte{})
limit := 30000 //FIXME : make it configurable
needComma := false
Expand Down Expand Up @@ -348,8 +348,13 @@
//data = KeepLongestDecision(data)
ret["new"] = FormatDecisions(data)

since := time.Time{}
if bouncerInfo.LastPull != nil {
since = bouncerInfo.LastPull.Add(-2 * time.Second)
}

Check warning on line 354 in pkg/apiserver/controllers/v1/decisions.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/controllers/v1/decisions.go#L354

Added line #L354 was not covered by tests

// getting expired decisions
data, err = c.DBClient.QueryExpiredDecisionsSinceWithFilters(bouncerInfo.LastPull.Add((-2 * time.Second)), filters) // do we want to give exactly lastPull time ?
data, err = c.DBClient.QueryExpiredDecisionsSinceWithFilters(&since, filters) // do we want to give exactly lastPull time ?
if err != nil {
log.Errorf("unable to query expired decision for '%s' : %v", bouncerInfo.Name, err)
gctx.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
Expand Down
13 changes: 11 additions & 2 deletions pkg/database/bouncers.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@
return nil
}

func (c *Client) QueryBouncersLastPulltimeLT(t time.Time) ([]*ent.Bouncer, error) {
return c.Ent.Bouncer.Query().Where(bouncer.LastPullLT(t)).All(c.CTX)
func (c *Client) QueryBouncersInactiveSince(t time.Time) ([]*ent.Bouncer, error) {
return c.Ent.Bouncer.Query().Where(
// poor man's coalesce

Check warning on line 120 in pkg/database/bouncers.go

View check run for this annotation

Codecov / codecov/patch

pkg/database/bouncers.go#L120

Added line #L120 was not covered by tests
bouncer.Or(
bouncer.LastPullLT(t),
bouncer.And(
bouncer.LastPullIsNil(),
bouncer.CreatedAtLT(t),
),
),
).All(c.CTX)
}
15 changes: 11 additions & 4 deletions pkg/database/decisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,15 @@
)
}

func (c *Client) QueryExpiredDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
func (c *Client) QueryExpiredDecisionsSinceWithFilters(since *time.Time, filters map[string][]string) ([]*ent.Decision, error) {
query := c.Ent.Decision.Query().Where(
decision.UntilLT(time.Now().UTC()),
decision.UntilGT(since),
)

Check warning on line 261 in pkg/database/decisions.go

View check run for this annotation

Codecov / codecov/patch

pkg/database/decisions.go#L261

Added line #L261 was not covered by tests
if since != nil {
query = query.Where(decision.UntilGT(*since))
}

Check warning on line 264 in pkg/database/decisions.go

View check run for this annotation

Codecov / codecov/patch

pkg/database/decisions.go#L264

Added line #L264 was not covered by tests

// Allow a bouncer to ask for non-deduplicated results
if v, ok := filters["dedup"]; !ok || v[0] != "false" {
query = query.Where(longestDecisionForScopeTypeValue)
Expand All @@ -281,12 +285,15 @@
return data, nil
}

func (c *Client) QueryNewDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
func (c *Client) QueryNewDecisionsSinceWithFilters(since *time.Time, filters map[string][]string) ([]*ent.Decision, error) {
query := c.Ent.Decision.Query().Where(
decision.CreatedAtGT(since),
decision.UntilGT(time.Now().UTC()),
)

if since != nil {
query = query.Where(decision.CreatedAtGT(*since))
}

Check warning on line 295 in pkg/database/decisions.go

View check run for this annotation

Codecov / codecov/patch

pkg/database/decisions.go#L295

Added line #L295 was not covered by tests

// Allow a bouncer to ask for non-deduplicated results
if v, ok := filters["dedup"]; !ok || v[0] != "false" {
query = query.Where(longestDecisionForScopeTypeValue)
Expand Down
11 changes: 7 additions & 4 deletions pkg/database/ent/bouncer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions pkg/database/ent/bouncer/bouncer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions pkg/database/ent/bouncer/where.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 1 addition & 8 deletions pkg/database/ent/bouncer_create.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions pkg/database/ent/bouncer_update.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/database/ent/migrate/schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 20 additions & 1 deletion pkg/database/ent/mutation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions pkg/database/ent/runtime.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions pkg/database/ent/schema/bouncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ func (Bouncer) Fields() []ent.Field {
field.String("ip_address").Default("").Optional().StructTag(`json:"ip_address"`),
field.String("type").Optional().StructTag(`json:"type"`),
field.String("version").Optional().StructTag(`json:"version"`),
field.Time("last_pull").
Default(types.UtcNow).StructTag(`json:"last_pull"`),
field.Time("last_pull").Nillable().Optional().StructTag(`json:"last_pull"`),
field.String("auth_type").StructTag(`json:"auth_type"`).Default(types.ApiKeyAuthType),
}
}
Expand Down
26 changes: 24 additions & 2 deletions test/bats/10_bouncers.bats
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,30 @@ teardown() {
assert_output --partial "API key for 'ciTestBouncer':"
rune -0 cscli bouncers delete ciTestBouncer
rune -0 cscli bouncers list -o json
assert_output '[]'
assert_json '[]'
}

@test "cscli bouncers list" {
export API_KEY=bouncerkey
rune -0 cscli bouncers add ciTestBouncer --key "$API_KEY"

rune -0 cscli bouncers list -o json
rune -0 jq -c '.[] | [.ip_address,.last_pull,.name]' <(output)
assert_json '["",null,"ciTestBouncer"]'
rune -0 cscli bouncers list -o raw
assert_line 'name,ip,revoked,last_pull,type,version,auth_type'
assert_line 'ciTestBouncer,,validated,,,,api-key'
rune -0 cscli bouncers list -o human
assert_output --regexp 'ciTestBouncer.*api-key.*'

# the first connection sets last_pull and ip address
rune -0 lapi-get '/v1/decisions'
rune -0 cscli bouncers list -o json
rune -0 jq -r '.[] | .ip_address' <(output)
assert_output 127.0.0.1
rune -0 cscli bouncers list -o json
rune -0 jq -r '.[] | .last_pull' <(output)
refute_output null
}

@test "we can create a bouncer with a known key" {
Expand Down Expand Up @@ -83,4 +106,3 @@ teardown() {
rune -0 cscli bouncers prune
assert_output 'No bouncers to prune.'
}

Loading