Repository: ansible-collections/community.general

Issue:
nmcli error while adding mac to existing connection
### Summary

Adding a mac address to an exisitng and previously mac-less connection errors out, because value is `None` and code calls `upper()` on it. 

    Traceback (most recent call last):
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 107, in <module>
        _ansiballz_main()
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 99, in _ansiballz_main
        invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 47, in invoke_module
        runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.net_tools.nmcli', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.net_tools.nmcli', _modlib_path=modlib_path),
    File "/usr/lib64/python3.10/runpy.py", line 224, in run_module
        return _run_module_code(code, init_globals, run_name, mod_spec)
    File "/usr/lib64/python3.10/runpy.py", line 96, in _run_module_code
        _run_code(code, mod_globals, init_globals,
    File "/usr/lib64/python3.10/runpy.py", line 86, in _run_code
        exec(code, run_globals)
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2368, in <module>
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2330, in main
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2143, in is_connection_changed
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2095, in _compare_conn_params
    AttributeError: 'NoneType' object has no attribute 'upper'


### Issue Type

Bug Report

### Component Name

nmcli

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.12.7]
  config file = /home/giorgio/Projects/infra/ansible.cfg
  configured module search path = ['/home/giorgio/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.10/site-packages/ansible
  ansible collection location = /home/giorgio/Projects/infra/galaxy/collections
  executable location = /usr/bin/ansible
  python version = 3.10.6 (main, Aug  2 2022, 00:00:00) [GCC 12.1.1 20220507 (Red Hat 12.1.1-1)]
  jinja version = 3.0.3
  libyaml = True
```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general

Collection        Version
----------------- -------
community.general 5.5.0  
```


### Configuration

*no relevant changes to default config*

### OS / Environment

Fedora f36 (irrelevant)

### Steps to Reproduce

1. create a new connection with `community.general.nmcli` (or by other means) without assigning  a mac
2. use `community.general.nmcli` to assign a mac

### Expected Results

it should work

### Actual Results

(see error above)


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct
nmcli error while adding mac to existing connection
### Summary

Adding a mac address to an exisitng and previously mac-less connection errors out, because value is `None` and code calls `upper()` on it. 

    Traceback (most recent call last):
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 107, in <module>
        _ansiballz_main()
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 99, in _ansiballz_main
        invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
    File "/home/user/.ansible/tmp/ansible-tmp-1663420215.47344-164730-139061857592873/AnsiballZ_nmcli.py", line 47, in invoke_module
        runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.net_tools.nmcli', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.net_tools.nmcli', _modlib_path=modlib_path),
    File "/usr/lib64/python3.10/runpy.py", line 224, in run_module
        return _run_module_code(code, init_globals, run_name, mod_spec)
    File "/usr/lib64/python3.10/runpy.py", line 96, in _run_module_code
        _run_code(code, mod_globals, init_globals,
    File "/usr/lib64/python3.10/runpy.py", line 86, in _run_code
        exec(code, run_globals)
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2368, in <module>
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2330, in main
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2143, in is_connection_changed
    File "/tmp/ansible_community.general.nmcli_payload_5wdkozfd/ansible_community.general.nmcli_payload.zip/ansible_collections/community/general/plugins/modules/net_tools/nmcli.py", line 2095, in _compare_conn_params
    AttributeError: 'NoneType' object has no attribute 'upper'


### Issue Type

Bug Report

### Component Name

nmcli

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.12.7]
  config file = /home/giorgio/Projects/infra/ansible.cfg
  configured module search path = ['/home/giorgio/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.10/site-packages/ansible
  ansible collection location = /home/giorgio/Projects/infra/galaxy/collections
  executable location = /usr/bin/ansible
  python version = 3.10.6 (main, Aug  2 2022, 00:00:00) [GCC 12.1.1 20220507 (Red Hat 12.1.1-1)]
  jinja version = 3.0.3
  libyaml = True
```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general

Collection        Version
----------------- -------
community.general 5.5.0  
```


### Configuration

*no relevant changes to default config*

### OS / Environment

Fedora f36 (irrelevant)

### Steps to Reproduce

1. create a new connection with `community.general.nmcli` (or by other means) without assigning  a mac
2. use `community.general.nmcli` to assign a mac

### Expected Results

it should work

### Actual Results

(see error above)


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/net_tools/nmcli.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/net_tools/nmcli.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @alcamie101
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
The issue is around [line 2098 of nmcli.py](https://github.com/ansible-collections/community.general/blob/b4f89b78dd43f75f434db3086d5302d104af070d/plugins/modules/net_tools/nmcli.py#L2098):

    if key == self.mac_setting:
        # MAC addresses are case insensitive, nmcli always reports them in uppercase
        value = value.upper()
        # ensure current_value is also converted to uppercase in case nmcli changes behaviour
        current_value = current_value.upper()

Files identified in the description:
* [`plugins/modules/net_tools/nmcli.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/net_tools/nmcli.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @alcamie101
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
The issue is around [line 2098 of nmcli.py](https://github.com/ansible-collections/community.general/blob/b4f89b78dd43f75f434db3086d5302d104af070d/plugins/modules/net_tools/nmcli.py#L2098):

    if key == self.mac_setting:
        # MAC addresses are case insensitive, nmcli always reports them in uppercase
        value = value.upper()
        # ensure current_value is also converted to uppercase in case nmcli changes behaviour
        current_value = current_value.upper()


Resolving patch:
diff --git a/plugins/modules/net_tools/nmcli.py b/plugins/modules/net_tools/nmcli.py
--- a/plugins/modules/net_tools/nmcli.py
+++ b/plugins/modules/net_tools/nmcli.py
@@ -2099,15 +2099,18 @@ def _compare_conn_params(self, conn_info, options):
                     # MAC addresses are case insensitive, nmcli always reports them in uppercase
                     value = value.upper()
                     # ensure current_value is also converted to uppercase in case nmcli changes behaviour
-                    current_value = current_value.upper()
+                    if current_value:
+                        current_value = current_value.upper()
                 if key == 'gsm.apn':
                     # Depending on version nmcli adds double-qoutes to gsm.apn
                     # Need to strip them in order to compare both
-                    current_value = current_value.strip('"')
+                    if current_value:
+                        current_value = current_value.strip('"')
                 if key == self.mtu_setting and self.mtu is None:
                     self.mtu = 0
                 if key == 'vpn.data':
-                    current_value = sorted(re.sub(r'\s*=\s*', '=', part.strip(), count=1) for part in current_value.split(','))
+                    if current_value:
+                        current_value = sorted(re.sub(r'\s*=\s*', '=', part.strip(), count=1) for part in current_value.split(','))
                     value = sorted(part.strip() for part in value.split(','))
             else:
                 # parameter does not exist


Test patch: