Repository: saltstack/salt
Pull request: docker_network.present fix for 60316
### What does this PR do?

updates `com.docker.network.bridge.name` in comparison network so there isn't a conflict. and ignores the setting in the comparison. 

### What issues does this PR fix or reference?
Fixes: #60316

### Merge requirements satisfied?
**[NOTICE] Bug fixes or features added to Salt require tests.**
<!-- Please review the [test documentation](https://docs.saltproject.io/en/master/topics/tutorials/writing_tests.html) for details on how to implement tests into Salt's test suite. -->
- [ ] Docs
- [x] Changelog - https://docs.saltproject.io/en/master/topics/development/changelog.html
- [x] Tests written/updated

### Commits signed with GPG?
No

Problem statement:
[BUG] docker_network.present error on subsequent run when using driver_opts
**Description**
I'm trying to set a bridge name name using `driver_opts` in the `docker_network.present` module. The network is created with the correct name when it does not exist. When it does exist, the state fails.

**Setup**
```
Create mynet:
  docker_network.present:
    - name: mynet
    - subnet: 192.168.1.0/24
    - driver: bridge
    - driver_opts:
      - com.docker.network.bridge.name: mynet
```

**Steps to Reproduce the behavior**
```
user@ubuntu20:~$ ip -br a |grep mynet
user@ubuntu20:~$ sudo salt ubuntu20 state.apply docker.test
ubuntu20:
----------
          ID: Create mynet
    Function: docker_network.present
        Name: mynet
      Result: True
     Comment: Network 'mynet' created
     Started: 09:37:52.418626
    Duration: 35.727 ms
     Changes:   
              ----------
              created:
                  True

Summary for ubuntu20
------------
Succeeded: 1 (changed=1)
Failed:    0
------------
Total states run:     1
Total run time:  35.727 ms


user@ubuntu20:~$ ip -br a |grep mynet
mynet            DOWN           192.168.1.1/24 


user@ubuntu20:~$ sudo salt ubuntu20 state.apply docker.test
ubuntu20:
----------
          ID: Create mynet
    Function: docker_network.present
        Name: mynet
      Result: False
     Comment: Failed to create temp network for comparison: Error 403: cannot create network 4131269881dc6d3ae7917613212b0425b5d20ee157c19177a7716503d680e65a (mynet): conflicts with network 4b0464d8d2971fea352a55de34b68a40b0b8a8d70739cf552a8cfffc600ef5cb (mynet): networks have same bridge name
     Started: 09:37:57.082647
    Duration: 9.174 ms
     Changes:   

Summary for ubuntu20
------------
Succeeded: 0
Failed:    1
------------
Total states run:     1
Total run time:   9.174 ms
ERROR: Minions returned with non-zero exit code
```


**Expected behavior**
I expect the state to not fail and proceed without changes.


**Versions Report**
<details><summary>salt --versions-report</summary>
(Provided by running salt --versions-report. Please also mention any differences in master/minion versions.) 

```
Salt Version:
          Salt: 3003
 
Dependency Versions:
          cffi: 1.14.4
      cherrypy: unknown
      dateutil: 2.7.3
     docker-py: 5.0.0
         gitdb: 2.0.6
     gitpython: 3.0.7
        Jinja2: 2.10.1
       libgit2: 1.1.0
      M2Crypto: Not Installed
          Mako: Not Installed
       msgpack: 0.6.2
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     pycparser: 2.20
      pycrypto: Not Installed
  pycryptodome: 3.6.1
        pygit2: 1.4.0
        Python: 3.8.5 (default, Jul 28 2020, 12:59:40)
  python-gnupg: 0.4.5
        PyYAML: 5.3.1
         PyZMQ: 18.1.1
         smmap: 2.0.5
       timelib: Not Installed
       Tornado: 4.5.3
           ZMQ: 4.3.2
 
System Versions:
          dist: ubuntu 20.04 focal
        locale: utf-8
       machine: x86_64
       release: 5.4.0-52-generic
        system: Linux
       version: Ubuntu 20.04 focal
```
</details>

**Additional context**
I tried to circumvent the error with `ignore_collisions: True` and `check_duplicate: False` to no avail.

Hints from issue discussion:
@supfors thanks for the report.  It looks like the state module is not handling the scenario when the network already exists when using a bridge name.

Commit message: Merge branch 'master' into 60316

Patch to review:
diff --git a/changelog/60316.fixed b/changelog/60316.fixed
new file mode 100644
index 000000000000..d1bb23e925a9
--- /dev/null
+++ b/changelog/60316.fixed
@@ -0,0 +1 @@
+fix docker_network.present when com.docker.network.bridge.name is being used as the unixes can not have a bridge of the same name
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
index 199f10f27736..d8581586ca72 100644
--- a/salt/modules/dockermod.py
+++ b/salt/modules/dockermod.py
@@ -1331,6 +1331,17 @@ def compare_networks(first, second, ignore="Name,Id,Created,Containers"):
                         "old": subval1,
                         "new": subval2,
                     }
+        elif item == "Options":
+            for subkey in val1:
+                subval1 = val1[subkey]
+                subval2 = val2.get(subkey)
+                if subkey == "com.docker.network.bridge.name":
+                    continue
+                elif subval1 != subval2:
+                    ret.setdefault("Options", {})[subkey] = {
+                        "old": subval1,
+                        "new": subval2,
+                    }
         elif val1 != val2:
             ret[item] = {"old": val1, "new": val2}
 
diff --git a/salt/states/docker_network.py b/salt/states/docker_network.py
index 0c43a3a46c00..4097e9fea2db 100644
--- a/salt/states/docker_network.py
+++ b/salt/states/docker_network.py
@@ -644,11 +644,21 @@ def present(
             # wouldng't know if the IPv4 subnet in the existing network was
             # explicitly configured or was automatically assigned by Docker.
             enable_ipv6 = kwargs.pop("enable_ipv6", None)
+            kwargs2 = kwargs
+            driver = kwargs.get(
+                "driver",
+            )
+            driver_opts = kwargs.get("options", {})
+            bridge_name = driver_opts.get("com.docker.network.bridge.name", None)
+
+            if driver == "bridge" and bridge_name is not None:
+                tmp_name = str(bridge_name) + "comp"
+                kwargs2["options"]["com.docker.network.bridge.name"] = tmp_name[-14:]
             __salt__["docker.create_network"](
                 temp_net_name,
                 skip_translate=True,  # No need to translate (already did)
                 enable_ipv6=False,
-                **kwargs
+                **kwargs2
             )
         except CommandExecutionError as exc:
             ret["comment"] = "Failed to create temp network for comparison: {}".format(
diff --git a/tests/integration/states/test_docker_network.py b/tests/integration/states/test_docker_network.py
index f249804cf92f..ce8da074d409 100644
--- a/tests/integration/states/test_docker_network.py
+++ b/tests/integration/states/test_docker_network.py
@@ -465,3 +465,34 @@ def test_present_with_custom_ipv6(self, ipv4_net, ipv6_net1, ipv6_net2):
             ret["comment"],
             "Network '{}' was replaced with updated config".format(ipv4_net.name),
         )
+
+    @with_network(subnet="10.247.197.96/27")
+    @pytest.mark.slow_test
+    def test_bridge_dupname_update(self, net):
+        # com.docker.network.bridge.name can not have names over 15 chars. so grab the last 8
+        self.assertSaltTrueReturn(
+            self.run_state(
+                "docker_network.present",
+                name=net.name,
+                subnet=net.subnet,
+                driver="bridge",
+                driver_opts=[{"com.docker.network.bridge.name": net.name[-8:]}],
+            )
+        )
+        # Second run to make sure everything is still fine.
+        ret = self.run_state(
+            "docker_network.present",
+            name=net.name,
+            subnet=net.subnet,
+            driver="bridge",
+            driver_opts=[{"com.docker.network.bridge.name": net.name[-8:]}],
+        )
+        self.assertSaltTrueReturn(ret)
+        ret = ret[next(iter(ret))]
+        self.assertEqual(ret["changes"], {})
+        self.assertEqual(
+            ret["comment"],
+            "Network '{}' already exists, and is configured as specified".format(
+                net.name
+            ),
+        )


Code review comments:
diff_hunk: @@ -644,11 +644,21 @@ def present(
             # wouldng't know if the IPv4 subnet in the existing network was
             # explicitly configured or was automatically assigned by Docker.
             enable_ipv6 = kwargs.pop("enable_ipv6", None)
+            kwargs2 = kwargs
path: salt/states/docker_network.py
text: @user1:
why kwargs2?