From 7ad8f6b1761e9e33a8d19e70856c77e3582b9d40 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Tue, 13 Aug 2013 09:27:45 -0500 Subject: [PATCH 1/3] added firewalld module update with feedback from pull request --- library/net_infrastructure/firewalld | 288 +++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 library/net_infrastructure/firewalld diff --git a/library/net_infrastructure/firewalld b/library/net_infrastructure/firewalld new file mode 100644 index 0000000000..5e16ac4734 --- /dev/null +++ b/library/net_infrastructure/firewalld @@ -0,0 +1,288 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, Adam Miller (maxamillion@fedoraproject.org) +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: firewalld +short_description: Manage arbitrary ports/services with firewalld +description: + - This module allows for addition or deletion of services and ports either tcp or udp in either running or permanent firewalld rules +version_added: "1.3" +options: + service: + description: + - "Name of a service to add/remove to/from firewalld - service must be listed in /etc/services" + required: false + default: null + port: + description: + - "Name of a port to add/remove to/from firewalld must be in the form PORT/PROTOCOL" + required: false + default: null + zone: + description: + - 'The firewalld zone to add/remove to/from (NOTE: default zone can be configured per system but "public" is default from upstream. Available choices can be extended based on per-system configs, listed here are "out of the box" defaults).' + required: false + default: system-default(public) + choices: [ "work", "drop", "internal", "external", "trusted", "home", "dmz", "public", "block"] + permanent: + description: + - "Should this configuration be in the running firewalld configuration or persist across reboots" + required: true + default: true + state: + description: + - "Should this port accept(enabled) or reject(disabled) connections" + required: true + default: enabled + timeout: + description: + - "The amount of time the rule should be in effect for when non-permanent" + required: false + default: 0 +notes: + - Not tested on any debian based system +requirements: [ firewalld ] +author: Adam Miller +''' + +EXAMPLES = ''' +- firewalld: service=https permanent=true state=enabled +- firewalld: port=8081/tcp permanent=true state=disabled +- firewalld: zone=dmz service=http permanent=true state=enabled +''' + +import os +import re +import sys + +try: + from firewall.client import FirewallClient + fw = FirewallClient() +except ImportError: + print "fail=True msg='firewalld required for this module'" + sys.exit(1) + +################ +# port handling +# +def get_port_enabled(zone, port_proto): + if port_proto in fw.getPorts(zone): + return True + else: + return False + +def set_port_enabled(zone, port, protocol, timeout): + fw.addPort(zone, port, protocol, timeout) + +def set_port_disabled(zone, port, protocol): + fw.removePort(zone, port, protocol) + +def get_port_enabled_permanent(zone, port_proto): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + if tuple(port_proto) in fw_settings.getPorts(): + return True + else: + return False + +def set_port_enabled_permanent(zone, port, protocol): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.addPort(port, protocol) + fw_zone.update(fw_settings) + +def set_port_disabled_permanent(zone, port, protocol): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.removePort(port, protocol) + fw_zone.update(fw_settings) + + +#################### +# service handling +# +def get_service_enabled(zone): + if service in fw.getServices(zone): + return True + else: + return False + +def set_service_enabled(zone, service, timeout): + fw.addService(zone, service, timeout) + +def set_service_disabled(zone, service): + fw.removeService(zone, service) + +def get_service_enabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + if service in fw_settings.getServices(): + return True + else: + return False + +def set_service_enabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.addService(service) + fw_zone.update(fw_settings) + +def set_service_disabled_permanent(zone, service): + fw_zone = fw.config().getZoneByName(zone) + fw_settings = fw_zone.getSettings() + fw_settings.removeService(service) + fw_zone.update(fw_settings) + +def main(): + + module = AnsibleModule( + argument_spec = dict( + service=dict(required=False,default=None), + port=dict(required=False,default=None), + zone=dict(required=False,default=None), + permanent=dict(type='bool',required=True), + state=dict(choices=['enabled', 'disabled'], required=True), + timeout=dict(required=False,default=0), + ), + supports_check_mode=True + ) + + ## Global Vars + changed=False + msgs = [] + service = module.params['service'] + + if module.params['port'] != None: + port, protocol = module.params['port'].split('/') + if protocol == None: + module.fail_json(msg='improper port format (missing protocol?)') + else: + port = None + + if module.params['zone'] != None: + zone = module.params['zone'] + else: + zone = fw.getDefaultZone() + + permanent = module.params['permanent'] + desired_state = module.params['state'] + timeout = module.params['timeout'] + + ## Check for firewalld running + if fw.connected == False: + module.fail_json(msg='firewalld service must be running') + + if service != None and port != None: + module.fail_json(msg='can only operate on port or service at once') + + if service != None: + if permanent: + is_enabled = get_service_enabled_permanent(zone, service) + msgs.append('Permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_service_enabled_permanent(zone, service) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_service_disabled_permanent(zone, service) + changed=True + else: + is_enabled = get_service_enabled(zone, service) + msgs.append('Non-permanent operation') + + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_service_enabled(zone, service, timeout) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_service_disabled(zone, service) + changed=True + + if changed == True: + msgs.append("Changed service %s to %s" % (service, desired_state)) + + if port != None: + if permanent: + is_enabled = get_port_enabled_permanent(zone, [port, protocol]) + msgs.append('Permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_port_enabled_permanent(zone, port, protocol) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_port_disabled_permanent(zone, port, protocol) + changed=True + else: + is_enabled = get_port_enabled(zone, [port,protocol]) + msgs.append('Non-permanent operation') + + if desired_state == "enabled": + if is_enabled == False: + if module.check_mode: + module.exit_json(changed=True) + + set_port_enabled(zone, port, protocol, timeout) + changed=True + elif desired_state == "disabled": + if is_enabled == True: + if module.check_mode: + module.exit_json(changed=True) + + set_port_disabled(zone, port, protocol) + changed=True + + if changed == True: + msgs.append("Changed port %s to %s" % ("%s/%s" % (port, protocol), \ + desired_state)) + + module.exit_json(changed=changed, msg=', '.join(msgs)) + + +################################################# +# include magic from lib/ansible/module_common.py +#<> + +main() + From 50adda50962cf1a3d1b6aacc94d669df80be97a6 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Fri, 16 Aug 2013 17:29:57 -0500 Subject: [PATCH 2/3] added version checking, doesn't work in older versions --- library/net_infrastructure/firewalld | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/net_infrastructure/firewalld b/library/net_infrastructure/firewalld index 5e16ac4734..531e48a539 100644 --- a/library/net_infrastructure/firewalld +++ b/library/net_infrastructure/firewalld @@ -59,7 +59,7 @@ options: default: 0 notes: - Not tested on any debian based system -requirements: [ firewalld ] +requirements: [ firewalld >= 0.2.11 ] author: Adam Miller ''' @@ -74,6 +74,9 @@ import re import sys try: + import firewall.config + FW_VERSION = firewall.config.VERSION + from firewall.client import FirewallClient fw = FirewallClient() except ImportError: @@ -165,6 +168,10 @@ def main(): supports_check_mode=True ) + ## Pre-run version checking + if FW_VERSION < "0.2.11": + module.fail_json(msg='unsupported version of firewalld, requires >= 2.0.11') + ## Global Vars changed=False msgs = [] From 4220c3cc30b11351457d7e779cbf5b6a1d9b80f3 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Mon, 9 Sep 2013 10:03:59 -0500 Subject: [PATCH 3/3] added try/catch around .connected call --- library/net_infrastructure/firewalld | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/net_infrastructure/firewalld b/library/net_infrastructure/firewalld index 531e48a539..01d4f3fae6 100644 --- a/library/net_infrastructure/firewalld +++ b/library/net_infrastructure/firewalld @@ -194,8 +194,12 @@ def main(): timeout = module.params['timeout'] ## Check for firewalld running - if fw.connected == False: - module.fail_json(msg='firewalld service must be running') + try: + if fw.connected == False: + module.fail_json(msg='firewalld service must be running') + except AttributeError: + module.fail_json(msg="firewalld connection can't be established,\ + version likely too old. Requires firewalld >= 2.0.11") if service != None and port != None: module.fail_json(msg='can only operate on port or service at once')