We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Seport: support list input for ports
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Feature Idea

##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
seport

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.3.0
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
N/A

##### SUMMARY
<!--- Explain the problem briefly -->
It would be nice if the `ports` option allowed for a list of strings instead of just a string.

https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/seport.py#L234

##### 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 -->
##### EXPECTED RESULTS
```yaml
- seport:
    ports: 
    - "10000-10100"
    - "10112"
    proto: tcp
    setype: memcache_port_t
    state: present
```

##### ACTUAL RESULTS
```yaml
- seport:
    ports: 10000-10100,10112
    proto: tcp
    setype: memcache_port_t
    state: present
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansible/modules/system/seport.py`
Content:
```
1 #!/usr/bin/python
2 
3 # Copyright: (c) 2014, Dan Keder <dan.keder@gmail.com>
4 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5 
6 from __future__ import absolute_import, division, print_function
7 __metaclass__ = type
8 
9 ANSIBLE_METADATA = {'metadata_version': '1.1',
10                     'status': ['preview'],
11                     'supported_by': 'community'}
12 
13 DOCUMENTATION = '''
14 ---
15 module: seport
16 short_description: Manages SELinux network port type definitions
17 description:
18      - Manages SELinux network port type definitions.
19 version_added: "2.0"
20 options:
21   ports:
22     description:
23       - Ports or port ranges, separated by a comma.
24     required: true
25   proto:
26     description:
27       - Protocol for the specified port.
28     required: true
29     choices: [ tcp, udp ]
30   setype:
31     description:
32       - SELinux type for the specified port.
33     required: true
34   state:
35     description:
36       - Desired boolean value.
37     required: true
38     choices: [ absent, present ]
39     default: present
40   reload:
41     description:
42       - Reload SELinux policy after commit.
43     type: bool
44     default: 'yes'
45 notes:
46    - The changes are persistent across reboots.
47    - Not tested on any debian based system.
48 requirements:
49 - libselinux-python
50 - policycoreutils-python
51 author:
52 - Dan Keder
53 '''
54 
55 EXAMPLES = '''
56 - name: Allow Apache to listen on tcp port 8888
57   seport:
58     ports: 8888
59     proto: tcp
60     setype: http_port_t
61     state: present
62 
63 - name: Allow sshd to listen on tcp port 8991
64   seport:
65     ports: 8991
66     proto: tcp
67     setype: ssh_port_t
68     state: present
69 
70 - name: Allow memcached to listen on tcp ports 10000-10100 and 10112
71   seport:
72     ports: 10000-10100,10112
73     proto: tcp
74     setype: memcache_port_t
75     state: present
76 '''
77 
78 import traceback
79 
80 try:
81     import selinux
82     HAVE_SELINUX = True
83 except ImportError:
84     HAVE_SELINUX = False
85 
86 try:
87     import seobject
88     HAVE_SEOBJECT = True
89 except ImportError:
90     HAVE_SEOBJECT = False
91 
92 from ansible.module_utils.basic import AnsibleModule, HAVE_SELINUX
93 from ansible.module_utils._text import to_native
94 
95 
96 def semanage_port_get_ports(seport, setype, proto):
97     """ Get the list of ports that have the specified type definition.
98 
99     :param seport: Instance of seobject.portRecords
100 
101     :type setype: str
102     :param setype: SELinux type.
103 
104     :type proto: str
105     :param proto: Protocol ('tcp' or 'udp')
106 
107     :rtype: list
108     :return: List of ports that have the specified SELinux type.
109     """
110     records = seport.get_all_by_type()
111     if (setype, proto) in records:
112         return records[(setype, proto)]
113     else:
114         return []
115 
116 
117 def semanage_port_get_type(seport, port, proto):
118     """ Get the SELinux type of the specified port.
119 
120     :param seport: Instance of seobject.portRecords
121 
122     :type port: str
123     :param port: Port or port range (example: "8080", "8080-9090")
124 
125     :type proto: str
126     :param proto: Protocol ('tcp' or 'udp')
127 
128     :rtype: tuple
129     :return: Tuple containing the SELinux type and MLS/MCS level, or None if not found.
130     """
131     ports = port.split('-', 1)
132     if len(ports) == 1:
133         ports.extend(ports)
134     key = (int(ports[0]), int(ports[1]), proto)
135 
136     records = seport.get_all()
137     if key in records:
138         return records[key]
139     else:
140         return None
141 
142 
143 def semanage_port_add(module, ports, proto, setype, do_reload, serange='s0', sestore=''):
144     """ Add SELinux port type definition to the policy.
145 
146     :type module: AnsibleModule
147     :param module: Ansible module
148 
149     :type ports: list
150     :param ports: List of ports and port ranges to add (e.g. ["8080", "8080-9090"])
151 
152     :type proto: str
153     :param proto: Protocol ('tcp' or 'udp')
154 
155     :type setype: str
156     :param setype: SELinux type
157 
158     :type do_reload: bool
159     :param do_reload: Whether to reload SELinux policy after commit
160 
161     :type serange: str
162     :param serange: SELinux MLS/MCS range (defaults to 's0')
163 
164     :type sestore: str
165     :param sestore: SELinux store
166 
167     :rtype: bool
168     :return: True if the policy was changed, otherwise False
169     """
170     try:
171         seport = seobject.portRecords(sestore)
172         seport.set_reload(do_reload)
173         change = False
174         ports_by_type = semanage_port_get_ports(seport, setype, proto)
175         for port in ports:
176             if port not in ports_by_type:
177                 change = True
178                 port_type = semanage_port_get_type(seport, port, proto)
179                 if port_type is None and not module.check_mode:
180                     seport.add(port, proto, serange, setype)
181                 elif port_type is not None and not module.check_mode:
182                     seport.modify(port, proto, serange, setype)
183 
184     except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:
185         module.fail_json(msg="%s: %s\n" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())
186 
187     return change
188 
189 
190 def semanage_port_del(module, ports, proto, setype, do_reload, sestore=''):
191     """ Delete SELinux port type definition from the policy.
192 
193     :type module: AnsibleModule
194     :param module: Ansible module
195 
196     :type ports: list
197     :param ports: List of ports and port ranges to delete (e.g. ["8080", "8080-9090"])
198 
199     :type proto: str
200     :param proto: Protocol ('tcp' or 'udp')
201 
202     :type setype: str
203     :param setype: SELinux type.
204 
205     :type do_reload: bool
206     :param do_reload: Whether to reload SELinux policy after commit
207 
208     :type sestore: str
209     :param sestore: SELinux store
210 
211     :rtype: bool
212     :return: True if the policy was changed, otherwise False
213     """
214     try:
215         seport = seobject.portRecords(sestore)
216         seport.set_reload(do_reload)
217         change = False
218         ports_by_type = semanage_port_get_ports(seport, setype, proto)
219         for port in ports:
220             if port in ports_by_type:
221                 change = True
222                 if not module.check_mode:
223                     seport.delete(port, proto)
224 
225     except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:
226         module.fail_json(msg="%s: %s\n" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())
227 
228     return change
229 
230 
231 def main():
232     module = AnsibleModule(
233         argument_spec=dict(
234             ports=dict(type='str', required=True),
235             proto=dict(type='str', required=True, choices=['tcp', 'udp']),
236             setype=dict(type='str', required=True),
237             state=dict(type='str', required=True, choices=['absent', 'present']),
238             reload=dict(type='bool', default=True),
239         ),
240         supports_check_mode=True,
241     )
242 
243     if not HAVE_SELINUX:
244         module.fail_json(msg="This module requires libselinux-python")
245 
246     if not HAVE_SEOBJECT:
247         module.fail_json(msg="This module requires policycoreutils-python")
248 
249     if not selinux.is_selinux_enabled():
250         module.fail_json(msg="SELinux is disabled on this host.")
251 
252     ports = [x.strip() for x in str(module.params['ports']).split(',')]
253     proto = module.params['proto']
254     setype = module.params['setype']
255     state = module.params['state']
256     do_reload = module.params['reload']
257 
258     result = {
259         'ports': ports,
260         'proto': proto,
261         'setype': setype,
262         'state': state,
263     }
264 
265     if state == 'present':
266         result['changed'] = semanage_port_add(module, ports, proto, setype, do_reload)
267     elif state == 'absent':
268         result['changed'] = semanage_port_del(module, ports, proto, setype, do_reload)
269     else:
270         module.fail_json(msg='Invalid value of argument "state": {0}'.format(state))
271 
272     module.exit_json(**result)
273 
274 
275 if __name__ == '__main__':
276     main()
277
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/ansible/modules/system/seport.py b/lib/ansible/modules/system/seport.py
--- a/lib/ansible/modules/system/seport.py
+++ b/lib/ansible/modules/system/seport.py
@@ -15,12 +15,12 @@
 module: seport
 short_description: Manages SELinux network port type definitions
 description:
-     - Manages SELinux network port type definitions.
+    - Manages SELinux network port type definitions.
 version_added: "2.0"
 options:
   ports:
     description:
-      - Ports or port ranges, separated by a comma.
+      - Ports or port ranges. Can be a list (since 2.6) or comma separated string.
     required: true
   proto:
     description:
@@ -73,6 +73,15 @@
     proto: tcp
     setype: memcache_port_t
     state: present
+
+- name: Allow memcached to listen on tcp ports 10000-10100 and 10112
+  seport:
+    ports:
+      - 10000-10100
+      - 10112
+    proto: tcp
+    setype: memcache_port_t
+    state: present
 '''
 
 import traceback
@@ -231,7 +240,7 @@
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            ports=dict(type='str', required=True),
+            ports=dict(type='list', required=True),
             proto=dict(type='str', required=True, choices=['tcp', 'udp']),
             setype=dict(type='str', required=True),
             state=dict(type='str', required=True, choices=['absent', 'present']),
@@ -249,7 +258,7 @@
     if not selinux.is_selinux_enabled():
         module.fail_json(msg="SELinux is disabled on this host.")
 
-    ports = [x.strip() for x in str(module.params['ports']).split(',')]
+    ports = module.params['ports']
     proto = module.params['proto']
     setype = module.params['setype']
     state = module.params['state']

{"golden_diff": "diff --git a/lib/ansible/modules/system/seport.py b/lib/ansible/modules/system/seport.py\n--- a/lib/ansible/modules/system/seport.py\n+++ b/lib/ansible/modules/system/seport.py\n@@ -15,12 +15,12 @@\n module: seport\n short_description: Manages SELinux network port type definitions\n description:\n-     - Manages SELinux network port type definitions.\n+    - Manages SELinux network port type definitions.\n version_added: \"2.0\"\n options:\n   ports:\n     description:\n-      - Ports or port ranges, separated by a comma.\n+      - Ports or port ranges. Can be a list (since 2.6) or comma separated string.\n     required: true\n   proto:\n     description:\n@@ -73,6 +73,15 @@\n     proto: tcp\n     setype: memcache_port_t\n     state: present\n+\n+- name: Allow memcached to listen on tcp ports 10000-10100 and 10112\n+  seport:\n+    ports:\n+      - 10000-10100\n+      - 10112\n+    proto: tcp\n+    setype: memcache_port_t\n+    state: present\n '''\n \n import traceback\n@@ -231,7 +240,7 @@\n def main():\n     module = AnsibleModule(\n         argument_spec=dict(\n-            ports=dict(type='str', required=True),\n+            ports=dict(type='list', required=True),\n             proto=dict(type='str', required=True, choices=['tcp', 'udp']),\n             setype=dict(type='str', required=True),\n             state=dict(type='str', required=True, choices=['absent', 'present']),\n@@ -249,7 +258,7 @@\n     if not selinux.is_selinux_enabled():\n         module.fail_json(msg=\"SELinux is disabled on this host.\")\n \n-    ports = [x.strip() for x in str(module.params['ports']).split(',')]\n+    ports = module.params['ports']\n     proto = module.params['proto']\n     setype = module.params['setype']\n     state = module.params['state']\n", "issue": "Seport: support list input for ports\n<!---\r\nVerify first that your issue/request is not already reported on GitHub.\r\nAlso test if the latest release, and devel branch are affected too.\r\n-->\r\n\r\n##### ISSUE TYPE\r\n<!--- Pick one below and delete the rest -->\r\n - Feature Idea\r\n\r\n##### COMPONENT NAME\r\n<!---\r\nName of the module, plugin, task or feature\r\nDo not include extra details here, e.g. \"vyos_command\" not \"the network module vyos_command\" or the full path\r\n-->\r\nseport\r\n\r\n##### ANSIBLE VERSION\r\n<!--- Paste verbatim output from \"ansible --version\" between quotes below -->\r\n```\r\nansible 2.4.3.0\r\n```\r\n\r\n##### CONFIGURATION\r\n<!---\r\nIf using Ansible 2.4 or above, paste the results of \"ansible-config dump --only-changed\"\r\nOtherwise, mention any settings you have changed/added/removed in ansible.cfg\r\n(or using the ANSIBLE_* environment variables).\r\n-->\r\n\r\n##### OS / ENVIRONMENT\r\n<!---\r\nMention the OS you are running Ansible from, and the OS you are\r\nmanaging, or say \"N/A\" for anything that is not platform-specific.\r\nAlso mention the specific version of what you are trying to control,\r\ne.g. if this is a network bug the version of firmware on the network device.\r\n-->\r\nN/A\r\n\r\n##### SUMMARY\r\n<!--- Explain the problem briefly -->\r\nIt would be nice if the `ports` option allowed for a list of strings instead of just a string.\r\n\r\nhttps://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/seport.py#L234\r\n\r\n##### STEPS TO REPRODUCE\r\n<!---\r\nFor bugs, show exactly how to reproduce the problem, using a minimal test-case.\r\nFor new features, show how the feature would be used.\r\n-->\r\n\r\n<!--- Paste example playbooks or commands between quotes below -->\r\n##### EXPECTED RESULTS\r\n```yaml\r\n- seport:\r\n    ports: \r\n    - \"10000-10100\"\r\n    - \"10112\"\r\n    proto: tcp\r\n    setype: memcache_port_t\r\n    state: present\r\n```\r\n\r\n##### ACTUAL RESULTS\r\n```yaml\r\n- seport:\r\n    ports: 10000-10100,10112\r\n    proto: tcp\r\n    setype: memcache_port_t\r\n    state: present\r\n```\r\n\n", "before_files": [{"content": "#!/usr/bin/python\n\n# Copyright: (c) 2014, Dan Keder <dan.keder@gmail.com>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: seport\nshort_description: Manages SELinux network port type definitions\ndescription:\n     - Manages SELinux network port type definitions.\nversion_added: \"2.0\"\noptions:\n  ports:\n    description:\n      - Ports or port ranges, separated by a comma.\n    required: true\n  proto:\n    description:\n      - Protocol for the specified port.\n    required: true\n    choices: [ tcp, udp ]\n  setype:\n    description:\n      - SELinux type for the specified port.\n    required: true\n  state:\n    description:\n      - Desired boolean value.\n    required: true\n    choices: [ absent, present ]\n    default: present\n  reload:\n    description:\n      - Reload SELinux policy after commit.\n    type: bool\n    default: 'yes'\nnotes:\n   - The changes are persistent across reboots.\n   - Not tested on any debian based system.\nrequirements:\n- libselinux-python\n- policycoreutils-python\nauthor:\n- Dan Keder\n'''\n\nEXAMPLES = '''\n- name: Allow Apache to listen on tcp port 8888\n  seport:\n    ports: 8888\n    proto: tcp\n    setype: http_port_t\n    state: present\n\n- name: Allow sshd to listen on tcp port 8991\n  seport:\n    ports: 8991\n    proto: tcp\n    setype: ssh_port_t\n    state: present\n\n- name: Allow memcached to listen on tcp ports 10000-10100 and 10112\n  seport:\n    ports: 10000-10100,10112\n    proto: tcp\n    setype: memcache_port_t\n    state: present\n'''\n\nimport traceback\n\ntry:\n    import selinux\n    HAVE_SELINUX = True\nexcept ImportError:\n    HAVE_SELINUX = False\n\ntry:\n    import seobject\n    HAVE_SEOBJECT = True\nexcept ImportError:\n    HAVE_SEOBJECT = False\n\nfrom ansible.module_utils.basic import AnsibleModule, HAVE_SELINUX\nfrom ansible.module_utils._text import to_native\n\n\ndef semanage_port_get_ports(seport, setype, proto):\n    \"\"\" Get the list of ports that have the specified type definition.\n\n    :param seport: Instance of seobject.portRecords\n\n    :type setype: str\n    :param setype: SELinux type.\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :rtype: list\n    :return: List of ports that have the specified SELinux type.\n    \"\"\"\n    records = seport.get_all_by_type()\n    if (setype, proto) in records:\n        return records[(setype, proto)]\n    else:\n        return []\n\n\ndef semanage_port_get_type(seport, port, proto):\n    \"\"\" Get the SELinux type of the specified port.\n\n    :param seport: Instance of seobject.portRecords\n\n    :type port: str\n    :param port: Port or port range (example: \"8080\", \"8080-9090\")\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :rtype: tuple\n    :return: Tuple containing the SELinux type and MLS/MCS level, or None if not found.\n    \"\"\"\n    ports = port.split('-', 1)\n    if len(ports) == 1:\n        ports.extend(ports)\n    key = (int(ports[0]), int(ports[1]), proto)\n\n    records = seport.get_all()\n    if key in records:\n        return records[key]\n    else:\n        return None\n\n\ndef semanage_port_add(module, ports, proto, setype, do_reload, serange='s0', sestore=''):\n    \"\"\" Add SELinux port type definition to the policy.\n\n    :type module: AnsibleModule\n    :param module: Ansible module\n\n    :type ports: list\n    :param ports: List of ports and port ranges to add (e.g. [\"8080\", \"8080-9090\"])\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :type setype: str\n    :param setype: SELinux type\n\n    :type do_reload: bool\n    :param do_reload: Whether to reload SELinux policy after commit\n\n    :type serange: str\n    :param serange: SELinux MLS/MCS range (defaults to 's0')\n\n    :type sestore: str\n    :param sestore: SELinux store\n\n    :rtype: bool\n    :return: True if the policy was changed, otherwise False\n    \"\"\"\n    try:\n        seport = seobject.portRecords(sestore)\n        seport.set_reload(do_reload)\n        change = False\n        ports_by_type = semanage_port_get_ports(seport, setype, proto)\n        for port in ports:\n            if port not in ports_by_type:\n                change = True\n                port_type = semanage_port_get_type(seport, port, proto)\n                if port_type is None and not module.check_mode:\n                    seport.add(port, proto, serange, setype)\n                elif port_type is not None and not module.check_mode:\n                    seport.modify(port, proto, serange, setype)\n\n    except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:\n        module.fail_json(msg=\"%s: %s\\n\" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())\n\n    return change\n\n\ndef semanage_port_del(module, ports, proto, setype, do_reload, sestore=''):\n    \"\"\" Delete SELinux port type definition from the policy.\n\n    :type module: AnsibleModule\n    :param module: Ansible module\n\n    :type ports: list\n    :param ports: List of ports and port ranges to delete (e.g. [\"8080\", \"8080-9090\"])\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :type setype: str\n    :param setype: SELinux type.\n\n    :type do_reload: bool\n    :param do_reload: Whether to reload SELinux policy after commit\n\n    :type sestore: str\n    :param sestore: SELinux store\n\n    :rtype: bool\n    :return: True if the policy was changed, otherwise False\n    \"\"\"\n    try:\n        seport = seobject.portRecords(sestore)\n        seport.set_reload(do_reload)\n        change = False\n        ports_by_type = semanage_port_get_ports(seport, setype, proto)\n        for port in ports:\n            if port in ports_by_type:\n                change = True\n                if not module.check_mode:\n                    seport.delete(port, proto)\n\n    except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:\n        module.fail_json(msg=\"%s: %s\\n\" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())\n\n    return change\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            ports=dict(type='str', required=True),\n            proto=dict(type='str', required=True, choices=['tcp', 'udp']),\n            setype=dict(type='str', required=True),\n            state=dict(type='str', required=True, choices=['absent', 'present']),\n            reload=dict(type='bool', default=True),\n        ),\n        supports_check_mode=True,\n    )\n\n    if not HAVE_SELINUX:\n        module.fail_json(msg=\"This module requires libselinux-python\")\n\n    if not HAVE_SEOBJECT:\n        module.fail_json(msg=\"This module requires policycoreutils-python\")\n\n    if not selinux.is_selinux_enabled():\n        module.fail_json(msg=\"SELinux is disabled on this host.\")\n\n    ports = [x.strip() for x in str(module.params['ports']).split(',')]\n    proto = module.params['proto']\n    setype = module.params['setype']\n    state = module.params['state']\n    do_reload = module.params['reload']\n\n    result = {\n        'ports': ports,\n        'proto': proto,\n        'setype': setype,\n        'state': state,\n    }\n\n    if state == 'present':\n        result['changed'] = semanage_port_add(module, ports, proto, setype, do_reload)\n    elif state == 'absent':\n        result['changed'] = semanage_port_del(module, ports, proto, setype, do_reload)\n    else:\n        module.fail_json(msg='Invalid value of argument \"state\": {0}'.format(state))\n\n    module.exit_json(**result)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/seport.py"}], "after_files": [{"content": "#!/usr/bin/python\n\n# Copyright: (c) 2014, Dan Keder <dan.keder@gmail.com>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: seport\nshort_description: Manages SELinux network port type definitions\ndescription:\n    - Manages SELinux network port type definitions.\nversion_added: \"2.0\"\noptions:\n  ports:\n    description:\n      - Ports or port ranges. Can be a list (since 2.6) or comma separated string.\n    required: true\n  proto:\n    description:\n      - Protocol for the specified port.\n    required: true\n    choices: [ tcp, udp ]\n  setype:\n    description:\n      - SELinux type for the specified port.\n    required: true\n  state:\n    description:\n      - Desired boolean value.\n    required: true\n    choices: [ absent, present ]\n    default: present\n  reload:\n    description:\n      - Reload SELinux policy after commit.\n    type: bool\n    default: 'yes'\nnotes:\n   - The changes are persistent across reboots.\n   - Not tested on any debian based system.\nrequirements:\n- libselinux-python\n- policycoreutils-python\nauthor:\n- Dan Keder\n'''\n\nEXAMPLES = '''\n- name: Allow Apache to listen on tcp port 8888\n  seport:\n    ports: 8888\n    proto: tcp\n    setype: http_port_t\n    state: present\n\n- name: Allow sshd to listen on tcp port 8991\n  seport:\n    ports: 8991\n    proto: tcp\n    setype: ssh_port_t\n    state: present\n\n- name: Allow memcached to listen on tcp ports 10000-10100 and 10112\n  seport:\n    ports: 10000-10100,10112\n    proto: tcp\n    setype: memcache_port_t\n    state: present\n\n- name: Allow memcached to listen on tcp ports 10000-10100 and 10112\n  seport:\n    ports:\n      - 10000-10100\n      - 10112\n    proto: tcp\n    setype: memcache_port_t\n    state: present\n'''\n\nimport traceback\n\ntry:\n    import selinux\n    HAVE_SELINUX = True\nexcept ImportError:\n    HAVE_SELINUX = False\n\ntry:\n    import seobject\n    HAVE_SEOBJECT = True\nexcept ImportError:\n    HAVE_SEOBJECT = False\n\nfrom ansible.module_utils.basic import AnsibleModule, HAVE_SELINUX\nfrom ansible.module_utils._text import to_native\n\n\ndef semanage_port_get_ports(seport, setype, proto):\n    \"\"\" Get the list of ports that have the specified type definition.\n\n    :param seport: Instance of seobject.portRecords\n\n    :type setype: str\n    :param setype: SELinux type.\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :rtype: list\n    :return: List of ports that have the specified SELinux type.\n    \"\"\"\n    records = seport.get_all_by_type()\n    if (setype, proto) in records:\n        return records[(setype, proto)]\n    else:\n        return []\n\n\ndef semanage_port_get_type(seport, port, proto):\n    \"\"\" Get the SELinux type of the specified port.\n\n    :param seport: Instance of seobject.portRecords\n\n    :type port: str\n    :param port: Port or port range (example: \"8080\", \"8080-9090\")\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :rtype: tuple\n    :return: Tuple containing the SELinux type and MLS/MCS level, or None if not found.\n    \"\"\"\n    ports = port.split('-', 1)\n    if len(ports) == 1:\n        ports.extend(ports)\n    key = (int(ports[0]), int(ports[1]), proto)\n\n    records = seport.get_all()\n    if key in records:\n        return records[key]\n    else:\n        return None\n\n\ndef semanage_port_add(module, ports, proto, setype, do_reload, serange='s0', sestore=''):\n    \"\"\" Add SELinux port type definition to the policy.\n\n    :type module: AnsibleModule\n    :param module: Ansible module\n\n    :type ports: list\n    :param ports: List of ports and port ranges to add (e.g. [\"8080\", \"8080-9090\"])\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :type setype: str\n    :param setype: SELinux type\n\n    :type do_reload: bool\n    :param do_reload: Whether to reload SELinux policy after commit\n\n    :type serange: str\n    :param serange: SELinux MLS/MCS range (defaults to 's0')\n\n    :type sestore: str\n    :param sestore: SELinux store\n\n    :rtype: bool\n    :return: True if the policy was changed, otherwise False\n    \"\"\"\n    try:\n        seport = seobject.portRecords(sestore)\n        seport.set_reload(do_reload)\n        change = False\n        ports_by_type = semanage_port_get_ports(seport, setype, proto)\n        for port in ports:\n            if port not in ports_by_type:\n                change = True\n                port_type = semanage_port_get_type(seport, port, proto)\n                if port_type is None and not module.check_mode:\n                    seport.add(port, proto, serange, setype)\n                elif port_type is not None and not module.check_mode:\n                    seport.modify(port, proto, serange, setype)\n\n    except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:\n        module.fail_json(msg=\"%s: %s\\n\" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())\n\n    return change\n\n\ndef semanage_port_del(module, ports, proto, setype, do_reload, sestore=''):\n    \"\"\" Delete SELinux port type definition from the policy.\n\n    :type module: AnsibleModule\n    :param module: Ansible module\n\n    :type ports: list\n    :param ports: List of ports and port ranges to delete (e.g. [\"8080\", \"8080-9090\"])\n\n    :type proto: str\n    :param proto: Protocol ('tcp' or 'udp')\n\n    :type setype: str\n    :param setype: SELinux type.\n\n    :type do_reload: bool\n    :param do_reload: Whether to reload SELinux policy after commit\n\n    :type sestore: str\n    :param sestore: SELinux store\n\n    :rtype: bool\n    :return: True if the policy was changed, otherwise False\n    \"\"\"\n    try:\n        seport = seobject.portRecords(sestore)\n        seport.set_reload(do_reload)\n        change = False\n        ports_by_type = semanage_port_get_ports(seport, setype, proto)\n        for port in ports:\n            if port in ports_by_type:\n                change = True\n                if not module.check_mode:\n                    seport.delete(port, proto)\n\n    except (ValueError, IOError, KeyError, OSError, RuntimeError) as e:\n        module.fail_json(msg=\"%s: %s\\n\" % (e.__class__.__name__, to_native(e)), exception=traceback.format_exc())\n\n    return change\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            ports=dict(type='list', required=True),\n            proto=dict(type='str', required=True, choices=['tcp', 'udp']),\n            setype=dict(type='str', required=True),\n            state=dict(type='str', required=True, choices=['absent', 'present']),\n            reload=dict(type='bool', default=True),\n        ),\n        supports_check_mode=True,\n    )\n\n    if not HAVE_SELINUX:\n        module.fail_json(msg=\"This module requires libselinux-python\")\n\n    if not HAVE_SEOBJECT:\n        module.fail_json(msg=\"This module requires policycoreutils-python\")\n\n    if not selinux.is_selinux_enabled():\n        module.fail_json(msg=\"SELinux is disabled on this host.\")\n\n    ports = module.params['ports']\n    proto = module.params['proto']\n    setype = module.params['setype']\n    state = module.params['state']\n    do_reload = module.params['reload']\n\n    result = {\n        'ports': ports,\n        'proto': proto,\n        'setype': setype,\n        'state': state,\n    }\n\n    if state == 'present':\n        result['changed'] = semanage_port_add(module, ports, proto, setype, do_reload)\n    elif state == 'absent':\n        result['changed'] = semanage_port_del(module, ports, proto, setype, do_reload)\n    else:\n        module.fail_json(msg='Invalid value of argument \"state\": {0}'.format(state))\n\n    module.exit_json(**result)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/seport.py"}]}