# -*- coding: utf-8 -*-
'''
Management of NFS exports
===============================================

.. versionadded:: 2018.3.0

To ensure an NFS export exists:

.. code-block:: yaml

    add_simple_export:
      nfs_export.present:
        - name:     '/srv/nfs'
        - hosts:    '10.0.2.0/24'
        - options:
          - 'rw'

This creates the following in /etc/exports:

.. code-block:: bash

    /srv/nfs 10.0.2.0/24(rw)

For more complex exports with multiple groups of hosts, use 'clients':

.. code-block:: yaml

    add_complex_export:
      nfs_export.present:
        - name: '/srv/nfs'
        - clients:
          # First export, same as simple one above
          - hosts: '10.0.2.0/24'
            options:
              - 'rw'
          # Second export
          - hosts: '*.example.com'
            options:
              - 'ro'
              - 'subtree_check'

This creates the following in /etc/exports:

.. code-block:: bash

    /srv/nfs 10.0.2.0/24(rw) 192.168.0.0/24,172.19.0.0/16(ro,subtree_check)

Any export of the given path will be modified to match the one specified.

To ensure an NFS export is absent:

.. code-block:: yaml

    delete_export:
      nfs_export.absent:
        - name: '/srv/nfs'

'''
from __future__ import absolute_import, print_function, unicode_literals
import salt.utils.path


def __virtual__():
    '''
    Only work with nfs tools installed
    '''
    cmd = 'exportfs'
    if salt.utils.path.which(cmd):
        return bool(cmd)

    return(
        False,
        'The nfs_exports state module failed to load: '
        'the exportfs binary is not in the path'
    )


def present(name,
            clients=None,
            hosts=None,
            options=None,
            exports='/etc/exports'):
    '''
    Ensure that the named export is present with the given options

    name
        The export path to configure

    clients
        A list of hosts and the options applied to them.
        This option may not be used in combination with
        the 'hosts' or 'options' shortcuts.

    .. code-block:: yaml

        - clients:
          # First export
          - hosts: '10.0.2.0/24'
            options:
              - 'rw'
          # Second export
          - hosts: '*.example.com'
            options:
              - 'ro'
              - 'subtree_check'

    hosts
        A string matching a number of hosts, for example:

    .. code-block:: yaml

        hosts: '10.0.2.123'

        hosts: '10.0.2.0/24'

        hosts: 'minion1.example.com'

        hosts: '*.example.com'

        hosts: '*'

    options
        A list of NFS options, for example:

    .. code-block:: yaml

        options:
          - 'rw'
          - 'subtree_check'

    '''
    path = name
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    if not clients:
        if not hosts:
            ret['result'] = False
            ret['comment'] = 'Either \'clients\' or \'hosts\' must be defined'
            return ret
        # options being None is handled by add_export()
        clients = [{'hosts': hosts, 'options': options}]

    old = __salt__['nfs3.list_exports'](exports)
    if path in old:
        if old[path] == clients:
            ret['result'] = True
            ret['comment'] = 'Export {0} already configured'.format(path)
            return ret

        ret['changes']['new'] = clients
        ret['changes']['old'] = old[path]
        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = 'Export {0} would be changed'.format(path)
            return ret

        __salt__['nfs3.del_export'](exports, path)

    else:
        ret['changes']['old'] = None
        ret['changes']['new'] = clients
        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = 'Export {0} would be added'.format(path)
            return ret

    add_export = __salt__['nfs3.add_export']
    for exp in clients:
        add_export(exports, path, exp['hosts'], exp['options'])

    ret['changes']['new'] = clients

    try_reload = __salt__['nfs3.reload_exports']()
    ret['comment'] = try_reload['stderr']
    ret['result'] = try_reload['result']
    return ret


def absent(name, exports='/etc/exports'):
    '''
    Ensure that the named path is not exported

    name
        The export path to remove
    '''

    path = name
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    old = __salt__['nfs3.list_exports'](exports)
    if path in old:
        if __opts__['test']:
            ret['comment'] = 'Export {0} would be removed'.format(path)
            ret['changes'][path] = old[path]
            ret['result'] = None
            return ret

        __salt__['nfs3.del_export'](exports, path)
        try_reload = __salt__['nfs3.reload_exports']()
        if not try_reload['result']:
            ret['comment'] = try_reload['stderr']
        else:
            ret['comment'] = 'Export {0} removed'.format(path)

        ret['result'] = try_reload['result']
        ret['changes'][path] = old[path]
    else:
        ret['comment'] = 'Export {0} already absent'.format(path)
        ret['result'] = True

    return ret
