Repository: cobbler/cobbler

Issue:
cobbler sync fails with a Type Error
### Describe the bug

<!--- A clear and concise description of what the bug is. -->

<!--- HINT: You can paste gist.github.com links for long logs or larger files -->

Running `cobbler sync` fails with a Type Error:

```
$ cobbler sync
...
Exception occurred: <class 'TypeError'>
Exception value: can't pickle _thread.RLock objects
Exception Info:
!!! TASK FAILED !!!
```

### Steps to reproduce

1. Create a distro
2. Create a profile
3. Run `cobbler sync`

### Expected behavior

<!--- A clear and concise description of what you expected to happen. -->

This command should not fail.

### Cobbler version

<!--- Paste output from `cobbler version` -->
````paste below
Cobbler 3.2.1
  source: ?, ?
  build time: Mon Jun 21 17:54:49 2021
````

### Operating system

<!--- On which operating system do you use Cobbler? -->

CentOS 8.

### Cobbler log

<!--- Paste (partial) output from `/var/log/cobbler/cobbler.log` -->
````paste below
[2021-06-21_231907_sync] 2021-06-21T23:19:08 - INFO | Exception occurred: <class 'TypeError'>
[2021-06-21_231907_sync] 2021-06-21T23:19:08 - INFO | Exception value: can't pickle _thread.RLock objects
[2021-06-21_231907_sync] 2021-06-21T23:19:08 - INFO | Exception Info:
  File "/usr/lib/python3.6/site-packages/cobbler/remote.py", line 96, in run
    rc = self._run(self)

  File "/usr/lib/python3.6/site-packages/cobbler/remote.py", line 212, in runner
    self.remote.api.sync(self.options.get("verbose", False), what=what)

  File "/usr/lib/python3.6/site-packages/cobbler/api.py", line 1379, in sync
    sync_obj.run()

  File "/usr/lib/python3.6/site-packages/cobbler/actions/sync.py", line 160, in run
    self.write_dhcp()

  File "/usr/lib/python3.6/site-packages/cobbler/actions/sync.py", line 242, in write_dhcp
    self.dhcp.write_configs()

  File "/usr/lib/python3.6/site-packages/cobbler/modules/managers/isc.py", line 406, in write_configs
    self.write_v4_config()

  File "/usr/lib/python3.6/site-packages/cobbler/modules/managers/isc.py", line 99, in write_v4_config
    interface = copy.deepcopy(system_interface)

  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)

  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)

  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)

  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)

  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)

  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)

  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)

  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)

  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)

  File "/usr/lib64/python3.6/copy.py", line 215, in _deepcopy_list
    append(deepcopy(a, memo))

  File "/usr/lib64/python3.6/copy.py", line 180, in deepcopy
    y = _reconstruct(x, memo, *rv)

  File "/usr/lib64/python3.6/copy.py", line 280, in _reconstruct
    state = deepcopy(state, memo)

  File "/usr/lib64/python3.6/copy.py", line 150, in deepcopy
    y = copier(x, memo)

  File "/usr/lib64/python3.6/copy.py", line 240, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)

  File "/usr/lib64/python3.6/copy.py", line 169, in deepcopy
    rv = reductor(4)l
````



Discussion:
This needs to use the new `to_dict` method to not fail. The logger and other internal attributes of an interface need to be excluded from the process.

Resolving patch:
diff --git a/cobbler/modules/managers/isc.py b/cobbler/modules/managers/isc.py
--- a/cobbler/modules/managers/isc.py
+++ b/cobbler/modules/managers/isc.py
@@ -96,7 +96,7 @@ def write_v4_config(self):
 
                 # We make a copy because we may modify it before adding it to the dhcp_tags and we don't want to affect
                 # the master copy.
-                interface = copy.deepcopy(system_interface)
+                interface = system_interface.to_dict()
 
                 if interface["if_gateway"]:
                     interface["gateway"] = interface["if_gateway"]
@@ -261,7 +261,7 @@ def write_v6_config(self):
 
                 # We make a copy because we may modify it before adding it to the dhcp_tags and we don't want to affect
                 # the master copy.
-                interface = copy.deepcopy(system_interface)
+                interface = system_interface.to_dict()
 
                 if interface["if_gateway"]:
                     interface["gateway"] = interface["if_gateway"]


Test patch: