mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-31 05:07:01 +00:00
feat: enforce hard-fail behavior for explicitly specified ports
When users explicitly specify a port via command-line flags (e.g., -s3.port=8333), the server should fail immediately if the port is unavailable, rather than silently falling back to an alternative port. This prevents user confusion and makes misconfiguration failures obvious. Changes: - Modified ensurePortAvailableOnIP() to check if a port was explicitly passed via isFlagPassed() - If an explicit port is unavailable, return error instead of silently allocating alternative - Updated ensureAllPortsAvailableOnIP() to handle the returned error and fail startup - Modified runMini() to check error from ensureAllPortsAvailableOnIP() and return false on failure - Default ports (not explicitly specified) continue to fallback to available alternatives This ensures: - Explicit ports: fail if unavailable (e.g., -s3.port=8333 fails if 8333 is taken) - Default ports: fallback to alternatives (e.g., s3.port without flag falls back to 8334 if 8333 taken)
This commit is contained in:
+35
-15
@@ -380,14 +380,21 @@ func findAvailablePortOnIP(ip string, startPort int, maxAttempts int, reservedPo
|
||||
// ensurePortAvailableOnIP ensures a port pointer points to an available port on a specific IP
|
||||
// If the port is not available, it finds the next available port and updates the pointer
|
||||
// The reservedPorts map contains ports that should not be allocated (for gRPC collision avoidance)
|
||||
func ensurePortAvailableOnIP(portPtr *int, serviceName string, ip string, reservedPorts map[int]bool) {
|
||||
func ensurePortAvailableOnIP(portPtr *int, serviceName string, ip string, reservedPorts map[int]bool, flagName string) error {
|
||||
if portPtr == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
original := *portPtr
|
||||
|
||||
// Check if this port was explicitly specified by the user
|
||||
isExplicitPort := isFlagPassed(flagName)
|
||||
|
||||
// Skip if this port is reserved for gRPC calculation
|
||||
if reservedPorts[original] {
|
||||
if isExplicitPort {
|
||||
return fmt.Errorf("port %d for %s (specified by flag %s) is reserved for gRPC calculation and cannot be used", original, serviceName, flagName)
|
||||
}
|
||||
glog.Warningf("Port %d for %s is reserved for gRPC calculation, finding alternative...", original, serviceName)
|
||||
newPort := findAvailablePortOnIP(ip, original+1, 100, reservedPorts)
|
||||
if newPort == 0 {
|
||||
@@ -396,11 +403,14 @@ func ensurePortAvailableOnIP(portPtr *int, serviceName string, ip string, reserv
|
||||
glog.Infof("Port %d for %s is available, using it instead of %d", newPort, serviceName, original)
|
||||
*portPtr = newPort
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check on both the specific IP and on all interfaces (0.0.0.0) for maximum reliability
|
||||
if !isPortOpenOnIP(ip, original) || !isPortAvailable(original) {
|
||||
if isExplicitPort {
|
||||
return fmt.Errorf("port %d for %s (specified by flag %s) is not available on %s and cannot be used", original, serviceName, flagName, ip)
|
||||
}
|
||||
glog.Warningf("Port %d for %s is not available on %s, finding alternative port...", original, serviceName, ip)
|
||||
newPort := findAvailablePortOnIP(ip, original+1, 100, reservedPorts)
|
||||
if newPort == 0 {
|
||||
@@ -412,22 +422,25 @@ func ensurePortAvailableOnIP(portPtr *int, serviceName string, ip string, reserv
|
||||
} else {
|
||||
glog.V(1).Infof("Port %d for %s is available on %s", original, serviceName, ip)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureAllPortsAvailableOnIP ensures all mini service ports are available on a specific IP
|
||||
// Returns an error if an explicitly specified port is unavailable.
|
||||
// This should be called before starting any services
|
||||
func ensureAllPortsAvailableOnIP(bindIp string) {
|
||||
func ensureAllPortsAvailableOnIP(bindIp string) error {
|
||||
portConfigs := []struct {
|
||||
port *int
|
||||
name string
|
||||
grpcPtr *int
|
||||
port *int
|
||||
name string
|
||||
flagName string
|
||||
grpcPtr *int
|
||||
}{
|
||||
{miniMasterOptions.port, "Master", miniMasterOptions.portGrpc},
|
||||
{miniFilerOptions.port, "Filer", miniFilerOptions.portGrpc},
|
||||
{miniOptions.v.port, "Volume", miniOptions.v.portGrpc},
|
||||
{miniS3Options.port, "S3", miniS3Options.portGrpc},
|
||||
{miniWebDavOptions.port, "WebDAV", nil},
|
||||
{miniAdminOptions.port, "Admin", miniAdminOptions.grpcPort},
|
||||
{miniMasterOptions.port, "Master", "master.port", miniMasterOptions.portGrpc},
|
||||
{miniFilerOptions.port, "Filer", "filer.port", miniFilerOptions.portGrpc},
|
||||
{miniOptions.v.port, "Volume", "volume.port", miniOptions.v.portGrpc},
|
||||
{miniS3Options.port, "S3", "s3.port", miniS3Options.portGrpc},
|
||||
{miniWebDavOptions.port, "WebDAV", "webdav.port", nil},
|
||||
{miniAdminOptions.port, "Admin", "admin.port", miniAdminOptions.grpcPort},
|
||||
}
|
||||
|
||||
// First, reserve all gRPC ports that will be calculated to prevent HTTP port allocation from using them
|
||||
@@ -447,7 +460,9 @@ func ensureAllPortsAvailableOnIP(bindIp string) {
|
||||
// Also avoid allocating ports that are reserved for gRPC calculation
|
||||
for _, config := range portConfigs {
|
||||
original := *config.port
|
||||
ensurePortAvailableOnIP(config.port, config.name, bindIp, reservedPorts)
|
||||
if err := ensurePortAvailableOnIP(config.port, config.name, bindIp, reservedPorts, config.flagName); err != nil {
|
||||
return err
|
||||
}
|
||||
// If port was changed, update the reserved gRPC ports mapping
|
||||
if *config.port != original && config.grpcPtr != nil && *config.grpcPtr == 0 {
|
||||
delete(reservedPorts, original+GrpcPortOffset)
|
||||
@@ -469,6 +484,8 @@ func ensureAllPortsAvailableOnIP(bindIp string) {
|
||||
glog.Infof("gRPC port configuration - Master: %d, Filer: %d, Volume: %d, S3: %d, Admin: %d",
|
||||
*miniMasterOptions.portGrpc, *miniFilerOptions.portGrpc, *miniOptions.v.portGrpc,
|
||||
*miniS3Options.portGrpc, *miniAdminOptions.grpcPort)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeGrpcPortsOnIP initializes all gRPC ports based on their HTTP ports on a specific IP
|
||||
@@ -670,7 +687,10 @@ func runMini(cmd *Command, args []string) bool {
|
||||
bindIp := getBindIp()
|
||||
|
||||
// Ensure all ports are available, find alternatives if needed
|
||||
ensureAllPortsAvailableOnIP(bindIp)
|
||||
if err := ensureAllPortsAvailableOnIP(bindIp); err != nil {
|
||||
glog.Errorf("Port allocation failed: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Set master.peers to "none" if not specified (single master mode)
|
||||
if *miniMasterOptions.peers == "" {
|
||||
|
||||
Reference in New Issue
Block a user