Skip to content

Commit

Permalink
chore: add validation for port ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustavo Franco committed Jun 26, 2024
1 parent 79587b6 commit 0f55fc1
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 5 deletions.
6 changes: 2 additions & 4 deletions internal/api/handlers/schedulers_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import (

"github.com/topfreegames/maestro/internal/core/ports"

"github.com/go-playground/validator/v10"

"github.com/topfreegames/maestro/internal/api/handlers/requestadapters"
"github.com/topfreegames/maestro/internal/core/logs"
"go.uber.org/zap"
Expand Down Expand Up @@ -138,7 +136,7 @@ func (h *SchedulersHandler) CreateScheduler(ctx context.Context, request *api.Cr
handlerLogger.Info("handling create scheduler request")
scheduler, err := requestadapters.FromApiCreateSchedulerRequestToEntity(request)
if err != nil {
apiValidationError := parseValidationError(err.(validator.ValidationErrors))
apiValidationError := parseValidationError(err)
handlerLogger.Error("error parsing scheduler", zap.Error(apiValidationError))
return nil, status.Error(codes.InvalidArgument, apiValidationError.Error())
}
Expand Down Expand Up @@ -166,7 +164,7 @@ func (h *SchedulersHandler) NewSchedulerVersion(ctx context.Context, request *ap
handlerLogger.Info("handling new scheduler version request")
scheduler, err := requestadapters.FromApiNewSchedulerVersionRequestToEntity(request)
if err != nil {
apiValidationError := parseValidationError(err.(validator.ValidationErrors))
apiValidationError := parseValidationError(err)
handlerLogger.Error("error parsing scheduler version", zap.Error(apiValidationError))
return nil, status.Error(codes.InvalidArgument, apiValidationError.Error())
}
Expand Down
55 changes: 54 additions & 1 deletion internal/core/entities/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package entities

import (
"errors"
"time"

"github.com/topfreegames/maestro/internal/core/entities/autoscaling"
Expand Down Expand Up @@ -50,6 +51,12 @@ const (
StateOnError = "on-error"
)

var (
ErrNoPortRangeConfigured = errors.New("must configure scheduler.PortRange or scheduler.Spec.Container.Ports.TargetPortRange")
ErrBothPortRangesConfigured = errors.New("cannot configure both scheduler.PortRange and scheduler.Spec.Container.Ports.TargetPortRange")
ErrMissingContainerPortRange = errors.New("must configure TargetPortRange for all scheduler.Spec.Container.Ports")
)

// Scheduler represents one of the basic maestro structs.
// It holds GameRooms specifications, as well as optional events forwarders.
type Scheduler struct {
Expand Down Expand Up @@ -108,7 +115,17 @@ func (s *Scheduler) SetSchedulerRollbackVersion(version string) {
}

func (s *Scheduler) Validate() error {
return validations.Validate.Struct(s)
err := validations.Validate.Struct(s)
if err != nil {
return err
}

err = s.HasValidPortRangeConfiguration()
if err != nil {
return err
}

return nil
}

// IsMajorVersion checks if the scheduler changes are major or not.
Expand Down Expand Up @@ -145,3 +162,39 @@ func (s *Scheduler) IsMajorVersion(newScheduler *Scheduler) bool {
),
)
}

// HasValidPortRangeConfiguration checks if the scheduler's port range configuration is valid.
// It is possible to configure PortRange in the scheduler, but also TargetPortRange in each Spec.Container.Ports,
// both port ranges were made optional in the API, so we need to validate them here.
// The scheduler.PortRange was kept to avoid a breaking change to schedulers in older versions.
func (s *Scheduler) HasValidPortRangeConfiguration() error {
hasSchedulerPortRange := false
if s.PortRange != nil {
hasSchedulerPortRange = true
}

hasContainerPortRange := false
for _, c := range s.Spec.Containers {
amountOfTargetPortRanges := 0
for _, p := range c.Ports {
if p.TargetPortRange != nil {
amountOfTargetPortRanges++
hasContainerPortRange = true
}
}

if !hasSchedulerPortRange && len(c.Ports) != amountOfTargetPortRanges {
return ErrMissingContainerPortRange
}
}

if hasSchedulerPortRange && hasContainerPortRange {
return ErrBothPortRangesConfigured
}

if !hasSchedulerPortRange && !hasContainerPortRange {
return ErrNoPortRangeConfigured
}

return nil
}
76 changes: 76 additions & 0 deletions internal/core/entities/scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,79 @@ func TestIsMajorVersion(t *testing.T) {
})
}
}

func TestHasValidPortRangeConfiguration(t *testing.T) {
tests := map[string]struct {
scheduler *entities.Scheduler
expected error
}{
"should succeed if only scheduler.portrange is configured": {
scheduler: &entities.Scheduler{PortRange: &port.PortRange{}},
expected: nil,
},
"should succeed if only scheduler.spec.container.ports.targetportrange is configured": {
scheduler: &entities.Scheduler{
Spec: game_room.Spec{
Containers: []game_room.Container{
{
Ports: []game_room.ContainerPort{
{
TargetPortRange: &port.PortRange{},
},
},
},
},
},
},
expected: nil,
},
"should fail if neither scheduler.portrange nor container.ports.targetportrange are configured": {
scheduler: &entities.Scheduler{},
expected: entities.ErrNoPortRangeConfigured,
},
"should fail if both scheduler.portrange and container.ports.targetportrange are configured": {
scheduler: &entities.Scheduler{
PortRange: &port.PortRange{},
Spec: game_room.Spec{
Containers: []game_room.Container{
{
Ports: []game_room.ContainerPort{
{
TargetPortRange: &port.PortRange{},
},
},
},
},
},
},
expected: entities.ErrBothPortRangesConfigured,
},
"should fail if not all container.ports have targetportrange configured": {
scheduler: &entities.Scheduler{
PortRange: &port.PortRange{},
Spec: game_room.Spec{
Containers: []game_room.Container{
{
Ports: []game_room.ContainerPort{
{
TargetPortRange: &port.PortRange{},
},
{
TargetPortRange: nil,
},
},
},
},
},
},
expected: entities.ErrBothPortRangesConfigured,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
err := test.scheduler.HasValidPortRangeConfiguration()
require.ErrorIs(t, test.expected, err)
})
}
}

0 comments on commit 0f55fc1

Please sign in to comment.