File: //usr/lib/python2.7/site-packages/salt/modules/nfs3.py
# -*- coding: utf-8 -*-
'''
Module for managing NFS version 3.
'''
from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import logging
# Import salt libs
from salt.ext import six
import salt.utils.files
import salt.utils.path
import salt.utils.stringutils
log = logging.getLogger(__name__)
def __virtual__():
'''
Only work on POSIX-like systems
'''
if not salt.utils.path.which('showmount'):
return (False, 'The nfs3 execution module failed to load: the showmount binary is not in the path.')
return True
def list_exports(exports='/etc/exports'):
'''
List configured exports
CLI Example:
.. code-block:: bash
salt '*' nfs.list_exports
'''
ret = {}
with salt.utils.files.fopen(exports, 'r') as efl:
for line in salt.utils.stringutils.to_unicode(efl.read()).splitlines():
if not line:
continue
if line.startswith('#'):
continue
comps = line.split()
# Handle the case where the same path is given twice
if not comps[0] in ret:
ret[comps[0]] = []
newshares = []
for perm in comps[1:]:
if perm.startswith('/'):
newshares.append(perm)
continue
permcomps = perm.split('(')
permcomps[1] = permcomps[1].replace(')', '')
hosts = permcomps[0]
if not isinstance(hosts, six.string_types):
# Lists, etc would silently mangle /etc/exports
raise TypeError('hosts argument must be a string')
options = permcomps[1].split(',')
ret[comps[0]].append({'hosts': hosts, 'options': options})
for share in newshares:
ret[share] = ret[comps[0]]
return ret
def del_export(exports='/etc/exports', path=None):
'''
Remove an export
CLI Example:
.. code-block:: bash
salt '*' nfs.del_export /media/storage
'''
edict = list_exports(exports)
del edict[path]
_write_exports(exports, edict)
return edict
def add_export(exports='/etc/exports', path=None, hosts=None, options=None):
'''
Add an export
CLI Example:
.. code-block:: bash
salt '*' nfs3.add_export path='/srv/test' hosts='127.0.0.1' options=['rw']
'''
if options is None:
options = []
if not isinstance(hosts, six.string_types):
# Lists, etc would silently mangle /etc/exports
raise TypeError('hosts argument must be a string')
edict = list_exports(exports)
if path not in edict:
edict[path] = []
new = {'hosts': hosts, 'options': options}
edict[path].append(new)
_write_exports(exports, edict)
return new
def _write_exports(exports, edict):
'''
Write an exports file to disk
If multiple shares were initially configured per line, like:
/media/storage /media/data *(ro,sync,no_subtree_check)
...then they will be saved to disk with only one share per line:
/media/storage *(ro,sync,no_subtree_check)
/media/data *(ro,sync,no_subtree_check)
'''
with salt.utils.files.fopen(exports, 'w') as efh:
for export in edict:
line = salt.utils.stringutils.to_str(export)
for perms in edict[export]:
hosts = perms['hosts']
options = ','.join(perms['options'])
line += ' {0}({1})'.format(hosts, options)
efh.write('{0}\n'.format(line))
def reload_exports():
'''
Trigger a reload of the exports file to apply changes
CLI Example:
.. code-block:: bash
salt '*' nfs3.reload_exports
'''
ret = {}
command = 'exportfs -r'
output = __salt__['cmd.run_all'](command)
ret['stdout'] = output['stdout']
ret['stderr'] = output['stderr']
# exportfs always returns 0, so retcode is useless
# We will consider it an error if stderr is nonempty
ret['result'] = output['stderr'] == ''
return ret