Skip to content

Commit

Permalink
feat: configurable port ranges for each container port (#624)
Browse files Browse the repository at this point in the history
* chore: remove import cycle

* feat: port range per container.port

* fix: tests

* chore: add tests

* chore: parse new port range fields from proto

* chore: add validation for port ranges

* fix: create scheduler test

* Update proto/api/v1/messages.proto

Co-authored-by: João Bologna <31311651+joaobologna@users.noreply.github.com>

* Update internal/core/entities/scheduler.go

Co-authored-by: João Bologna <31311651+joaobologna@users.noreply.github.com>

* fix: mr suggestions

* chore: add docs

* Update docs/reference/Scheduler.md

Co-authored-by: Reinaldo Oliveira <reinaldo.oliveira@wildlifestudios.com>

---------

Co-authored-by: Gustavo Franco <gustavo.franco@wildlifestudios.com>
Co-authored-by: João Bologna <31311651+joaobologna@users.noreply.github.com>
Co-authored-by: Reinaldo Oliveira <reinaldo.oliveira@wildlifestudios.com>
  • Loading branch information
4 people authored Jul 1, 2024
1 parent 0ad706f commit 5f7fd7d
Show file tree
Hide file tree
Showing 34 changed files with 871 additions and 634 deletions.
8 changes: 6 additions & 2 deletions docs/reference/Scheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ annotation: Map
the [Switch Active Version](Operations.md#switch-active-version) (Major change) operation will replace pods from 3 to
3;
- **portRange**: Range of ports that can be used by Maestro to create GRUs for the specified scheduler. Can be altered
by the user anytime. More info [here](#portrange);
by the user anytime. More info [here](#portrange); Mutually exclusive with the Spec.Containers.Ports.HostPortRange configuration.
- **forwarders**: Maestro can pass ahead info sent by the game rooms, such as Ping (Ready, Occupied, Terminating...),
player and rooms events. The receivers can be configured here. More info [here](#forwarders);
- **autoscaling**: Optional autoscaling policy configuration. More info [here](../tutorials/Autoscaling.md);
Expand All @@ -269,6 +269,8 @@ start: Integer
end: Integer
```
You **must** configure the port range either in `.PortRange` or in `.Spec.Containers.Ports.HostPortRange` - they are mutually exclusive configurations. If you want to configure a single port range for all container ports, use `.PortRange`, otherwise use `HostPortRange` in every Spec to configure the port range for each one - this is useful when avoiding port conflicts on different protocols in case the network doesn't support it, for example.

### Forwarders
Forwarders are configured to pass ahead info offered by the game rooms to Maestro.
More than one forwarder can be configured for a scheduler.
Expand Down Expand Up @@ -395,8 +397,10 @@ It is represented as:
- name: String
protocol: String
port: Integer
hostPortRange: PortRange
```

- **name**: Name of the port. Facilitates on recognition;
- **protocol**: Port protocol. Can be UDP, TCP or SCTP.;
- **port**: The port exposed.
- **port**: The port exposed.
- **hostPortRange**: The [port range](#portrange) for the port to be allocated in the host. Mutually exclusive with the port range configured in the root structure.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/topfreegames/maestro/internal/core/entities"
"github.com/topfreegames/maestro/internal/core/entities/forwarder"
"github.com/topfreegames/maestro/internal/core/entities/game_room"
"github.com/topfreegames/maestro/internal/core/entities/port"

"github.com/stretchr/testify/require"
"github.com/topfreegames/maestro/test"
Expand Down Expand Up @@ -174,7 +175,7 @@ func generateScheduler() *entities.Scheduler {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down
8 changes: 4 additions & 4 deletions internal/adapters/portallocator/random/random.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,24 @@ package random
import (
"math/rand"

"github.com/topfreegames/maestro/internal/core/entities"
"github.com/topfreegames/maestro/internal/core/entities/port"
"github.com/topfreegames/maestro/internal/core/ports"
"github.com/topfreegames/maestro/internal/core/ports/errors"
)

var _ ports.PortAllocator = (*RandomPortAllocator)(nil)

type RandomPortAllocator struct {
defaultPortRange *entities.PortRange
defaultPortRange *port.PortRange
}

func NewRandomPortAllocator(portRange *entities.PortRange) *RandomPortAllocator {
func NewRandomPortAllocator(portRange *port.PortRange) *RandomPortAllocator {
return &RandomPortAllocator{
defaultPortRange: portRange,
}
}

func (r *RandomPortAllocator) Allocate(portRange *entities.PortRange, quantity int) ([]int32, error) {
func (r *RandomPortAllocator) Allocate(portRange *port.PortRange, quantity int) ([]int32, error) {
currentRange := r.defaultPortRange
if portRange != nil {
currentRange = portRange
Expand Down
12 changes: 6 additions & 6 deletions internal/adapters/portallocator/random/random_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ import (
"testing"

"github.com/stretchr/testify/require"
"github.com/topfreegames/maestro/internal/core/entities"
"github.com/topfreegames/maestro/internal/core/entities/port"
)

func TestRandomPortAllocator(t *testing.T) {
cases := map[string]struct {
defaultPortRange *entities.PortRange
portRange *entities.PortRange
defaultPortRange *port.PortRange
portRange *port.PortRange
quantity int
expectedPorts []int32
withError bool
}{
"correct number of ports": {
portRange: &entities.PortRange{Start: 1000, End: 1004},
portRange: &port.PortRange{Start: 1000, End: 1004},
quantity: 5,
expectedPorts: []int32{1000, 1001, 1002, 1003, 1004},
},
"not enough ports": {
portRange: &entities.PortRange{Start: 1000, End: 1004},
portRange: &port.PortRange{Start: 1000, End: 1004},
quantity: 7,
withError: true,
},
"use default portRange": {
defaultPortRange: &entities.PortRange{Start: 2000, End: 2004},
defaultPortRange: &port.PortRange{Start: 2000, End: 2004},
quantity: 5,
expectedPorts: []int32{2000, 2001, 2002, 2003, 2004},
},
Expand Down
3 changes: 2 additions & 1 deletion internal/adapters/storage/postgres/scheduler/db_scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/topfreegames/maestro/internal/core/entities/autoscaling"

"github.com/topfreegames/maestro/internal/core/entities/forwarder"
"github.com/topfreegames/maestro/internal/core/entities/port"

"github.com/ghodss/yaml"

Expand Down Expand Up @@ -57,7 +58,7 @@ type schedulerInfo struct {
Toleration string
Affinity string
Containers []game_room.Container
PortRange *entities.PortRange
PortRange *port.PortRange
MaxSurge string
RoomsReplicas int
Forwarders []*forwarder.Forwarder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/topfreegames/maestro/internal/core/entities"
"github.com/topfreegames/maestro/internal/core/entities/game_room"
"github.com/topfreegames/maestro/internal/core/entities/port"
)

func TestScheduler_ToScheduler(t *testing.T) {
Expand Down Expand Up @@ -77,7 +78,7 @@ func TestScheduler_ToScheduler(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -171,7 +172,7 @@ func TestScheduler_ToScheduler(t *testing.T) {
Affinity: "affinity",
TerminationGracePeriod: 60,
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (

"github.com/topfreegames/maestro/internal/core/entities"
"github.com/topfreegames/maestro/internal/core/entities/game_room"
"github.com/topfreegames/maestro/internal/core/entities/port"
"github.com/topfreegames/maestro/internal/core/filters"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -71,7 +72,7 @@ var expectedScheduler = &entities.Scheduler{
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -131,7 +132,7 @@ func TestSchedulerStorage_GetSchedulers(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand All @@ -149,7 +150,7 @@ func TestSchedulerStorage_GetSchedulers(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -188,7 +189,7 @@ func TestSchedulerStorage_GetAllSchedulers(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand All @@ -206,7 +207,7 @@ func TestSchedulerStorage_GetAllSchedulers(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -237,7 +238,7 @@ func TestSchedulerStorage_GetSchedulersWithFilter(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand All @@ -255,7 +256,7 @@ func TestSchedulerStorage_GetSchedulersWithFilter(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -522,7 +523,7 @@ func TestSchedulerStorage_CreateSchedulerVersion(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down Expand Up @@ -623,7 +624,7 @@ func TestSchedulerStorage_RunWithTransaction(t *testing.T) {
Toleration: "toleration",
Affinity: "affinity",
},
PortRange: &entities.PortRange{
PortRange: &port.PortRange{
Start: 40000,
End: 60000,
},
Expand Down
41 changes: 26 additions & 15 deletions internal/api/handlers/requestadapters/schedulers.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/topfreegames/maestro/internal/core/services/schedulers/patch"

"github.com/topfreegames/maestro/internal/core/entities/autoscaling"
"github.com/topfreegames/maestro/internal/core/entities/port"

"google.golang.org/protobuf/types/known/durationpb"
_struct "google.golang.org/protobuf/types/known/structpb"
Expand All @@ -48,7 +49,7 @@ func FromApiPatchSchedulerRequestToChangeMap(request *api.PatchSchedulerRequest)
}

if request.PortRange != nil {
patchMap[patch.LabelSchedulerPortRange] = entities.NewPortRange(
patchMap[patch.LabelSchedulerPortRange] = port.NewPortRange(
request.GetPortRange().GetStart(),
request.GetPortRange().GetEnd(),
)
Expand Down Expand Up @@ -121,10 +122,7 @@ func FromApiCreateSchedulerRequestToEntity(request *api.CreateSchedulerRequest)
entities.StateCreating,
request.GetMaxSurge(),
*fromApiSpec(request.GetSpec()),
entities.NewPortRange(
request.GetPortRange().GetStart(),
request.GetPortRange().GetEnd(),
),
fromApiPortRange(request.PortRange),
int(request.GetRoomsReplicas()),
schedulerAutoscaling,
fromApiForwarders(request.GetForwarders()),
Expand Down Expand Up @@ -158,7 +156,7 @@ func FromApiNewSchedulerVersionRequestToEntity(request *api.NewSchedulerVersionR
entities.StateCreating,
request.GetMaxSurge(),
*fromApiSpec(request.GetSpec()),
entities.NewPortRange(
port.NewPortRange(
request.GetPortRange().GetStart(),
request.GetPortRange().GetEnd(),
),
Expand Down Expand Up @@ -346,6 +344,17 @@ func fromApiSpec(apiSpec *api.Spec) *game_room.Spec {
)
}

func fromApiPortRange(apiPortRange *api.PortRange) *port.PortRange {
if apiPortRange != nil {
return port.NewPortRange(
apiPortRange.GetStart(),
apiPortRange.GetEnd(),
)
}

return nil
}

func fromApiAutoscalingPolicy(apiAutoscalingPolicy *api.AutoscalingPolicy) autoscaling.Policy {
var policy autoscaling.Policy
if policyType := apiAutoscalingPolicy.GetType(); policyType != "" {
Expand Down Expand Up @@ -423,10 +432,11 @@ func fromApiContainerPorts(apiPorts []*api.ContainerPort) []game_room.ContainerP
var ports []game_room.ContainerPort
for _, apiPort := range apiPorts {
port := game_room.ContainerPort{
Name: apiPort.GetName(),
Port: int(apiPort.GetPort()),
Protocol: apiPort.GetProtocol(),
HostPort: int(apiPort.GetHostPort()),
Name: apiPort.GetName(),
Port: int(apiPort.GetPort()),
Protocol: apiPort.GetProtocol(),
HostPort: int(apiPort.GetHostPort()),
HostPortRange: fromApiPortRange(apiPort.HostPortRange),
}
ports = append(ports, port)
}
Expand Down Expand Up @@ -486,7 +496,7 @@ func fromApiForwarders(apiForwarders []*api.Forwarder) []*forwarder.Forwarder {
return forwarders
}

func getPortRange(portRange *entities.PortRange) *api.PortRange {
func getPortRange(portRange *port.PortRange) *api.PortRange {
if portRange != nil {
return &api.PortRange{
Start: portRange.Start,
Expand Down Expand Up @@ -605,10 +615,11 @@ func fromEntityContainerPortsToApiContainerPorts(ports []game_room.ContainerPort
var convertedContainerPort []*api.ContainerPort
for _, port := range ports {
convertedContainerPort = append(convertedContainerPort, &api.ContainerPort{
Name: port.Name,
Protocol: port.Protocol,
Port: int32(port.Port),
HostPort: int32(port.HostPort),
Name: port.Name,
Protocol: port.Protocol,
Port: int32(port.Port),
HostPort: int32(port.HostPort),
HostPortRange: getPortRange(port.HostPortRange),
})
}
return convertedContainerPort
Expand Down
Loading

0 comments on commit 5f7fd7d

Please sign in to comment.