Merge branch '19830-pysdk-util-docs'
[arvados.git] / sdk / python / tests / run_test_server.py
index 1a146e26d50ad5d12cda9728414e1dac25050b00..787837b72334cbd58f52981d9b1d45ee216bdffb 100644 (file)
@@ -2,23 +2,18 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-from __future__ import print_function
-from __future__ import division
-from builtins import str
-from builtins import range
 import argparse
 import atexit
 import errno
 import glob
 import httplib2
 import os
-import pipes
 import random
 import re
+import shlex
 import shutil
 import signal
 import socket
-import string
 import subprocess
 import sys
 import tempfile
@@ -26,10 +21,7 @@ import time
 import unittest
 import yaml
 
-try:
-    from urllib.parse import urlparse
-except ImportError:
-    from urlparse import urlparse
+from urllib.parse import urlparse
 
 MY_DIRNAME = os.path.dirname(os.path.realpath(__file__))
 if __name__ == '__main__' and os.path.exists(
@@ -41,6 +33,15 @@ if __name__ == '__main__' and os.path.exists(
 import arvados
 import arvados.config
 
+# This module starts subprocesses and records them in pidfiles so they
+# can be managed by other processes (incl. after this process
+# exits). But if we don't keep a reference to each subprocess object
+# somewhere, the subprocess destructor runs, and we get a lot of
+# ResourceWarning noise in test logs. This is our bucket of subprocess
+# objects whose destructors we don't want to run but are otherwise
+# unneeded.
+_detachedSubprocesses = []
+
 ARVADOS_DIR = os.path.realpath(os.path.join(MY_DIRNAME, '../../..'))
 SERVICES_SRC_DIR = os.path.join(ARVADOS_DIR, 'services')
 
@@ -248,14 +249,17 @@ def _logfilename(label):
         stdbuf+['cat', fifo],
         stdin=open('/dev/null'),
         stdout=subprocess.PIPE)
+    _detachedSubprocesses.append(cat)
     tee = subprocess.Popen(
         stdbuf+['tee', '-a', logfilename],
         stdin=cat.stdout,
         stdout=subprocess.PIPE)
-    subprocess.Popen(
+    _detachedSubprocesses.append(tee)
+    sed = subprocess.Popen(
         stdbuf+['sed', '-e', 's/^/['+label+'] /'],
         stdin=tee.stdout,
         stdout=sys.stderr)
+    _detachedSubprocesses.append(sed)
     return fifo
 
 def run(leave_running_atexit=False):
@@ -338,7 +342,7 @@ def run(leave_running_atexit=False):
     resdir = subprocess.check_output(['bundle', 'exec', 'passenger-config', 'about', 'resourcesdir']).decode().rstrip()
     with open(resdir + '/templates/standalone/config.erb') as f:
         template = f.read()
-    newtemplate = re.sub('http {', 'http {\n        passenger_stat_throttle_rate 0;', template)
+    newtemplate = re.sub(r'http \{', 'http {\n        passenger_stat_throttle_rate 0;', template)
     if newtemplate == template:
         raise "template edit failed"
     with open('tmp/passenger-nginx.conf.erb', 'w') as f:
@@ -361,14 +365,13 @@ def run(leave_running_atexit=False):
         '--no-friendly-error-pages',
         '--disable-anonymous-telemetry',
         '--disable-security-update-check',
-        '--no-compile-runtime',
-        '--no-install-runtime',
          '--pid-file', pid_file,
          '--log-file', '/dev/stdout',
          '--ssl',
          '--ssl-certificate', 'tmp/self-signed.pem',
          '--ssl-certificate-key', 'tmp/self-signed.key'],
         env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
+    _detachedSubprocesses.append(railsapi)
 
     if not leave_running_atexit:
         atexit.register(kill_server_pid, pid_file, passenger_root=api_src_dir)
@@ -446,6 +449,7 @@ def run_controller():
     controller = subprocess.Popen(
         ["arvados-server", "controller"],
         stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
+    _detachedSubprocesses.append(controller)
     with open(_pidfile('controller'), 'w') as f:
         f.write(str(controller.pid))
     _wait_until_port_listens(port)
@@ -465,6 +469,7 @@ def run_ws():
     ws = subprocess.Popen(
         ["arvados-server", "ws"],
         stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
+    _detachedSubprocesses.append(ws)
     with open(_pidfile('ws'), 'w') as f:
         f.write(str(ws.pid))
     _wait_until_port_listens(port)
@@ -498,6 +503,7 @@ def _start_keep(n, blob_signing=False):
         with open('/dev/null') as _stdin:
             child = subprocess.Popen(
                 keep_cmd, stdin=_stdin, stdout=logf, stderr=logf, close_fds=True)
+            _detachedSubprocesses.append(child)
 
     print('child.pid is %d'%child.pid, file=sys.stderr)
     with open(_pidfile('keep{}'.format(n)), 'w') as f:
@@ -537,7 +543,7 @@ def run_keep(num_servers=2, **kwargs):
     # If keepproxy and/or keep-web is running, send SIGHUP to make
     # them discover the new keepstore services.
     for svc in ('keepproxy', 'keep-web'):
-        pidfile = _pidfile('keepproxy')
+        pidfile = _pidfile(svc)
         if os.path.exists(pidfile):
             try:
                 with open(pidfile) as pid:
@@ -563,7 +569,8 @@ def run_keep_proxy():
     env['ARVADOS_API_TOKEN'] = auth_token('anonymous')
     logf = open(_logfilename('keepproxy'), WRITE_MODE)
     kp = subprocess.Popen(
-        ['keepproxy'], env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
+        ['arvados-server', 'keepproxy'], env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf, close_fds=True)
+    _detachedSubprocesses.append(kp)
 
     with open(_pidfile('keepproxy'), 'w') as f:
         f.write(str(kp.pid))
@@ -600,17 +607,18 @@ def run_arv_git_httpd():
     gitport = internal_port_from_config("GitHTTP")
     env = os.environ.copy()
     env.pop('ARVADOS_API_TOKEN', None)
-    logf = open(_logfilename('arv-git-httpd'), WRITE_MODE)
-    agh = subprocess.Popen(['arv-git-httpd'],
+    logf = open(_logfilename('githttpd'), WRITE_MODE)
+    agh = subprocess.Popen(['arvados-server', 'git-httpd'],
         env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
-    with open(_pidfile('arv-git-httpd'), 'w') as f:
+    _detachedSubprocesses.append(agh)
+    with open(_pidfile('githttpd'), 'w') as f:
         f.write(str(agh.pid))
     _wait_until_port_listens(gitport)
 
 def stop_arv_git_httpd():
     if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
         return
-    kill_server_pid(_pidfile('arv-git-httpd'))
+    kill_server_pid(_pidfile('githttpd'))
 
 def run_keep_web():
     if 'ARVADOS_TEST_PROXY_SERVICES' in os.environ:
@@ -621,8 +629,9 @@ def run_keep_web():
     env = os.environ.copy()
     logf = open(_logfilename('keep-web'), WRITE_MODE)
     keepweb = subprocess.Popen(
-        ['keep-web'],
+        ['arvados-server', 'keep-web'],
         env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
+    _detachedSubprocesses.append(keepweb)
     with open(_pidfile('keep-web'), 'w') as f:
         f.write(str(keepweb.pid))
     _wait_until_port_listens(keepwebport)
@@ -637,7 +646,8 @@ def run_nginx():
         return
     stop_nginx()
     nginxconf = {}
-    nginxconf['LISTENHOST'] = 'localhost'
+    nginxconf['UPSTREAMHOST'] = '127.0.0.1'
+    nginxconf['LISTENHOST'] = '127.0.0.1'
     nginxconf['CONTROLLERPORT'] = internal_port_from_config("Controller")
     nginxconf['ARVADOS_API_HOST'] = "0.0.0.0:" + str(external_port_from_config("Controller"))
     nginxconf['CONTROLLERSSLPORT'] = external_port_from_config("Controller")
@@ -652,7 +662,6 @@ def run_nginx():
     nginxconf['HEALTHSSLPORT'] = external_port_from_config("Health")
     nginxconf['WSPORT'] = internal_port_from_config("Websocket")
     nginxconf['WSSSLPORT'] = external_port_from_config("Websocket")
-    nginxconf['WORKBENCH1PORT'] = internal_port_from_config("Workbench1")
     nginxconf['WORKBENCH1SSLPORT'] = external_port_from_config("Workbench1")
     nginxconf['WORKBENCH2PORT'] = internal_port_from_config("Workbench2")
     nginxconf['WORKBENCH2SSLPORT'] = external_port_from_config("Workbench2")
@@ -661,6 +670,7 @@ def run_nginx():
     nginxconf['ACCESSLOG'] = _logfilename('nginx_access')
     nginxconf['ERRORLOG'] = _logfilename('nginx_error')
     nginxconf['TMPDIR'] = TEST_TMPDIR + '/nginx'
+    nginxconf['INTERNALSUBNETS'] = '169.254.0.0/16 0;'
 
     conftemplatefile = os.path.join(MY_DIRNAME, 'nginx.conf')
     conffile = os.path.join(TEST_TMPDIR, 'nginx.conf')
@@ -678,6 +688,7 @@ def run_nginx():
          '-g', 'error_log stderr info; pid '+_pidfile('nginx')+';',
          '-c', conffile],
         env=env, stdin=open('/dev/null'), stdout=sys.stderr)
+    _detachedSubprocesses.append(nginx)
     _wait_until_port_listens(nginxconf['CONTROLLERSSLPORT'])
 
 def setup_config():
@@ -686,7 +697,6 @@ def setup_config():
     controller_external_port = find_available_port()
     websocket_port = find_available_port()
     websocket_external_port = find_available_port()
-    workbench1_port = find_available_port()
     workbench1_external_port = find_available_port()
     workbench2_port = find_available_port()
     workbench2_external_port = find_available_port()
@@ -699,7 +709,6 @@ def setup_config():
     keepstore_ports = sorted([str(find_available_port()) for _ in range(0,4)])
     keep_web_port = find_available_port()
     keep_web_external_port = find_available_port()
-    keep_web_dl_port = find_available_port()
     keep_web_dl_external_port = find_available_port()
 
     configsrc = os.environ.get("CONFIGSRC", None)
@@ -739,9 +748,6 @@ def setup_config():
         },
         "Workbench1": {
             "ExternalURL": "https://%s:%s/" % (localhost, workbench1_external_port),
-            "InternalURLs": {
-                "http://%s:%s"%(localhost, workbench1_port): {},
-            },
         },
         "Workbench2": {
             "ExternalURL": "https://%s:%s/" % (localhost, workbench2_external_port),
@@ -781,7 +787,7 @@ def setup_config():
         "WebDAVDownload": {
             "ExternalURL": "https://%s:%s" % (localhost, keep_web_dl_external_port),
             "InternalURLs": {
-                "http://%s:%s"%(localhost, keep_web_dl_port): {},
+                "http://%s:%s"%(localhost, keep_web_port): {},
             },
         },
     }
@@ -793,6 +799,7 @@ def setup_config():
                 "SystemRootToken": auth_token('system_user'),
                 "API": {
                     "RequestTimeout": "30s",
+                    "LockBeforeUpdate": True,
                 },
                 "Login": {
                     "Test": {
@@ -833,6 +840,10 @@ def setup_config():
                     "JobsAPI": {
                         "GitInternalDir": os.path.join(SERVICES_SRC_DIR, 'api', 'tmp', 'internal.git'),
                     },
+                    "LocalKeepBlobBuffersPerVCPU": 0,
+                    "Logging": {
+                        "SweepInterval": 0, # disable, otherwise test cases can't acquire dblock
+                    },
                     "SupportedDockerImageFormats": {"v1": {}},
                     "ShellAccess": {
                         "Admin": True,
@@ -926,7 +937,6 @@ class TestCaseWithServers(unittest.TestCase):
         cls._orig_config = arvados.config.settings().copy()
         cls._cleanup_funcs = []
         os.environ.pop('ARVADOS_KEEP_SERVICES', None)
-        os.environ.pop('ARVADOS_EXTERNAL_CLIENT', None)
         for server_kwargs, start_func, stop_func in (
                 (cls.MAIN_SERVER, run, reset),
                 (cls.WS_SERVER, run_ws, stop_ws),
@@ -961,7 +971,7 @@ if __name__ == "__main__":
         'start_keep', 'stop_keep',
         'start_keep_proxy', 'stop_keep_proxy',
         'start_keep-web', 'stop_keep-web',
-        'start_arv-git-httpd', 'stop_arv-git-httpd',
+        'start_githttpd', 'stop_githttpd',
         'start_nginx', 'stop_nginx', 'setup_config',
     ]
     parser = argparse.ArgumentParser()
@@ -977,14 +987,17 @@ if __name__ == "__main__":
               format(args.action, actions),
               file=sys.stderr)
         sys.exit(1)
+    # Create a new process group so our child processes don't exit on
+    # ^C in run-tests.sh interactive mode.
+    os.setpgid(0, 0)
     if args.action == 'start':
         stop(force=('ARVADOS_TEST_API_HOST' not in os.environ))
         run(leave_running_atexit=True)
         host = os.environ['ARVADOS_API_HOST']
         if args.auth is not None:
             token = auth_token(args.auth)
-            print("export ARVADOS_API_TOKEN={}".format(pipes.quote(token)))
-            print("export ARVADOS_API_HOST={}".format(pipes.quote(host)))
+            print("export ARVADOS_API_TOKEN={}".format(shlex.quote(token)))
+            print("export ARVADOS_API_HOST={}".format(shlex.quote(host)))
             print("export ARVADOS_API_HOST_INSECURE=true")
         else:
             print(host)
@@ -1006,9 +1019,9 @@ if __name__ == "__main__":
         run_keep_proxy()
     elif args.action == 'stop_keep_proxy':
         stop_keep_proxy()
-    elif args.action == 'start_arv-git-httpd':
+    elif args.action == 'start_githttpd':
         run_arv_git_httpd()
-    elif args.action == 'stop_arv-git-httpd':
+    elif args.action == 'stop_githttpd':
         stop_arv_git_httpd()
     elif args.action == 'start_keep-web':
         run_keep_web()