Example #1
0
def main():
    helper = get_connection(
        vsys_importable=True,
        template=True,
        with_classic_provider_spec=True,
        with_state=True,
        min_pandevice_version=(0, 8, 0),
        argument_spec=dict(
            if_name=dict(required=True),
            ip=dict(type='list', elements='str'),
            ipv6_enabled=dict(type='bool'),
            management_profile=dict(),
            mtu=dict(type='int'),
            netflow_profile=dict(),
            comment=dict(),
            zone_name=dict(),
            vr_name=dict(),
            commit=dict(type='bool', default=False),

            # TODO(gfreeman) - remove this in 2.12
            vsys_dg=dict(),
        ),
    )

    module = AnsibleModule(
        argument_spec=helper.argument_spec,
        supports_check_mode=True,
        required_one_of=helper.required_one_of,
    )

    # Get the object params.
    spec = {
        'name': module.params['if_name'],
        'ip': module.params['ip'],
        'ipv6_enabled': module.params['ipv6_enabled'],
        'management_profile': module.params['management_profile'],
        'mtu': module.params['mtu'],
        'netflow_profile': module.params['netflow_profile'],
        'comment': module.params['comment'],
    }

    # Get other info.
    state = module.params['state']
    zone_name = module.params['zone_name']
    vr_name = module.params['vr_name']
    vsys = module.params['vsys']
    vsys_dg = module.params['vsys_dg']
    commit = module.params['commit']

    # TODO(gfreeman) - Remove vsys_dg in 2.12, as well as this code chunk.
    # In the mean time, we'll need to do this special handling.
    if vsys_dg is not None:
        module.deprecate('Param "vsys_dg" is deprecated, use "vsys"',
                         version='3.0.0',
                         collection_name='paloaltonetworks.panos')

        if vsys is None:
            vsys = vsys_dg
        else:
            msg = [
                'Params "vsys" and "vsys_dg" both given',
                'Specify one or the other, not both.',
            ]
            module.fail_json(msg='.  '.join(msg))
    elif vsys is None:
        # TODO(gfreeman) - v2.12, just set the default for vsys to 'vsys1'.
        vsys = 'vsys1'

    # Make sure 'vsys' is set appropriately.
    module.params['vsys'] = vsys

    # Verify libs are present, get the parent object.
    parent = helper.get_pandevice_parent(module)

    # Retrieve the current config.
    try:
        interfaces = TunnelInterface.refreshall(parent,
                                                add=False,
                                                matching_vsys=False)
    except PanDeviceError as e:
        module.fail_json(msg='Failed refresh: {0}'.format(e))

    # Build the object based on the user spec.
    obj = TunnelInterface(**spec)
    parent.add(obj)

    # Which action should we take on the interface?
    changed = False
    diff = None
    reference_params = {
        'refresh': True,
        'update': not module.check_mode,
        'return_type': 'bool',
    }
    if state == 'present':
        for item in interfaces:
            if item.name != obj.name:
                continue
            diff = dict(before=eltostr(item))
            # Interfaces have children, so don't compare them.
            if not item.equal(obj, compare_children=False):
                changed = True
                obj.extend(item.children)
                diff['after'] = eltostr(obj)
                if not module.check_mode:
                    try:
                        obj.apply()
                    except PanDeviceError as e:
                        module.fail_json(msg='Failed apply: {0}'.format(e))
            break
        else:
            changed = True
            diff = dict(before="", after=eltostr(obj))
            if not module.check_mode:
                try:
                    obj.create()
                except PanDeviceError as e:
                    module.fail_json(msg='Failed create: {0}'.format(e))

        # Set references.
        try:
            changed |= obj.set_vsys(vsys, **reference_params)
            changed |= obj.set_zone(zone_name,
                                    mode='layer3',
                                    **reference_params)
            changed |= obj.set_virtual_router(vr_name, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg='Failed setref: {0}'.format(e))
    elif state == 'absent':
        # Remove references.
        try:
            changed |= obj.set_virtual_router(None, **reference_params)
            changed |= obj.set_zone(None, mode='layer3', **reference_params)
            changed |= obj.set_vsys(None, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg='Failed setref: {0}'.format(e))

        # Remove the interface.
        if obj.name in [x.name for x in interfaces]:
            changed = True
            diff = dict(before=eltostr(obj), after="")
            if not module.check_mode:
                try:
                    obj.delete()
                except PanDeviceError as e:
                    module.fail_json(msg='Failed delete: {0}'.format(e))

    # Commit if we were asked to do so.
    if changed and commit:
        helper.commit(module)

    # Done!
    module.exit_json(changed=changed, diff=diff, msg='Done')
Example #2
0
def main():
    helper = get_connection(
        vsys_importable=True,
        template=True,
        with_classic_provider_spec=True,
        with_state=True,
        min_pandevice_version=(0, 8, 0),
        argument_spec=dict(
            if_name=dict(required=True),
            mode=dict(
                default="layer3",
                choices=[
                    "layer3",
                    "layer2",
                    "virtual-wire",
                    "tap",
                    "ha",
                    "decrypt-mirror",
                    "aggregate-group",
                ],
            ),
            ip=dict(type="list", elements="str"),
            ipv6_enabled=dict(type="bool"),
            management_profile=dict(),
            mtu=dict(type="int"),
            adjust_tcp_mss=dict(type="bool"),
            netflow_profile=dict(),
            lldp_enabled=dict(),
            lldp_profile=dict(),
            netflow_profile_l2=dict(),
            link_speed=dict(choices=["auto", "10", "100", "1000"]),
            link_duplex=dict(choices=["auto", "full", "half"]),
            link_state=dict(choices=["auto", "up", "down"]),
            aggregate_group=dict(),
            comment=dict(),
            ipv4_mss_adjust=dict(type="int"),
            ipv6_mss_adjust=dict(type="int"),
            enable_dhcp=dict(type="bool", default=True),
            create_default_route=dict(type="bool", default=False),
            dhcp_default_route_metric=dict(type="int"),
            zone_name=dict(),
            vr_name=dict(default="default"),
            vlan_name=dict(),
            commit=dict(type="bool", default=False),
            # TODO(gfreeman) - remove this in 2.12.
            vsys_dg=dict(),
        ),
    )
    module = AnsibleModule(
        argument_spec=helper.argument_spec,
        supports_check_mode=True,
        required_one_of=helper.required_one_of,
    )

    # Get the object params.
    spec = {
        "name": module.params["if_name"],
        "mode": module.params["mode"],
        "ip": module.params["ip"],
        "ipv6_enabled": module.params["ipv6_enabled"],
        "management_profile": module.params["management_profile"],
        "mtu": module.params["mtu"],
        "adjust_tcp_mss": module.params["adjust_tcp_mss"],
        "netflow_profile": module.params["netflow_profile"],
        "lldp_enabled": module.params["lldp_enabled"],
        "lldp_profile": module.params["lldp_profile"],
        "netflow_profile_l2": module.params["netflow_profile_l2"],
        "link_speed": module.params["link_speed"],
        "link_duplex": module.params["link_duplex"],
        "link_state": module.params["link_state"],
        "aggregate_group": module.params["aggregate_group"],
        "comment": module.params["comment"],
        "ipv4_mss_adjust": module.params["ipv4_mss_adjust"],
        "ipv6_mss_adjust": module.params["ipv6_mss_adjust"],
        "enable_dhcp": True if module.params["enable_dhcp"] else None,
        # 'create_dhcp_default_route': set below
        "dhcp_default_route_metric":
        module.params["dhcp_default_route_metric"],
    }

    if module.params["create_default_route"]:
        spec["create_dhcp_default_route"] = True
    elif spec["enable_dhcp"]:
        spec["create_dhcp_default_route"] = False
    else:
        spec["create_dhcp_default_route"] = None

    # Get other info.
    state = module.params["state"]
    zone_name = module.params["zone_name"]
    vlan_name = module.params["vlan_name"]
    vr_name = module.params["vr_name"] if module.params["vr_name"] else None
    vsys = module.params["vsys"]
    vsys_dg = module.params["vsys_dg"]

    # TODO(gfreeman) - Remove vsys_dg in 2.12, as well as this code chunk.
    # In the mean time, we'll need to do this special handling.
    if vsys_dg is not None:
        module.deprecate(
            'Param "vsys_dg" is deprecated, use "vsys"',
            version="3.0.0",
            collection_name="paloaltonetworks.panos",
        )
        if vsys is None:
            vsys = vsys_dg
        else:
            msg = [
                'Params "vsys" and "vsys_dg" both given',
                "Specify one or the other, not both.",
            ]
            module.fail_json(msg=".  ".join(msg))
    elif vsys is None:
        # TODO(gfreeman) - v2.12, just set the default for vsys to 'vsys1'.
        vsys = "vsys1"

    module.params["vsys"] = vsys

    # Verify libs are present, get the parent object.
    parent = helper.get_pandevice_parent(module)

    # Retrieve the current config.
    try:
        interfaces = EthernetInterface.refreshall(parent,
                                                  add=False,
                                                  matching_vsys=False)
    except PanDeviceError as e:
        module.fail_json(msg=e.message)

    # Build the object based on the user spec.
    eth = EthernetInterface(**spec)
    parent.add(eth)

    # Which action should we take on the interface?
    changed = False
    diff = None
    reference_params = {
        "refresh": True,
        "update": not module.check_mode,
        "return_type": "bool",
    }
    if state == "present":
        for item in interfaces:
            if item.name != eth.name:
                continue
            diff = dict(before=eltostr(item))
            # Interfaces have children, so don't compare them.
            if not item.equal(eth, compare_children=False):
                changed = True
                eth.extend(item.children)
                diff["after"] = eltostr(eth)
                if not module.check_mode:
                    try:
                        eth.apply()
                    except PanDeviceError as e:
                        module.fail_json(msg="Failed apply: {0}".format(e))
            break
        else:
            changed = True
            diff = dict(before="", after=eltostr(eth))
            if not module.check_mode:
                try:
                    eth.create()
                except PanDeviceError as e:
                    module.fail_json(msg="Failed create: {0}".format(e))

        # Set references.
        try:
            changed |= eth.set_vsys(vsys, **reference_params)
            changed |= eth.set_zone(zone_name,
                                    mode=eth.mode,
                                    **reference_params)
            changed |= eth.set_vlan(vlan_name, **reference_params)
            changed |= eth.set_virtual_router(vr_name, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg="Failed setref: {0}".format(e))
    elif state == "absent":
        # Remove references.
        try:
            changed |= eth.set_virtual_router(None, **reference_params)
            changed |= eth.set_vlan(None, **reference_params)
            changed |= eth.set_zone(None, mode=eth.mode, **reference_params)
            changed |= eth.set_vsys(None, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg="Failed setref: {0}".format(e))

        # Remove the interface.
        if eth.name in [x.name for x in interfaces]:
            changed = True
            diff = dict(before=eltostr(eth), after="")
            if not module.check_mode:
                try:
                    eth.delete()
                except PanDeviceError as e:
                    module.fail_json(msg="Failed delete: {0}".format(e))

    # Commit if we were asked to do so.
    if changed and module.params["commit"]:
        helper.commit(module)

    # Done!
    module.exit_json(changed=changed, diff=diff, msg="Done")
Example #3
0
def main():
    helper = get_connection(
        vsys_importable=True,
        template=True,
        with_classic_provider_spec=True,
        with_state=True,
        min_pandevice_version=(0, 8, 0),
        argument_spec=dict(
            if_name=dict(required=True),
            mode=dict(
                default='layer3',
                choices=[
                    'layer3', 'layer2', 'virtual-wire', 'tap', 'ha',
                    'decrypt-mirror', 'aggregate-group',
                ],
            ),
            ip=dict(type='list'),
            ipv6_enabled=dict(type='bool'),
            management_profile=dict(),
            mtu=dict(type='int'),
            adjust_tcp_mss=dict(type='bool'),
            netflow_profile=dict(),
            lldp_enabled=dict(),
            lldp_profile=dict(),
            netflow_profile_l2=dict(),
            link_speed=dict(choices=['auto', '10', '100', '1000']),
            link_duplex=dict(choices=['auto', 'full', 'half']),
            link_state=dict(choices=['auto', 'up', 'down']),
            aggregate_group=dict(),
            comment=dict(),
            ipv4_mss_adjust=dict(type='int'),
            ipv6_mss_adjust=dict(type='int'),
            enable_dhcp=dict(type='bool', default=True),
            create_default_route=dict(type='bool', default=False),
            dhcp_default_route_metric=dict(type='int'),
            zone_name=dict(),
            vr_name=dict(default='default'),
            vlan_name=dict(),
            commit=dict(type='bool', default=True),

            # TODO(gfreeman) - remove this in 2.12.
            vsys_dg=dict(),

            # TODO(gfreeman) - remove in the next release.
            operation=dict(),
        ),
    )
    module = AnsibleModule(
        argument_spec=helper.argument_spec,
        supports_check_mode=True,
        required_one_of=helper.required_one_of,
    )

    # TODO(gfreeman) - remove in the next release.
    if module.params['operation'] is not None:
        module.fail_json(msg='Operation has been removed; use "state"')

    # Get the object params.
    spec = {
        'name': module.params['if_name'],
        'mode': module.params['mode'],
        'ip': module.params['ip'],
        'ipv6_enabled': module.params['ipv6_enabled'],
        'management_profile': module.params['management_profile'],
        'mtu': module.params['mtu'],
        'adjust_tcp_mss': module.params['adjust_tcp_mss'],
        'netflow_profile': module.params['netflow_profile'],
        'lldp_enabled': module.params['lldp_enabled'],
        'lldp_profile': module.params['lldp_profile'],
        'netflow_profile_l2': module.params['netflow_profile_l2'],
        'link_speed': module.params['link_speed'],
        'link_duplex': module.params['link_duplex'],
        'link_state': module.params['link_state'],
        'aggregate_group': module.params['aggregate_group'],
        'comment': module.params['comment'],
        'ipv4_mss_adjust': module.params['ipv4_mss_adjust'],
        'ipv6_mss_adjust': module.params['ipv6_mss_adjust'],
        'enable_dhcp': True if module.params['enable_dhcp'] else None,
        # 'create_dhcp_default_route': set below
        'dhcp_default_route_metric': module.params['dhcp_default_route_metric'],
    }

    if module.params['create_default_route']:
        spec['create_dhcp_default_route'] = True
    elif spec['enable_dhcp']:
        spec['create_dhcp_default_route'] = False
    else:
        spec['create_dhcp_default_route'] = None

    # Get other info.
    state = module.params['state']
    zone_name = module.params['zone_name']
    vlan_name = module.params['vlan_name']
    vr_name = module.params['vr_name'] if module.params['vr_name'] else None
    vsys = module.params['vsys']
    vsys_dg = module.params['vsys_dg']

    # TODO(gfreeman) - Remove vsys_dg in 2.12, as well as this code chunk.
    # In the mean time, we'll need to do this special handling.
    if vsys_dg is not None:
        module.deprecate('Param "vsys_dg" is deprecated, use "vsys"', '2.12')
        if vsys is None:
            vsys = vsys_dg
        else:
            msg = [
                'Params "vsys" and "vsys_dg" both given',
                'Specify one or the other, not both.',
            ]
            module.fail_json(msg='.  '.join(msg))
    elif vsys is None:
        # TODO(gfreeman) - v2.12, just set the default for vsys to 'vsys1'.
        vsys = 'vsys1'

    module.params['vsys'] = vsys

    # Verify libs are present, get the parent object.
    parent = helper.get_pandevice_parent(module)

    # Retrieve the current config.
    try:
        interfaces = EthernetInterface.refreshall(
            parent, add=False, matching_vsys=False)
    except PanDeviceError:
        e = get_exception()
        module.fail_json(msg=e.message)

    # Build the object based on the user spec.
    eth = EthernetInterface(**spec)
    parent.add(eth)

    # Which action should we take on the interface?
    changed = False
    diff = None
    reference_params = {
        'refresh': True,
        'update': not module.check_mode,
        'return_type': 'bool',
    }
    if state == 'present':
        for item in interfaces:
            if item.name != eth.name:
                continue
            diff = dict(
                before=eltostr(item)
            )
            # Interfaces have children, so don't compare them.
            if not item.equal(eth, compare_children=False):
                changed = True
                eth.extend(item.children)
                diff['after'] = eltostr(eth)
                if not module.check_mode:
                    try:
                        eth.apply()
                    except PanDeviceError as e:
                        module.fail_json(msg='Failed apply: {0}'.format(e))
            break
        else:
            changed = True
            diff = dict(
                before="",
                after=eltostr(eth)
            )
            if not module.check_mode:
                try:
                    eth.create()
                except PanDeviceError as e:
                    module.fail_json(msg='Failed create: {0}'.format(e))

        # Set references.
        try:
            changed |= eth.set_vsys(vsys, **reference_params)
            changed |= eth.set_zone(zone_name, mode=eth.mode, **reference_params)
            changed |= eth.set_vlan(vlan_name, **reference_params)
            changed |= eth.set_virtual_router(vr_name, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg='Failed setref: {0}'.format(e))
    elif state == 'absent':
        # Remove references.
        try:
            changed |= eth.set_virtual_router(None, **reference_params)
            changed |= eth.set_vlan(None, **reference_params)
            changed |= eth.set_zone(None, mode=eth.mode, **reference_params)
            changed |= eth.set_vsys(None, **reference_params)
        except PanDeviceError as e:
            module.fail_json(msg='Failed setref: {0}'.format(e))

        # Remove the interface.
        if eth.name in [x.name for x in interfaces]:
            changed = True
            diff = dict(
                before=eltostr(eth),
                after=""
            )
            if not module.check_mode:
                try:
                    eth.delete()
                except PanDeviceError as e:
                    module.fail_json(msg='Failed delete: {0}'.format(e))

    # Commit if we were asked to do so.
    if changed and module.params['commit']:
        helper.commit(module)

    # Done!
    module.exit_json(changed=changed, diff=diff, msg='Done')
def main():
    helper = get_connection(
        with_classic_provider_spec=True,
        vsys=True,
        device_group=True,
        rulebase=True,
        error_on_firewall_shared=True,
        argument_spec=dict(
            rule_name=dict(required=True),
            description=dict(),
            nat_type=dict(default='ipv4', choices=['ipv4', 'nat64', 'nptv6']),
            source_zone=dict(type='list', elements='str'),
            source_ip=dict(type='list', elements='str', default=['any']),
            destination_zone=dict(type='str'),
            destination_ip=dict(type='list', elements='str', default=['any']),
            to_interface=dict(default='any'),
            service=dict(default='any'),
            snat_type=dict(choices=['static-ip', 'dynamic-ip-and-port', 'dynamic-ip']),
            snat_address_type=dict(choices=['interface-address', 'translated-address'], default='interface-address'),
            snat_static_address=dict(),
            snat_dynamic_address=dict(type='list', elements='str'),
            snat_interface=dict(),
            snat_interface_address=dict(),
            snat_bidirectional=dict(type='bool'),
            dnat_address=dict(),
            dnat_port=dict(),
            tag=dict(type='list', elements='str'),
            state=dict(default='present', choices=['present', 'absent', 'enable', 'disable']),
            location=dict(choices=['top', 'bottom', 'before', 'after']),
            existing_rule=dict(),
            commit=dict(type='bool', default=False),

            # TODO(gfreeman) - remove later.
            tag_name=dict(),
            devicegroup=dict(),
            operation=dict(),
        ),
    )

    module = AnsibleModule(
        argument_spec=helper.argument_spec,
        supports_check_mode=True,
        required_one_of=helper.required_one_of,
    )

    # TODO(gfreeman) - remove later.
    if module.params['operation'] is not None:
        module.fail_json(msg='Param "operation" is removed; use "state"')
    if module.params['devicegroup'] is not None:
        module.deprecate(
            'Param "devicegroup" is deprecated; use "device_group"',
            version='3.0.0', collection_name='paloaltonetworks.panos'
        )
        module.params['device_group'] = module.params['devicegroup']
    if module.params['tag_name'] is not None:
        tag_val = module.params['tag_name']
        module.deprecate(
            'Param "tag_name" is deprecated; use "tag"',
            version='3.0.0', collection_name='paloaltonetworks.panos'
        )
        if module.params['tag']:
            module.fail_json(msg='Both "tag" and "tag_name" specified, use only one')
    else:
        tag_val = module.params['tag']

    parent = helper.get_pandevice_parent(module)

    # Get object params.
    rule_name = module.params['rule_name']
    description = module.params['description']
    source_zone = module.params['source_zone']
    source_ip = module.params['source_ip']
    destination_zone = module.params['destination_zone']
    destination_ip = module.params['destination_ip']
    service = module.params['service']
    to_interface = module.params['to_interface']
    nat_type = module.params['nat_type']
    snat_type = module.params['snat_type']
    snat_address_type = module.params['snat_address_type']
    snat_static_address = module.params['snat_static_address']
    snat_dynamic_address = module.params['snat_dynamic_address']
    snat_interface = module.params['snat_interface']
    snat_interface_address = module.params['snat_interface_address']
    snat_bidirectional = module.params['snat_bidirectional']
    dnat_address = module.params['dnat_address']
    dnat_port = module.params['dnat_port']

    # Get other info.
    state = module.params['state']
    location = module.params['location']
    existing_rule = module.params['existing_rule']

    # Sanity check the location / existing_rule params.
    if location in ('before', 'after') and not existing_rule:
        module.fail_json(msg="'existing_rule' must be specified if location is 'before' or 'after'.")

    # Get the current NAT rules.
    try:
        rules = NatRule.refreshall(parent)
    except PanDeviceError as e:
        module.fail_json(msg='Failed NAT refreshall: {0}'.format(e))

    # Create the desired rule.
    new_rule = create_nat_rule(
        rule_name=rule_name,
        description=description,
        tag_val=tag_val,
        source_zone=source_zone,
        destination_zone=destination_zone,
        source_ip=source_ip,
        destination_ip=destination_ip,
        service=service,
        to_interface=to_interface,
        nat_type=nat_type,
        snat_type=snat_type,
        snat_address_type=snat_address_type,
        snat_static_address=snat_static_address,
        snat_dynamic_address=snat_dynamic_address,
        snat_interface=snat_interface,
        snat_interface_address=snat_interface_address,
        snat_bidirectional=snat_bidirectional,
        dnat_address=dnat_address,
        dnat_port=dnat_port
    )

    if not new_rule:
        module.fail_json(msg='Incorrect NAT rule params specified; quitting')

    # Perform the desired operation.
    changed = False
    diff = None
    if state in ('enable', 'disable'):
        for rule in rules:
            if rule.name == new_rule.name:
                break
        else:
            module.fail_json(msg='Rule "{0}" not present'.format(new_rule.name))
        if state == 'enable' and rule.disabled:
            changed = True
        elif state == 'disable' and not rule.disabled:
            changed = True
        if changed:
            diff = dict(
                before=eltostr(rule)
            )
            rule.disabled = not rule.disabled
            diff['after'] = eltostr(rule)
            if not module.check_mode:
                try:
                    rule.update('disabled')
                except PanDeviceError as e:
                    module.fail_json(msg='Failed enable: {0}'.format(e))
    else:
        parent.add(new_rule)
        changed, diff = helper.apply_state(new_rule, rules, module)
        if state == 'present':
            changed |= helper.apply_position(new_rule, location, existing_rule, module)

    if changed and module.params['commit']:
        helper.commit(module)

    module.exit_json(changed=changed, diff=diff, msg='Done')
Example #5
0
def main():
    helper = get_connection(
        with_classic_provider_spec=True,
        vsys=True,
        device_group=True,
        rulebase=True,
        error_on_firewall_shared=True,
        argument_spec=dict(
            rule_name=dict(required=True),
            description=dict(),
            nat_type=dict(default="ipv4", choices=["ipv4", "nat64", "nptv6"]),
            source_zone=dict(type="list", elements="str"),
            source_ip=dict(type="list", elements="str", default=["any"]),
            destination_zone=dict(type="str"),
            destination_ip=dict(type="list", elements="str", default=["any"]),
            to_interface=dict(default="any"),
            service=dict(default="any"),
            snat_type=dict(
                choices=["static-ip", "dynamic-ip-and-port", "dynamic-ip"]),
            snat_address_type=dict(
                choices=["interface-address", "translated-address"],
                default="interface-address",
            ),
            snat_static_address=dict(),
            snat_dynamic_address=dict(type="list", elements="str"),
            snat_interface=dict(),
            snat_interface_address=dict(),
            snat_bidirectional=dict(type="bool"),
            dnat_address=dict(),
            dnat_port=dict(),
            tag=dict(type="list", elements="str"),
            state=dict(default="present",
                       choices=["present", "absent", "enable", "disable"]),
            location=dict(choices=["top", "bottom", "before", "after"]),
            existing_rule=dict(),
            target=dict(type="list", elements="str"),
            negate_target=dict(type="bool"),
            commit=dict(type="bool", default=False),
            # TODO(gfreeman) - remove later.
            tag_name=dict(),
            devicegroup=dict(),
            operation=dict(),
        ),
    )

    module = AnsibleModule(
        argument_spec=helper.argument_spec,
        supports_check_mode=True,
        required_one_of=helper.required_one_of,
    )

    # TODO(gfreeman) - remove later.
    if module.params["operation"] is not None:
        module.fail_json(msg='Param "operation" is removed; use "state"')
    if module.params["devicegroup"] is not None:
        module.deprecate(
            'Param "devicegroup" is deprecated; use "device_group"',
            version="3.0.0",
            collection_name="paloaltonetworks.panos",
        )
        module.params["device_group"] = module.params["devicegroup"]
    if module.params["tag_name"] is not None:
        tag_val = module.params["tag_name"]
        module.deprecate(
            'Param "tag_name" is deprecated; use "tag"',
            version="3.0.0",
            collection_name="paloaltonetworks.panos",
        )
        if module.params["tag"]:
            module.fail_json(
                msg='Both "tag" and "tag_name" specified, use only one')
    else:
        tag_val = module.params["tag"]

    parent = helper.get_pandevice_parent(module)

    # Get object params.
    rule_name = module.params["rule_name"]
    description = module.params["description"]
    source_zone = module.params["source_zone"]
    source_ip = module.params["source_ip"]
    destination_zone = module.params["destination_zone"]
    destination_ip = module.params["destination_ip"]
    service = module.params["service"]
    to_interface = module.params["to_interface"]
    nat_type = module.params["nat_type"]
    snat_type = module.params["snat_type"]
    snat_address_type = module.params["snat_address_type"]
    snat_static_address = module.params["snat_static_address"]
    snat_dynamic_address = module.params["snat_dynamic_address"]
    snat_interface = module.params["snat_interface"]
    snat_interface_address = module.params["snat_interface_address"]
    snat_bidirectional = module.params["snat_bidirectional"]
    dnat_address = module.params["dnat_address"]
    dnat_port = module.params["dnat_port"]

    # Get other info.
    state = module.params["state"]
    location = module.params["location"]
    existing_rule = module.params["existing_rule"]
    target = module.params["target"]
    negate_target = module.params["negate_target"]

    # Sanity check the location / existing_rule params.
    if location in ("before", "after") and not existing_rule:
        module.fail_json(
            msg=
            "'existing_rule' must be specified if location is 'before' or 'after'."
        )

    # Get the current NAT rules.
    try:
        rules = NatRule.refreshall(parent)
    except PanDeviceError as e:
        module.fail_json(msg="Failed NAT refreshall: {0}".format(e))

    # Create the desired rule.
    new_rule = create_nat_rule(
        rule_name=rule_name,
        description=description,
        tag_val=tag_val,
        source_zone=source_zone,
        destination_zone=destination_zone,
        source_ip=source_ip,
        destination_ip=destination_ip,
        service=service,
        to_interface=to_interface,
        nat_type=nat_type,
        snat_type=snat_type,
        snat_address_type=snat_address_type,
        snat_static_address=snat_static_address,
        snat_dynamic_address=snat_dynamic_address,
        snat_interface=snat_interface,
        snat_interface_address=snat_interface_address,
        snat_bidirectional=snat_bidirectional,
        dnat_address=dnat_address,
        dnat_port=dnat_port,
        target=target,
        negate_target=negate_target,
    )

    if not new_rule:
        module.fail_json(msg="Incorrect NAT rule params specified; quitting")

    # Perform the desired operation.
    changed = False
    diff = None
    if state in ("enable", "disable"):
        for rule in rules:
            if rule.name == new_rule.name:
                break
        else:
            module.fail_json(
                msg='Rule "{0}" not present'.format(new_rule.name))
        if state == "enable" and rule.disabled:
            changed = True
        elif state == "disable" and not rule.disabled:
            changed = True
        if changed:
            diff = dict(before=eltostr(rule))
            rule.disabled = not rule.disabled
            diff["after"] = eltostr(rule)
            if not module.check_mode:
                try:
                    rule.update("disabled")
                except PanDeviceError as e:
                    module.fail_json(msg="Failed enable: {0}".format(e))
    else:
        parent.add(new_rule)
        changed, diff = helper.apply_state(new_rule, rules, module)
        if state == "present":
            changed |= helper.apply_position(new_rule, location, existing_rule,
                                             module)

    if changed and module.params["commit"]:
        helper.commit(module)

    module.exit_json(changed=changed, diff=diff, msg="Done")