Repository: kubernetes/minikube
Pull request #15085 (2022-10-07 18:23:43)

Allow passing only exposed port to --ports
Fixes https://github.com/kubernetes/minikube/issues/14731

When port validation was added the case for just passing the port to expose was forgotten and made that possibility impossible.

**Before:**
```
$ minikube start --ports 8080
😄  minikube v1.27.0 on Darwin 12.6 (arm64)
✨  Automatically selected the docker driver. Other choices: ssh, qemu2 (experimental)

❌  Exiting due to MK_USAGE: Sorry, one of the ports provided with --ports flag is not valid [8080]
```

**After:**
```
$ minikube start --ports 8080
😄  minikube v1.27.0 on Darwin 12.6 (arm64)
✨  Automatically selected the docker driver. Other choices: ssh, qemu2 (experimental)
📌  Using Docker Desktop driver with root privileges
👍  Starting control plane node minikube in cluster minikube
🚜  Pulling base image ...
🔥  Creating docker container (CPUs=2, Memory=4000MB) ...
🐳  Preparing Kubernetes v1.25.2 on Docker 20.10.18 ...
❌  Unable to load cached images: loading cached images: stat /Users/powellsteven/.minikube/cache/images/arm64/registry.k8s.io/kube-controller-manager_v1.25.2: no such file or directory
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

$  docker ps --format "{{.Ports}}"
0.0.0.0:64745->22/tcp, 0.0.0.0:64746->2376/tcp, 0.0.0.0:64748->5000/tcp, 0.0.0.0:64749->8080/tcp, 0.0.0.0:64750->8443/tcp, 0.0.0.0:64747->32443/tcp
```


Patch:
diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go
index 6eb57cf23..0f37fdcd8 100644
--- a/cmd/minikube/cmd/start.go
+++ b/cmd/minikube/cmd/start.go
@@ -1253,24 +1253,48 @@ func validateFlags(cmd *cobra.Command, drvName string) {
 
 // validatePorts validates that the --ports are not below 1024 for the host and not outside range
 func validatePorts(ports []string) error {
-	_, portBindingsMap, err := nat.ParsePortSpecs(ports)
+	var exposedPorts, hostPorts, portSpecs []string
+	for _, p := range ports {
+		if strings.Contains(p, ":") {
+			portSpecs = append(portSpecs, p)
+		} else {
+			exposedPorts = append(exposedPorts, p)
+		}
+	}
+	_, portBindingsMap, err := nat.ParsePortSpecs(portSpecs)
 	if err != nil {
 		return errors.Errorf("Sorry, one of the ports provided with --ports flag is not valid %s (%v)", ports, err)
 	}
-	for _, portBindings := range portBindingsMap {
+	for exposedPort, portBindings := range portBindingsMap {
+		exposedPorts = append(exposedPorts, exposedPort.Port())
 		for _, portBinding := range portBindings {
-			p, err := strconv.Atoi(portBinding.HostPort)
-			if err != nil {
-				return errors.Errorf("Sorry, one of the ports provided with --ports flag is not valid %s", ports)
-			}
-			if p > 65535 || p < 1 {
-				return errors.Errorf("Sorry, one of the ports provided with --ports flag is outside range %s", ports)
-			}
-			if detect.IsMicrosoftWSL() && p < 1024 {
-				return errors.Errorf("Sorry, you cannot use privileged ports on the host (below 1024) %s", ports)
-			}
+			hostPorts = append(hostPorts, portBinding.HostPort)
+		}
+	}
+	for _, p := range exposedPorts {
+		if err := validatePort(p, false); err != nil {
+			return err
 		}
 	}
+	for _, p := range hostPorts {
+		if err := validatePort(p, true); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func validatePort(port string, isHost bool) error {
+	p, err := strconv.Atoi(port)
+	if err != nil {
+		return errors.Errorf("Sorry, one of the ports provided with --ports flag is not valid: %s", port)
+	}
+	if p > 65535 || p < 1 {
+		return errors.Errorf("Sorry, one of the ports provided with --ports flag is outside range: %s", port)
+	}
+	if isHost && detect.IsMicrosoftWSL() && p < 1024 {
+		return errors.Errorf("Sorry, you cannot use privileged ports on the host (below 1024): %s", port)
+	}
 	return nil
 }
 


Test patch:
diff --git a/cmd/minikube/cmd/start_test.go b/cmd/minikube/cmd/start_test.go
index 0ce1ce971..838d79afb 100644
--- a/cmd/minikube/cmd/start_test.go
+++ b/cmd/minikube/cmd/start_test.go
@@ -489,12 +489,12 @@ func TestValidatePorts(t *testing.T) {
 		{
 			isTarget: true,
 			ports:    []string{"0:80"},
-			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range [0:80]",
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
 		},
 		{
 			isTarget: true,
 			ports:    []string{"0:80/tcp"},
-			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range [0:80/tcp]",
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
 		},
 		{
 			isTarget: true,
@@ -504,12 +504,12 @@ func TestValidatePorts(t *testing.T) {
 		{
 			isTarget: true,
 			ports:    []string{"0-1:80-81/tcp"},
-			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range [0-1:80-81/tcp]",
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
 		},
 		{
 			isTarget: true,
 			ports:    []string{"0-1:80-81/udp"},
-			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range [0-1:80-81/udp]",
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
 		},
 		{
 			isTarget: !isMicrosoftWSL,
@@ -519,22 +519,22 @@ func TestValidatePorts(t *testing.T) {
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"80:80"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [80:80]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 80",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"1023-1025:8023-8025"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [1023-1025:8023-8025]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 1023",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"1023-1025:8023-8025/tcp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [1023-1025:8023-8025/tcp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 1023",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"1023-1025:8023-8025/udp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [1023-1025:8023-8025/udp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 1023",
 		},
 		{
 			isTarget: true,
@@ -554,27 +554,72 @@ func TestValidatePorts(t *testing.T) {
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"127.0.0.1:80:80"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [127.0.0.1:80:80]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 80",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"127.0.0.1:81:81/tcp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [127.0.0.1:81:81/tcp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 81",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"127.0.0.1:81:81/udp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [127.0.0.1:81:81/udp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 81",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"127.0.0.1:80-83:80-83/tcp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [127.0.0.1:80-83:80-83/tcp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 80",
 		},
 		{
 			isTarget: isMicrosoftWSL,
 			ports:    []string{"127.0.0.1:80-83:80-83/udp"},
-			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024) [127.0.0.1:80-83:80-83/udp]",
+			errorMsg: "Sorry, you cannot use privileged ports on the host (below 1024): 80",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"80"},
+			errorMsg: "",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"80", "65535", "65536"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 65536",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"0", "80", "65535"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"cats"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is not valid: cats",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"127.0.0.1:81:0/tcp"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is outside range: 0",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"127.0.0.1:81:65536/tcp"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is not valid [127.0.0.1:81:65536/tcp] (Invalid containerPort: 65536)",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"1-65536:80-81/tcp"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is not valid [1-65536:80-81/tcp] (Invalid hostPort: 1-65536)",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"1-80:0-81/tcp"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is not valid [1-80:0-81/tcp] (Invalid ranges specified for container and host Ports: 0-81 and 1-80)",
+		},
+		{
+			isTarget: true,
+			ports:    []string{"1-80:1-65536/tcp"},
+			errorMsg: "Sorry, one of the ports provided with --ports flag is not valid [1-80:1-65536/tcp] (Invalid containerPort: 1-65536)",
 		},
 	}
 	for _, test := range tests {