Skip to content

[supervisor] localify struct of ports sort #14070

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

Closed
wants to merge 3 commits into from
Closed
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 @@ -1756,7 +1756,6 @@ type PortConfig struct {
Visibility string `json:"visibility,omitempty"`
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
Sort uint32 `json:"sort,omitempty"`
}

// TaskConfig is the TaskConfig message type
Expand Down
68 changes: 42 additions & 26 deletions components/supervisor/pkg/ports/ports-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,36 @@ 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
workspaceConfigs map[uint32]*SortConfig
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 _, configs := range []map[uint32]*SortConfig{configs.instancePortConfigs, configs.workspaceConfigs} {
for port, config := range configs {
_, exists := visited[port]
if exists {
Expand All @@ -60,7 +68,7 @@ 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
}
Expand All @@ -74,13 +82,15 @@ func (configs *Configs) Get(port uint32) (*gitpod.PortConfig, ConfigKind, bool)
}
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 @@ -170,22 +180,26 @@ 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) {
func parseWorkspaceConfigs(ports []*gitpod.PortConfig) (portConfigs map[uint32]*SortConfig) {
if len(ports) == 0 {
return nil
}
portConfigs = make(map[uint32]*gitpod.PortConfig)
portConfigs = make(map[uint32]*SortConfig)
for _, config := range ports {
port := uint32(config.Port)
_, exists := portConfigs[port]
if !exists {
portConfigs[port] = config
portConfigs[port] = &SortConfig{
PortConfig: *config,
// We don't care about workspace configs but instance config
Sort: NON_CONFIGED_BASIC_SCORE - 1,
}
}
}
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 +209,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 +240,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
6 changes: 3 additions & 3 deletions components/supervisor/pkg/ports/ports-config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,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 @@ -136,7 +136,7 @@ func TestPortsConfig(t *testing.T) {
t.Fatal(err)
case change := <-updates:
for _, config := range change.workspaceConfigs {
actual.WorkspaceConfigs = append(actual.WorkspaceConfigs, config)
actual.WorkspaceConfigs = append(actual.WorkspaceConfigs, &config.PortConfig)
}
}

Expand All @@ -150,7 +150,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 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))
Copy link
Member

Choose a reason for hiding this comment

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

Filtering maybe is alright just we need to keep public ports always

Copy link
Contributor Author

@mustard-mh mustard-mh Oct 21, 2022

Choose a reason for hiding this comment

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

It means, port will be gone if user switches a public not served port to private. 🤔

see also #13788 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

Ok, let’s keep it.

Another approach it is to filter ports which can be only local, ie nodejs debug ports. But I’m not sure how it can achieved on supervisor level. VS Code extensions certainly know it.

}
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