In a glaring oversight the changes made via targetd for nfs exports was lost on system reboot. This patch fixes that by taking every export that is listed via `exportfs -v` and writes each entry to /etc/exports.d.
At the moment for updates the code just removes every file that is has created and re-creates a new file for each entry. Not the most performant implementation, but it minimizes risk to updating an existing export and not getting the change written out correctly. In big config testing we may find that this simple approach is actually faster than opening and checking each file for correctness and then updating/deleting etc. as needed.
Signed-off-by: Tony Asleson tasleson@redhat.com --- targetd/nfs.py | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/targetd/nfs.py b/targetd/nfs.py index 6daf99e..3b157db 100644 --- a/targetd/nfs.py +++ b/targetd/nfs.py @@ -13,6 +13,15 @@
from subprocess import Popen, PIPE import re +import hashlib +import os +import os.path + + +def md5(t): + h = hashlib.md5() + h.update(t) + return h.hexdigest()
def invoke(cmd, raise_exception=True): @@ -189,12 +198,21 @@ class Export(object): return "%s%s(%s)" % (self.path.ljust(50), self.host, self.options_string())
+ def to_export_file(self, file_name): + content = "%s %s(%s)\n" % (self.path, self.host, self.options_string()) + + with open(file_name, 'w') as ef: + ef.write(content) +
class Nfs(object): """ Python module for configuring NFS exports """ - cmd = 'exportfs' + CMD = 'exportfs' + FILE_PREFIX = 'targetd_' + + EXPORT_FS_CONFIG_DIR = '/etc/exports.d'
def __init__(self): pass @@ -204,12 +222,25 @@ class Nfs(object): return "sys", "krb5", "krb5i", "krb5p"
@staticmethod + def _save_exports(): + #Remove all existing exports that we created + for root, dirs, files in os.walk(Nfs.EXPORT_FS_CONFIG_DIR): + for f in files: + if f[0:len(Nfs.FILE_PREFIX)] == Nfs.FILE_PREFIX: + os.remove(os.path.join(root, f)) + + #Recreate all existing exports + for e in Nfs.exports(): + fn = "%s%s.exports" % (Nfs.FILE_PREFIX, md5(str(e))) + e.to_export_file(os.path.join(Nfs.EXPORT_FS_CONFIG_DIR, fn)) + + @staticmethod def exports(): """ Return list of exports """ rc = [] - ec, out, error = invoke([Nfs.cmd, '-v']) + ec, out, error = invoke([Nfs.CMD, '-v']) rc = Export.parse(out) return rc
@@ -221,7 +252,7 @@ class Nfs(object): export = Export(host, path, bit_wise_options, key_value_options) options = export.options_string()
- cmd = [Nfs.cmd] + cmd = [Nfs.CMD]
if len(options): cmd.extend(['-o', options]) @@ -230,6 +261,7 @@ class Nfs(object):
ec, out, err = invoke(cmd, False) if ec == 0: + Nfs._save_exports() return None elif ec == 22: raise ValueError("Invalid option: %s" % err) @@ -240,5 +272,8 @@ class Nfs(object):
@staticmethod def export_remove(export): - ec, out, err = invoke([Nfs.cmd, '-u', '%s:%s' % + ec, out, err = invoke([Nfs.CMD, '-u', '%s:%s' % (export.host, export.path)]) + + if ec == 0: + Nfs._save_exports()