Repository: ansible/ansible

Issue:
FirewalldD Module Fails if Port is Already Opened
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report


##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
firewalld
##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.0.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Dec 18 2016, 07:03:39) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
```

##### CONFIGURATION
<!---
-->
##### OS / ENVIRONMENT
<!---

-->
OS Targeting, RHEL 7.3
##### SUMMARY
<!--- Explain the problem briefly -->

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Open Common Public Ports
  firewalld:
    port: "{{item.port}}"
    permanent: true
    state: enabled
    immediate: true
  with_items:
    - {port: '9080/tcp'}
    - {port: '9081/tcp'}
    - {port: '1443/tcp'}
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Expected results would be that if the the port is already opened, the firewalld module would gracefully notice that the port is already opened and skip the task. 

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
failed: [CPE-1] (item={u'port': u'9080/tcp'}) => {"failed": true, "item": {"port": "9080/tcp"}, "msg": "ERROR: Exception caught: ALREADY_ENABLED: '9080:tcp'"}
failed: [ICN-2] (item={u'port': u'1080/tcp'}) => {"failed": true, "item": {"port": "9081/tcp"}, "msg": "ERROR: Exception caught: org.fedoraproject.FirewallD1.Exception: ALREADY_ENABLED: '9081:tcp' already in 'public'"}
```



Discussion:
cc @maxamillion
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Was anyone able to replicate this?
I have been unable to reproduce this on both Fedora 25 or RHEL 7.3

Fedora 25:

```
[root@localhost ~]# cat /tmp/foo.yml
---
- name: test firewalld
  hosts: localhost
  tasks:

  - name: Open Common Public Ports
    firewalld:
      port: "{{item.port}}"
      permanent: true
      state: enabled
      immediate: true
    with_items:
      - {port: '9080/tcp'}
      - {port: '9081/tcp'}
      - {port: '1443/tcp'}
[root@localhost ~]# cat /etc/os-release
NAME=Fedora
VERSION="25 (Twenty Five)"
ID=fedora
VERSION_ID=25
PRETTY_NAME="Fedora 25 (Twenty Five)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:25"
HOME_URL="https://fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=25
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=25
PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy
[root@localhost ~]# ansible-playbook /tmp/foo.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [test firewalld] *************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]

TASK [Open Common Public Ports] ***************************************************************************************
ok: [localhost] => (item={u'port': u'9080/tcp'})
ok: [localhost] => (item={u'port': u'9081/tcp'})
ok: [localhost] => (item={u'port': u'1443/tcp'})

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

[root@localhost ~]# ansible-playbook /tmp/foo.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [test firewalld] *************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]

TASK [Open Common Public Ports] ***************************************************************************************
ok: [localhost] => (item={u'port': u'9080/tcp'})
ok: [localhost] => (item={u'port': u'9081/tcp'})
ok: [localhost] => (item={u'port': u'1443/tcp'})

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0
```

RHEL 7.3
```
[root@localhost ~]# cat /etc/os-release
NAME="Red Hat Enterprise Linux Server"
VERSION="7.3 (Maipo)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="7.3"
PRETTY_NAME="Red Hat Enterprise Linux"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:7.3:GA:server"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 7"
REDHAT_BUGZILLA_PRODUCT_VERSION=7.3
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="7.3"
[root@localhost ~]# cat /tmp/foo.yml
---
- name: test firewalld
  hosts: localhost
  tasks:

  - name: Open Common Public Ports
    firewalld:
      port: "{{item.port}}"
      permanent: true
      state: enabled
      immediate: true
    with_items:
      - {port: '9080/tcp'}
      - {port: '9081/tcp'}
      - {port: '1443/tcp'}
[root@localhost ~]# ansible-playbook /tmp/foo.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [test firewalld] *************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]

TASK [Open Common Public Ports] ***************************************************************************************
changed: [localhost] => (item={u'port': u'9080/tcp'})
changed: [localhost] => (item={u'port': u'9081/tcp'})
changed: [localhost] => (item={u'port': u'1443/tcp'})

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0

[root@localhost ~]# ansible-playbook /tmp/foo.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [test firewalld] *************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]

TASK [Open Common Public Ports] ***************************************************************************************
ok: [localhost] => (item={u'port': u'9080/tcp'})
ok: [localhost] => (item={u'port': u'9081/tcp'})
ok: [localhost] => (item={u'port': u'1443/tcp'})

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0

[root@localhost ~]# ansible-playbook /tmp/foo.yml
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [test firewalld] *************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]

TASK [Open Common Public Ports] ***************************************************************************************
ok: [localhost] => (item={u'port': u'9080/tcp'})
ok: [localhost] => (item={u'port': u'9081/tcp'})
ok: [localhost] => (item={u'port': u'1443/tcp'})

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0
```
I'm able to reproduce this on CentOS 7 with Ansible 2.3.1 by adding a leading whitespace to the port parameter value: 

```
    ...
    port: " {{item.port}}"
    ...
```
@vascobarroso :+1: I'll get a fix in. Thanks for the reproducer.

Resolving patch:
diff --git a/lib/ansible/modules/system/firewalld.py b/lib/ansible/modules/system/firewalld.py
--- a/lib/ansible/modules/system/firewalld.py
+++ b/lib/ansible/modules/system/firewalld.py
@@ -527,7 +527,7 @@ def main():
     source = module.params['source']
 
     if module.params['port'] is not None:
-        port, protocol = module.params['port'].split('/')
+        port, protocol = module.params['port'].strip().split('/')
         if protocol is None:
             module.fail_json(msg='improper port format (missing protocol?)')
     else:


Test patch: