""" Reprouce hang when using os.fdopen with inaccessible NFS server. Usage: python fdopen_nfs_test.py mountpoint server_address Example run: mount -t example.com mnt python fdopen_nfs_test.py mnt example.com """ import fcntl import logging import os import subprocess import sys import threading import time mount = sys.argv[1] server = sys.argv[2] logging.basicConfig( level=logging.INFO, format="%(asctime)s - (%(threadName)s) - %(message)s") filename = os.path.join(mount, "test") done = threading.Event() ready = threading.Event() def canary(): logging.info("Blocking access to storage") rule = ["-p", "tcp", "-d", server, "--dport", "2049", "-j", "DROP"] add_rule = ["iptables", "-A", "OUTPUT"] + rule check_rule = ["iptables", "-C", "OUTPUT"] + rule del_rule = ["iptables", "-D", "OUTPUT"] + rule subprocess.check_call(add_rule) logging.info("If this test is hang, please run: %s", " ".join(del_rule)) ready.set() for i in range(20): logging.info("check %d", i) if done.wait(1): break if subprocess.call(check_rule, stderr=subprocess.PIPE) == 0: logging.info("Unblocking access to storage") subprocess.check_call(del_rule) fd = os.open(filename, os.O_RDWR | os.O_CREAT) flags = fcntl.fcntl(fd, fcntl.F_GETFD) flags |= fcntl.FD_CLOEXEC fcntl.fcntl(fd, fcntl.F_SETFD, flags) logging.info("Starting canary thread") threading.Thread(target=canary, name="Canary").start() ready.wait() # For some reason blockng NFS takes time to apply. time.sleep(10) logging.info("Calling os.fdopen") with os.fdopen(fd, "r+") as f: logging.info("OK") logging.info("Done") done.set() os.unlink(filename)