mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:57:33 +00:00
feat: add quotas (#4779)
adds possibilities to cap authenticated requests and execution seconds of actions on a defined intervall
This commit is contained in:
135
internal/logstore/emitters/execution/database.go
Normal file
135
internal/logstore/emitters/execution/database.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/logstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
)
|
||||
|
||||
const (
|
||||
executionLogsTable = "logstore.execution"
|
||||
executionTimestampCol = "log_date"
|
||||
executionTookCol = "took"
|
||||
executionMessageCol = "message"
|
||||
executionLogLevelCol = "loglevel"
|
||||
executionInstanceIdCol = "instance_id"
|
||||
executionActionIdCol = "action_id"
|
||||
executionMetadataCol = "metadata"
|
||||
)
|
||||
|
||||
var _ logstore.UsageQuerier = (*databaseLogStorage)(nil)
|
||||
var _ logstore.LogCleanupper = (*databaseLogStorage)(nil)
|
||||
|
||||
type databaseLogStorage struct {
|
||||
dbClient *sql.DB
|
||||
}
|
||||
|
||||
func NewDatabaseLogStorage(dbClient *sql.DB) *databaseLogStorage {
|
||||
return &databaseLogStorage{dbClient: dbClient}
|
||||
}
|
||||
|
||||
func (l *databaseLogStorage) QuotaUnit() quota.Unit {
|
||||
return quota.ActionsAllRunsSeconds
|
||||
}
|
||||
|
||||
func (l *databaseLogStorage) Emit(ctx context.Context, bulk []logstore.LogRecord) error {
|
||||
builder := squirrel.Insert(executionLogsTable).
|
||||
Columns(
|
||||
executionTimestampCol,
|
||||
executionTookCol,
|
||||
executionMessageCol,
|
||||
executionLogLevelCol,
|
||||
executionInstanceIdCol,
|
||||
executionActionIdCol,
|
||||
executionMetadataCol,
|
||||
).
|
||||
PlaceholderFormat(squirrel.Dollar)
|
||||
|
||||
for idx := range bulk {
|
||||
item := bulk[idx].(*Record)
|
||||
|
||||
var took interface{}
|
||||
if item.Took > 0 {
|
||||
took = item.Took
|
||||
}
|
||||
|
||||
builder = builder.Values(
|
||||
item.LogDate,
|
||||
took,
|
||||
item.Message,
|
||||
item.LogLevel,
|
||||
item.InstanceID,
|
||||
item.ActionID,
|
||||
item.Metadata,
|
||||
)
|
||||
}
|
||||
|
||||
stmt, args, err := builder.ToSql()
|
||||
if err != nil {
|
||||
return caos_errors.ThrowInternal(err, "EXEC-KOS7I", "Errors.Internal")
|
||||
}
|
||||
|
||||
result, err := l.dbClient.ExecContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return caos_errors.ThrowInternal(err, "EXEC-0j6i5", "Errors.Access.StorageFailed")
|
||||
}
|
||||
|
||||
rows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return caos_errors.ThrowInternal(err, "EXEC-MGchJ", "Errors.Internal")
|
||||
}
|
||||
|
||||
logging.WithFields("rows", rows).Debug("successfully stored execution logs")
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: AS OF SYSTEM TIME
|
||||
func (l *databaseLogStorage) QueryUsage(ctx context.Context, instanceId string, start time.Time) (uint64, error) {
|
||||
stmt, args, err := squirrel.Select(
|
||||
fmt.Sprintf("COALESCE(SUM(%s)::INT,0)", executionTookCol),
|
||||
).
|
||||
From(executionLogsTable).
|
||||
Where(squirrel.And{
|
||||
squirrel.Eq{executionInstanceIdCol: instanceId},
|
||||
squirrel.GtOrEq{executionTimestampCol: start},
|
||||
squirrel.NotEq{executionTookCol: nil},
|
||||
}).
|
||||
PlaceholderFormat(squirrel.Dollar).
|
||||
ToSql()
|
||||
|
||||
if err != nil {
|
||||
return 0, caos_errors.ThrowInternal(err, "EXEC-DXtzg", "Errors.Internal")
|
||||
}
|
||||
|
||||
var durationSeconds uint64
|
||||
if err = l.dbClient.
|
||||
QueryRowContext(ctx, stmt, args...).
|
||||
Scan(&durationSeconds); err != nil {
|
||||
return 0, caos_errors.ThrowInternal(err, "EXEC-Ad8nP", "Errors.Logstore.Execution.ScanFailed")
|
||||
}
|
||||
return durationSeconds, nil
|
||||
}
|
||||
|
||||
func (l *databaseLogStorage) Cleanup(ctx context.Context, keep time.Duration) error {
|
||||
stmt, args, err := squirrel.Delete(executionLogsTable).
|
||||
Where(squirrel.LtOrEq{executionTimestampCol: time.Now().Add(-keep)}).
|
||||
PlaceholderFormat(squirrel.Dollar).
|
||||
ToSql()
|
||||
|
||||
if err != nil {
|
||||
return caos_errors.ThrowInternal(err, "EXEC-Bja8V", "Errors.Internal")
|
||||
}
|
||||
|
||||
execCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
_, err = l.dbClient.ExecContext(execCtx, stmt, args...)
|
||||
return err
|
||||
}
|
Reference in New Issue
Block a user