1# Copyright 2015 gRPC authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import urllib
16import jobset
17import logging
18import os
19import socket
20import subprocess
21import sys
22import tempfile
23import time
24
25# must be synchronized with test/core/utils/port_server_client.h
26_PORT_SERVER_PORT = 32766
27
28
29def start_port_server():
30    # check if a compatible port server is running
31    # if incompatible (version mismatch) ==> start a new one
32    # if not running ==> start a new one
33    # otherwise, leave it up
34    try:
35        version = int(
36            urllib.urlopen('http://localhost:%d/version_number' %
37                           _PORT_SERVER_PORT).read())
38        logging.info('detected port server running version %d', version)
39        running = True
40    except Exception as e:
41        logging.exception('failed to detect port server')
42        running = False
43    if running:
44        current_version = int(
45            subprocess.check_output([
46                sys.executable,
47                os.path.abspath('tools/run_tests/python_utils/port_server.py'),
48                'dump_version'
49            ]))
50        logging.info('my port server is version %d', current_version)
51        running = (version >= current_version)
52        if not running:
53            logging.info('port_server version mismatch: killing the old one')
54            urllib.urlopen(
55                'http://localhost:%d/quitquitquit' % _PORT_SERVER_PORT).read()
56            time.sleep(1)
57    if not running:
58        fd, logfile = tempfile.mkstemp()
59        os.close(fd)
60        logging.info('starting port_server, with log file %s', logfile)
61        args = [
62            sys.executable,
63            os.path.abspath('tools/run_tests/python_utils/port_server.py'),
64            '-p',
65            '%d' % _PORT_SERVER_PORT, '-l', logfile
66        ]
67        env = dict(os.environ)
68        env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
69        if jobset.platform_string() == 'windows':
70            # Working directory of port server needs to be outside of Jenkins
71            # workspace to prevent file lock issues.
72            tempdir = tempfile.mkdtemp()
73            port_server = subprocess.Popen(
74                args,
75                env=env,
76                cwd=tempdir,
77                creationflags=0x00000008,  # detached process
78                close_fds=True)
79        else:
80            port_server = subprocess.Popen(
81                args, env=env, preexec_fn=os.setsid, close_fds=True)
82        time.sleep(1)
83        # ensure port server is up
84        waits = 0
85        while True:
86            if waits > 10:
87                logging.warning(
88                    'killing port server due to excessive start up waits')
89                port_server.kill()
90            if port_server.poll() is not None:
91                logging.error('port_server failed to start')
92                # try one final time: maybe another build managed to start one
93                time.sleep(1)
94                try:
95                    urllib.urlopen(
96                        'http://localhost:%d/get' % _PORT_SERVER_PORT).read()
97                    logging.info(
98                        'last ditch attempt to contact port server succeeded')
99                    break
100                except:
101                    logging.exception(
102                        'final attempt to contact port server failed')
103                    port_log = open(logfile, 'r').read()
104                    print port_log
105                    sys.exit(1)
106            try:
107                port_server_url = 'http://localhost:%d/get' % _PORT_SERVER_PORT
108                urllib.urlopen(port_server_url).read()
109                logging.info('port server is up and ready')
110                break
111            except socket.timeout:
112                logging.exception('while waiting for port_server')
113                time.sleep(1)
114                waits += 1
115            except IOError:
116                logging.exception('while waiting for port_server')
117                time.sleep(1)
118                waits += 1
119            except:
120                logging.exception('error while contacting port server at "%s".'
121                                  'Will try killing it.', port_server_url)
122                port_server.kill()
123                raise
124