Creates Zabbix Action object or if differs update it according defined parameters

    :param name: Zabbix Action name
    :param params: Definition of the Zabbix Action
    :param _connection_user: Optional - zabbix user (can also be set in opts or pillar, see module's docstring)
    :param _connection_password: Optional - zabbix password (can also be set in opts or pillar, see module's docstring)
    :param _connection_url: Optional - url of zabbix frontend (can also be set in opts, pillar, see module's docstring)

    If there is a need to get a value from current zabbix online (e.g. id of a hostgroup you want to put a discovered
    system into), put a dictionary with two keys "query_object" and "query_name" instead of the value.
    In this example we want to get object id of hostgroup named "Virtual machines" and "Databases".

    .. code-block:: yaml

        zabbix-action-present:
            zabbix_action.present:
                - name: VMs
                - params:
                    eventsource: 2
                    status: 0
                    filter:
                        evaltype: 2
                        conditions:
                            - conditiontype: 24
                              operator: 2
                              value: 'virtual'
                            - conditiontype: 24
                              operator: 2
                              value: 'kvm'
                    operations:
                        - operationtype: 2
                        - operationtype: 4
                          opgroup:
                              - groupid:
                                  query_object: hostgroup
                                  query_name: Virtual machines
                              - groupid:
                                  query_object: hostgroup
                                  query_name: Databases

def present(name, params, **kwargs):
    '''
    Creates Zabbix Action object or if differs update it according defined parameters

    :param name: Zabbix Action name
    :param params: Definition of the Zabbix Action
    :param _connection_user: Optional - zabbix user (can also be set in opts or pillar, see module's docstring)
    :param _connection_password: Optional - zabbix password (can also be set in opts or pillar, see module's docstring)
    :param _connection_url: Optional - url of zabbix frontend (can also be set in opts, pillar, see module's docstring)

    If there is a need to get a value from current zabbix online (e.g. id of a hostgroup you want to put a discovered
    system into), put a dictionary with two keys "query_object" and "query_name" instead of the value.
    In this example we want to get object id of hostgroup named "Virtual machines" and "Databases".

    .. code-block:: yaml

        zabbix-action-present:
            zabbix_action.present:
                - name: VMs
                - params:
                    eventsource: 2
                    status: 0
                    filter:
                        evaltype: 2
                        conditions:
                            - conditiontype: 24
                              operator: 2
                              value: 'virtual'
                            - conditiontype: 24
                              operator: 2
                              value: 'kvm'
                    operations:
                        - operationtype: 2
                        - operationtype: 4
                          opgroup:
                              - groupid:
                                  query_object: hostgroup
                                  query_name: Virtual machines
                              - groupid:
                                  query_object: hostgroup
                                  query_name: Databases
    '''
    zabbix_id_mapper = __salt__['zabbix.get_zabbix_id_mapper']()

    dry_run = __opts__['test']
    ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}

    # Create input params substituting functions with their results
    params['name'] = name
    params['operations'] = params['operations'] if 'operations' in params else []
    if 'filter' in params:
        params['filter']['conditions'] = params['filter']['conditions'] if 'conditions' in params['filter'] else []

    input_params = __salt__['zabbix.substitute_params'](params, **kwargs)
    log.info('Zabbix Action: input params: %s', six.text_type(json.dumps(input_params, indent=4)))

    search = {'output': 'extend',
              'selectOperations': 'extend',
              'selectFilter': 'extend',
              'filter': {
                  'name': name
              }}
    # GET Action object if exists
    action_get = __salt__['zabbix.run_query']('action.get', search, **kwargs)
    log.info('Zabbix Action: action.get result: %s', six.text_type(json.dumps(action_get, indent=4)))

    existing_obj = __salt__['zabbix.substitute_params'](action_get[0], **kwargs) \
        if action_get and len(action_get) == 1 else False

    if existing_obj:
        diff_params = __salt__['zabbix.compare_params'](input_params, existing_obj)
        log.info('Zabbix Action: input params: {%s', six.text_type(json.dumps(input_params, indent=4)))
        log.info('Zabbix Action: Object comparison result. Differences: %s', six.text_type(diff_params))

        if diff_params:
            diff_params[zabbix_id_mapper['action']] = existing_obj[zabbix_id_mapper['action']]
            # diff_params['name'] = 'VMs' - BUG - https://support.zabbix.com/browse/ZBX-12078
            log.info('Zabbix Action: update params: %s', six.text_type(json.dumps(diff_params, indent=4)))

            if dry_run:
                ret['result'] = True
                ret['comment'] = 'Zabbix Action "{0}" would be fixed.'.format(name)
                ret['changes'] = {name: {'old': 'Zabbix Action "{0}" differs '
                                                'in following parameters: {1}'.format(name, diff_params),
                                         'new': 'Zabbix Action "{0}" would correspond to definition.'.format(name)}}
            else:
                action_update = __salt__['zabbix.run_query']('action.update', diff_params, **kwargs)
                log.info('Zabbix Action: action.update result: %s', six.text_type(action_update))
                if action_update:
                    ret['result'] = True
                    ret['comment'] = 'Zabbix Action "{0}" updated.'.format(name)
                    ret['changes'] = {name: {'old': 'Zabbix Action "{0}" differed '
                                                    'in following parameters: {1}'.format(name, diff_params),
                                             'new': 'Zabbix Action "{0}" fixed.'.format(name)}}

        else:
            ret['result'] = True
            ret['comment'] = 'Zabbix Action "{0}" already exists and corresponds to a definition.'.format(name)

    else:
        if dry_run:
            ret['result'] = True
            ret['comment'] = 'Zabbix Action "{0}" would be created.'.format(name)
            ret['changes'] = {name: {'old': 'Zabbix Action "{0}" does not exist.'.format(name),
                                     'new': 'Zabbix Action "{0}" would be created according definition.'.format(name)}}
        else:
            # ACTION.CREATE
            action_create = __salt__['zabbix.run_query']('action.create', input_params, **kwargs)
            log.info('Zabbix Action: action.create result: %s', action_create)

            if action_create:
                ret['result'] = True
                ret['comment'] = 'Zabbix Action "{0}" created.'.format(name)
                ret['changes'] = {name: {'old': 'Zabbix Action "{0}" did not exist.'.format(name),
                                         'new': 'Zabbix Action "{0}" created according definition.'.format(name)}}

    return ret