Configures the node with the specified commands.

    This method is used to send configuration commands to the node.  It
    will take either a string or a list and prepend the necessary commands
    to put the session into config mode.

    Returns the diff after the configuration commands are loaded.

    config_file
        The source file with the configuration commands to be sent to the
        device.

        The file can also be a template that can be rendered using the template
        engine of choice.

        This can be specified using the absolute path to the file, or using one
        of the following URL schemes:

        - ``salt://``, to fetch the file from the Salt fileserver.
        - ``http://`` or ``https://``
        - ``ftp://``
        - ``s3://``
        - ``swift://``

    commands
        The commands to send to the node in config mode.  If the commands
        argument is a string it will be cast to a list.
        The list of commands will also be prepended with the necessary commands
        to put the session in config mode.

        .. note::

            This argument is ignored when ``config_file`` is specified.

    template_engine: ``jinja``
        The template engine to use when rendering the source file. Default:
        ``jinja``. To simply fetch the file without attempting to render, set
        this argument to ``None``.

    context
        Variables to add to the template context.

    defaults
        Default values of the ``context`` dict.

    transport: ``https``
        Specifies the type of connection transport to use. Valid values for the
        connection are ``socket``, ``http_local``, ``http``, and  ``https``.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    host: ``localhost``
        The IP address or DNS host name of the connection device.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    username: ``admin``
        The username to pass to the device to authenticate the eAPI connection.

         .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    password
        The password to pass to the device to authenticate the eAPI connection.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    port
        The TCP port of the endpoint for the eAPI connection. If this keyword is
        not specified, the default value is automatically determined by the
        transport type (``80`` for ``http``, or ``443`` for ``https``).

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    enablepwd
        The enable mode password if required by the destination node.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    CLI Example:

    .. code-block:: bash

        salt '*' pyeapi.config commands="['ntp server 1.2.3.4', 'ntp server 5.6.7.8']"
        salt '*' pyeapi.config config_file=salt://config.txt
        salt '*' pyeapi.config config_file=https://bit.ly/2LGLcDy context="{'servers': ['1.2.3.4']}"

def config(commands=None,
           config_file=None,
           template_engine='jinja',
           context=None,
           defaults=None,
           saltenv='base',
           **kwargs):
    '''
    Configures the node with the specified commands.

    This method is used to send configuration commands to the node.  It
    will take either a string or a list and prepend the necessary commands
    to put the session into config mode.

    Returns the diff after the configuration commands are loaded.

    config_file
        The source file with the configuration commands to be sent to the
        device.

        The file can also be a template that can be rendered using the template
        engine of choice.

        This can be specified using the absolute path to the file, or using one
        of the following URL schemes:

        - ``salt://``, to fetch the file from the Salt fileserver.
        - ``http://`` or ``https://``
        - ``ftp://``
        - ``s3://``
        - ``swift://``

    commands
        The commands to send to the node in config mode.  If the commands
        argument is a string it will be cast to a list.
        The list of commands will also be prepended with the necessary commands
        to put the session in config mode.

        .. note::

            This argument is ignored when ``config_file`` is specified.

    template_engine: ``jinja``
        The template engine to use when rendering the source file. Default:
        ``jinja``. To simply fetch the file without attempting to render, set
        this argument to ``None``.

    context
        Variables to add to the template context.

    defaults
        Default values of the ``context`` dict.

    transport: ``https``
        Specifies the type of connection transport to use. Valid values for the
        connection are ``socket``, ``http_local``, ``http``, and  ``https``.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    host: ``localhost``
        The IP address or DNS host name of the connection device.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    username: ``admin``
        The username to pass to the device to authenticate the eAPI connection.

         .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    password
        The password to pass to the device to authenticate the eAPI connection.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    port
        The TCP port of the endpoint for the eAPI connection. If this keyword is
        not specified, the default value is automatically determined by the
        transport type (``80`` for ``http``, or ``443`` for ``https``).

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    enablepwd
        The enable mode password if required by the destination node.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    CLI Example:

    .. code-block:: bash

        salt '*' pyeapi.config commands="['ntp server 1.2.3.4', 'ntp server 5.6.7.8']"
        salt '*' pyeapi.config config_file=salt://config.txt
        salt '*' pyeapi.config config_file=https://bit.ly/2LGLcDy context="{'servers': ['1.2.3.4']}"
    '''
    initial_config = get_config(as_string=True, **kwargs)
    if config_file:
        file_str = __salt__['cp.get_file_str'](config_file, saltenv=saltenv)
        if file_str is False:
            raise CommandExecutionError('Source file {} not found'.format(config_file))
        log.debug('Fetched from %s', config_file)
        log.debug(file_str)
    elif commands:
        if isinstance(commands, (six.string_types, six.text_type)):
            commands = [commands]
        file_str = '\n'.join(commands)
        # unify all the commands in a single file, to render them in a go
    if template_engine:
        file_str = __salt__['file.apply_template_on_contents'](file_str,
                                                               template_engine,
                                                               context,
                                                               defaults,
                                                               saltenv)
        log.debug('Rendered:')
        log.debug(file_str)
    # whatever the source of the commands would be, split them line by line
    commands = [line for line in file_str.splitlines() if line.strip()]
    # push the commands one by one, removing empty lines
    configured = call('config', commands, **kwargs)
    current_config = get_config(as_string=True, **kwargs)
    diff = difflib.unified_diff(initial_config.splitlines(1)[4:], current_config.splitlines(1)[4:])
    return ''.join([x.replace('\r', '') for x in diff])