Postpone a job in the minion's schedule

    Current time and new time should be in date string format,
    default value is %Y-%m-%dT%H:%M:%S.

    .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' schedule.postpone_job job current_time new_time

        salt '*' schedule.postpone_job job current_time new_time time_fmt='%Y-%m-%dT%H:%M:%S'

def postpone_job(name,
                 current_time,
                 new_time,
                 **kwargs):
    '''
    Postpone a job in the minion's schedule

    Current time and new time should be in date string format,
    default value is %Y-%m-%dT%H:%M:%S.

    .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' schedule.postpone_job job current_time new_time

        salt '*' schedule.postpone_job job current_time new_time time_fmt='%Y-%m-%dT%H:%M:%S'
    '''

    time_fmt = kwargs.get('time_fmt') or '%Y-%m-%dT%H:%M:%S'
    ret = {'comment': [],
           'result': True}

    if not name:
        ret['comment'] = 'Job name is required.'
        ret['result'] = False
        return ret

    if not current_time:
        ret['comment'] = 'Job current time is required.'
        ret['result'] = False
        return ret
    else:
        try:
            # Validate date string
            datetime.datetime.strptime(current_time, time_fmt)
        except (TypeError, ValueError):
            log.error('Date string could not be parsed: %s, %s',
                      new_time, time_fmt)

            ret['comment'] = 'Date string could not be parsed.'
            ret['result'] = False
            return ret

    if not new_time:
        ret['comment'] = 'Job new_time is required.'
        ret['result'] = False
        return ret
    else:
        try:
            # Validate date string
            datetime.datetime.strptime(new_time, time_fmt)
        except (TypeError, ValueError):
            log.error('Date string could not be parsed: %s, %s',
                      new_time, time_fmt)

            ret['comment'] = 'Date string could not be parsed.'
            ret['result'] = False
            return ret

    if 'test' in __opts__ and __opts__['test']:
        ret['comment'] = 'Job: {0} would be postponed in schedule.'.format(name)
    else:

        if name in list_(show_all=True, where='opts', return_yaml=False):
            event_data = {'name': name,
                          'time': current_time,
                          'new_time': new_time,
                          'time_fmt': time_fmt,
                          'func': 'postpone_job'}
        elif name in list_(show_all=True, where='pillar', return_yaml=False):
            event_data = {'name': name,
                          'time': current_time,
                          'new_time': new_time,
                          'time_fmt': time_fmt,
                          'where': 'pillar',
                          'func': 'postpone_job'}
        else:
            ret['comment'] = 'Job {0} does not exist.'.format(name)
            ret['result'] = False
            return ret

        try:
            eventer = salt.utils.event.get_event('minion', opts=__opts__)
            res = __salt__['event.fire'](event_data, 'manage_schedule')
            if res:
                event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_postpone_job_complete', wait=30)
                if event_ret and event_ret['complete']:
                    schedule = event_ret['schedule']
                    # check item exists in schedule and is enabled
                    if name in schedule and schedule[name]['enabled']:
                        ret['result'] = True
                        ret['comment'] = 'Postponed Job {0} in schedule.'.format(name)
                    else:
                        ret['result'] = False
                        ret['comment'] = 'Failed to postpone job {0} in schedule.'.format(name)
                    return ret
        except KeyError:
            # Effectively a no-op, since we can't really return without an event system
            ret['comment'] = 'Event module not available. Schedule postpone job failed.'
    return ret