create or update any pagerduty resource
    Helper method for present().

    Determining if two resources are the same is different for different PD resource, so this method accepts a diff function.
    The diff function will be invoked as diff(state_information, object_returned_from_pagerduty), and
    should return a dict of data to pass to the PagerDuty update API method, or None if no update
    is to be performed.  If no diff method is provided, the default behavor is to scan the keys in the state_information,
    comparing the matching values in the object_returned_from_pagerduty, and update any values that differ.

    examples:
        create_or_update_resource("user", ["id","name","email"])
        create_or_update_resource("escalation_policies", ["id","name"], diff=my_diff_function)

def create_or_update_resource(resource_name, identifier_fields, data, diff=None, profile='pagerduty', subdomain=None, api_key=None):
    '''
    create or update any pagerduty resource
    Helper method for present().

    Determining if two resources are the same is different for different PD resource, so this method accepts a diff function.
    The diff function will be invoked as diff(state_information, object_returned_from_pagerduty), and
    should return a dict of data to pass to the PagerDuty update API method, or None if no update
    is to be performed.  If no diff method is provided, the default behavor is to scan the keys in the state_information,
    comparing the matching values in the object_returned_from_pagerduty, and update any values that differ.

    examples:
        create_or_update_resource("user", ["id","name","email"])
        create_or_update_resource("escalation_policies", ["id","name"], diff=my_diff_function)

    '''
    # try to locate the resource by any of the identifier_fields that are specified in data
    resource = None
    for field in identifier_fields:
        if field in data:
            resource = get_resource(resource_name, data[field], identifier_fields, profile, subdomain, api_key)
            if resource is not None:
                break

    if resource is None:
        if __opts__['test']:
            return 'would create'
        # flush the resource_cache, because we're modifying a resource
        del __context__['pagerduty_util.resource_cache'][resource_name]
        # create
        return _query(method='POST', action=resource_name, data=data, profile=profile, subdomain=subdomain, api_key=api_key)
    else:
        # update
        data_to_update = {}
        # if differencing function is provided, use it
        if diff:
            data_to_update = diff(data, resource)
        # else default to naive key-value walk of the dicts
        else:
            for k, v in data.items():
                if k.startswith('_'):
                    continue
                resource_value = resource.get(k, None)
                if resource_value is not None and resource_value != v:
                    data_to_update[k] = v
        if data_to_update:
            if __opts__['test']:
                return 'would update'
            # flush the resource_cache, because we're modifying a resource
            del __context__['pagerduty_util.resource_cache'][resource_name]
            resource_id = _get_resource_id(resource)
            return _query(method='PUT', action='{0}/{1}'.format(resource_name, resource_id), data=data_to_update,
                          profile=profile, subdomain=subdomain, api_key=api_key)
        else:
            return True