Skip to content

Improve ports respond in supervisor #14761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion components/gitpod-protocol/go/gitpod-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1951,7 +1951,6 @@ type PortConfig struct {
Visibility string `json:"visibility,omitempty"`
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
Sort uint32 `json:"sort,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should not be here in the first place. cc @geropl @easyCZ for review of webapp owned files

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not mentioned here at all. ✔️

}

// TaskConfig is the TaskConfig message type
Expand Down
101 changes: 39 additions & 62 deletions components/supervisor/pkg/ports/ports-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package ports

import (
"context"
"errors"
"fmt"
"reflect"
"regexp"
Expand All @@ -16,36 +15,41 @@ import (
"github.com/gitpod-io/gitpod/supervisor/pkg/config"
)

const NON_CONFIGED_BASIC_SCORE = 100000

// RangeConfig is a port range config.
type RangeConfig struct {
*gitpod.PortsItems
gitpod.PortsItems
Start uint32
End uint32
Sort uint32
}

// SortConfig is a port with a sort field
type SortConfig struct {
gitpod.PortConfig
Sort uint32
}

// Configs provides access to port configurations.
type Configs struct {
workspaceConfigs map[uint32]*gitpod.PortConfig
instancePortConfigs map[uint32]*gitpod.PortConfig
instancePortConfigs map[uint32]*SortConfig
instanceRangeConfigs []*RangeConfig
}

// ForEach iterates over all configured ports.
func (configs *Configs) ForEach(callback func(port uint32, config *gitpod.PortConfig)) {
func (configs *Configs) ForEach(callback func(port uint32, config *SortConfig)) {
if configs == nil {
return
}
visited := make(map[uint32]struct{})
for _, configs := range []map[uint32]*gitpod.PortConfig{configs.instancePortConfigs, configs.workspaceConfigs} {
for port, config := range configs {
_, exists := visited[port]
if exists {
continue
}
visited[port] = struct{}{}
callback(port, config)
for port, config := range configs.instancePortConfigs {
_, exists := visited[port]
if exists {
continue
}
visited[port] = struct{}{}
callback(port, config)
}
}

Expand All @@ -60,27 +64,25 @@ var (
)

// Get returns the config for the give port.
func (configs *Configs) Get(port uint32) (*gitpod.PortConfig, ConfigKind, bool) {
func (configs *Configs) Get(port uint32) (*SortConfig, ConfigKind, bool) {
if configs == nil {
return nil, PortConfigKind, false
}
config, exists := configs.instancePortConfigs[port]
if exists {
return config, PortConfigKind, true
}
config, exists = configs.workspaceConfigs[port]
if exists {
return config, PortConfigKind, true
}
for _, rangeConfig := range configs.instanceRangeConfigs {
if rangeConfig.Start <= port && port <= rangeConfig.End {
return &gitpod.PortConfig{
Port: float64(port),
OnOpen: rangeConfig.OnOpen,
Visibility: rangeConfig.Visibility,
Description: rangeConfig.Description,
Name: rangeConfig.Name,
Sort: rangeConfig.Sort,
return &SortConfig{
PortConfig: gitpod.PortConfig{
Port: float64(port),
OnOpen: rangeConfig.OnOpen,
Visibility: rangeConfig.Visibility,
Description: rangeConfig.Description,
Name: rangeConfig.Name,
},
Sort: rangeConfig.Sort,
}, RangeConfigKind, true
}
}
Expand Down Expand Up @@ -121,17 +123,6 @@ func (service *ConfigService) Observe(ctx context.Context) (<-chan *Configs, <-c
configs := service.configService.Observe(ctx)

current := &Configs{}
if service.gitpodAPI != nil {
info, err := service.gitpodAPI.GetWorkspace(ctx, service.workspaceID)
if err != nil {
errorsChan <- err
} else {
current.workspaceConfigs = parseWorkspaceConfigs(info.Workspace.Config.Ports)
updatesChan <- &Configs{workspaceConfigs: current.workspaceConfigs}
}
} else {
errorsChan <- errors.New("could not connect to Gitpod API to fetch workspace port configs")
}

for {
select {
Expand All @@ -146,7 +137,6 @@ func (service *ConfigService) Observe(ctx context.Context) (<-chan *Configs, <-c
continue
}
updatesChan <- &Configs{
workspaceConfigs: current.workspaceConfigs,
instancePortConfigs: current.instancePortConfigs,
instanceRangeConfigs: current.instanceRangeConfigs,
}
Expand All @@ -170,22 +160,7 @@ func (service *ConfigService) update(config *gitpod.GitpodConfig, current *Confi

var portRangeRegexp = regexp.MustCompile(`^(\d+)[-:](\d+)$`)

func parseWorkspaceConfigs(ports []*gitpod.PortConfig) (portConfigs map[uint32]*gitpod.PortConfig) {
if len(ports) == 0 {
return nil
}
portConfigs = make(map[uint32]*gitpod.PortConfig)
for _, config := range ports {
port := uint32(config.Port)
_, exists := portConfigs[port]
if !exists {
portConfigs[port] = config
}
}
return portConfigs
}

func parseInstanceConfigs(ports []*gitpod.PortsItems) (portConfigs map[uint32]*gitpod.PortConfig, rangeConfigs []*RangeConfig) {
func parseInstanceConfigs(ports []*gitpod.PortsItems) (portConfigs map[uint32]*SortConfig, rangeConfigs []*RangeConfig) {
for index, config := range ports {
if config == nil {
continue
Expand All @@ -195,18 +170,20 @@ func parseInstanceConfigs(ports []*gitpod.PortsItems) (portConfigs map[uint32]*g
Port, err := strconv.ParseUint(rawPort, 10, 16)
if err == nil {
if portConfigs == nil {
portConfigs = make(map[uint32]*gitpod.PortConfig)
portConfigs = make(map[uint32]*SortConfig)
}
port := uint32(Port)
_, exists := portConfigs[port]
if !exists {
portConfigs[port] = &gitpod.PortConfig{
OnOpen: config.OnOpen,
Port: float64(Port),
Visibility: config.Visibility,
Description: config.Description,
Name: config.Name,
Sort: uint32(index),
portConfigs[port] = &SortConfig{
PortConfig: gitpod.PortConfig{
OnOpen: config.OnOpen,
Port: float64(Port),
Visibility: config.Visibility,
Description: config.Description,
Name: config.Name,
},
Sort: uint32(index),
}
}
continue
Expand All @@ -224,7 +201,7 @@ func parseInstanceConfigs(ports []*gitpod.PortsItems) (portConfigs map[uint32]*g
continue
}
rangeConfigs = append(rangeConfigs, &RangeConfig{
PortsItems: config,
PortsItems: *config,
Start: uint32(start),
End: uint32(end),
Sort: uint32(index),
Expand Down
50 changes: 5 additions & 45 deletions components/supervisor/pkg/ports/ports-config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,14 @@ import (

func TestPortsConfig(t *testing.T) {
tests := []struct {
Desc string
WorkspacePorts []*gitpod.PortConfig
GitpodConfig *gitpod.GitpodConfig
Expectation *PortConfigTestExpectations
Desc string
GitpodConfig *gitpod.GitpodConfig
Expectation *PortConfigTestExpectations
}{
{
Desc: "no configs",
Expectation: &PortConfigTestExpectations{},
},
{
Desc: "workspace port config",
WorkspacePorts: []*gitpod.PortConfig{
{
Port: 9229,
OnOpen: "ignore",
Visibility: "public",
Name: "Nice Port Name",
Description: "Nice Port Description",
},
},
Expectation: &PortConfigTestExpectations{
WorkspaceConfigs: []*gitpod.PortConfig{
{
Port: 9229,
OnOpen: "ignore",
Visibility: "public",
Name: "Nice Port Name",
Description: "Nice Port Description",
},
},
},
},
{
Desc: "instance port config",
GitpodConfig: &gitpod.GitpodConfig{
Expand Down Expand Up @@ -89,7 +65,7 @@ func TestPortsConfig(t *testing.T) {
Expectation: &PortConfigTestExpectations{
InstanceRangeConfigs: []*RangeConfig{
{
PortsItems: &gitpod.PortsItems{
PortsItems: gitpod.PortsItems{
Port: "9229-9339",
OnOpen: "ignore",
Visibility: "public",
Expand Down Expand Up @@ -119,26 +95,11 @@ func TestPortsConfig(t *testing.T) {
defer ctrl.Finish()

gitpodAPI := gitpod.NewMockAPIInterface(ctrl)
gitpodAPI.EXPECT().GetWorkspace(context, workspaceID).Times(1).Return(&gitpod.WorkspaceInfo{
Workspace: &gitpod.Workspace{
Config: &gitpod.WorkspaceConfig{
Ports: test.WorkspacePorts,
},
},
}, nil)

service := NewConfigService(workspaceID, configService, gitpodAPI)
updates, errors := service.Observe(context)

actual := &PortConfigTestExpectations{}
select {
case err := <-errors:
t.Fatal(err)
case change := <-updates:
for _, config := range change.workspaceConfigs {
actual.WorkspaceConfigs = append(actual.WorkspaceConfigs, config)
}
}

if test.GitpodConfig != nil {
go func() {
Expand All @@ -150,7 +111,7 @@ func TestPortsConfig(t *testing.T) {
case change := <-updates:
actual.InstanceRangeConfigs = change.instanceRangeConfigs
for _, config := range change.instancePortConfigs {
actual.InstancePortConfigs = append(actual.InstancePortConfigs, config)
actual.InstancePortConfigs = append(actual.InstancePortConfigs, &config.PortConfig)
}
}
}
Expand All @@ -163,7 +124,6 @@ func TestPortsConfig(t *testing.T) {
}

type PortConfigTestExpectations struct {
WorkspaceConfigs []*gitpod.PortConfig
InstancePortConfigs []*gitpod.PortConfig
InstanceRangeConfigs []*RangeConfig
}
Expand Down
23 changes: 11 additions & 12 deletions components/supervisor/pkg/ports/ports.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func (pm *Manager) updateState(ctx context.Context, exposed []ExposedPort, serve
stateChanged := !reflect.DeepEqual(newState, pm.state)
pm.state = newState

if !stateChanged {
if !stateChanged && configured == nil {
return
}

Expand All @@ -315,10 +315,14 @@ func (pm *Manager) nextState(ctx context.Context) map[uint32]*managedPort {
return mp
}
config, _, exists := pm.configs.Get(port)
var portConfig *gitpod.PortConfig
if exists && config != nil {
portConfig = &config.PortConfig
}
mp := &managedPort{
LocalhostPort: port,
OnExposed: getOnExposedAction(config, port),
OnOpen: getOnOpenAction(config, port),
OnExposed: getOnExposedAction(portConfig, port),
OnOpen: getOnOpenAction(portConfig, port),
}
if exists {
mp.Name = config.Name
Expand Down Expand Up @@ -358,7 +362,7 @@ func (pm *Manager) nextState(ctx context.Context) map[uint32]*managedPort {

// 2. second capture configured since we don't want to auto expose already exposed ports
if pm.configs != nil {
pm.configs.ForEach(func(port uint32, config *gitpod.PortConfig) {
pm.configs.ForEach(func(port uint32, config *SortConfig) {
if pm.boundInternally(port) {
return
}
Expand Down Expand Up @@ -740,17 +744,12 @@ func (pm *Manager) Subscribe() (*Subscription, error) {
func (pm *Manager) getStatus() []*api.PortsStatus {
res := make([]*api.PortsStatus, 0, len(pm.state))
for port := range pm.state {
portStatus := pm.getPortStatus(port)
// Filter out ports that not served and not inside `.gitpod.yml`
if _, _, ok := pm.configs.Get(port); !ok && !portStatus.Served {
continue
}
res = append(res, portStatus)
res = append(res, pm.getPortStatus(port))
}
sort.SliceStable(res, func(i, j int) bool {
// Max number of port 65536
score1 := 100000 + res[i].LocalPort
score2 := 100000 + res[j].LocalPort
score1 := NON_CONFIGED_BASIC_SCORE + res[i].LocalPort
score2 := NON_CONFIGED_BASIC_SCORE + res[j].LocalPort
if c, _, ok := pm.configs.Get(res[i].LocalPort); ok {
score1 = c.Sort
}
Expand Down
Loading