def _nested_output(obj):
    '''
    Serialize obj and format for output.
    '''
    nested.__opts__ = __opts__
    ret = nested.output(obj).rstrip()
    return ret
def _nested_output(obj):
    '''
    Serialize obj and format for output.
    '''
    nested.__opts__ = __opts__
    ret = nested.output(obj).rstrip()
    return ret
예제 #3
0
def _nested_output(obj):
    '''
    Serialize obj and format for output
    '''
    # Explicit late import to avoid circular import
    from salt.output import nested
    nested.__opts__ = {}
    ret = nested.output(obj).rstrip()
    return ret
예제 #4
0
def _nested_output(obj):
    '''
    Serialize obj and format for output
    '''
    # Explicit late import to avoid circular import
    from salt.output import nested
    nested.__opts__ = {}
    ret = nested.output(obj).rstrip()
    return ret
예제 #5
0
 def test_output_with_indent(self):
     # Everything must be indented by exactly two spaces
     # (using nested_indent=2 sent to nested.output as kwarg)
     expected_output_str = (
         '  \x1b[0;36m----------\x1b[0;0m\n  \x1b[0;36mlocal\x1b[0;0m:\n      \x1b[0;36m----------\x1b[0;0m\n'
         '      \x1b[0;36margs\x1b[0;0m:\n          \x1b[0;1;33m- 1\x1b[0;0m\n          \x1b[0;32m- two\x1b[0;0m\n'
         '          \x1b[0;1;33m- 3.1\x1b[0;0m\n      \x1b[0;36mkwargs\x1b[0;0m:\n'
         '          \x1b[0;36m----------\x1b[0;0m\n          \x1b[0;36m__pub_fun\x1b[0;0m:\n'
         '              \x1b[0;32mtest.arg\x1b[0;0m\n          \x1b[0;36m__pub_jid\x1b[0;0m:\n'
         '              \x1b[0;32m20171207105927331329\x1b[0;0m\n          \x1b[0;36m__pub_pid\x1b[0;0m:\n'
         '              \x1b[0;1;33m25938\x1b[0;0m\n          \x1b[0;36m__pub_tgt\x1b[0;0m:\n'
         '              \x1b[0;32msalt-call\x1b[0;0m\n          \x1b[0;36mtxt\x1b[0;0m:\n'
         '              \x1b[0;32mhello\x1b[0;0m\n          \x1b[0;36mwow\x1b[0;0m:\n'
         '              \x1b[0;36m----------\x1b[0;0m\n              \x1b[0;36ma\x1b[0;0m:\n'
         '                  \x1b[0;1;33m1\x1b[0;0m\n              \x1b[0;36mb\x1b[0;0m:\n'
         '                  \x1b[0;32mhello\x1b[0;0m')
     ret = nested.output(self.data, nested_indent=2)
     self.assertEqual(ret, expected_output_str)
예제 #6
0
 def test_output_with_colors(self):
     # Should look exactly like that, with the default color scheme:
     #
     # local:
     #    ----------
     #    args:
     #        - 1
     #        - two
     #        - 3.1
     #    kwargs:
     #        ----------
     #        __pub_fun:
     #            test.arg
     #        __pub_jid:
     #            20171207105927331329
     #        __pub_pid:
     #            25938
     #        __pub_tgt:
     #            salt-call
     #        txt:
     #            hello
     #        wow:
     #            ----------
     #            a:
     #                1
     #            b:
     #                hello
     expected_output_str = (
         "\x1b[0;36mlocal\x1b[0;0m:\n    \x1b[0;36m----------\x1b[0;0m\n   "
         " \x1b[0;36margs\x1b[0;0m:\n        \x1b[0;1;33m- 1\x1b[0;0m\n       "
         " \x1b[0;32m- two\x1b[0;0m\n        \x1b[0;1;33m- 3.1\x1b[0;0m\n   "
         " \x1b[0;36mkwargs\x1b[0;0m:\n        \x1b[0;36m----------\x1b[0;0m\n      "
         "  \x1b[0;36m__pub_fun\x1b[0;0m:\n            \x1b[0;32mtest.arg\x1b[0;0m\n"
         "        \x1b[0;36m__pub_jid\x1b[0;0m:\n           "
         " \x1b[0;32m20171207105927331329\x1b[0;0m\n       "
         " \x1b[0;36m__pub_pid\x1b[0;0m:\n            \x1b[0;1;33m25938\x1b[0;0m\n  "
         "      \x1b[0;36m__pub_tgt\x1b[0;0m:\n           "
         " \x1b[0;32msalt-call\x1b[0;0m\n        \x1b[0;36mtxt\x1b[0;0m:\n          "
         "  \x1b[0;32mhello\x1b[0;0m\n        \x1b[0;36mwow\x1b[0;0m:\n           "
         " \x1b[0;36m----------\x1b[0;0m\n            \x1b[0;36ma\x1b[0;0m:\n       "
         "         \x1b[0;1;33m1\x1b[0;0m\n            \x1b[0;36mb\x1b[0;0m:\n      "
         "          \x1b[0;32mhello\x1b[0;0m")
     ret = nested.output(self.data)
     self.assertEqual(ret, expected_output_str)
예제 #7
0
 def test_output_with_retcode(self):
     # Non-zero retcode should change the colors
     # Same output format as above, just different colors
     expected_output_str = (
         '\x1b[0;31mlocal\x1b[0;0m:\n    \x1b[0;31m----------\x1b[0;0m\n    \x1b[0;31margs\x1b[0;0m:\n'
         '        \x1b[0;1;33m- 1\x1b[0;0m\n        \x1b[0;32m- two\x1b[0;0m\n        \x1b[0;1;33m- 3.1\x1b[0;0m\n'
         '    \x1b[0;31mkwargs\x1b[0;0m:\n        \x1b[0;31m----------\x1b[0;0m\n'
         '        \x1b[0;31m__pub_fun\x1b[0;0m:\n            \x1b[0;32mtest.arg\x1b[0;0m\n'
         '        \x1b[0;31m__pub_jid\x1b[0;0m:\n            \x1b[0;32m20171207105927331329\x1b[0;0m\n'
         '        \x1b[0;31m__pub_pid\x1b[0;0m:\n            \x1b[0;1;33m25938\x1b[0;0m\n'
         '        \x1b[0;31m__pub_tgt\x1b[0;0m:\n            \x1b[0;32msalt-call\x1b[0;0m\n'
         '        \x1b[0;31mtxt\x1b[0;0m:\n            \x1b[0;32mhello\x1b[0;0m\n        \x1b[0;31mwow\x1b[0;0m:\n'
         '            \x1b[0;31m----------\x1b[0;0m\n            \x1b[0;31ma\x1b[0;0m:\n'
         '                \x1b[0;1;33m1\x1b[0;0m\n            \x1b[0;31mb\x1b[0;0m:\n'
         '                \x1b[0;32mhello\x1b[0;0m')
     # You can notice that in test_output_with_colors the color code is \x1b[0;36m, i.e., GREEN,
     # while here the color code is \x1b[0;31m, i.e., RED (failure)
     ret = nested.output(self.data, _retcode=1)
     self.assertEqual(ret, expected_output_str)
예제 #8
0
파일: firewalld.py 프로젝트: rjmateus/salt
def _present(name,
            block_icmp=None,
            prune_block_icmp=False,
            default=None,
            masquerade=False,
            ports=None,
            prune_ports=False,
            port_fwd=None,
            prune_port_fwd=False,
            services=None,
            # TODO: prune_services=False in future release
            # prune_services=False,
            prune_services=None,
            interfaces=None,
            prune_interfaces=False,
            sources=None,
            prune_sources=False,
            rich_rules=None,
            prune_rich_rules=False):
    '''
    Ensure a zone has specific attributes.
    '''
    ret = {'name': name,
           'result': False,
           'changes': {},
           'comment': ''}

    try:
        zones = __salt__['firewalld.get_zones'](permanent=True)
    except CommandExecutionError as err:
        ret['comment'] = 'Error: {0}'.format(err)
        return ret

    if name not in zones:
        if not __opts__['test']:
            try:
                __salt__['firewalld.new_zone'](name)
            except CommandExecutionError as err:
                ret['comment'] = 'Error: {0}'.format(err)
                return ret

        ret['changes'].update({name:
                                {'old': zones,
                                'new': name}})

    if block_icmp or prune_block_icmp:
        block_icmp = block_icmp or []
        new_icmp_types = []
        old_icmp_types = []

        try:
            _current_icmp_blocks = __salt__['firewalld.list_icmp_block'](name,
                permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        if block_icmp:
            try:
                _valid_icmp_types = __salt__['firewalld.get_icmp_types'](
                    permanent=True)
            except CommandExecutionError as err:
                ret['comment'] = 'Error: {0}'.format(err)
                return ret

            # log errors for invalid ICMP types in block_icmp input
            for icmp_type in set(block_icmp) - set(_valid_icmp_types):
                log.error('%s is an invalid ICMP type', icmp_type)
                block_icmp.remove(icmp_type)

            new_icmp_types = set(block_icmp) - set(_current_icmp_blocks)
            for icmp_type in new_icmp_types:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.block_icmp'](name, icmp_type,
                                                         permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if prune_block_icmp:
            old_icmp_types = set(_current_icmp_blocks) - set(block_icmp)
            for icmp_type in old_icmp_types:
                # no need to check against _valid_icmp_types here, because all
                # elements in old_icmp_types are guaranteed to be in
                # _current_icmp_blocks, whose elements are inherently valid
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.allow_icmp'](name, icmp_type,
                                                         permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_icmp_types or old_icmp_types:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_block_icmp:
                block_icmp = list(new_icmp_types | set(_current_icmp_blocks))
            ret['changes'].update({'icmp_types':
                                    {'old': _current_icmp_blocks,
                                    'new': block_icmp}})

    # that's the only parameter that can't be permanent or runtime, it's
    # directly both
    if default:
        try:
            default_zone = __salt__['firewalld.default_zone']()
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret
        if name != default_zone:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.set_default_zone'](name)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret
            ret['changes'].update({'default':
                                  {'old': default_zone,
                                   'new': name}})

    try:
        masquerade_ret = __salt__['firewalld.get_masquerade'](name,
            permanent=True)
    except CommandExecutionError as err:
        ret['comment'] = 'Error: {0}'.format(err)
        return ret

    if masquerade and not masquerade_ret:
        if not __opts__['test']:
            try:
                __salt__['firewalld.add_masquerade'](name, permanent=True)
            except CommandExecutionError as err:
                ret['comment'] = 'Error: {0}'.format(err)
                return ret
        ret['changes'].update({'masquerade':
                              {'old': '',
                               'new': 'Masquerading successfully set.'}})
    elif not masquerade and masquerade_ret:
        if not __opts__['test']:
            try:
                __salt__['firewalld.remove_masquerade'](name,
                                                        permanent=True)
            except CommandExecutionError as err:
                ret['comment'] = 'Error: {0}'.format(err)
                return ret
        ret['changes'].update({'masquerade':
                              {'old': '',
                               'new': 'Masquerading successfully '
                               'disabled.'}})

    if ports or prune_ports:
        ports = ports or []
        try:
            _current_ports = __salt__['firewalld.list_ports'](name, permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        new_ports = set(ports) - set(_current_ports)
        old_ports = []

        for port in new_ports:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.add_port'](name, port, permanent=True, force_masquerade=False)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_ports:
            old_ports = set(_current_ports) - set(ports)
            for port in old_ports:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_port'](name, port, permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_ports or old_ports:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_ports:
                ports = list(new_ports | set(_current_ports))
            ret['changes'].update({'ports':
                                    {'old': _current_ports,
                                    'new': ports}})

    if port_fwd or prune_port_fwd:
        port_fwd = port_fwd or []
        try:
            _current_port_fwd = __salt__['firewalld.list_port_fwd'](name,
                                                                    permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        port_fwd = [_parse_forward(fwd) for fwd in port_fwd]
        _current_port_fwd = [
            ForwardingMapping(
                srcport=fwd['Source port'],
                destport=fwd['Destination port'],
                protocol=fwd['Protocol'],
                destaddr=fwd['Destination address']
            ) for fwd in _current_port_fwd]

        new_port_fwd = set(port_fwd) - set(_current_port_fwd)
        old_port_fwd = []

        for fwd in new_port_fwd:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.add_port_fwd'](name, fwd.srcport,
                        fwd.destport, fwd.protocol, fwd.destaddr, permanent=True,
                        force_masquerade=False)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_port_fwd:
            old_port_fwd = set(_current_port_fwd) - set(port_fwd)
            for fwd in old_port_fwd:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_port_fwd'](name, fwd.srcport,
                            fwd.destport, fwd.protocol, fwd.destaddr, permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_port_fwd or old_port_fwd:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_port_fwd:
                port_fwd = list(new_port_fwd | set(_current_port_fwd))
            ret['changes'].update({'port_fwd':
                                    {'old': [fwd.todict() for fwd in
                                             _current_port_fwd],
                                    'new': [fwd.todict() for fwd in port_fwd]}})

    if services or prune_services:
        services = services or []
        try:
            _current_services = __salt__['firewalld.list_services'](name,
                permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        new_services = set(services) - set(_current_services)
        old_services = []

        for new_service in new_services:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.add_service'](new_service, name,
                                                      permanent=True)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_services:
            old_services = set(_current_services) - set(services)
            for old_service in old_services:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_service'](old_service, name,
                                                             permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_services or old_services:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_services:
                services = list(new_services | set(_current_services))
            ret['changes'].update({'services':
                                    {'old': _current_services,
                                    'new': services}})

    if interfaces or prune_interfaces:
        interfaces = interfaces or []
        try:
            _current_interfaces = __salt__['firewalld.get_interfaces'](name,
                permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        new_interfaces = set(interfaces) - set(_current_interfaces)
        old_interfaces = []

        for interface in new_interfaces:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.change_interface'](name, interface,
                                                           permanent=True)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_interfaces:
            old_interfaces = set(_current_interfaces) - set(interfaces)
            for interface in old_interfaces:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_interface'](name, interface,
                                                               permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_interfaces or old_interfaces:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_interfaces:
                interfaces = list(new_interfaces | set(_current_interfaces))
            ret['changes'].update({'interfaces':
                                    {'old': _current_interfaces,
                                    'new': interfaces}})

    if sources or prune_sources:
        sources = sources or []
        try:
            _current_sources = __salt__['firewalld.get_sources'](name,
                                                                 permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        new_sources = set(sources) - set(_current_sources)
        old_sources = []

        for source in new_sources:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.add_source'](name, source, permanent=True)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_sources:
            old_sources = set(_current_sources) - set(sources)
            for source in old_sources:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_source'](name, source,
                                                            permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_sources or old_sources:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_sources:
                sources = list(new_sources | set(_current_sources))
            ret['changes'].update({'sources':
                                    {'old': _current_sources,
                                    'new': sources}})

    if rich_rules or prune_rich_rules:
        rich_rules = rich_rules or []
        try:
            _current_rich_rules = __salt__['firewalld.get_rich_rules'](name,
                permanent=True)
        except CommandExecutionError as err:
            ret['comment'] = 'Error: {0}'.format(err)
            return ret

        new_rich_rules = set(rich_rules) - set(_current_rich_rules)
        old_rich_rules = []

        for rich_rule in new_rich_rules:
            if not __opts__['test']:
                try:
                    __salt__['firewalld.add_rich_rule'](name, rich_rule,
                                                        permanent=True)
                except CommandExecutionError as err:
                    ret['comment'] = 'Error: {0}'.format(err)
                    return ret

        if prune_rich_rules:
            old_rich_rules = set(_current_rich_rules) - set(rich_rules)
            for rich_rule in old_rich_rules:
                if not __opts__['test']:
                    try:
                        __salt__['firewalld.remove_rich_rule'](name, rich_rule,
                                                               permanent=True)
                    except CommandExecutionError as err:
                        ret['comment'] = 'Error: {0}'.format(err)
                        return ret

        if new_rich_rules or old_rich_rules:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_rich_rules:
                rich_rules = list(new_rich_rules | set(_current_rich_rules))
            ret['changes'].update({'rich_rules':
                                  {'old': _current_rich_rules,
                                   'new': rich_rules}})

    # No changes
    if ret['changes'] == {}:
        ret['result'] = True
        ret['comment'] = '\'{0}\' is already in the desired state.'.format(name)
        return ret

    # test=True and changes predicted
    if __opts__['test']:
        ret['result'] = None
        # build comment string
        nested.__opts__ = __opts__
        comment = []
        comment.append('Configuration for \'{0}\' will change:'.format(name))
        comment.append(nested.output(ret['changes']).rstrip())
        ret['comment'] = '\n'.join(comment)
        ret['changes'] = {}
        return ret

    # Changes were made successfully
    ret['result'] = True
    ret['comment'] = '\'{0}\' was configured.'.format(name)
    return ret
예제 #9
0
def _present(
    name,
    block_icmp=None,
    prune_block_icmp=False,
    default=None,
    masquerade=False,
    ports=None,
    prune_ports=False,
    port_fwd=None,
    prune_port_fwd=False,
    services=None,
    # TODO: prune_services=False in future release
    # prune_services=False,
    prune_services=None,
    interfaces=None,
    prune_interfaces=False,
    sources=None,
    prune_sources=False,
    rich_rules=None,
    prune_rich_rules=False,
):
    """
    Ensure a zone has specific attributes.
    """
    ret = {"name": name, "result": False, "changes": {}, "comment": ""}

    try:
        zones = __salt__["firewalld.get_zones"](permanent=True)
    except CommandExecutionError as err:
        ret["comment"] = "Error: {}".format(err)
        return ret

    if name not in zones:
        if not __opts__["test"]:
            try:
                __salt__["firewalld.new_zone"](name)
            except CommandExecutionError as err:
                ret["comment"] = "Error: {}".format(err)
                return ret

        ret["changes"].update({name: {"old": zones, "new": name}})

    if block_icmp or prune_block_icmp:
        block_icmp = block_icmp or []
        new_icmp_types = []
        old_icmp_types = []

        try:
            _current_icmp_blocks = __salt__["firewalld.list_icmp_block"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        if block_icmp:
            try:
                _valid_icmp_types = __salt__["firewalld.get_icmp_types"](
                    permanent=True)
            except CommandExecutionError as err:
                ret["comment"] = "Error: {}".format(err)
                return ret

            # log errors for invalid ICMP types in block_icmp input
            for icmp_type in set(block_icmp) - set(_valid_icmp_types):
                log.error("%s is an invalid ICMP type", icmp_type)
                block_icmp.remove(icmp_type)

            new_icmp_types = set(block_icmp) - set(_current_icmp_blocks)
            for icmp_type in new_icmp_types:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.block_icmp"](name,
                                                         icmp_type,
                                                         permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if prune_block_icmp:
            old_icmp_types = set(_current_icmp_blocks) - set(block_icmp)
            for icmp_type in old_icmp_types:
                # no need to check against _valid_icmp_types here, because all
                # elements in old_icmp_types are guaranteed to be in
                # _current_icmp_blocks, whose elements are inherently valid
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.allow_icmp"](name,
                                                         icmp_type,
                                                         permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_icmp_types or old_icmp_types:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_block_icmp:
                block_icmp = list(new_icmp_types | set(_current_icmp_blocks))
            ret["changes"].update({
                "icmp_types": {
                    "old": _current_icmp_blocks,
                    "new": block_icmp
                }
            })

    # that's the only parameter that can't be permanent or runtime, it's
    # directly both
    if default:
        try:
            default_zone = __salt__["firewalld.default_zone"]()
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret
        if name != default_zone:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.set_default_zone"](name)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret
            ret["changes"].update(
                {"default": {
                    "old": default_zone,
                    "new": name
                }})

    try:
        masquerade_ret = __salt__["firewalld.get_masquerade"](name,
                                                              permanent=True)
    except CommandExecutionError as err:
        ret["comment"] = "Error: {}".format(err)
        return ret

    if masquerade and not masquerade_ret:
        if not __opts__["test"]:
            try:
                __salt__["firewalld.add_masquerade"](name, permanent=True)
            except CommandExecutionError as err:
                ret["comment"] = "Error: {}".format(err)
                return ret
        ret["changes"].update({
            "masquerade": {
                "old": "",
                "new": "Masquerading successfully set."
            }
        })
    elif not masquerade and masquerade_ret:
        if not __opts__["test"]:
            try:
                __salt__["firewalld.remove_masquerade"](name, permanent=True)
            except CommandExecutionError as err:
                ret["comment"] = "Error: {}".format(err)
                return ret
        ret["changes"].update({
            "masquerade": {
                "old": "",
                "new": "Masquerading successfully "
                "disabled."
            }
        })

    if ports or prune_ports:
        ports = ports or []
        try:
            _current_ports = __salt__["firewalld.list_ports"](name,
                                                              permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        new_ports = set(ports) - set(_current_ports)
        old_ports = []

        for port in new_ports:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_port"](name,
                                                   port,
                                                   permanent=True,
                                                   force_masquerade=False)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_ports:
            old_ports = set(_current_ports) - set(ports)
            for port in old_ports:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_port"](name,
                                                          port,
                                                          permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_ports or old_ports:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_ports:
                ports = list(new_ports | set(_current_ports))
            ret["changes"].update(
                {"ports": {
                    "old": _current_ports,
                    "new": ports
                }})

    if port_fwd or prune_port_fwd:
        port_fwd = port_fwd or []
        try:
            _current_port_fwd = __salt__["firewalld.list_port_fwd"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        port_fwd = [_parse_forward(fwd) for fwd in port_fwd]
        _current_port_fwd = [
            ForwardingMapping(
                srcport=fwd["Source port"],
                destport=fwd["Destination port"],
                protocol=fwd["Protocol"],
                destaddr=fwd["Destination address"],
            ) for fwd in _current_port_fwd
        ]

        new_port_fwd = set(port_fwd) - set(_current_port_fwd)
        old_port_fwd = []

        for fwd in new_port_fwd:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_port_fwd"](
                        name,
                        fwd.srcport,
                        fwd.destport,
                        fwd.protocol,
                        fwd.destaddr,
                        permanent=True,
                        force_masquerade=False,
                    )
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_port_fwd:
            old_port_fwd = set(_current_port_fwd) - set(port_fwd)
            for fwd in old_port_fwd:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_port_fwd"](
                            name,
                            fwd.srcport,
                            fwd.destport,
                            fwd.protocol,
                            fwd.destaddr,
                            permanent=True,
                        )
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_port_fwd or old_port_fwd:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_port_fwd:
                port_fwd = list(new_port_fwd | set(_current_port_fwd))
            ret["changes"].update({
                "port_fwd": {
                    "old": [fwd.todict() for fwd in _current_port_fwd],
                    "new": [fwd.todict() for fwd in port_fwd],
                }
            })

    if services or prune_services:
        services = services or []
        try:
            _current_services = __salt__["firewalld.list_services"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        new_services = set(services) - set(_current_services)
        old_services = []

        for new_service in new_services:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_service"](new_service,
                                                      name,
                                                      permanent=True)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_services:
            old_services = set(_current_services) - set(services)
            for old_service in old_services:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_service"](old_service,
                                                             name,
                                                             permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_services or old_services:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_services:
                services = list(new_services | set(_current_services))
            ret["changes"].update(
                {"services": {
                    "old": _current_services,
                    "new": services
                }})

    if interfaces or prune_interfaces:
        interfaces = interfaces or []
        try:
            _current_interfaces = __salt__["firewalld.get_interfaces"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        new_interfaces = set(interfaces) - set(_current_interfaces)
        old_interfaces = []

        for interface in new_interfaces:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_interface"](name,
                                                        interface,
                                                        permanent=True)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_interfaces:
            old_interfaces = set(_current_interfaces) - set(interfaces)
            for interface in old_interfaces:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_interface"](name,
                                                               interface,
                                                               permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_interfaces or old_interfaces:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_interfaces:
                interfaces = list(new_interfaces | set(_current_interfaces))
            ret["changes"].update({
                "interfaces": {
                    "old": _current_interfaces,
                    "new": interfaces
                }
            })

    if sources or prune_sources:
        sources = sources or []
        try:
            _current_sources = __salt__["firewalld.get_sources"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        new_sources = set(sources) - set(_current_sources)
        old_sources = []

        for source in new_sources:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_source"](name,
                                                     source,
                                                     permanent=True)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_sources:
            old_sources = set(_current_sources) - set(sources)
            for source in old_sources:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_source"](name,
                                                            source,
                                                            permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_sources or old_sources:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_sources:
                sources = list(new_sources | set(_current_sources))
            ret["changes"].update(
                {"sources": {
                    "old": _current_sources,
                    "new": sources
                }})

    if rich_rules or prune_rich_rules:
        rich_rules = rich_rules or []
        try:
            _current_rich_rules = __salt__["firewalld.get_rich_rules"](
                name, permanent=True)
        except CommandExecutionError as err:
            ret["comment"] = "Error: {}".format(err)
            return ret

        new_rich_rules = set(rich_rules) - set(_current_rich_rules)
        old_rich_rules = []

        for rich_rule in new_rich_rules:
            if not __opts__["test"]:
                try:
                    __salt__["firewalld.add_rich_rule"](name,
                                                        rich_rule,
                                                        permanent=True)
                except CommandExecutionError as err:
                    ret["comment"] = "Error: {}".format(err)
                    return ret

        if prune_rich_rules:
            old_rich_rules = set(_current_rich_rules) - set(rich_rules)
            for rich_rule in old_rich_rules:
                if not __opts__["test"]:
                    try:
                        __salt__["firewalld.remove_rich_rule"](name,
                                                               rich_rule,
                                                               permanent=True)
                    except CommandExecutionError as err:
                        ret["comment"] = "Error: {}".format(err)
                        return ret

        if new_rich_rules or old_rich_rules:
            # If we're not pruning, include current items in new output so it's clear
            # that they're still present
            if not prune_rich_rules:
                rich_rules = list(new_rich_rules | set(_current_rich_rules))
            ret["changes"].update({
                "rich_rules": {
                    "old": _current_rich_rules,
                    "new": rich_rules
                }
            })

    # No changes
    if ret["changes"] == {}:
        ret["result"] = True
        ret["comment"] = "'{}' is already in the desired state.".format(name)
        return ret

    # test=True and changes predicted
    if __opts__["test"]:
        ret["result"] = None
        # build comment string
        nested.__opts__ = __opts__
        comment = []
        comment.append("Configuration for '{}' will change:".format(name))
        comment.append(nested.output(ret["changes"]).rstrip())
        ret["comment"] = "\n".join(comment)
        ret["changes"] = {}
        return ret

    # Changes were made successfully
    ret["result"] = True
    ret["comment"] = "'{}' was configured.".format(name)
    return ret