crowdsec/pkg/database/bouncers.go
2024-11-19 14:47:59 +01:00

173 lines
4.6 KiB
Go

package database
import (
"context"
"fmt"
"strings"
"time"
"github.com/pkg/errors"
"github.com/crowdsecurity/crowdsec/pkg/database/ent"
"github.com/crowdsecurity/crowdsec/pkg/database/ent/bouncer"
"github.com/crowdsecurity/crowdsec/pkg/models"
)
type BouncerNotFoundError struct {
BouncerName string
}
func (e *BouncerNotFoundError) Error() string {
return fmt.Sprintf("'%s' does not exist", e.BouncerName)
}
func (c *Client) BouncerUpdateBaseMetrics(ctx context.Context, bouncerName string, bouncerType string, baseMetrics models.BaseMetrics) error {
os := baseMetrics.Os
features := strings.Join(baseMetrics.FeatureFlags, ",")
_, err := c.Ent.Bouncer.
Update().
Where(bouncer.NameEQ(bouncerName)).
SetNillableVersion(baseMetrics.Version).
SetOsname(*os.Name).
SetOsversion(*os.Version).
SetFeatureflags(features).
SetType(bouncerType).
Save(ctx)
if err != nil {
return fmt.Errorf("unable to update base bouncer metrics in database: %w", err)
}
return nil
}
func (c *Client) SelectBouncers(ctx context.Context, apiKeyHash string, authType string) ([]*ent.Bouncer, error) {
//Order by ID so manually created bouncer will be first in the list to use as the base name
//when automatically creating a new entry if API keys are shared
result, err := c.Ent.Bouncer.Query().Where(bouncer.APIKeyEQ(apiKeyHash), bouncer.AuthTypeEQ(authType)).Order(ent.Asc(bouncer.FieldID)).All(ctx)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) SelectBouncerWithIP(ctx context.Context, apiKeyHash string, clientIP string) (*ent.Bouncer, error) {
result, err := c.Ent.Bouncer.Query().Where(bouncer.APIKeyEQ(apiKeyHash), bouncer.IPAddressEQ(clientIP)).First(ctx)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) SelectBouncerByName(ctx context.Context, bouncerName string) (*ent.Bouncer, error) {
result, err := c.Ent.Bouncer.Query().Where(bouncer.NameEQ(bouncerName)).First(ctx)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) ListBouncers(ctx context.Context) ([]*ent.Bouncer, error) {
result, err := c.Ent.Bouncer.Query().All(ctx)
if err != nil {
return nil, errors.Wrapf(QueryFail, "listing bouncers: %s", err)
}
return result, nil
}
func (c *Client) CreateBouncer(ctx context.Context, name string, ipAddr string, apiKey string, authType string, autoCreated bool) (*ent.Bouncer, error) {
bouncer, err := c.Ent.Bouncer.
Create().
SetName(name).
SetAPIKey(apiKey).
SetRevoked(false).
SetAuthType(authType).
SetIPAddress(ipAddr).
SetAutoCreated(autoCreated).
Save(ctx)
if err != nil {
if ent.IsConstraintError(err) {
return nil, fmt.Errorf("bouncer %s already exists", name)
}
return nil, fmt.Errorf("unable to create bouncer: %w", err)
}
return bouncer, nil
}
func (c *Client) DeleteBouncer(ctx context.Context, name string) error {
nbDeleted, err := c.Ent.Bouncer.
Delete().
Where(bouncer.NameEQ(name)).
Exec(ctx)
if err != nil {
return err
}
if nbDeleted == 0 {
return &BouncerNotFoundError{BouncerName: name}
}
return nil
}
func (c *Client) BulkDeleteBouncers(ctx context.Context, bouncers []*ent.Bouncer) (int, error) {
ids := make([]int, len(bouncers))
for i, b := range bouncers {
ids[i] = b.ID
}
nbDeleted, err := c.Ent.Bouncer.Delete().Where(bouncer.IDIn(ids...)).Exec(ctx)
if err != nil {
return nbDeleted, fmt.Errorf("unable to delete bouncers: %w", err)
}
return nbDeleted, nil
}
func (c *Client) UpdateBouncerLastPull(ctx context.Context, lastPull time.Time, id int) error {
_, err := c.Ent.Bouncer.UpdateOneID(id).
SetLastPull(lastPull).
Save(ctx)
if err != nil {
return fmt.Errorf("unable to update machine last pull in database: %w", err)
}
return nil
}
func (c *Client) UpdateBouncerIP(ctx context.Context, ipAddr string, id int) error {
_, err := c.Ent.Bouncer.UpdateOneID(id).SetIPAddress(ipAddr).Save(ctx)
if err != nil {
return fmt.Errorf("unable to update bouncer ip address in database: %w", err)
}
return nil
}
func (c *Client) UpdateBouncerTypeAndVersion(ctx context.Context, bType string, version string, id int) error {
_, err := c.Ent.Bouncer.UpdateOneID(id).SetVersion(version).SetType(bType).Save(ctx)
if err != nil {
return fmt.Errorf("unable to update bouncer type and version in database: %w", err)
}
return nil
}
func (c *Client) QueryBouncersInactiveSince(ctx context.Context, t time.Time) ([]*ent.Bouncer, error) {
return c.Ent.Bouncer.Query().Where(
// poor man's coalesce
bouncer.Or(
bouncer.LastPullLT(t),
bouncer.And(
bouncer.LastPullIsNil(),
bouncer.CreatedAtLT(t),
),
),
).All(ctx)
}