Skip to content

Commit d11503d

Browse files
authored
[process-compose] Improve port selection (#1835)
## Summary This helps fix the lapp and lepp stack test issues. It also provides a more reliable way to provide an unused port that does not have race condition issues or the limit of 10 ports. ## How was it tested? devbox services start
1 parent 10c436f commit d11503d

File tree

2 files changed

+68
-21
lines changed

2 files changed

+68
-21
lines changed

internal/services/manager.go

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,9 @@ import (
2424

2525
const (
2626
processComposeLogfile = ".devbox/compose.log"
27-
startingPort = 8260
28-
maxPortTries = 10
2927
fileLockTimeout = 5 * time.Second
3028
)
3129

32-
func getAvailablePort(config *globalProcessComposeConfig) (int, bool) {
33-
for i := 0; i < maxPortTries; i++ {
34-
port := startingPort + i
35-
available := true
36-
for _, instance := range config.Instances {
37-
if instance.Port == port {
38-
available = false
39-
}
40-
}
41-
if available {
42-
return port, true
43-
}
44-
}
45-
return 0, false
46-
}
47-
4830
type instance struct {
4931
Pid int `json:"pid"`
5032
Port int `json:"port"`
@@ -143,9 +125,9 @@ func StartProcessManager(
143125
config.File = configFile
144126

145127
// Get the port to use for this project
146-
port, available := getAvailablePort(config)
147-
if !available {
148-
return fmt.Errorf("no available ports to start process-compose. You should run `devbox services stop` in your projects to free up ports")
128+
port, err := getAvailablePort()
129+
if err != nil {
130+
return err
149131
}
150132

151133
// Start building the process-compose command

internal/services/ports.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package services
2+
3+
import (
4+
"net"
5+
6+
"github.com/pkg/errors"
7+
)
8+
9+
var disallowedPorts = map[int]string{
10+
// Anything <= 1024
11+
1433: "MS-SQL (Microsoft SQL Server database management system)",
12+
1434: "MS-SQL (Microsoft SQL Server database management system)",
13+
1521: "Oracle SQL",
14+
1701: "L2TP (Layer 2 Tunneling Protocol)",
15+
1723: "PPTP (Point-to-Point Tunneling Protocol)",
16+
2049: "NFS (Network File System)",
17+
3000: "Node.js (Server-side JavaScript environment)",
18+
3001: "Node.js (Server-side JavaScript environment)",
19+
3306: "MySQL (Database system)",
20+
3389: "RDP (Remote Desktop Protocol)",
21+
5060: "SIP (Session Initiation Protocol)",
22+
5145: "RSH (Remote Shell)",
23+
5353: "mDNS (Multicast DNS)",
24+
5432: "PostgreSQL (Database system)",
25+
5900: "VNC (Virtual Network Computing)",
26+
6379: "Redis (Database system)",
27+
8000: "HTTP Alternate (http_alt)",
28+
8080: "HTTP Alternate (http_alt)",
29+
8082: "PHP FPM",
30+
8443: "HTTPS Alternate (https_alt)",
31+
9443: "Redis Enterprise (Database system)",
32+
}
33+
34+
func getAvailablePort() (int, error) {
35+
get := func() (int, error) {
36+
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
37+
if err != nil {
38+
return 0, errors.WithStack(err)
39+
}
40+
41+
l, err := net.ListenTCP("tcp", addr)
42+
if err != nil {
43+
return 0, errors.WithStack(err)
44+
}
45+
defer l.Close()
46+
return l.Addr().(*net.TCPAddr).Port, nil
47+
}
48+
49+
for range 1000 {
50+
port, err := get()
51+
if err != nil {
52+
return 0, errors.WithStack(err)
53+
}
54+
55+
if isAllowed(port) {
56+
return port, nil
57+
}
58+
}
59+
60+
return 0, errors.New("no available port")
61+
}
62+
63+
func isAllowed(port int) bool {
64+
return port > 1024 && disallowedPorts[port] == ""
65+
}

0 commit comments

Comments
 (0)