wificell: keep tmp files under /tmp/autotest-* and clean them out

We don't want garbage from previous tests to affect future ones. Keep
them in a well-known subdirectory of /tmp and clear them out each time
we spin up a new test on a router or pcap device.

netserver is an odd case:
 * it hardcodes /tmp in the source code;
 * it prodcues empty logfiles that we were never capturing in the first
   place; and
 * it has several users, where some run on LinuxSystem (i.e., the
   router), some run on the client (WiFiClient), and NetperfRunner isn't
   very well designed to care about which one is which.
Given all that, I found it easier to just run it with an ephemeral /tmp,
via minijail.

BUG=chromium:1033275
TEST=run a few tests from suite:wifi_matfunc, suite:wifi_perf

Change-Id: Ic2f0618d330ba8ebe48692b3cc7af998f1eade64
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/1965856
Tested-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Shuo-Peng Liao <deanliao@chromium.org>
Commit-Queue: Brian Norris <briannorris@chromium.org>
diff --git a/server/cros/network/netperf_runner.py b/server/cros/network/netperf_runner.py
index a63af25..c8cd7fd 100644
--- a/server/cros/network/netperf_runner.py
+++ b/server/cros/network/netperf_runner.py
@@ -498,6 +498,18 @@
             self._server_host = client_proxy.host
             self._client_host = server_proxy.host
             self._target_ip = client_proxy.wifi_ip
+
+        # Assume minijail0 is on ${PATH}, but raise exception if it's not
+        # available on both server and client.
+        self._minijail = 'minijail0'
+        path_utils.must_be_installed(self._minijail, host=self._server_host)
+        path_utils.must_be_installed(self._minijail, host=self._client_host)
+        # Bind mount a tmpfs over /tmp, since netserver hard-codes the /tmp
+        # path. netserver's log files aren't useful anyway.
+        self._minijail = ("%s -v -k 'tmpfs,/tmp,tmpfs,"
+                          "MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M'"
+                          % self._minijail)
+
         self._command_netserv = path_utils.must_be_installed(
                 'netserver', host=self._server_host)
         self._command_netperf = path_utils.must_be_installed(
@@ -525,8 +537,9 @@
     def _restart_netserv(self):
         logging.info('Starting netserver...')
         self._kill_netserv()
-        self._server_host.run('%s -p %d' %
-                              (self._command_netserv, self.NETPERF_PORT))
+        self._server_host.run('%s %s -p %d' %
+                              (self._minijail, self._command_netserv,
+                               self.NETPERF_PORT))
         startup_time = time.time()
         self._client_proxy.firewall_open('tcp', self._server_proxy.wifi_ip)
         self._client_proxy.firewall_open('udp', self._server_proxy.wifi_ip)
diff --git a/server/cros/network/packet_capturer.py b/server/cros/network/packet_capturer.py
index 099e4d9..eda42be 100644
--- a/server/cros/network/packet_capturer.py
+++ b/server/cros/network/packet_capturer.py
@@ -96,13 +96,13 @@
 
 
 def get_packet_capturer(host, host_description=None, cmd_ip=None, cmd_iw=None,
-                        cmd_netdump=None, ignore_failures=False):
+                        cmd_netdump=None, ignore_failures=False, logdir=None):
     cmd_iw = cmd_iw or path_utils.get_install_path('iw', host=host)
     cmd_ip = cmd_ip or path_utils.get_install_path('ip', host=host)
     cmd_netdump = (cmd_netdump or
                    path_utils.get_install_path('tcpdump', host=host))
     host_description = host_description or 'cap_%s' % uuid.uuid4().hex
-    if None in [cmd_iw, cmd_ip, cmd_netdump, host_description]:
+    if None in [cmd_iw, cmd_ip, cmd_netdump, host_description, logdir]:
         if ignore_failures:
             logging.warning('Creating a disabled packet capturer for %s.',
                             host_description)
@@ -111,7 +111,8 @@
             raise error.TestFail('Missing commands needed for '
                                  'capturing packets')
 
-    return PacketCapturer(host, host_description, cmd_ip, cmd_iw, cmd_netdump)
+    return PacketCapturer(host, host_description, cmd_ip, cmd_iw, cmd_netdump,
+                          logdir=logdir)
 
 
 class DisabledPacketCapturer(object):
@@ -212,7 +213,7 @@
 
 
     def __init__(self, host, host_description, cmd_ip, cmd_iw, cmd_netdump,
-                 disable_captures=False):
+                 logdir, disable_captures=False):
         self._cmd_netdump = cmd_netdump
         self._cmd_iw = cmd_iw
         self._cmd_ip = cmd_ip
@@ -223,6 +224,7 @@
         self._created_managed_devices = []
         self._created_raw_devices = []
         self._host_description = host_description
+        self._logdir = logdir
 
 
     def __enter__(self):
@@ -363,7 +365,7 @@
 
         """
         remote_file = (remote_file or
-                       '/tmp/%s.%d.pcap' % (self._host_description,
+                       '%s/%s.%d.pcap' % (self._logdir, self._host_description,
                                             self._cap_num))
         self._cap_num += 1
         remote_log_file = '%s.log' % remote_file
diff --git a/server/site_linux_router.py b/server/site_linux_router.py
index c3b3747..5057781 100644
--- a/server/site_linux_router.py
+++ b/server/site_linux_router.py
@@ -5,6 +5,7 @@
 import collections
 import copy
 import logging
+import os
 import random
 import string
 import tempfile
@@ -102,17 +103,17 @@
     SUFFIX_LETTERS = string.ascii_lowercase + string.digits
     SUBNET_PREFIX_OCTETS = (192, 168)
 
-    HOSTAPD_CONF_FILE_PATTERN = '/tmp/hostapd-test-%s.conf'
-    HOSTAPD_LOG_FILE_PATTERN = '/tmp/hostapd-test-%s.log'
-    HOSTAPD_STDERR_LOG_FILE_PATTERN = '/tmp/hostapd-stderr-test-%s.log'
-    HOSTAPD_CONTROL_INTERFACE_PATTERN = '/tmp/hostapd-test-%s.ctrl'
+    HOSTAPD_CONF_FILE_PATTERN = 'hostapd-test-%s.conf'
+    HOSTAPD_LOG_FILE_PATTERN = 'hostapd-test-%s.log'
+    HOSTAPD_STDERR_LOG_FILE_PATTERN = 'hostapd-stderr-test-%s.log'
+    HOSTAPD_CONTROL_INTERFACE_PATTERN = 'hostapd-test-%s.ctrl'
     HOSTAPD_DRIVER_NAME = 'nl80211'
 
     STATION_CONF_FILE_PATTERN = '/tmp/wpa-supplicant-test-%s.conf'
     STATION_LOG_FILE_PATTERN = '/tmp/wpa-supplicant-test-%s.log'
     STATION_PID_FILE_PATTERN = '/tmp/wpa-supplicant-test-%s.pid'
 
-    MGMT_FRAME_SENDER_LOG_FILE = '/tmp/send_management_frame-test.log'
+    MGMT_FRAME_SENDER_LOG_FILE = 'send_management_frame-test.log'
 
     PROBE_RESPONSE_FOOTER_FILE = '/tmp/autotest-probe_response_footer'
 
@@ -183,8 +184,8 @@
                 '/usr/sbin/hostapd_cli', host=self.host)
         self.cmd_wpa_supplicant = path_utils.must_be_installed(
                 '/usr/sbin/wpa_supplicant', host=self.host)
-        self.dhcpd_conf = '/tmp/dhcpd.%s.conf'
-        self.dhcpd_leases = '/tmp/dhcpd.leases'
+        self.dhcpd_conf = os.path.join(self.logdir, 'dhcpd.%s.conf')
+        self.dhcpd_leases = os.path.join(self.logdir, 'dhcpd.leases')
 
         # Log the most recent message on the router so that we can rebuild the
         # suffix relevant to us when debugging failures.
@@ -249,13 +250,15 @@
 
     def close(self):
         """Close global resources held by this system."""
+        router_log = os.path.join(self.logdir, 'router_log')
         self.deconfig()
         # dnsmasq and hostapd cause interesting events to go to system logs.
         # Retrieve only the suffix of the logs after the timestamp we stored on
         # router creation.
-        self.host.run("sed -n -e '/%s/,$p' /var/log/messages >/tmp/router_log" %
-                      self._log_start_timestamp, ignore_status=True)
-        self.host.get_file('/tmp/router_log', 'debug/router_host_messages')
+        self.host.run("sed -n -e '/%s/,$p' /var/log/messages >%s" %
+                      (self._log_start_timestamp, router_log),
+                      ignore_status=True)
+        self.host.get_file(router_log, 'debug/router_host_messages')
         super(LinuxRouter, self).close()
 
 
@@ -285,10 +288,14 @@
                                     configuration.min_streams)
         phy_name = self.iw_runner.get_interface(interface).phy
 
-        conf_file = self.HOSTAPD_CONF_FILE_PATTERN % interface
-        log_file = self.HOSTAPD_LOG_FILE_PATTERN % interface
-        stderr_log_file = self.HOSTAPD_STDERR_LOG_FILE_PATTERN % interface
-        control_interface = self.HOSTAPD_CONTROL_INTERFACE_PATTERN % interface
+        conf_file = os.path.join(self.logdir,
+                self.HOSTAPD_CONF_FILE_PATTERN % interface)
+        log_file = os.path.join(self.logdir,
+                self.HOSTAPD_LOG_FILE_PATTERN % interface)
+        stderr_log_file = os.path.join(self.logdir,
+                self.HOSTAPD_STDERR_LOG_FILE_PATTERN % interface)
+        control_interface = os.path.join(self.logdir,
+                self.HOSTAPD_CONTROL_INTERFACE_PATTERN % interface)
         hostapd_conf_dict = configuration.generate_dict(
                 interface, control_interface,
                 self.build_unique_ssid(suffix=configuration.ssid_suffix))
@@ -1053,7 +1060,8 @@
         if probe_resp_footer is not None:
             self._prep_probe_response_footer(footer=probe_resp_footer)
             command += ' -f %s' % (self.PROBE_RESPONSE_FOOTER_FILE)
-        command += ' > %s 2>&1 & echo $!' % (self.MGMT_FRAME_SENDER_LOG_FILE)
+        command += ' > %s 2>&1 & echo $!' % (os.path.join(self.logdir,
+            self.MGMT_FRAME_SENDER_LOG_FILE))
         pid = int(self.router.run(command).stdout)
         return pid
 
diff --git a/server/site_linux_system.py b/server/site_linux_system.py
index dbe197b..d02c18d 100644
--- a/server/site_linux_system.py
+++ b/server/site_linux_system.py
@@ -49,6 +49,7 @@
     MAC_RETRY_LIMIT = 1000
 
     _UMA_EVENTS = '/var/lib/metrics/uma-events'
+    _LOG_PATH_PREFIX = '/tmp/autotest-'
 
 
     @property
@@ -84,6 +85,12 @@
         or to re-establish a good state after a reboot.
 
         """
+        # hostapd, tcpdump, netperf, etc., may leave behind logs, pcap files,
+        # etc., which can fill up tmpfs. Clear them out now.
+        self.host.run('rm -rf %s*' % self._LOG_PATH_PREFIX)
+        self._logdir = self.host.run('mktemp -d %sXXXXXX' %
+                self._LOG_PATH_PREFIX).stdout.strip()
+
         # Command locations.
         cmd_iw = path_utils.must_be_installed('/usr/sbin/iw', host=self.host)
         self.cmd_ip = path_utils.must_be_installed('/usr/sbin/ip',
@@ -93,7 +100,7 @@
 
         self._packet_capturer = packet_capturer.get_packet_capturer(
                 self.host, host_description=self.role, cmd_ip=self.cmd_ip,
-                cmd_iw=cmd_iw, ignore_failures=True)
+                cmd_iw=cmd_iw, ignore_failures=True, logdir=self.logdir)
         self.iw_runner = iw_runner.IwRunner(remote_host=self.host,
                                             command_iw=cmd_iw)
 
@@ -749,3 +756,11 @@
         """
         logging.info('Pinging from the %s.', self.role)
         return self._ping_runner.ping(ping_config)
+
+
+    @property
+    def logdir(self):
+        """Return a directory for storing temporary logs.
+        @return string path to temporary log directory.
+        """
+        return self._logdir