Repository: kubernetes/minikube
Pull request #17323 (2023-09-29 17:38:39)

Fix network not found not being detected on new Docker versions
Fixes https://github.com/kubernetes/minikube/issues/17278

Docker 20.X.X and before returns `No such network` when network isn't found
Docker 23.X.X and later returns `network %s not found` when network isn't found

We only had a check for `No such network` so we were outputting an error on newer versions of Docker

**Before**
```
$ docker network create --driver=bridge --subnet=192.168.49.0/24 --gateway=192.168.49.1 -o --ip-masq -o --icc -o com.docker.network.driver.mtu=65535 --label=created_by.minikube.sigs.k8s.io=true --label=name.minikube.sigs.k8s.io=minikube abcde123
2e7f334091b6401798a1449bb0aff8e793f80581fa240e1c2a8e52dba7ddbe95

$ minikube start --network abcde123 -p p2
😄  [p2] minikube v1.31.2 on Debian 11.7 (amd64)
✨  Automatically selected the docker driver. Other choices: qemu2, ssh
📌  Using Docker driver with root privileges
👍  Starting control plane node p2 in cluster p2
🚜  Pulling base image ...
🔥  Creating docker container (CPUs=2, Memory=8000MB) ...
🐳  Preparing Kubernetes v1.28.2 on Docker 24.0.6 ...E0929 17:13:22.689810 2528575 start.go:131] Unable to get host IP: network inspect: docker network inspect p2 --format "{"Name": "{{.Name}}","Driver": "{{.Driver}}","Subnet": "{{range .IPAM.Config}}{{.Subnet}}{{end}}","Gateway": "{{range .IPAM.Config}}{{.Gateway}}{{end}}","MTU": {{if (index .Options "com.docker.network.driver.mtu")}}{{(index .Options "com.docker.network.driver.mtu")}}{{else}}0{{end}}, "ContainerIPs": [{{range $k,$v := .Containers }}"{{$v.IPv4Address}}",{{end}}]}": exit status 1
stdout:


stderr:
Error response from daemon: network p2 not found

    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "p2" cluster and "default" namespace by default
```

**After:**
```
$ docker network create --driver=bridge --subnet=192.168.49.0/24 --gateway=192.168.49.1 -o --ip-masq -o --icc -o com.docker.network.driver.mtu=65535 --label=created_by.minikube.sigs.k8s.io=true --label=name.minikube.sigs.k8s.io=minikube abcde123
2e7f334091b6401798a1449bb0aff8e793f80581fa240e1c2a8e52dba7ddbe95

$ minikube start --network abcde123 -p p2
😄  [p2] minikube v1.31.2 on Debian 11.7 (amd64)
✨  Automatically selected the docker driver. Other choices: qemu2, ssh
📌  Using Docker driver with root privileges
👍  Starting control plane node p2 in cluster p2
🚜  Pulling base image ...
🔥  Creating docker container (CPUs=2, Memory=8000MB) ...
🐳  Preparing Kubernetes v1.28.2 on Docker 24.0.6 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "p2" cluster and "default" namespace by default
```


Patch:
diff --git a/pkg/drivers/kic/oci/network_create.go b/pkg/drivers/kic/oci/network_create.go
index a8d617caf..5e5aaaff4 100644
--- a/pkg/drivers/kic/oci/network_create.go
+++ b/pkg/drivers/kic/oci/network_create.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"net"
 	"os/exec"
+	"regexp"
 	"strings"
 
 	"github.com/blang/semver/v4"
@@ -207,8 +208,7 @@ func dockerNetworkInspect(name string) (netInfo, error) {
 	rr, err := dockerInspectGetter(name)
 	if err != nil {
 		logDockerNetworkInspect(Docker, name)
-		if strings.Contains(rr.Output(), "No such network") {
-
+		if isNetworkNotFound(rr.Output()) {
 			return info, ErrNetworkNotFound
 		}
 		return info, err
@@ -293,7 +293,7 @@ func RemoveNetwork(ociBin string, name string) error {
 	}
 	rr, err := runCmd(exec.Command(ociBin, "network", "rm", name))
 	if err != nil {
-		if strings.Contains(rr.Output(), "No such network") {
+		if isNetworkNotFound(rr.Output()) {
 			return ErrNetworkNotFound
 		}
 		// Error response from daemon: error while removing network: network mynet123 id f9e1c50b89feb0b8f4b687f3501a81b618252c9907bc20666e386d0928322387 has active endpoints
@@ -347,3 +347,9 @@ func DeleteKICNetworksByLabel(ociBin string, label string) []error {
 	}
 	return nil
 }
+
+func isNetworkNotFound(output string) bool {
+	// "No such network" on Docker 20.X.X and before, "network %s not found" on Docker 23.X.X and later
+	re := regexp.MustCompile(`(No such network)|(network .+ not found)`)
+	return re.MatchString(output)
+}


Test patch:
diff --git a/pkg/drivers/kic/oci/network_create_test.go b/pkg/drivers/kic/oci/network_create_test.go
index a4d25bf28..ac4e1c45e 100644
--- a/pkg/drivers/kic/oci/network_create_test.go
+++ b/pkg/drivers/kic/oci/network_create_test.go
@@ -143,3 +143,65 @@ func TestPodmanInspect(t *testing.T) {
 		})
 	}
 }
+
+func TestIsNetworkNotFound(t *testing.T) {
+	tests := []struct {
+		output     string
+		isNotFound bool
+	}{
+		{"Error: No such network: cat", true},
+		{"Error response from daemon: network cat not found", true},
+		{`[
+    {
+        "Name": "abcde123",
+        "Id": "4683c88eb412f2744e9763a4bebcb5e3b73a11dbcc79d6d9ab64ab2f10e08faa",
+        "Created": "2023-09-29T17:12:11.774716834Z",
+        "Scope": "local",
+        "Driver": "bridge",
+        "EnableIPv6": false,
+        "IPAM": {
+            "Driver": "default",
+            "Options": {},
+            "Config": [
+                {
+                    "Subnet": "192.168.49.0/24",
+                    "Gateway": "192.168.49.1"
+                }
+            ]
+        },
+        "Internal": false,
+        "Attachable": false,
+        "Ingress": false,
+        "ConfigFrom": {
+            "Network": ""
+        },
+        "ConfigOnly": false,
+        "Containers": {
+            "b6954f226ccfdb7d190e3792be8d569e4bc5e3c44833d9e274835212fca4f4d2": {
+                "Name": "p2",
+                "EndpointID": "30fd6525dab2b0a4f1953a3c8cae7485be272e09938dffe3d6de81e84c574826",
+                "MacAddress": "02:42:c0:a8:31:02",
+                "IPv4Address": "192.168.49.2/24",
+                "IPv6Address": ""
+            }
+        },
+        "Options": {
+            "--icc": "",
+            "--ip-masq": "",
+            "com.docker.network.driver.mtu": "65535"
+        },
+        "Labels": {
+            "created_by.minikube.sigs.k8s.io": "true",
+            "name.minikube.sigs.k8s.io": "minikube"
+        }
+    }
+]`, false},
+	}
+
+	for _, tc := range tests {
+		got := isNetworkNotFound(tc.output)
+		if got != tc.isNotFound {
+			t.Errorf("isNetworkNotFound(%s) = %t; want = %t", tc.output, got, tc.isNotFound)
+		}
+	}
+}