From 892e3dac831fb50eb41c15b3122f08faac3360be Mon Sep 17 00:00:00 2001 From: Daniel Baptista Dias Date: Thu, 29 Jun 2023 18:46:17 -0300 Subject: [PATCH] Standardize old resources to to use list method with SQL Injection protection and stardardize PollingProfile file (#2839) * wip: update list on demo and environment to use the same standards as tests and transactions * Fixing provisioning test * Update provisioning test --- server/Makefile | 2 +- server/config/demo/demo_repository.go | 37 ++++--- server/environment/environment_repository.go | 22 ++-- .../polling_profile_entities.go | 100 ++++++++++++++++++ ...ource.go => polling_profile_repository.go} | 93 ---------------- ....go => polling_profile_repository_test.go} | 0 6 files changed, 134 insertions(+), 120 deletions(-) create mode 100644 server/executor/pollingprofile/polling_profile_entities.go rename server/executor/pollingprofile/{polling_profile_resource.go => polling_profile_repository.go} (58%) rename server/executor/pollingprofile/{polling_profile_resource_test.go => polling_profile_repository_test.go} (100%) diff --git a/server/Makefile b/server/Makefile index 6256cfc242..64d112630a 100644 --- a/server/Makefile +++ b/server/Makefile @@ -18,7 +18,7 @@ init-submodule: git submodule init git submodule update -test: # run go tests for this application +test: ## run go tests for this application go test -timeout 150s -coverprofile=coverage.out ./... vet: ## run vet tool to analyze the code for suspicious, abnormal, or useless code diff --git a/server/config/demo/demo_repository.go b/server/config/demo/demo_repository.go index c1cdbb36b6..c165a03f67 100644 --- a/server/config/demo/demo_repository.go +++ b/server/config/demo/demo_repository.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/kubeshop/tracetest/server/pkg/id" + "github.com/kubeshop/tracetest/server/pkg/sqlutil" "github.com/kubeshop/tracetest/server/resourcemanager" ) @@ -182,30 +183,34 @@ func (r Repository) SortingFields() []string { return []string{"id", "name", "type"} } -func (r *Repository) List(ctx context.Context, take, skip int, query, sortBy, sortDirection string) ([]Demo, error) { - listQuery := baseSelect +func listQuery(baseSQL, query string, params []any) (string, []any) { + paramNumber := len(params) + 1 + condition := fmt.Sprintf(" AND (t.name ilike $%d)", paramNumber) - if sortDirection == "" { - sortDirection = "ASC" - } + sql, params := sqlutil.Search(baseSQL, condition, query, params) - if query != "" { - listQuery = fmt.Sprintf("%s WHERE %s", listQuery, query) - } + return sql, params +} - if sortBy != "" { - listQuery = fmt.Sprintf("%s ORDER BY %s %s", listQuery, sortBy, sortDirection) - } +func (r *Repository) List(ctx context.Context, take, skip int, query, sortBy, sortDirection string) ([]Demo, error) { + q, params := listQuery(baseSelect, query, []any{take, skip}) - if take > 0 { - listQuery = fmt.Sprintf("%s LIMIT %d", listQuery, take) + sortingFields := map[string]string{ + "id": "id", + "name": "name", + "type": "type", } - if skip > 0 { - listQuery = fmt.Sprintf("%s OFFSET %d", listQuery, skip) + q = sqlutil.Sort(q, sortBy, sortDirection, "name", sortingFields) + q += " LIMIT $1 OFFSET $2" + + stmt, err := r.db.Prepare(q) + if err != nil { + return nil, err } + defer stmt.Close() - rows, err := r.db.QueryContext(ctx, listQuery) + rows, err := stmt.QueryContext(ctx, params...) if err != nil { return nil, fmt.Errorf("sql query: %w", err) } diff --git a/server/environment/environment_repository.go b/server/environment/environment_repository.go index f824db5e81..303c274fc7 100644 --- a/server/environment/environment_repository.go +++ b/server/environment/environment_repository.go @@ -9,6 +9,7 @@ import ( "time" "github.com/kubeshop/tracetest/server/pkg/id" + "github.com/kubeshop/tracetest/server/pkg/sqlutil" ) type Repository struct { @@ -119,27 +120,28 @@ func (r *Repository) Delete(ctx context.Context, id id.ID) error { return nil } +func listQuery(baseSQL, query string, params []any) (string, []any) { + paramNumber := len(params) + 1 + condition := fmt.Sprintf(" AND (t.name ilike $%d OR e.description ilike $%d)", paramNumber, paramNumber) + + sql, params := sqlutil.Search(baseSQL, condition, query, params) + + return sql, params +} + func (r *Repository) List(ctx context.Context, take, skip int, query, sortBy, sortDirection string) ([]Environment, error) { if take == 0 { take = 20 } - params := []any{take, skip} - - sql := getQuery - - const condition = "WHERE (e.name ilike $3 OR e.description ilike $3) " - if query != "" { - sql += condition - params = append(params, query) - } + sql, params := listQuery(getQuery, query, []any{take, skip}) sortingFields := map[string]string{ "created": "e.created_at", "name": "e.name", } - sql = sortQuery(sql, sortBy, sortDirection, sortingFields) + sql = sqlutil.Sort(sql, sortBy, sortDirection, "created", sortingFields) sql += ` LIMIT $1 OFFSET $2 ` stmt, err := r.db.Prepare(sql) diff --git a/server/executor/pollingprofile/polling_profile_entities.go b/server/executor/pollingprofile/polling_profile_entities.go new file mode 100644 index 0000000000..9fab223bc6 --- /dev/null +++ b/server/executor/pollingprofile/polling_profile_entities.go @@ -0,0 +1,100 @@ +package pollingprofile + +import ( + "fmt" + "math" + "time" + + "github.com/kubeshop/tracetest/server/pkg/id" + "github.com/kubeshop/tracetest/server/resourcemanager" +) + +type Strategy string + +const ( + Periodic Strategy = "periodic" +) + +const ( + ResourceName = "PollingProfile" + ResourceNamePlural = "PollingProfiles" +) + +var Operations = []resourcemanager.Operation{ + resourcemanager.OperationGet, + resourcemanager.OperationList, + resourcemanager.OperationUpdate, +} + +var DefaultPollingProfile = PollingProfile{ + ID: id.ID("current"), + Name: "default", + Default: true, + Strategy: Periodic, + Periodic: &PeriodicPollingConfig{ + Timeout: "1m", + RetryDelay: "5s", + }, +} + +type PollingProfile struct { + ID id.ID `json:"id"` + Name string `json:"name"` + Default bool `json:"default"` + Strategy Strategy `json:"strategy"` + Periodic *PeriodicPollingConfig `json:"periodic"` +} + +type PeriodicPollingConfig struct { + RetryDelay string `json:"retryDelay"` + Timeout string `json:"timeout"` + SelectorMatchRetries int `json:"selectorMatchRetries"` +} + +func (ppc *PeriodicPollingConfig) TimeoutDuration() time.Duration { + d, _ := time.ParseDuration(ppc.Timeout) + return d +} + +func (ppc *PeriodicPollingConfig) RetryDelayDuration() time.Duration { + d, _ := time.ParseDuration(ppc.RetryDelay) + return d +} + +func (ppc *PeriodicPollingConfig) MaxTracePollRetry() int { + return int(math.Ceil(float64(ppc.TimeoutDuration()) / float64(ppc.RetryDelayDuration()))) +} + +func (ppc *PeriodicPollingConfig) Validate() error { + if ppc == nil { + return fmt.Errorf("missing periodic polling profile configuration") + } + + if _, err := time.ParseDuration(ppc.RetryDelay); err != nil { + return fmt.Errorf("retry delay configuration is invalid: %w", err) + } + + if _, err := time.ParseDuration(ppc.Timeout); err != nil { + return fmt.Errorf("timeout configuration is invalid: %w", err) + } + + return nil +} + +func (pp PollingProfile) HasID() bool { + return pp.ID.String() != "" +} + +func (pp PollingProfile) GetID() id.ID { + return pp.ID +} + +func (pp PollingProfile) Validate() error { + if pp.Strategy == Periodic { + if err := pp.Periodic.Validate(); err != nil { + return err + } + } + + return nil +} diff --git a/server/executor/pollingprofile/polling_profile_resource.go b/server/executor/pollingprofile/polling_profile_repository.go similarity index 58% rename from server/executor/pollingprofile/polling_profile_resource.go rename to server/executor/pollingprofile/polling_profile_repository.go index 17f1fcd65f..0b82b61318 100644 --- a/server/executor/pollingprofile/polling_profile_resource.go +++ b/server/executor/pollingprofile/polling_profile_repository.go @@ -6,103 +6,10 @@ import ( "encoding/json" "errors" "fmt" - "math" - "time" "github.com/kubeshop/tracetest/server/pkg/id" - "github.com/kubeshop/tracetest/server/resourcemanager" ) -type Strategy string - -const ( - Periodic Strategy = "periodic" -) - -const ( - ResourceName = "PollingProfile" - ResourceNamePlural = "PollingProfiles" -) - -var Operations = []resourcemanager.Operation{ - resourcemanager.OperationGet, - resourcemanager.OperationList, - resourcemanager.OperationUpdate, -} - -var DefaultPollingProfile = PollingProfile{ - ID: id.ID("current"), - Name: "default", - Default: true, - Strategy: Periodic, - Periodic: &PeriodicPollingConfig{ - Timeout: "1m", - RetryDelay: "5s", - }, -} - -type PollingProfile struct { - ID id.ID `json:"id"` - Name string `json:"name"` - Default bool `json:"default"` - Strategy Strategy `json:"strategy"` - Periodic *PeriodicPollingConfig `json:"periodic"` -} - -type PeriodicPollingConfig struct { - RetryDelay string `json:"retryDelay"` - Timeout string `json:"timeout"` - SelectorMatchRetries int `json:"selectorMatchRetries"` -} - -func (ppc *PeriodicPollingConfig) TimeoutDuration() time.Duration { - d, _ := time.ParseDuration(ppc.Timeout) - return d -} - -func (ppc *PeriodicPollingConfig) RetryDelayDuration() time.Duration { - d, _ := time.ParseDuration(ppc.RetryDelay) - return d -} - -func (ppc *PeriodicPollingConfig) MaxTracePollRetry() int { - return int(math.Ceil(float64(ppc.TimeoutDuration()) / float64(ppc.RetryDelayDuration()))) -} - -func (ppc *PeriodicPollingConfig) Validate() error { - if ppc == nil { - return fmt.Errorf("missing periodic polling profile configuration") - } - - if _, err := time.ParseDuration(ppc.RetryDelay); err != nil { - return fmt.Errorf("retry delay configuration is invalid: %w", err) - } - - if _, err := time.ParseDuration(ppc.Timeout); err != nil { - return fmt.Errorf("timeout configuration is invalid: %w", err) - } - - return nil -} - -func (pp PollingProfile) HasID() bool { - return pp.ID.String() != "" -} - -func (pp PollingProfile) GetID() id.ID { - return pp.ID -} - -func (pp PollingProfile) Validate() error { - if pp.Strategy == Periodic { - if err := pp.Periodic.Validate(); err != nil { - return err - } - } - - return nil -} - func NewRepository(db *sql.DB) *Repository { return &Repository{db} } diff --git a/server/executor/pollingprofile/polling_profile_resource_test.go b/server/executor/pollingprofile/polling_profile_repository_test.go similarity index 100% rename from server/executor/pollingprofile/polling_profile_resource_test.go rename to server/executor/pollingprofile/polling_profile_repository_test.go