Search code examples
pythonlinuxnfs

Check in python script if NFS server is mounted and online


I have a question similar to Check if NFS share is mounted in python script, however in my case the NFS server is mounted, but the server crashed and went offline. I tried to take this into account by using os.dir.ismount('/path/to/mountpoint/) however my problem is that this command takes forever to finish.

When I try to make a simple ls /path/to/mountpoint this command also does not finish. Is there something fundamentally wrong? My setup is a linux NFSv3 server and a linux NFS client.

I usually expect that if the NFS server is unmountable or not reachable anymore that the ls command shows the content of the local directory instead of halting the terminal.


Solution

  • This happens with NFS, if you have mounted an NFS share and the server is no longer network reachable frequently what happens is any IO access to the mount just gets stuck. If you try and run ls in a terminal you will see it just gets stuck, doesn't fail just waits endlessly for a response it will never get. So what I recommend you do is run ls in your python code and then set a timeout. Once this timeout is reached you can have it raise an exception. Below is an implementation I have tested. call_timeout is a function that you give the command you want to execute and the timeout period in seconds. If the command completes before timeout it returns immediately, otherwise it kills the process it spawned and raises an OSError which you can catch. You could chose to return True or False instead, it's a design choice. Some sample calls are provided below as well.

    code

    from subprocess import Popen, check_output
    import time
    
    def call_timeout(cmd, timeout):
        start = time.time()
        p = Popen(cmd)
        while time.time() - start < timeout:
            if p.poll() is not None:
                return
            time.sleep(0.1)
        p.kill()
        raise OSError('command timed out')
    

    Example calls

    this should return with no errors:

    call_timeout(["sleep", "1"], 0.5)
    

    this will raise OSError error:

    call_timeout(["sleep", "1"], 1.5)
    

    you want something along these lines:

    call_timeout(["ls", "/path/to/mountpoint"], 5.0)