Skip to content

Commit

Permalink
NAS-131762 / 25.04 / Add private NFS method to clear rmtab or selecte…
Browse files Browse the repository at this point in the history
…d entries. (#15276)


Make call to clear rmtab from nfs.setup_directories.
Cannot use middleware setup hook because /var/db/system/nfs is not yet available at that point.
  • Loading branch information
mgrimesix authored Dec 31, 2024
1 parent 2746368 commit 42ab42a
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/middlewared/middlewared/plugins/nfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ def setup_directories(self):
except Exception:
self.logger.error('Unexpected failure initializing %r', path, exc_info=True)

# Clear rmtab on boot.
# We call this here because /var/db/system/nfs is not yet available
# in a middleware 'setup' hook. See NAS-131762
if not self.middleware.call_sync('system.ready'):
self.middleware.call_sync('nfs.clear_nfs3_rmtab')

@private
async def nfs_extend(self, nfs):
keytab_has_nfs = await self.middleware.call("kerberos.keytab.has_nfs_principal")
Expand Down
44 changes: 39 additions & 5 deletions src/middlewared/middlewared/plugins/nfs_/status.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import os
import tempfile
import yaml

from contextlib import suppress
from middlewared.plugins.nfs import NFSServicePathInfo
from middlewared.schema import accepts, Int, returns, Str, Dict
from middlewared.service import Service, private, filterable, filterable_returns
from middlewared.utils import filter_list
from middlewared.service_exception import CallError
from contextlib import suppress

import yaml
import os
from middlewared.utils import filter_list


class NFSService(Service):
Expand All @@ -31,6 +32,39 @@ def get_rmtab(self):

return entries

@private
def clear_nfs3_rmtab(self, ip_to_clear=["all"]):
"""
Clear some or all NFSv3 client entries in rmtab.
rmtab can become clogged with stale entries, this provides a
method to clear all or selected entries.
Optional input: list of ip to remove, e.g. ip_to_clear=["a.b.c.d"]
DEFAULT: Clear all entries
"""
rmtab = os.path.join(NFSServicePathInfo.STATEDIR.path(), "rmtab")
with suppress(FileNotFoundError):
# Handle default: clear all
if "all" in ip_to_clear:
with open(rmtab, "w"):
# Use 'w' open to truncate
pass
else:
# Replace rmtab excluding ip_to_clear
with tempfile.NamedTemporaryFile(
mode='wt',
dir=NFSServicePathInfo.STATEDIR.path(),
delete=False
) as outf:
with open(rmtab, "r") as inf:
for entry in inf:
if entry.split(':')[0] in ip_to_clear:
continue
else:
outf.write(entry)
outf.flush()
os.fsync(outf.fileno())
os.rename(outf.name, rmtab)

# NFS_WRITE because this exposes hostnames and IP addresses
# READONLY is considered administrative-level permission
@filterable(roles=['READONLY_ADMIN', 'SHARING_NFS_WRITE'])
Expand Down

0 comments on commit 42ab42a

Please sign in to comment.