• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15from __future__ import print_function
16
17import logging
18import os
19import socket
20import subprocess
21import sys
22import tempfile
23import time
24
25import six.moves.urllib.request as request
26
27sys.path.append(os.path.dirname(os.path.abspath(__file__)))
28import jobset
29
30# must be synchronized with test/core/test_util/port_server_client.h
31_PORT_SERVER_PORT = 32766
32
33
34def start_port_server(verbose=False):
35    # check if a compatible port server is running
36    # if incompatible (version mismatch) ==> start a new one
37    # if not running ==> start a new one
38    # otherwise, leave it up
39    try:
40        version = int(
41            request.urlopen(
42                "http://localhost:%d/version_number" % _PORT_SERVER_PORT
43            ).read()
44        )
45        logging.info("detected port server running version %d", version)
46        running = True
47    except Exception as e:
48        if verbose:
49            logging.exception("failed to detect port server")
50        running = False
51    if running:
52        current_version = int(
53            subprocess.check_output(
54                [
55                    sys.executable,  # use the same python binary as this process
56                    os.path.abspath(
57                        "tools/run_tests/python_utils/port_server.py"
58                    ),
59                    "dump_version",
60                ]
61            ).decode()
62        )
63        logging.info("my port server is version %d", current_version)
64        running = version >= current_version
65        if not running:
66            logging.info("port_server version mismatch: killing the old one")
67            request.urlopen(
68                "http://localhost:%d/quitquitquit" % _PORT_SERVER_PORT
69            ).read()
70            time.sleep(1)
71    if not running:
72        fd, logfile = tempfile.mkstemp()
73        os.close(fd)
74        logging.info("starting port_server, with log file %s", logfile)
75        args = [
76            sys.executable,
77            os.path.abspath("tools/run_tests/python_utils/port_server.py"),
78            "-p",
79            "%d" % _PORT_SERVER_PORT,
80            "-l",
81            logfile,
82        ]
83        env = dict(os.environ)
84        env["BUILD_ID"] = "pleaseDontKillMeJenkins"
85        if jobset.platform_string() == "windows":
86            # Working directory of port server needs to be outside of Jenkins
87            # workspace to prevent file lock issues.
88            tempdir = tempfile.mkdtemp()
89            if sys.version_info.major == 2:
90                creationflags = 0x00000008  # detached process
91            else:
92                creationflags = (
93                    0  # DETACHED_PROCESS doesn't seem to work with python3
94                )
95            port_server = subprocess.Popen(
96                args,
97                env=env,
98                cwd=tempdir,
99                creationflags=creationflags,
100                close_fds=True,
101            )
102        else:
103            port_server = subprocess.Popen(
104                args, env=env, preexec_fn=os.setsid, close_fds=True
105            )
106        time.sleep(1)
107        # ensure port server is up
108        waits = 0
109        while True:
110            if waits > 10:
111                logging.warning(
112                    "killing port server due to excessive start up waits"
113                )
114                port_server.kill()
115            if port_server.poll() is not None:
116                logging.error("port_server failed to start")
117                # try one final time: maybe another build managed to start one
118                time.sleep(1)
119                try:
120                    request.urlopen(
121                        "http://localhost:%d/get" % _PORT_SERVER_PORT
122                    ).read()
123                    logging.info(
124                        "last ditch attempt to contact port server succeeded"
125                    )
126                    break
127                except:
128                    logging.exception(
129                        "final attempt to contact port server failed"
130                    )
131                    port_log = open(logfile, "r").read()
132                    print(port_log)
133                    sys.exit(1)
134            try:
135                port_server_url = "http://localhost:%d/get" % _PORT_SERVER_PORT
136                request.urlopen(port_server_url).read()
137                logging.info("port server is up and ready")
138                break
139            except socket.timeout:
140                logging.exception("while waiting for port_server")
141                time.sleep(1)
142                waits += 1
143            except IOError:
144                logging.exception("while waiting for port_server")
145                time.sleep(1)
146                waits += 1
147            except:
148                logging.exception(
149                    (
150                        'error while contacting port server at "%s".'
151                        "Will try killing it."
152                    ),
153                    port_server_url,
154                )
155                port_server.kill()
156                raise
157