.. versionadded:: 2019.2.0

    Create or update a security rule within a specified network security group.

    :param name: The name of the security rule to create.

    :param access:
        'allow' or 'deny'

    :param direction:
        'inbound' or 'outbound'

    :param priority:
        Integer between 100 and 4096 used for ordering rule application.

    :param protocol:
        'tcp', 'udp', or '*'

    :param destination_address_prefix:
        The CIDR or destination IP range. Asterix '*' can also be used to match all destination IPs.
        Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used.
        If this is an ingress rule, specifies where network traffic originates from.

    :param destination_port_range:
        The destination port or range. Integer or range between 0 and 65535. Asterix '*'
        can also be used to match all ports.

    :param source_address_prefix:
        The CIDR or source IP range. Asterix '*' can also be used to match all source IPs.
        Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used.
        If this is an ingress rule, specifies where network traffic originates from.

    :param source_port_range:
        The source port or range. Integer or range between 0 and 65535. Asterix '*'
        can also be used to match all ports.

    :param destination_address_prefixes:
        A list of destination_address_prefix values. This parameter overrides destination_address_prefix
        and will cause any value entered there to be ignored.

    :param destination_port_ranges:
        A list of destination_port_range values. This parameter overrides destination_port_range
        and will cause any value entered there to be ignored.

    :param source_address_prefixes:
        A list of source_address_prefix values. This parameter overrides source_address_prefix
        and will cause any value entered there to be ignored.

    :param source_port_ranges:
        A list of source_port_range values. This parameter overrides source_port_range
        and will cause any value entered there to be ignored.

    :param security_group: The network security group containing the
        security rule.

    :param resource_group: The resource group name assigned to the
        network security group.

    CLI Example:

    .. code-block:: bash

        salt-call azurearm_network.security_rule_create_or_update testrule1 allow outbound 101 tcp testnsg testgroup \
                  source_address_prefix='*' destination_address_prefix=internet source_port_range='*' \
                  destination_port_range='1-1024'

def security_rule_create_or_update(name, access, direction, priority, protocol, security_group, resource_group,
                                   source_address_prefix=None, destination_address_prefix=None, source_port_range=None,
                                   destination_port_range=None, source_address_prefixes=None,
                                   destination_address_prefixes=None, source_port_ranges=None,
                                   destination_port_ranges=None, **kwargs):
    '''
    .. versionadded:: 2019.2.0

    Create or update a security rule within a specified network security group.

    :param name: The name of the security rule to create.

    :param access:
        'allow' or 'deny'

    :param direction:
        'inbound' or 'outbound'

    :param priority:
        Integer between 100 and 4096 used for ordering rule application.

    :param protocol:
        'tcp', 'udp', or '*'

    :param destination_address_prefix:
        The CIDR or destination IP range. Asterix '*' can also be used to match all destination IPs.
        Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used.
        If this is an ingress rule, specifies where network traffic originates from.

    :param destination_port_range:
        The destination port or range. Integer or range between 0 and 65535. Asterix '*'
        can also be used to match all ports.

    :param source_address_prefix:
        The CIDR or source IP range. Asterix '*' can also be used to match all source IPs.
        Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used.
        If this is an ingress rule, specifies where network traffic originates from.

    :param source_port_range:
        The source port or range. Integer or range between 0 and 65535. Asterix '*'
        can also be used to match all ports.

    :param destination_address_prefixes:
        A list of destination_address_prefix values. This parameter overrides destination_address_prefix
        and will cause any value entered there to be ignored.

    :param destination_port_ranges:
        A list of destination_port_range values. This parameter overrides destination_port_range
        and will cause any value entered there to be ignored.

    :param source_address_prefixes:
        A list of source_address_prefix values. This parameter overrides source_address_prefix
        and will cause any value entered there to be ignored.

    :param source_port_ranges:
        A list of source_port_range values. This parameter overrides source_port_range
        and will cause any value entered there to be ignored.

    :param security_group: The network security group containing the
        security rule.

    :param resource_group: The resource group name assigned to the
        network security group.

    CLI Example:

    .. code-block:: bash

        salt-call azurearm_network.security_rule_create_or_update testrule1 allow outbound 101 tcp testnsg testgroup \
                  source_address_prefix='*' destination_address_prefix=internet source_port_range='*' \
                  destination_port_range='1-1024'

    '''
    exclusive_params = [
        ('source_port_ranges', 'source_port_range'),
        ('source_address_prefixes', 'source_address_prefix'),
        ('destination_port_ranges', 'destination_port_range'),
        ('destination_address_prefixes', 'destination_address_prefix'),
    ]

    for params in exclusive_params:
        # pylint: disable=eval-used
        if not eval(params[0]) and not eval(params[1]):
            log.error(
                'Either the %s or %s parameter must be provided!',
                params[0], params[1]
            )
            return False
        # pylint: disable=eval-used
        if eval(params[0]):
            # pylint: disable=exec-used
            exec('{0} = None'.format(params[1]))

    netconn = __utils__['azurearm.get_client']('network', **kwargs)

    try:
        rulemodel = __utils__['azurearm.create_object_model'](
            'network',
            'SecurityRule',
            name=name,
            access=access,
            direction=direction,
            priority=priority,
            protocol=protocol,
            source_port_ranges=source_port_ranges,
            source_port_range=source_port_range,
            source_address_prefixes=source_address_prefixes,
            source_address_prefix=source_address_prefix,
            destination_port_ranges=destination_port_ranges,
            destination_port_range=destination_port_range,
            destination_address_prefixes=destination_address_prefixes,
            destination_address_prefix=destination_address_prefix,
            **kwargs
        )
    except TypeError as exc:
        result = {'error': 'The object model could not be built. ({0})'.format(str(exc))}
        return result

    try:
        secrule = netconn.security_rules.create_or_update(
            resource_group_name=resource_group,
            network_security_group_name=security_group,
            security_rule_name=name,
            security_rule_parameters=rulemodel
        )
        secrule.wait()
        secrule_result = secrule.result()
        result = secrule_result.as_dict()
    except CloudError as exc:
        __utils__['azurearm.log_cloud_error']('network', str(exc), **kwargs)
        result = {'error': str(exc)}
    except SerializationError as exc:
        result = {'error': 'The object model could not be parsed. ({0})'.format(str(exc))}

    return result