Преглед на файлове

Make a unique directory each chutney run, and symlink to a standard name

Instead of moving the directory to a unique path at the start of the next
run, which makes it impossible to find if running several networks in
succession, like we do in 'make test-network-all'.

Closes 21567.
teor преди 7 години
родител
ревизия
f2fe67e98d
променени са 1 файла, в които са добавени 69 реда и са изтрити 10 реда
  1. 69 10
      lib/chutney/TorNet.py

+ 69 - 10
lib/chutney/TorNet.py

@@ -68,6 +68,26 @@ def get_absolute_net_path():
     # ok, it's relative to the current directory, whatever that is
     return os.path.abspath(relative_net_path)
 
+def get_absolute_nodes_path():
+    # there's no way to customise this: we really don't need more options
+    return os.path.join(get_absolute_net_path(), 'nodes')
+
+def get_new_absolute_nodes_path(now=time.time()):
+    # automatically chosen to prevent path collisions, and result in an ordered
+    # series of directory path names
+    # should only be called by 'chutney configure', all other chutney commands
+    # should use get_absolute_nodes_path()
+    nodesdir = get_absolute_nodes_path()
+    newdir = newdirbase = "%s.%d" % (nodesdir, now)
+    # if the time is the same, fall back to a simple integer count
+    # (this is very unlikely to happen unless the clock changes: it's not
+    # possible to run multiple chutney networks at the same time)
+    i = 0
+    while os.path.exists(newdir):
+        i += 1
+        newdir = "%s.%d" % (newdirbase, i)
+    return newdir
+
 class Node(object):
 
     """A Node represents a Tor node or a set of Tor nodes.  It's created
@@ -838,29 +858,68 @@ class Network(object):
         self._nextnodenum += 1
         self._nodes.append(n)
 
-    def move_aside_nodes(self):
-        net_base_dir = get_absolute_net_path()
-        nodesdir = os.path.join(net_base_dir, 'nodes')
+    def move_aside_nodes_dir(self):
+        """Move aside the nodes directory, if it exists and is not a link.
+        Used for backwards-compatibility only: nodes is created as a link to
+        a new directory with a unique name in the current implementation.
+        """
+        nodesdir = get_absolute_nodes_path()
 
+        # only move the directory if it exists
         if not os.path.exists(nodesdir):
             return
+        # and if it's not a link
+        if os.path.islink(nodesdir):
+            return
 
-        newdir = newdirbase = "%s.%d" % (nodesdir, time.time())
-        i = 0
-        while os.path.exists(newdir):
-            i += 1
-            newdir = "%s.%d" % (newdirbase, i)
+        # subtract 1 second to avoid collisions and get the correct ordering
+        newdir = get_new_absolute_nodes_path(time.time() - 1)
 
         print("NOTE: renaming %r to %r" % (nodesdir, newdir))
         os.rename(nodesdir, newdir)
 
+    def create_new_nodes_dir(self):
+        """Create a new directory with a unique name, and symlink it to nodes
+        """
+        # for backwards compatibility, move aside the old nodes directory
+        # (if it's not a link)
+        self.move_aside_nodes_dir()
+
+        # the unique directory we'll create
+        newnodesdir = get_new_absolute_nodes_path()
+        # the canonical name we'll link it to
+        nodeslink = get_absolute_nodes_path()
+
+        # this path should be unique and should not exist
+        if os.path.exists(newnodesdir):
+            raise RuntimeError(
+                'get_new_absolute_nodes_path returned a path that exists')
+
+        # if this path exists, it must be a link
+        if os.path.exists(nodeslink) and not os.path.islink(nodeslink):
+            raise RuntimeError(
+                'get_absolute_nodes_path returned a path that exists and is not a link')
+
+        # create the new, uniquely named directory, and link it to nodes
+        print("NOTE: creating %r, linking to %r" % (newnodesdir, nodeslink))
+        # this gets created with mode 0700, that's probably ok
+        mkdir_p(newnodesdir)
+        try:
+            os.unlink(nodeslink)
+        except OSError as e:
+            # it's ok if the link doesn't exist, we're just about to make it
+            if e.errno == errno.ENOENT:
+                pass
+            else:
+                raise
+        os.symlink(newnodesdir, nodeslink)
+
     def _checkConfig(self):
         for n in self._nodes:
             n.getBuilder().checkConfig(self)
 
     def configure(self):
-        # shutil.rmtree(os.path.join(os.getcwd(),'net','nodes'),ignore_errors=True)
-        self.move_aside_nodes()
+        self.create_new_nodes_dir()
         network = self
         altauthlines = []
         bridgelines = []