Builds the config logic for `load_config` and `load_template` functions.

def _config_logic(napalm_device,
                  loaded_result,
                  test=False,
                  debug=False,
                  replace=False,
                  commit_config=True,
                  loaded_config=None,
                  commit_in=None,
                  commit_at=None,
                  revert_in=None,
                  revert_at=None,
                  commit_jid=None,
                  **kwargs):
    '''
    Builds the config logic for `load_config` and `load_template` functions.
    '''
    # As the Salt logic is built around independent events
    # when it comes to configuration changes in the
    # candidate DB on the network devices, we need to
    # make sure we're using the same session.
    # Hence, we need to pass the same object around.
    # the napalm_device object is inherited from
    # the load_config or load_template functions
    # and forwarded to compare, discard, commit etc.
    # then the decorator will make sure that
    # if not proxy (when the connection is always alive)
    # and the `inherit_napalm_device` is set,
    # `napalm_device` will be overridden.
    # See `salt.utils.napalm.proxy_napalm_wrap` decorator.

    current_jid = kwargs.get('__pub_jid')
    if not current_jid:
        current_jid = '{0:%Y%m%d%H%M%S%f}'.format(datetime.datetime.now())

    loaded_result['already_configured'] = False

    loaded_result['loaded_config'] = ''
    if debug:
        loaded_result['loaded_config'] = loaded_config

    _compare = compare_config(inherit_napalm_device=napalm_device)
    if _compare.get('result', False):
        loaded_result['diff'] = _compare.get('out')
        loaded_result.pop('out', '')  # not needed
    else:
        loaded_result['diff'] = None
        loaded_result['result'] = False
        loaded_result['comment'] = _compare.get('comment')
        __context__['retcode'] = 1
        return loaded_result

    _loaded_res = loaded_result.get('result', False)
    if not _loaded_res or test:
        # if unable to load the config (errors / warnings)
        # or in testing mode,
        # will discard the config
        if loaded_result['comment']:
            loaded_result['comment'] += '\n'
        if not loaded_result.get('diff', ''):
            loaded_result['already_configured'] = True
        discarded = _safe_dicard_config(loaded_result, napalm_device)
        if not discarded['result']:
            return loaded_result
        loaded_result['comment'] += 'Configuration discarded.'
        # loaded_result['result'] = False not necessary
        # as the result can be true when test=True
        _explicit_close(napalm_device)
        if not loaded_result['result']:
            __context__['retcode'] = 1
        return loaded_result

    if not test and commit_config:
        # if not in testing mode and trying to commit
        if commit_jid:
            log.info('Committing the JID: %s', str(commit_jid))
            removed = cancel_commit(commit_jid)
            log.debug('Cleaned up the commit from the schedule')
            log.debug(removed['comment'])
        if loaded_result.get('diff', ''):
            # if not testing mode
            # and also the user wants to commit (default)
            # and there are changes to commit
            if commit_in or commit_at:
                commit_time = __utils__['timeutil.get_time_at'](time_in=commit_in,
                                                                time_at=commit_in)
                # schedule job
                scheduled_job_name = '__napalm_commit_{}'.format(current_jid)
                temp_file = salt.utils.files.mkstemp()
                with salt.utils.files.fopen(temp_file, 'w') as fp_:
                    fp_.write(loaded_config)
                scheduled = __salt__['schedule.add'](scheduled_job_name,
                                                     function='net.load_config',
                                                     job_kwargs={
                                                         'filename': temp_file,
                                                         'commit_jid': current_jid,
                                                         'replace': replace
                                                     },
                                                     once=commit_time)
                log.debug('Scheduling job')
                log.debug(scheduled)
                saved = __salt__['schedule.save']()  # ensure the schedule is
                # persistent cross Minion restart
                discarded = _safe_dicard_config(loaded_result, napalm_device)
                # discard the changes
                if not discarded['result']:
                    discarded['comment'] += ('Scheduled the job to be executed at {schedule_ts}, '
                        'but was unable to discard the config: \n').format(schedule_ts=commit_time)
                    return discarded
                loaded_result['comment'] = ('Changes discarded for now, and scheduled commit at: {schedule_ts}.\n'
                    'The commit ID is: {current_jid}.\n'
                    'To discard this commit, you can execute: \n\n'
                    'salt {min_id} net.cancel_commit {current_jid}').format(schedule_ts=commit_time,
                                                                             min_id=__opts__['id'],
                                                                             current_jid=current_jid)
                loaded_result['commit_id'] = current_jid
                return loaded_result
            log.debug('About to commit:')
            log.debug(loaded_result['diff'])
            if revert_in or revert_at:
                revert_time = __utils__['timeutil.get_time_at'](time_in=revert_in,
                                                                time_at=revert_at)
                if __grains__['os'] == 'junos':
                    if not HAS_JXMLEASE:
                        loaded_result['comment'] = ('This feature requires the library jxmlease to be installed.\n'
                                'To install, please execute: ``pip install jxmlease``.')
                        loaded_result['result'] = False
                        return loaded_result
                    timestamp_at = __utils__['timeutil.get_timestamp_at'](time_in=revert_in,
                                                                          time_at=revert_at)
                    minutes = int((timestamp_at - time.time())/60)
                    _comm = __salt__['napalm.junos_commit'](confirm=minutes)
                    if not _comm['out']:
                        # If unable to commit confirm, should try to bail out
                        loaded_result['comment'] = 'Unable to commit confirm: {}'.format(_comm['message'])
                        loaded_result['result'] = False
                        # But before exiting, we must gracefully discard the config
                        discarded = _safe_dicard_config(loaded_result, napalm_device)
                        if not discarded['result']:
                            return loaded_result
                else:
                    temp_file = salt.utils.files.mkstemp()
                    running_config = __salt__['net.config'](source='running')['out']['running']
                    with salt.utils.files.fopen(temp_file, 'w') as fp_:
                        fp_.write(running_config)
                    committed = _safe_commit_config(loaded_result, napalm_device)
                    if not committed['result']:
                        # If unable to commit, dicard the config (which is
                        # already done by the _safe_commit_config function), and
                        # return with the command and other details.
                        return loaded_result
                    scheduled_job_name = '__napalm_commit_{}'.format(current_jid)
                    scheduled = __salt__['schedule.add'](scheduled_job_name,
                                                         function='net.load_config',
                                                         job_kwargs={
                                                             'filename': temp_file,
                                                             'commit_jid': current_jid,
                                                             'replace': True
                                                         },
                                                         once=revert_time)
                    log.debug('Scheduling commit confirmed')
                    log.debug(scheduled)
                    saved = __salt__['schedule.save']()
                loaded_result['comment'] = ('The commit ID is: {current_jid}.\n'
                        'This commit will be reverted at: {schedule_ts}, unless confirmed.\n'
                        'To confirm the commit and avoid reverting, you can execute:\n\n'
                        'salt {min_id} net.confirm_commit {current_jid}').format(schedule_ts=revert_time,
                                                                                 min_id=__opts__['id'],
                                                                                 current_jid=current_jid)
                loaded_result['commit_id'] = current_jid
                return loaded_result
            committed = _safe_commit_config(loaded_result, napalm_device)
            if not committed['result']:
                return loaded_result
        else:
            # would like to commit, but there's no change
            # need to call discard_config() to release the config DB
            discarded = _safe_dicard_config(loaded_result, napalm_device)
            if not discarded['result']:
                return loaded_result
            loaded_result['already_configured'] = True
            loaded_result['comment'] = 'Already configured.'
    _explicit_close(napalm_device)
    if not loaded_result['result']:
        __context__['retcode'] = 1
    return loaded_result