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